aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco')
-rw-r--r--lib/megaco/AUTHORS10
-rw-r--r--lib/megaco/Makefile198
-rw-r--r--lib/megaco/configure.in262
-rw-r--r--lib/megaco/doc/html/.gitignore0
-rw-r--r--lib/megaco/doc/man3/.gitignore0
-rw-r--r--lib/megaco/doc/pdf/.gitignore0
-rw-r--r--lib/megaco/doc/src/MG-startup_flow_noMID.fig77
-rw-r--r--lib/megaco/doc/src/MG-startup_flow_noMID.gifbin0 -> 5663 bytes
-rw-r--r--lib/megaco/doc/src/MG-startup_flow_noMID.ps267
-rw-r--r--lib/megaco/doc/src/MGC_startup_call_flow.gifbin0 -> 3317 bytes
-rw-r--r--lib/megaco/doc/src/MGC_startup_call_flow.ps217
-rw-r--r--lib/megaco/doc/src/MG_startup_call_flow.gifbin0 -> 4560 bytes
-rw-r--r--lib/megaco/doc/src/MG_startup_call_flow.ps250
-rw-r--r--lib/megaco/doc/src/Makefile289
-rw-r--r--lib/megaco/doc/src/book.gifbin0 -> 1081 bytes
-rw-r--r--lib/megaco/doc/src/book.xml48
-rw-r--r--lib/megaco/doc/src/call_flow.gifbin0 -> 4673 bytes
-rw-r--r--lib/megaco/doc/src/call_flow.ps253
-rw-r--r--lib/megaco/doc/src/call_flow_cont.gifbin0 -> 4738 bytes
-rw-r--r--lib/megaco/doc/src/call_flow_cont.ps271
-rw-r--r--lib/megaco/doc/src/definitions/cite.defs26
-rw-r--r--lib/megaco/doc/src/definitions/cite.defs.xml70
-rw-r--r--lib/megaco/doc/src/definitions/term.defs215
-rw-r--r--lib/megaco/doc/src/definitions/term.defs.xml1525
-rw-r--r--lib/megaco/doc/src/distr_node_config.gifbin0 -> 4992 bytes
-rw-r--r--lib/megaco/doc/src/distr_node_config.ps20151
-rw-r--r--lib/megaco/doc/src/fascicules.xml18
-rw-r--r--lib/megaco/doc/src/files.mk73
-rw-r--r--lib/megaco/doc/src/index.html.src112
-rw-r--r--lib/megaco/doc/src/make.dep59
-rw-r--r--lib/megaco/doc/src/meas.log132
-rw-r--r--lib/megaco/doc/src/megaco.xml2173
-rw-r--r--lib/megaco/doc/src/megaco_architecture.xml187
-rw-r--r--lib/megaco/doc/src/megaco_codec_meas.xml61
-rw-r--r--lib/megaco/doc/src/megaco_codec_mstone1.xml131
-rw-r--r--lib/megaco/doc/src/megaco_codec_mstone2.xml66
-rw-r--r--lib/megaco/doc/src/megaco_codec_transform.xml70
-rw-r--r--lib/megaco/doc/src/megaco_debug.xml271
-rw-r--r--lib/megaco/doc/src/megaco_edist_compress.xml69
-rw-r--r--lib/megaco/doc/src/megaco_encode.xml498
-rw-r--r--lib/megaco/doc/src/megaco_encoder.xml209
-rw-r--r--lib/megaco/doc/src/megaco_examples.xml104
-rw-r--r--lib/megaco/doc/src/megaco_flex_scanner.xml157
-rw-r--r--lib/megaco/doc/src/megaco_intro.xml168
-rw-r--r--lib/megaco/doc/src/megaco_mib.xml67
-rw-r--r--lib/megaco/doc/src/megaco_performance.xml328
-rw-r--r--lib/megaco/doc/src/megaco_run.xml373
-rw-r--r--lib/megaco/doc/src/megaco_sys_arch.gifbin0 -> 7270 bytes
-rw-r--r--lib/megaco/doc/src/megaco_sys_arch.ps18674
-rw-r--r--lib/megaco/doc/src/megaco_tcp.xml188
-rw-r--r--lib/megaco/doc/src/megaco_transport.xml141
-rw-r--r--lib/megaco/doc/src/megaco_transport_mechanisms.xml65
-rw-r--r--lib/megaco/doc/src/megaco_udp.xml195
-rw-r--r--lib/megaco/doc/src/megaco_user.xml738
-rw-r--r--lib/megaco/doc/src/mstone1-s8flex.log234
-rw-r--r--lib/megaco/doc/src/mstone1.gifbin0 -> 30004 bytes
-rw-r--r--lib/megaco/doc/src/mstone1.jpgbin0 -> 17845 bytes
-rw-r--r--lib/megaco/doc/src/mstone1.pngbin0 -> 53099 bytes
-rw-r--r--lib/megaco/doc/src/mstone1.ps1959
-rw-r--r--lib/megaco/doc/src/note.gifbin0 -> 1539 bytes
-rw-r--r--lib/megaco/doc/src/notes.gifbin0 -> 2005 bytes
-rw-r--r--lib/megaco/doc/src/notes.xml1167
-rw-r--r--lib/megaco/doc/src/notes_history.xml3365
-rw-r--r--lib/megaco/doc/src/part.xml45
-rw-r--r--lib/megaco/doc/src/part_notes.xml39
-rw-r--r--lib/megaco/doc/src/part_notes_history.xml40
-rw-r--r--lib/megaco/doc/src/ref_man.gifbin0 -> 1530 bytes
-rw-r--r--lib/megaco/doc/src/ref_man.xml48
-rw-r--r--lib/megaco/doc/src/single_node_config.gifbin0 -> 3043 bytes
-rw-r--r--lib/megaco/doc/src/single_node_config.ps10881
-rw-r--r--lib/megaco/doc/src/user_guide.gifbin0 -> 1581 bytes
-rw-r--r--lib/megaco/doc/src/warning.gifbin0 -> 1498 bytes
-rw-r--r--lib/megaco/doc/standard/H.248.1-Corr1-200403.docbin0 -> 296448 bytes
-rw-r--r--lib/megaco/doc/standard/draft-ietf-megaco-h248v2-04.txt12079
-rw-r--r--lib/megaco/doc/standard/implementors_guide_v10-13.pdfbin0 -> 219014 bytes
-rw-r--r--lib/megaco/doc/standard/rfc2327.txt2355
-rw-r--r--lib/megaco/doc/standard/rfc3266.txt283
-rw-r--r--lib/megaco/doc/standard/rfc3525.txt11931
-rw-r--r--lib/megaco/doc/standard/rfc4234.txt899
-rw-r--r--lib/megaco/doc/standard/rfc4566.txt2747
-rw-r--r--lib/megaco/ebin/.gitignore0
-rw-r--r--lib/megaco/examples/meas/Makefile132
-rw-r--r--lib/megaco/examples/meas/meas.sh.skel41
-rw-r--r--lib/megaco/examples/meas/megaco_codec_meas.erl655
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone1.erl408
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone2.erl400
-rw-r--r--lib/megaco/examples/meas/megaco_codec_mstone_lib.erl534
-rw-r--r--lib/megaco/examples/meas/megaco_codec_transform.erl305
-rw-r--r--lib/megaco/examples/meas/modules.mk35
-rw-r--r--lib/megaco/examples/meas/mstone1.sh.skel239
-rw-r--r--lib/megaco/examples/meas/time_test.msgs149
-rw-r--r--lib/megaco/examples/simple/Makefile153
-rw-r--r--lib/megaco/examples/simple/megaco_simple_mg.erl437
-rw-r--r--lib/megaco/examples/simple/megaco_simple_mgc.erl455
-rw-r--r--lib/megaco/examples/simple/modules.mk27
-rw-r--r--lib/megaco/include/megaco.hrl333
-rw-r--r--lib/megaco/include/megaco_message_prev3a.hrl599
-rw-r--r--lib/megaco/include/megaco_message_prev3b.hrl599
-rw-r--r--lib/megaco/include/megaco_message_prev3c.hrl784
-rw-r--r--lib/megaco/include/megaco_message_v1.hrl439
-rw-r--r--lib/megaco/include/megaco_message_v2.hrl561
-rw-r--r--lib/megaco/include/megaco_message_v3.hrl779
-rw-r--r--lib/megaco/include/megaco_sdp.hrl1471
-rw-r--r--lib/megaco/info5
-rw-r--r--lib/megaco/prebuild.skip2
-rw-r--r--lib/megaco/priv/lib/.gitignore0
-rw-r--r--lib/megaco/src/Makefile37
-rw-r--r--lib/megaco/src/app/Makefile129
-rw-r--r--lib/megaco/src/app/depend.mk22
-rw-r--r--lib/megaco/src/app/megaco.app.src143
-rw-r--r--lib/megaco/src/app/megaco.appup.src165
-rw-r--r--lib/megaco/src/app/megaco.erl1017
-rw-r--r--lib/megaco/src/app/megaco.mk56
-rw-r--r--lib/megaco/src/app/megaco_internal.hrl183
-rw-r--r--lib/megaco/src/app/modules.mk36
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn1001
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn1001
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn1073
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn982
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn966
-rw-r--r--lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn1068
-rw-r--r--lib/megaco/src/binary/Makefile212
-rw-r--r--lib/megaco/src/binary/depend.mk557
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config44
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_encoder.erl716
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config44
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config43
-rw-r--r--lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_encoder.erl346
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder.erl588
-rw-r--r--lib/megaco/src/binary/megaco_binary_encoder_lib.erl317
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl2003
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl2003
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl2004
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl1613
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl1681
-rw-r--r--lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl2016
-rw-r--r--lib/megaco/src/binary/megaco_binary_term_id.erl187
-rw-r--r--lib/megaco/src/binary/megaco_binary_term_id_gen.erl436
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl1629
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl1629
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl1756
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v1.erl1261
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v2.erl1544
-rw-r--r--lib/megaco/src/binary/megaco_binary_transformer_v3.erl1763
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_encoder.erl447
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_encoder.erl291
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn1
-rw-r--r--lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn1
-rw-r--r--lib/megaco/src/binary/modules.mk128
-rw-r--r--lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl319
-rw-r--r--lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl255
-rw-r--r--lib/megaco/src/engine/Makefile107
-rw-r--r--lib/megaco/src/engine/depend.mk81
-rw-r--r--lib/megaco/src/engine/megaco_config.erl2113
-rw-r--r--lib/megaco/src/engine/megaco_digit_map.erl856
-rw-r--r--lib/megaco/src/engine/megaco_edist_compress.erl33
-rw-r--r--lib/megaco/src/engine/megaco_encoder.erl37
-rw-r--r--lib/megaco/src/engine/megaco_erl_dist_encoder.erl275
-rw-r--r--lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl1894
-rw-r--r--lib/megaco/src/engine/megaco_filter.erl350
-rw-r--r--lib/megaco/src/engine/megaco_message_internal.hrl159
-rw-r--r--lib/megaco/src/engine/megaco_messenger.erl5158
-rw-r--r--lib/megaco/src/engine/megaco_messenger_misc.erl409
-rw-r--r--lib/megaco/src/engine/megaco_misc_sup.erl77
-rw-r--r--lib/megaco/src/engine/megaco_monitor.erl365
-rw-r--r--lib/megaco/src/engine/megaco_sdp.erl1645
-rw-r--r--lib/megaco/src/engine/megaco_stats.erl207
-rw-r--r--lib/megaco/src/engine/megaco_sup.erl116
-rw-r--r--lib/megaco/src/engine/megaco_timer.erl117
-rw-r--r--lib/megaco/src/engine/megaco_trans_sender.erl699
-rw-r--r--lib/megaco/src/engine/megaco_trans_sup.erl88
-rw-r--r--lib/megaco/src/engine/megaco_transport.erl32
-rw-r--r--lib/megaco/src/engine/megaco_user_default.erl185
-rw-r--r--lib/megaco/src/engine/modules.mk47
-rw-r--r--lib/megaco/src/flex/Makefile43
-rw-r--r--lib/megaco/src/flex/Makefile.in396
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner.erl230
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src1943
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_handler.erl232
-rw-r--r--lib/megaco/src/flex/modules.mk27
-rw-r--r--lib/megaco/src/flex/prebuild.skip1
-rw-r--r--lib/megaco/src/rules.mk100
-rw-r--r--lib/megaco/src/subdirs.mk21
-rw-r--r--lib/megaco/src/tcp/Makefile107
-rw-r--r--lib/megaco/src/tcp/depend.mk42
-rw-r--r--lib/megaco/src/tcp/megaco_tcp.erl692
-rw-r--r--lib/megaco/src/tcp/megaco_tcp.hrl68
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_accept.erl123
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_accept_sup.erl95
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_connection.erl275
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_connection_sup.erl114
-rw-r--r--lib/megaco/src/tcp/megaco_tcp_sup.erl145
-rw-r--r--lib/megaco/src/tcp/modules.mk33
-rw-r--r--lib/megaco/src/text/Makefile148
-rw-r--r--lib/megaco/src/text/depend.mk187
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder.erl560
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl297
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl432
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl455
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v1.erl407
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v2.erl413
-rw-r--r--lib/megaco/src/text/megaco_compact_text_encoder_v3.erl455
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder.erl613
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl303
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl437
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl483
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl407
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl430
-rw-r--r--lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl462
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3a.hrl2945
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3b.hrl2966
-rw-r--r--lib/megaco/src/text/megaco_text_gen_prev3c.hrl3443
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v1.hrl2404
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v2.hrl2794
-rw-r--r--lib/megaco/src/text/megaco_text_gen_v3.hrl3457
-rw-r--r--lib/megaco/src/text/megaco_text_mini_decoder.erl88
-rw-r--r--lib/megaco/src/text/megaco_text_mini_parser.hrl1246
-rw-r--r--lib/megaco/src/text/megaco_text_mini_parser.yrl398
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3a.hrl1670
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3a.yrl1591
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3b.hrl1717
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3b.yrl1601
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3c.hrl1980
-rw-r--r--lib/megaco/src/text/megaco_text_parser_prev3c.yrl1673
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v1.hrl1410
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v1.yrl1364
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v2.hrl1643
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v2.yrl1538
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v3.hrl2002
-rw-r--r--lib/megaco/src/text/megaco_text_parser_v3.yrl1680
-rw-r--r--lib/megaco/src/text/megaco_text_scanner.erl869
-rw-r--r--lib/megaco/src/text/megaco_text_tokens.hrl475
-rw-r--r--lib/megaco/src/text/modules.mk65
-rw-r--r--lib/megaco/src/udp/Makefile117
-rw-r--r--lib/megaco/src/udp/megaco_udp.erl324
-rw-r--r--lib/megaco/src/udp/megaco_udp.hrl64
-rw-r--r--lib/megaco/src/udp/megaco_udp_server.erl234
-rw-r--r--lib/megaco/src/udp/megaco_udp_sup.erl112
-rw-r--r--lib/megaco/src/udp/modules.mk30
-rw-r--r--lib/megaco/subdirs.mk21
-rw-r--r--lib/megaco/test/Makefile611
-rw-r--r--lib/megaco/test/megaco.cover70
-rw-r--r--lib/megaco/test/megaco.spec5
-rw-r--r--lib/megaco/test/megaco.spec.vxworks5
-rw-r--r--lib/megaco/test/megaco_SUITE.erl142
-rw-r--r--lib/megaco/test/megaco_actions_test.erl446
-rw-r--r--lib/megaco/test/megaco_app_test.erl308
-rw-r--r--lib/megaco/test/megaco_appup_mg.erl198
-rw-r--r--lib/megaco/test/megaco_appup_mgc.erl107
-rw-r--r--lib/megaco/test/megaco_appup_test.erl516
-rw-r--r--lib/megaco/test/megaco_binary_term_id_test.erl1012
-rw-r--r--lib/megaco/test/megaco_call_flow_test.erl1767
-rw-r--r--lib/megaco/test/megaco_codec_flex_lib.erl174
-rw-r--r--lib/megaco/test/megaco_codec_mini_test.erl220
-rw-r--r--lib/megaco/test/megaco_codec_prev3a_test.erl7350
-rw-r--r--lib/megaco/test/megaco_codec_prev3b_test.erl7828
-rw-r--r--lib/megaco/test/megaco_codec_prev3c_test.erl8336
-rw-r--r--lib/megaco/test/megaco_codec_test.erl63
-rw-r--r--lib/megaco/test/megaco_codec_test_lib.erl1024
-rw-r--r--lib/megaco/test/megaco_codec_v1_test.erl7305
-rw-r--r--lib/megaco/test/megaco_codec_v2_test.erl6992
-rw-r--r--lib/megaco/test/megaco_codec_v3_test.erl8479
-rw-r--r--lib/megaco/test/megaco_config_test.erl1110
-rw-r--r--lib/megaco/test/megaco_digit_map_test.erl637
-rw-r--r--lib/megaco/test/megaco_examples_test.erl174
-rw-r--r--lib/megaco/test/megaco_flex_test.erl230
-rw-r--r--lib/megaco/test/megaco_load_test.erl692
-rw-r--r--lib/megaco/test/megaco_mess_otp8212_test.erl181
-rw-r--r--lib/megaco/test/megaco_mess_test.erl13733
-rw-r--r--lib/megaco/test/megaco_mess_user_test.erl309
-rw-r--r--lib/megaco/test/megaco_mib_test.erl1619
-rw-r--r--lib/megaco/test/megaco_mreq_test.erl470
-rw-r--r--lib/megaco/test/megaco_pending_limit_test.erl2158
-rw-r--r--lib/megaco/test/megaco_profile.erl138
-rw-r--r--lib/megaco/test/megaco_sdp_test.erl1286
-rw-r--r--lib/megaco/test/megaco_segment_test.erl7819
-rw-r--r--lib/megaco/test/megaco_tc_controller.erl171
-rw-r--r--lib/megaco/test/megaco_tcp_test.erl1253
-rw-r--r--lib/megaco/test/megaco_test_deliver.erl188
-rw-r--r--lib/megaco/test/megaco_test_generator.erl549
-rw-r--r--lib/megaco/test/megaco_test_generator_lib.erl83
-rw-r--r--lib/megaco/test/megaco_test_generic_transport.erl354
-rw-r--r--lib/megaco/test/megaco_test_lib.erl841
-rw-r--r--lib/megaco/test/megaco_test_lib.hrl87
-rw-r--r--lib/megaco/test/megaco_test_megaco_generator.erl1120
-rw-r--r--lib/megaco/test/megaco_test_mg.erl1585
-rw-r--r--lib/megaco/test/megaco_test_mgc.erl1221
-rw-r--r--lib/megaco/test/megaco_test_msg_prev3a_lib.erl7503
-rw-r--r--lib/megaco/test/megaco_test_msg_prev3b_lib.erl7489
-rw-r--r--lib/megaco/test/megaco_test_msg_prev3c_lib.erl8643
-rw-r--r--lib/megaco/test/megaco_test_msg_v1_lib.erl7024
-rw-r--r--lib/megaco/test/megaco_test_msg_v2_lib.erl7037
-rw-r--r--lib/megaco/test/megaco_test_msg_v3_lib.erl8724
-rw-r--r--lib/megaco/test/megaco_test_tcp_generator.erl504
-rw-r--r--lib/megaco/test/megaco_timer_test.erl472
-rw-r--r--lib/megaco/test/megaco_trans_test.erl9401
-rw-r--r--lib/megaco/test/megaco_udp_test.erl1251
-rw-r--r--lib/megaco/test/modules.mk82
-rw-r--r--lib/megaco/vsn.mk144
342 files changed, 358591 insertions, 0 deletions
diff --git a/lib/megaco/AUTHORS b/lib/megaco/AUTHORS
new file mode 100644
index 0000000000..4cf1e961a0
--- /dev/null
+++ b/lib/megaco/AUTHORS
@@ -0,0 +1,10 @@
+Original Authors:
+
+ H�kan Mattsson
+ Lars Thorsen
+
+Contributors:
+
+
+
+
diff --git a/lib/megaco/Makefile b/lib/megaco/Makefile
new file mode 100644
index 0000000000..d4698eb558
--- /dev/null
+++ b/lib/megaco/Makefile
@@ -0,0 +1,198 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# --------------------------------------------------------------------
+# If downloading this app separately (not as part of
+# an OTP source release), then there is two ways to
+# build and install this app.
+# 1) Replace the megaco source dir in an existing
+# OTP source tree. Then re-configure, build and
+# install OTP.
+# Note that the directory name has to be renamed
+# from megaco-<version> to megaco.
+# 2) Unpack outside an OTP-source tree.
+# a) Configure app (make ERL_TOP=</path/to/top/OTP-source/dir> conf)
+# b) make ERL_TOP=</path/to/top/OTP-source/dir>
+# c) make ERL_TOP=</path/to/top/OTP-source/dir> \
+# OTP_INSTALL_DIR=</path/to/top/OTP-install/dir> app_install
+# (e.g. if otp is installed in /usr/local/otp-r9b,
+# then OTP_INSTALL_DIR is /usr/local/otp-r9b and
+# the app will be installed in dir
+# /usr/local/otp-r9b/lib/erlang/lib/megaco-<version>)
+# -----------------------------------------------------------------------
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include vsn.mk
+VSN=$(MEGACO_VSN)
+
+DIR_NAME = megaco_src-$(VSN)$(PRE_VSN)
+
+ifndef APP_RELEASE_DIR
+ ifndef TESTROOT
+ APP_RELEASE_DIR = /tmp
+ else
+ APP_RELEASE_DIR = $(TESTROOT)
+ endif
+endif
+
+ifndef APP_TAR_FILE
+ APP_TAR_FILE = $(APP_RELEASE_DIR)/$(DIR_NAME).tgz
+endif
+
+APP_DIR = $(APP_RELEASE_DIR)/$(DIR_NAME)
+
+ifdef OTP_INSTALL_DIR
+ APP_INSTALL_DIR = $(OTP_INSTALL_DIR)/lib/erlang
+else
+ # If installing into an OTP structure created
+ # by installing an source OTP build, the '/tmp'
+ # shall be replaced with the value of ERL_TOP
+ APP_INSTALL_DIR = /tmp/lib/erlang
+endif
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SUB_DIRECTORIES = $(SUB_DIRS) doc/src
+
+SPECIAL_TARGETS =
+
+ifeq ($(FLEX_SCANNER_LINENO),disable)
+ FLEX_SCANNER_LINENO_ENABLER = --disable-megaco-flex-scanner-lineno
+else
+ FLEX_SCANNER_LINENO_ENABLER = --enable-megaco-flex-scanner-lineno
+endif
+
+ifeq ($(FLEX_SCANNER_REENTRANT),disable)
+ FLEX_SCANNER_REENTRANT_ENABLER = --disable-megaco-reentrant-flex-scanner
+else
+ FLEX_SCANNER_REENTRANT_ENABLER = --enable-megaco-reentrant-flex-scanner
+endif
+
+CONFIGURE_OPTS = $(FLEX_SCANNER_LINENO_ENABLER) $(FLEX_SCANNER_REENTRANT_ENABLER)
+
+
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+reconf:
+ (cd $(ERL_TOP) && \
+ ./otp_build autoconf && \
+ ./otp_build configure && \
+ cd $(ERL_TOP)/../libraries/megaco)
+
+conf: do_configure
+
+dconf:
+ $(MAKE) conf FLEX_SCANNER_REENTRANT=disable
+
+econf:
+ $(MAKE) conf FLEX_SCANNER_REENTRANT=enable
+
+do_configure: configure
+ ./configure $(CONFIGURE_OPTS)
+
+configure: configure.in
+ autoconf
+
+setup:
+ (cd src && $(MAKE) $@)
+
+info:
+ @echo "APP_RELEASE_DIR: $(APP_RELEASE_DIR)"
+ @echo "APP_DIR: $(APP_DIR)"
+ @echo "APP_TAR_FILE: $(APP_TAR_FILE)"
+ @echo "OTP_INSTALL_DIR: $(OTP_INSTALL_DIR)"
+ @echo "APP_INSTALL_DIR: $(APP_INSTALL_DIR)"
+
+version:
+ @echo "$(VSN)"
+
+
+# ----------------------------------------------------
+# Application install (of a app built from source) targets
+# ----------------------------------------------------
+app_install:
+ $(MAKE) TESTROOT=$(APP_INSTALL_DIR) release
+
+
+# ----------------------------------------------------
+# Application (source) release targets
+# ----------------------------------------------------
+app_release: app_doc tar
+
+app_doc:
+ cd doc/src; $(MAKE) html man
+
+app_dir: $(APP_DIR)
+
+tar_exclude: TAR.exclude2
+
+TAR.exclude2: Makefile TAR.exclude
+ cat TAR.exclude > TAR.exclude2; \
+ echo "megaco/TAR.exclude2" >> TAR.exclude2; \
+ echo "megaco/priv/lib/$(TARGET)" >> TAR.exclude2; \
+ echo "megaco/src/flex/$(TARGET)" >> TAR.exclude2; \
+ (cd ..; find megaco -name 'prebuild.skip' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name 'findmerge.*' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '*.contrib*' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '*.keep*' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '*.mkelem*' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '*~' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name 'erl_crash.dump' >> megaco/TAR.exclude2)
+ (cd ..; find megaco/test -name '*.beam' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '*.log' >> megaco/TAR.exclude2)
+ (cd ..; find megaco/examples/meas -name '*.xls' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name 'core' >> megaco/TAR.exclude2)
+ (cd ..; find megaco -name '.cmake.state' >> megaco/TAR.exclude2)
+
+$(APP_DIR): tar_exclude
+ mkdir -p $(APP_DIR); \
+ (cd ..; tar cfX - megaco/TAR.exclude2 megaco) | \
+ (cd $(APP_DIR); tar xf -); \
+ mv $(APP_DIR)/megaco/* $(APP_DIR)/; \
+ mkdir $(APP_DIR)/autoconf; \
+ cp autoconf/config.guess $(APP_DIR)/autoconf/; \
+ cp autoconf/config.sub $(APP_DIR)/autoconf/; \
+ cp autoconf/install-sh $(APP_DIR)/autoconf/; \
+ rmdir $(APP_DIR)/megaco
+
+tar: $(APP_TAR_FILE)
+
+$(APP_TAR_FILE): $(APP_DIR)
+ (cd $(APP_RELEASE_DIR); gtar zcf $(APP_TAR_FILE) $(DIR_NAME))
+
+dialyzer:
+ (cd ./ebin; \
+ dialyzer --build_plt \
+ --output_plt ../priv/megaco.plt \
+ -r ../../megaco/ebin \
+ --verbose)
diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in
new file mode 100644
index 0000000000..297d618369
--- /dev/null
+++ b/lib/megaco/configure.in
@@ -0,0 +1,262 @@
+dnl Process this file with autoconf to produce a configure script. -*-m4-*-
+dnl
+dnl %CopyrightBegin%
+dnl
+dnl Copyright Ericsson AB 2001-2009. All Rights Reserved.
+dnl
+dnl The contents of this file are subject to the Erlang Public License,
+dnl Version 1.1, (the "License"); you may not use this file except in
+dnl compliance with the License. You should have received a copy of the
+dnl Erlang Public License along with this software. If not, it can be
+dnl retrieved online at http://www.erlang.org/.
+dnl
+dnl Software distributed under the License is distributed on an "AS IS"
+dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+dnl the License for the specific language governing rights and limitations
+dnl under the License.
+dnl
+dnl %CopyrightEnd%
+dnl
+
+dnl define([AC_CACHE_LOAD], )dnl
+dnl define([AC_CACHE_SAVE], )dnl
+
+if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
+ # We do not want to use a common cache!
+ cache_file=/dev/null
+fi
+
+AC_INIT(vsn.mk)
+
+if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then
+ AC_CONFIG_AUX_DIRS(autoconf)
+else
+ erl_top=${ERL_TOP}
+ AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
+fi
+
+if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
+ AC_CANONICAL_HOST
+else
+ host_os=win32
+fi
+
+
+dnl ----------------------------------------------------------------------
+dnl Checks for programs.
+dnl ----------------------------------------------------------------------
+
+AC_DEFUN(ERL_REENTRANT_FLEX,
+[flex_compile='$LEX -R -Pconftest -oconftest.c conftest.flex 1>&AC_FD_CC'
+changequote(253, 273)dnl
+cat > conftest.flex <<EOF
+/*
+ * This (reentrant) example code comes from the flex manual
+ */
+
+%option reentrant stack noyywrap
+%x COMMENT
+
+%%
+
+"//" yy_push_state( COMMENT, yyscanner);
+.|\n
+
+<COMMENT>\n yy_pop_state( yyscanner );
+<COMMENT>[^\n]+ fprintf( yyout, "%s\n", yytext);
+
+%%
+
+int main ( int argc, char * argv[] )
+{
+ yyscan_t scanner;
+
+ yylex_init ( &scanner );
+ yylex ( scanner );
+ yylex_destroy ( scanner );
+ return 0;
+}
+EOF
+changequote([, ])dnl
+AC_MSG_CHECKING(for reentrant capable flex)
+if AC_TRY_EVAL(flex_compile) && test -s conftest.c; then
+ ifelse([$1], , :, [
+ $1])
+ AC_MSG_RESULT([yes])
+else
+ echo "configure: failed program was:" 1>&AC_FD_CC
+ cat conftest.flex 1>&AC_FD_CC
+ echo "configure: PATH was $PATH" 1>&AC_FD_CC
+ifelse([$2], , , [
+ $2
+])dnl
+ AC_MSG_RESULT([no])
+fi
+])
+
+
+dnl
+dnl Shall we attempt to use reentrant flex scanner or not
+dnl
+AC_ARG_ENABLE(megaco_reentrant_flex_scanner,
+[ --enable-megaco-reentrant-flex-scanner enable reentrant megaco flex scanner
+ --disable-megaco-reentrant-flex-scanner disable reentrant megaco flex scanner],
+ if test x${enable_megaco_reentrant_flex_scanner} = xno ; then
+ ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false
+ else
+ ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true
+ fi,
+ ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true)
+
+
+dnl
+dnl flex is needed by megaco. lex wont do!
+dnl
+
+AC_PROG_LEX
+if test "$LEX" != flex; then
+ ENABLE_MEGACO_FLEX_SCANNER=false
+else
+ ENABLE_MEGACO_FLEX_SCANNER=true
+ dnl Check if we can generate a reentrant scanner
+ dnl ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true
+ if ${ENABLE_REENTRANT_MEGACO_FLEX_SCANNER} = true ; then
+ ERL_REENTRANT_FLEX(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=true,
+ ENABLE_REENTRANT_MEGACO_FLEX_SCANNER=false)
+ fi
+fi
+AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER)
+AC_SUBST(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER)
+
+
+
+dnl
+dnl For increased performance it is possible to disable lineno
+dnl
+AC_ARG_ENABLE(megaco_flex_scanner_lineno,
+[ --enable-megaco-flex-scanner-lineno enable megaco flex scanner lineno
+ --disable-megaco-flex-scanner-lineno disable megaco flex scanner lineno],
+ if test x${enable_megaco_flex_scanner_lineno} = xno ; then
+ ENABLE_MEGACO_FLEX_SCANNER_LINENO=false
+ else
+ ENABLE_MEGACO_FLEX_SCANNER_LINENO=true
+ fi,
+ ENABLE_MEGACO_FLEX_SCANNER_LINENO=true)
+AC_SUBST(ENABLE_MEGACO_FLEX_SCANNER_LINENO)
+
+
+
+dnl
+dnl C compiler (related) defs
+dnl
+
+AC_PROG_CC
+
+dnl Magic test for clearcase.
+if test -d ../../system; then
+ OTP_EXTRA_FLAGS=-DOTP_RELEASE
+else
+ OTP_EXTRA_FLAGS=
+fi
+
+
+dnl
+dnl The ErlDrvEntry struct changed in R13 (another field)
+dnl
+AC_CHECK_MEMBERS([struct ErlDrvEntry.stop_select],
+ [
+ CFLAGS="$CFLAGS -DMEGACO_DRV_ENTRY_HAS_STOP_SELECT"
+ ],
+ [],
+ [
+ #include "erl_driver.h"
+ ])
+
+
+dnl
+dnl Flags to the C compiler
+dnl
+dnl make sure we find config.h
+CFLAGS="$CFLAGS -I${ERL_TOP}/erts/$host -I${ERL_TOP}/erts/include/$host $OTP_EXTRA_FLAGS"
+
+if test "X$host" = "Xwin32"; then
+ DED_CFLAGS="$CFLAGS"
+else
+ case $host_os in
+ darwin*)
+ CFLAGS="$CFLAGS -no-cpp-precomp"
+ ;;
+ esac
+
+ if test "x$GCC" = xyes; then
+ DED_CFLAGS="$CFLAGS -fPIC $DED_CFLAGS"
+ else
+ DED_CFLAGS="$CFLAGS $DED_CFLAGS"
+ fi
+fi
+
+dnl emulator includes needed
+DED_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host"
+
+DED_CFLAGS="$DED_INCLUDE $DED_CFLAGS"
+
+
+
+AC_SUBST(DED_CFLAGS)
+
+
+AC_CHECK_PROGS(DED_LD, [ld.sh ld], no_ld)
+if test "$DED_LD" = no_ld; then
+ AC_MSG_ERROR([ld is required to build the flex scanner!])
+fi
+
+
+AC_MSG_CHECKING(for linker flags for loadable drivers)
+case $host_os in
+ win32)
+ DED_LDFLAGS="-dll"
+ ;;
+ solaris2*|sysv4*)
+ DED_LDFLAGS="-G"
+ ;;
+ aix4*)
+ DED_LDFLAGS="-G -bnoentry -bexpall"
+ ;;
+ freebsd2*)
+ # Non-ELF GNU linker
+ DED_LDFLAGS="-Bshareable"
+ ;;
+ darwin*)
+ # Mach-O linker, a shared lib and a loadable
+ # object file is not the same thing.
+ DED_LDFLAGS="-bundle -flat_namespace -undefined suppress"
+ DED_CFLAGS="$DED_CFLAGS -fno-common"
+ ;;
+ *)
+ # assume GNU linker and ELF
+ DED_LDFLAGS="-shared"
+ ;;
+esac
+DED_LDFLAGS="$LDFLAGS $DED_LDFLAGS"
+AC_MSG_RESULT([$DED_LDFLAGS])
+AC_SUBST(DED_LDFLAGS)
+
+
+AC_CHECK_PROG(PERL, perl, perl, no_perl)
+if test "$PERL" = no_perl; then
+ AC_MSG_ERROR([Perl is required to build the flex scanner!])
+fi
+
+
+dnl This is the os flavour, should be unix, vxworks or win32
+if test "X$host" = "Xwin32"; then
+ ERLANG_OSTYPE=win32
+else
+ ERLANG_OSTYPE=unix
+fi
+
+AC_SUBST(ERLANG_OSTYPE)
+
+
+AC_OUTPUT(src/flex/$host/Makefile:src/flex/Makefile.in)
+
diff --git a/lib/megaco/doc/html/.gitignore b/lib/megaco/doc/html/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/megaco/doc/html/.gitignore
diff --git a/lib/megaco/doc/man3/.gitignore b/lib/megaco/doc/man3/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/megaco/doc/man3/.gitignore
diff --git a/lib/megaco/doc/pdf/.gitignore b/lib/megaco/doc/pdf/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/megaco/doc/pdf/.gitignore
diff --git a/lib/megaco/doc/src/MG-startup_flow_noMID.fig b/lib/megaco/doc/src/MG-startup_flow_noMID.fig
new file mode 100644
index 0000000000..301fb784fd
--- /dev/null
+++ b/lib/megaco/doc/src/MG-startup_flow_noMID.fig
@@ -0,0 +1,77 @@
+#FIG 3.1
+Landscape
+Flush left
+Inches
+1200 2
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 1200 802 1200 7470
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 3600 877 3600 7485
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 6000 877 6000 7485
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 8400 877 8385 7515
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 1200 1125 3600 1125
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3615 1695 1215 1695
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 8430 4410 9780 4410
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 1 2
+ 1 1 1.00 60.00 120.00
+ 6000 3495 3600 3495
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 1200 1890 3600 1890
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3630 2490 1230 2490
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 1 2
+ 1 1 1.00 60.00 120.00
+ 3630 3015 1230 3015
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3585 4185 8385 4185
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 6015 3675 3615 3675
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 9705 4845 8430 4845
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 8355 5160 3555 5160
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 1 2
+ 1 1 1.00 60.00 120.00
+ 6060 5670 3660 5670
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 6015 5925 3615 5925
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3615 7305 1215 7305
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 1 2
+ 1 1 1.00 60.00 120.00
+ 3615 6885 1215 6885
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 1 1 1.00 60.00 120.00
+ 3600 6645 1200 6645
+4 0 -1 0 0 0 12 0.0000 4 135 345 3465 660 main\001
+4 0 -1 0 0 0 12 0.0000 4 135 555 5775 675 encoder\001
+4 0 -1 0 0 0 12 0.0000 4 165 630 8070 690 transport\001
+4 0 -1 0 0 0 12 0.0000 4 90 300 1095 660 user\001
+4 0 -1 0 0 0 14 0.0000 4 165 1905 1260 2385 (return of mecaco:return/4)\001
+4 0 -1 0 0 0 14 0.0000 4 180 960 1335 2865 megaco:call/3\001
+4 0 -1 0 0 0 14 0.0000 4 180 1905 5370 4065 SendMod:send_message/2\001
+4 0 -1 0 0 0 14 0.0000 4 180 960 8520 4320 send bytes(1)\001
+4 0 -1 0 0 0 14 0.0000 4 180 1995 3645 3375 EndMod:encode_message/2\001
+4 0 -1 0 0 0 14 0.0000 4 180 4380 1290 1575 UserMod:handle_connect/2 (RemoteMid = preliminary.mid)\001
+4 0 -1 0 0 0 14 0.0000 4 180 3675 1275 1050 megaco:connect/4 (RemoteMid = preliminary.mid)\001
+4 0 -1 0 0 0 14 0.0000 4 180 1125 8490 4710 receive bytes(2)\001
+4 0 -1 0 0 0 14 0.0000 4 180 1950 5265 5055 megaco_receive_message/4\001
+4 0 -1 0 0 0 14 0.0000 4 180 1980 3690 5520 EncMod:decode_message/2\001
+4 0 -1 0 0 0 14 0.0000 4 180 1740 1275 7200 (return of megaco:call/3)\001
+4 0 -1 0 0 0 14 0.0000 4 165 4725 1260 6540 UserMod:handle_connect/2 (RemoteMid = actual MID of MGC)\001
diff --git a/lib/megaco/doc/src/MG-startup_flow_noMID.gif b/lib/megaco/doc/src/MG-startup_flow_noMID.gif
new file mode 100644
index 0000000000..49b8fc9b8d
--- /dev/null
+++ b/lib/megaco/doc/src/MG-startup_flow_noMID.gif
Binary files differ
diff --git a/lib/megaco/doc/src/MG-startup_flow_noMID.ps b/lib/megaco/doc/src/MG-startup_flow_noMID.ps
new file mode 100644
index 0000000000..cf8917e364
--- /dev/null
+++ b/lib/megaco/doc/src/MG-startup_flow_noMID.ps
@@ -0,0 +1,267 @@
+%!PS-Adobe-2.0
+%%Title: MG-startup_flow_noMID.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Thu Jun 14 16:55:25 2001
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 65 340 588 759
+%%Pages: 1
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+0.0 792.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+%%Page: 1 1
+7.500 slw
+% Polyline
+n 1200 802 m 1200 7470 l gs col-1 s gr
+% Polyline
+n 3600 877 m 3600 7485 l gs col-1 s gr
+% Polyline
+n 6000 877 m 6000 7485 l gs col-1 s gr
+% Polyline
+n 8400 877 m 8385 7515 l gs col-1 s gr
+% Polyline
+gs clippath
+3453 1095 m 3573 1125 l 3453 1155 l 3615 1155 l 3615 1095 l cp clip
+n 1200 1125 m 3600 1125 l gs col-1 s gr gr
+
+% arrowhead
+n 3453 1095 m 3573 1125 l 3453 1155 l col-1 s
+% Polyline
+gs clippath
+1362 1725 m 1242 1695 l 1362 1665 l 1200 1665 l 1200 1725 l cp clip
+n 3615 1695 m 1215 1695 l gs col-1 s gr gr
+
+% arrowhead
+n 1362 1725 m 1242 1695 l 1362 1665 l 1362 1695 l 1362 1725 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9633 4380 m 9753 4410 l 9633 4440 l 9795 4440 l 9795 4380 l cp clip
+n 8430 4410 m 9780 4410 l gs col-1 s gr gr
+
+% arrowhead
+n 9633 4380 m 9753 4410 l 9633 4440 l 9633 4410 l 9633 4380 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5853 3465 m 5973 3495 l 5853 3525 l 6015 3525 l 6015 3465 l cp clip
+n 6000 3495 m 3600 3495 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 3465 m 5973 3495 l 5853 3525 l 5853 3495 l 5853 3465 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3453 1860 m 3573 1890 l 3453 1920 l 3615 1920 l 3615 1860 l cp clip
+n 1200 1890 m 3600 1890 l gs col-1 s gr gr
+
+% arrowhead
+n 3453 1860 m 3573 1890 l 3453 1920 l 3453 1890 l 3453 1860 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1377 2520 m 1257 2490 l 1377 2460 l 1215 2460 l 1215 2520 l cp clip
+n 3630 2490 m 1230 2490 l gs col-1 s gr gr
+
+% arrowhead
+n 1377 2520 m 1257 2490 l 1377 2460 l 1377 2490 l 1377 2520 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3483 2985 m 3603 3015 l 3483 3045 l 3645 3045 l 3645 2985 l cp clip
+n 3630 3015 m 1230 3015 l gs col-1 s gr gr
+
+% arrowhead
+n 3483 2985 m 3603 3015 l 3483 3045 l 3483 3015 l 3483 2985 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+8238 4155 m 8358 4185 l 8238 4215 l 8400 4215 l 8400 4155 l cp clip
+n 3585 4185 m 8385 4185 l gs col-1 s gr gr
+
+% arrowhead
+n 8238 4155 m 8358 4185 l 8238 4215 l 8238 4185 l 8238 4155 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3762 3705 m 3642 3675 l 3762 3645 l 3600 3645 l 3600 3705 l cp clip
+n 6015 3675 m 3615 3675 l gs col-1 s gr gr
+
+% arrowhead
+n 3762 3705 m 3642 3675 l 3762 3645 l 3762 3675 l 3762 3705 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+8577 4875 m 8457 4845 l 8577 4815 l 8415 4815 l 8415 4875 l cp clip
+n 9705 4845 m 8430 4845 l gs col-1 s gr gr
+
+% arrowhead
+n 8577 4875 m 8457 4845 l 8577 4815 l 8577 4845 l 8577 4875 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3702 5190 m 3582 5160 l 3702 5130 l 3540 5130 l 3540 5190 l cp clip
+n 8355 5160 m 3555 5160 l gs col-1 s gr gr
+
+% arrowhead
+n 3702 5190 m 3582 5160 l 3702 5130 l 3702 5160 l 3702 5190 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5913 5640 m 6033 5670 l 5913 5700 l 6075 5700 l 6075 5640 l cp clip
+n 6060 5670 m 3660 5670 l gs col-1 s gr gr
+
+% arrowhead
+n 5913 5640 m 6033 5670 l 5913 5700 l 5913 5670 l 5913 5640 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3762 5955 m 3642 5925 l 3762 5895 l 3600 5895 l 3600 5955 l cp clip
+n 6015 5925 m 3615 5925 l gs col-1 s gr gr
+
+% arrowhead
+n 3762 5955 m 3642 5925 l 3762 5895 l 3762 5925 l 3762 5955 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1362 7335 m 1242 7305 l 1362 7275 l 1200 7275 l 1200 7335 l cp clip
+n 3615 7305 m 1215 7305 l gs col-1 s gr gr
+
+% arrowhead
+n 1362 7335 m 1242 7305 l 1362 7275 l 1362 7305 l 1362 7335 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3468 6855 m 3588 6885 l 3468 6915 l 3630 6915 l 3630 6855 l cp clip
+n 3615 6885 m 1215 6885 l gs col-1 s gr gr
+
+% arrowhead
+n 3468 6855 m 3588 6885 l 3468 6915 l 3468 6885 l 3468 6855 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1347 6675 m 1227 6645 l 1347 6615 l 1185 6615 l 1185 6675 l cp clip
+n 3600 6645 m 1200 6645 l gs col-1 s gr gr
+
+% arrowhead
+n 1347 6675 m 1227 6645 l 1347 6615 l 1347 6645 l 1347 6675 l cp gs 0.00 setgray ef gr col-1 s
+/Times-Roman ff 180.00 scf sf
+3465 660 m
+gs 1 -1 sc (main) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5775 675 m
+gs 1 -1 sc (encoder) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8070 690 m
+gs 1 -1 sc (transport) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1095 660 m
+gs 1 -1 sc (user) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1260 2385 m
+gs 1 -1 sc (\(return of mecaco:return/4\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1335 2865 m
+gs 1 -1 sc (megaco:call/3) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5370 4065 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+8520 4320 m
+gs 1 -1 sc (send bytes\(1\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3645 3375 m
+gs 1 -1 sc (EndMod:encode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1290 1575 m
+gs 1 -1 sc (UserMod:handle_connect/2 \(RemoteMid = preliminary.mid\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1275 1050 m
+gs 1 -1 sc (megaco:connect/4 \(RemoteMid = preliminary.mid\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+8490 4710 m
+gs 1 -1 sc (receive bytes\(2\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5265 5055 m
+gs 1 -1 sc (megaco_receive_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3690 5520 m
+gs 1 -1 sc (EncMod:decode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1275 7200 m
+gs 1 -1 sc (\(return of megaco:call/3\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1260 6540 m
+gs 1 -1 sc (UserMod:handle_connect/2 \(RemoteMid = actual MID of MGC\)) col-1 sh gr
+showpage
+$F2psEnd
+rs
diff --git a/lib/megaco/doc/src/MGC_startup_call_flow.gif b/lib/megaco/doc/src/MGC_startup_call_flow.gif
new file mode 100644
index 0000000000..24f4348dc9
--- /dev/null
+++ b/lib/megaco/doc/src/MGC_startup_call_flow.gif
Binary files differ
diff --git a/lib/megaco/doc/src/MGC_startup_call_flow.ps b/lib/megaco/doc/src/MGC_startup_call_flow.ps
new file mode 100644
index 0000000000..2507d2f407
--- /dev/null
+++ b/lib/megaco/doc/src/MGC_startup_call_flow.ps
@@ -0,0 +1,217 @@
+%!PS-Adobe-2.0
+%%Title: MGC_startup_call_flow.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Fri Jun 15 13:10:17 2001
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 59 484 584 759
+%%Pages: 1
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+0.0 792.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+%%Page: 1 1
+7.500 slw
+% Polyline
+n 4800 952 m 4800 5115 l gs col-1 s gr
+% Polyline
+gs clippath
+2547 3930 m 2427 3900 l 2547 3870 l 2385 3870 l 2385 3930 l cp clip
+n 4800 3900 m 2400 3900 l gs col-1 s gr gr
+
+% arrowhead
+n 2547 3930 m 2427 3900 l 2547 3870 l 2547 3900 l 2547 3930 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4653 1470 m 4773 1500 l 4653 1530 l 4815 1530 l 4815 1470 l cp clip
+n 4800 1500 m 2400 1500 l gs col-1 s gr gr
+
+% arrowhead
+n 4653 1470 m 4773 1500 l 4653 1530 l 4653 1500 l 4653 1470 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4947 1905 m 4827 1875 l 4947 1845 l 4785 1845 l 4785 1905 l cp clip
+n 7200 1875 m 4800 1875 l gs col-1 s gr gr
+
+% arrowhead
+n 4947 1905 m 4827 1875 l 4947 1845 l 4947 1875 l 4947 1905 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7053 1620 m 7173 1650 l 7053 1680 l 7215 1680 l 7215 1620 l cp clip
+n 4800 1650 m 7200 1650 l gs col-1 s gr gr
+
+% arrowhead
+n 7053 1620 m 7173 1650 l 7053 1680 l 7053 1650 l 7053 1620 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9453 2370 m 9573 2400 l 9453 2430 l 9615 2430 l 9615 2370 l cp clip
+n 4800 2400 m 9600 2400 l gs col-1 s gr gr
+
+% arrowhead
+n 9453 2370 m 9573 2400 l 9453 2430 l 9453 2400 l 9453 2370 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4872 3480 m 4752 3450 l 4872 3420 l 4710 3420 l 4710 3480 l cp clip
+n 7125 3450 m 4725 3450 l gs col-1 s gr gr
+
+% arrowhead
+n 4872 3480 m 4752 3450 l 4872 3420 l 4872 3450 l 4872 3480 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7053 3195 m 7173 3225 l 7053 3255 l 7215 3255 l 7215 3195 l cp clip
+n 4800 3225 m 7200 3225 l gs col-1 s gr gr
+
+% arrowhead
+n 7053 3195 m 7173 3225 l 7053 3255 l 7053 3225 l 7053 3195 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+2547 3930 m 2427 3900 l 2547 3870 l 2385 3870 l 2385 3930 l cp clip
+n 4800 3900 m 2400 3900 l gs col-1 s gr gr
+
+% arrowhead
+n 2547 3930 m 2427 3900 l 2547 3870 l 2547 3900 l 2547 3930 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+2253 1245 m 2373 1275 l 2253 1305 l 2415 1305 l 2415 1245 l cp clip
+n 1125 1275 m 2400 1275 l gs col-1 s gr gr
+
+% arrowhead
+n 2253 1245 m 2373 1275 l 2253 1305 l col-1 s
+% Polyline
+gs clippath
+4917 2625 m 4797 2595 l 4917 2565 l 4755 2565 l 4755 2625 l cp clip
+n 9570 2595 m 4770 2595 l gs col-1 s gr gr
+
+% arrowhead
+n 4917 2625 m 4797 2595 l 4917 2565 l 4917 2595 l 4917 2625 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1272 4620 m 1152 4590 l 1272 4560 l 1110 4560 l 1110 4620 l cp clip
+n 1125 4590 m 2400 4590 l gs col-1 s gr gr
+
+% arrowhead
+n 1272 4620 m 1152 4590 l 1272 4560 l 1272 4590 l 1272 4620 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+n 2400 877 m 2400 5085 l gs col-1 s gr
+% Polyline
+n 9600 877 m 9600 5085 l gs col-1 s gr
+% Polyline
+n 7200 877 m 7200 5085 l gs col-1 s gr
+/Times-Roman ff 180.00 scf sf
+2145 690 m
+gs 1 -1 sc (transport) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9420 660 m
+gs 1 -1 sc (user) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+990 1155 m
+gs 1 -1 sc (receive bytes\(1\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2535 1380 m
+gs 1 -1 sc (megaco:receive_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4965 1515 m
+gs 1 -1 sc (EncMod:decode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+6735 2295 m
+gs 1 -1 sc (UserMod:handle_connect/3) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2475 3705 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1110 4350 m
+gs 1 -1 sc (send bytes\(2\)) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 675 m
+gs 1 -1 sc (encoder) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4590 735 m
+gs 1 -1 sc (main) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4875 3060 m
+gs 1 -1 sc (EncMod:encode_message/2) col-1 sh gr
+showpage
+$F2psEnd
+rs
diff --git a/lib/megaco/doc/src/MG_startup_call_flow.gif b/lib/megaco/doc/src/MG_startup_call_flow.gif
new file mode 100644
index 0000000000..8feb006aee
--- /dev/null
+++ b/lib/megaco/doc/src/MG_startup_call_flow.gif
Binary files differ
diff --git a/lib/megaco/doc/src/MG_startup_call_flow.ps b/lib/megaco/doc/src/MG_startup_call_flow.ps
new file mode 100644
index 0000000000..c4e7e4932f
--- /dev/null
+++ b/lib/megaco/doc/src/MG_startup_call_flow.ps
@@ -0,0 +1,250 @@
+%!PS-Adobe-2.0
+%%Title: MG_startup_call_flow.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Thu Jun 14 17:18:16 2001
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 65 377 569 761
+%%Pages: 1
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+0.0 792.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+%%Page: 1 1
+7.500 slw
+% Polyline
+n 1200 802 m 1200 6900 l gs col-1 s gr
+% Polyline
+n 3600 877 m 3600 6900 l gs col-1 s gr
+% Polyline
+n 6000 877 m 6000 6900 l gs col-1 s gr
+% Polyline
+gs clippath
+3453 1095 m 3573 1125 l 3453 1155 l 3615 1155 l 3615 1095 l cp clip
+n 1200 1125 m 3600 1125 l gs col-1 s gr gr
+
+% arrowhead
+n 3453 1095 m 3573 1125 l 3453 1155 l col-1 s
+% Polyline
+gs clippath
+1362 1725 m 1242 1695 l 1362 1665 l 1200 1665 l 1200 1725 l cp clip
+n 3615 1695 m 1215 1695 l gs col-1 s gr gr
+
+% arrowhead
+n 1362 1725 m 1242 1695 l 1362 1665 l 1362 1695 l 1362 1725 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3762 5415 m 3642 5385 l 3762 5355 l 3600 5355 l 3600 5415 l cp clip
+n 8115 5385 m 3615 5385 l gs col-1 s gr gr
+
+% arrowhead
+n 3762 5415 m 3642 5385 l 3762 5355 l 3762 5385 l 3762 5415 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3762 6270 m 3642 6240 l 3762 6210 l 3600 6210 l 3600 6270 l cp clip
+n 6015 6240 m 3615 6240 l gs col-1 s gr gr
+
+% arrowhead
+n 3762 6270 m 3642 6240 l 3762 6210 l 3762 6240 l 3762 6270 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1347 6630 m 1227 6600 l 1347 6570 l 1185 6570 l 1185 6630 l cp clip
+n 3600 6600 m 1200 6600 l gs col-1 s gr gr
+
+% arrowhead
+n 1347 6630 m 1227 6600 l 1347 6570 l 1347 6600 l 1347 6630 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5853 3465 m 5973 3495 l 5853 3525 l 6015 3525 l 6015 3465 l cp clip
+n 6000 3495 m 3600 3495 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 3465 m 5973 3495 l 5853 3525 l 5853 3495 l 5853 3465 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3453 1860 m 3573 1890 l 3453 1920 l 3615 1920 l 3615 1860 l cp clip
+n 1200 1890 m 3600 1890 l gs col-1 s gr gr
+
+% arrowhead
+n 3453 1860 m 3573 1890 l 3453 1920 l 3453 1890 l 3453 1860 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1377 2520 m 1257 2490 l 1377 2460 l 1215 2460 l 1215 2520 l cp clip
+n 3630 2490 m 1230 2490 l gs col-1 s gr gr
+
+% arrowhead
+n 1377 2520 m 1257 2490 l 1377 2460 l 1377 2490 l 1377 2520 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3483 2985 m 3603 3015 l 3483 3045 l 3645 3045 l 3645 2985 l cp clip
+n 3630 3015 m 1230 3015 l gs col-1 s gr gr
+
+% arrowhead
+n 3483 2985 m 3603 3015 l 3483 3045 l 3483 3015 l 3483 2985 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7968 4140 m 8088 4170 l 7968 4200 l 8130 4200 l 8130 4140 l cp clip
+n 3585 4185 m 8115 4170 l gs col-1 s gr gr
+
+% arrowhead
+n 7968 4140 m 8088 4170 l 7968 4200 l 7968 4170 l 7968 4140 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5883 5955 m 6003 5985 l 5883 6015 l 6045 6015 l 6045 5955 l cp clip
+n 6030 5985 m 3630 5985 l gs col-1 s gr gr
+
+% arrowhead
+n 5883 5955 m 6003 5985 l 5883 6015 l 5883 5985 l 5883 5955 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3762 3705 m 3642 3675 l 3762 3645 l 3600 3645 l 3600 3705 l cp clip
+n 6015 3675 m 3615 3675 l gs col-1 s gr gr
+
+% arrowhead
+n 3762 3705 m 3642 3675 l 3762 3645 l 3762 3675 l 3762 3705 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+n 8115 877 m 8115 6900 l gs col-1 s gr
+% Polyline
+gs clippath
+9318 4440 m 9438 4470 l 9318 4500 l 9480 4500 l 9480 4440 l cp clip
+n 8115 4470 m 9465 4470 l gs col-1 s gr gr
+
+% arrowhead
+n 9318 4440 m 9438 4470 l 9318 4500 l 9318 4470 l 9318 4440 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+8277 5100 m 8157 5070 l 8277 5040 l 8115 5040 l 8115 5100 l cp clip
+n 9405 5070 m 8130 5070 l gs col-1 s gr gr
+
+% arrowhead
+n 8277 5100 m 8157 5070 l 8277 5040 l 8277 5070 l 8277 5100 l cp gs 0.00 setgray ef gr col-1 s
+/Times-Roman ff 180.00 scf sf
+3465 660 m
+gs 1 -1 sc (main) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5775 675 m
+gs 1 -1 sc (encoder) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1095 660 m
+gs 1 -1 sc (user) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1290 1575 m
+gs 1 -1 sc (UserMod:handle_connect/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1260 2385 m
+gs 1 -1 sc (\(return of mecaco:return/4\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1335 2865 m
+gs 1 -1 sc (megaco:call/3) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5370 4065 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1380 6540 m
+gs 1 -1 sc (\(return of megaco:call/3\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3645 3375 m
+gs 1 -1 sc (EndMod:encode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3645 5880 m
+gs 1 -1 sc (EncMod:decode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5415 5295 m
+gs 1 -1 sc (megaco_receive_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1275 1050 m
+gs 1 -1 sc (megaco:connect/4) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+7830 660 m
+gs 1 -1 sc (transport) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+8250 4965 m
+gs 1 -1 sc (receive bytes\(2\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+8190 4350 m
+gs 1 -1 sc (send bytes\(1\)) col-1 sh gr
+showpage
+$F2psEnd
+rs
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
new file mode 100644
index 0000000000..2c55e92914
--- /dev/null
+++ b/lib/megaco/doc/src/Makefile
@@ -0,0 +1,289 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+APPLICATION=megaco
+
+# ----------------------------------------------------
+# Include dependency
+# ----------------------------------------------------
+
+ifndef DOCSUPPORT
+include make.dep
+endif
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include files.mk
+
+
+# ----------------------------------------------------
+
+INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html)
+
+HTML_APP_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html)
+HTML_EXTRA_FILES = $(XML_EXTRA_FILES:%.xml=$(HTMLDIR)/%.html)
+HTML_PART_FILES = $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+HTML_FILES = $(HTML_APP_FILES) $(HTML_EXTRA_FILES) $(HTML_PART_FILES)
+
+INFO_FILE = ../../info
+
+HTML_REF3_FILES = $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html)
+HTML_CHAPTER_FILES = $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+
+EXTRA_FILES = \
+ $(DEFAULT_GIF_FILES) \
+ $(DEFAULT_HTML_FILES) \
+ $(HTML_REF3_FILES) \
+ $(HTML_CHAPTER_FILES)
+
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+
+ifdef DOCSUPPORT
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+else
+
+TEX_FILES_BOOK = \
+ $(BOOK_FILES:%.xml=%.tex)
+TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
+ $(XML_APPLICATION_FILES:%.xml=%.tex)
+TEX_FILES_USERS_GUIDE = \
+ $(XML_CHAPTER_FILES:%.xml=%.tex)
+
+TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
+TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
+
+$(TOP_PDF_FILE): book.dvi ../../vsn.mk
+ $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
+
+$(TOP_PS_FILE): book.dvi $(APP_FILE)
+ $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
+
+
+TOP_HTML_FILES = $(INDEX_TARGET)
+
+endif
+
+INDEX_FILE = index.html
+INDEX_SRC = $(INDEX_FILE).src
+INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE)
+
+STANDARD_DIR = ../standard
+STANDARDS = $(STANDARD_DIR)/rfc3015.txt \
+ $(STANDARD_DIR)/implementors_guide_v6.pdf
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif
+ $(INSTALL_DATA) $< $@
+
+ifdef DOCSUPPORT
+
+docs: pdf html man
+
+ldocs: local_docs $(INDEX_TARGET)
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+clean clean_docs: clean_html clean_man
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+else
+
+ifeq ($(DOCTYPE),pdf)
+docs: pdf
+else
+ifeq ($(DOCTYPE),ps)
+docs: ps
+else
+docs: html gifs man
+endif
+endif
+
+pdf: $(TOP_PDF_FILE)
+
+ps: $(TOP_PS_FILE)
+
+html: gifs $(HTML_FILES) $(TOP_HTML_FILES)
+
+mhtml: html $(HTML_REF3_FILES) $(HTML_CHAPTER_FILES)
+
+clean: clean_html clean_man clean_pdf
+ rm -f core *~
+ rm -f *.aux *.cites *.citeshd *.dvi *.idx *.ilg *.ind
+ rm -f *.indhd *.lof *.lofhd *.lot *.lothd *.otpdef
+ rm -f *.otpuse *.terms *.termshd *.toc *.makeindexlog *.dvipslog
+ rm -f *.bib *.bbl *.blg *.bibhd
+
+clean_pdf:
+ rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
+ rm -f $(TEX_FILES_USERS_GUIDE)
+ rm -f $(TEX_FILES_REF_MAN)
+ rm -f $(TEX_FILES_BOOK)
+
+endif
+
+clean_man:
+ rm -f $(MAN3DIR)/*
+
+clean_html:
+ rm -rf $(HTMLDIR)/*
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+man: $(MAN3_FILES)
+
+$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE)
+ sed -e 's/%VSN%/$(VSN)/; \
+ s/%ERLANG_SITE%/www\.erlang\.se\//; \
+ s/%UP_ONE_LEVEL%/..\/..\/..\/doc\/index.html/; \
+ s/%OFF_PRINT%/pdf\/megaco-$(VSN).pdf/' $< > $@
+
+debug opt:
+
+info:
+ @echo "->Makefile<-"
+ @echo ""
+ @echo "DOCSUPPORT = $(DOCSUPPORT)"
+ @echo ""
+ @echo "INDEX_FILE = $(INDEX_FILE)"
+ @echo "INDEX_SRC = $(INDEX_SRC)"
+ @echo "INDEX_TARGET = $(INDEX_TARGET)"
+ @echo ""
+ @echo "XML_APPLICATION_FILES = $(XML_APPLICATION_FILES)"
+ @echo "XML_PART_FILES = $(XML_PART_FILES)"
+ @echo "XML_REF3_FILES = $(XML_REF3_FILES)"
+ @echo "XML_CHAPTER_FILES = $(XML_CHAPTER_FILES)"
+ @echo ""
+ @echo "GIF_FILES = $(GIF_FILES)"
+ @echo ""
+ @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)"
+ @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)"
+ @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)"
+ @echo ""
+ @echo "MAN3_FILES = $(MAN3_FILES)"
+ @echo ""
+ @echo "HTML_FILES = $(HTML_FILES)"
+ @echo "TOP_HTML_FILES = $(TOP_HTML_FILES)"
+ @echo ""
+ @echo "DEFAULT_HTML_FILES = $(DEFAULT_HTML_FILES)"
+ @echo "DEFAULT_GIF_FILES = $(DEFAULT_GIF_FILES)"
+ @echo ""
+ @echo ""
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+ifdef DOCSUPPORT
+
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(HTMLDIR)/* \
+ $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/standard
+ $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard
+
+else
+
+ifeq ($(DOCTYPE),pdf)
+release_docs_spec: pdf
+ $(INSTALL_DIR) $(RELEASE_PATH)/pdf
+ $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
+else
+ifeq ($(DOCTYPE),ps)
+release_docs_spec: ps
+ $(INSTALL_DIR) $(RELEASE_PATH)/ps
+ $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
+else
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
+ $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(TOP_HTML_FILES) $(RELSYSDIR)/doc
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/standard
+ $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard
+endif
+endif
+
+endif
+
+release_spec:
+
+$(HTMLDIR)/megaco_architecture.html: megaco_architecture.xml
+$(HTMLDIR)/megaco_codec_meas.html: megaco_codec_meas.xml
+$(HTMLDIR)/megaco_codec_transform.html: megaco_codec_transform.xml
+$(HTMLDIR)/megaco_debug.html: megaco_debug.xml
+$(HTMLDIR)/megaco_encoder.html: megaco_encoder.xml
+$(HTMLDIR)/megaco_encode.html: megaco_encode.xml
+$(HTMLDIR)/megaco_examples.html: megaco_examples.xml
+$(HTMLDIR)/megaco_flex_scanner.html: megaco_flex_scanner.xml
+$(HTMLDIR)/megaco_intro.html: megaco_intro.xml
+$(HTMLDIR)/megaco_mib.html: megaco_mib.xml
+$(HTMLDIR)/megaco_performance.html: megaco_performance.xml
+$(HTMLDIR)/megaco_run.html: megaco_run.xml
+$(HTMLDIR)/megaco.html: megaco.xml
+$(HTMLDIR)/megaco_tcp.html: megaco_tcp.xml
+$(HTMLDIR)/megaco_transport_mechanisms.html: megaco_transport_mechanisms.xml
+$(HTMLDIR)/megaco_transport.html: megaco_transport.xml
+$(HTMLDIR)/megaco_udp.html: megaco_udp.xml
+$(HTMLDIR)/megaco_user.html: megaco_user.xml
+
diff --git a/lib/megaco/doc/src/book.gif b/lib/megaco/doc/src/book.gif
new file mode 100644
index 0000000000..94b3868792
--- /dev/null
+++ b/lib/megaco/doc/src/book.gif
Binary files differ
diff --git a/lib/megaco/doc/src/book.xml b/lib/megaco/doc/src/book.xml
new file mode 100644
index 0000000000..c0ed250b7d
--- /dev/null
+++ b/lib/megaco/doc/src/book.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco/H.248</title>
+ <prepared>H&aring;kan Mattsson and Lars Thors&eacute;n</prepared>
+ <docno></docno>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>book.xml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>Megaco/H.248</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+ <index></index>
+</book>
+
diff --git a/lib/megaco/doc/src/call_flow.gif b/lib/megaco/doc/src/call_flow.gif
new file mode 100644
index 0000000000..2089f287eb
--- /dev/null
+++ b/lib/megaco/doc/src/call_flow.gif
Binary files differ
diff --git a/lib/megaco/doc/src/call_flow.ps b/lib/megaco/doc/src/call_flow.ps
new file mode 100644
index 0000000000..7287c81b2e
--- /dev/null
+++ b/lib/megaco/doc/src/call_flow.ps
@@ -0,0 +1,253 @@
+%!PS-Adobe-2.0
+%%Title: call_flow.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Thu Jun 14 17:25:31 2001
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 65 377 557 759
+%%Pages: 1
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+0.0 792.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+%%Page: 1 1
+7.500 slw
+% Polyline
+n 1200 802 m 1200 6900 l gs col-1 s gr
+% Polyline
+n 3600 877 m 3600 6900 l gs col-1 s gr
+% Polyline
+n 6000 877 m 6000 6900 l gs col-1 s gr
+% Polyline
+gs clippath
+3453 1095 m 3573 1125 l 3453 1155 l 3615 1155 l 3615 1095 l cp clip
+n 1200 1125 m 3600 1125 l gs col-1 s gr gr
+
+% arrowhead
+n 3453 1095 m 3573 1125 l 3453 1155 l col-1 s
+% Polyline
+gs clippath
+5853 1320 m 5973 1350 l 5853 1380 l 6015 1380 l 6015 1320 l cp clip
+n 3600 1350 m 6000 1350 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 1320 m 5973 1350 l 5853 1380 l 5853 1350 l 5853 1320 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3747 1605 m 3627 1575 l 3747 1545 l 3585 1545 l 3585 1605 l cp clip
+n 6000 1575 m 3600 1575 l gs col-1 s gr gr
+
+% arrowhead
+n 3747 1605 m 3627 1575 l 3747 1545 l 3747 1575 l 3747 1605 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7728 1995 m 7848 2025 l 7728 2055 l 7890 2055 l 7890 1995 l cp clip
+n 3600 2025 m 7875 2025 l gs col-1 s gr gr
+
+% arrowhead
+n 7728 1995 m 7848 2025 l 7728 2055 l 7728 2025 l 7728 1995 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3747 3180 m 3627 3150 l 3747 3120 l 3585 3120 l 3585 3180 l cp clip
+n 7890 3150 m 3600 3150 l gs col-1 s gr gr
+
+% arrowhead
+n 3747 3180 m 3627 3150 l 3747 3120 l 3747 3150 l 3747 3180 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5853 3720 m 5973 3750 l 5853 3780 l 6015 3780 l 6015 3720 l cp clip
+n 3600 3750 m 6000 3750 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 3720 m 5973 3750 l 5853 3780 l 5853 3750 l 5853 3720 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3747 4005 m 3627 3975 l 3747 3945 l 3585 3945 l 3585 4005 l cp clip
+n 6000 3975 m 3600 3975 l gs col-1 s gr gr
+
+% arrowhead
+n 3747 4005 m 3627 3975 l 3747 3945 l 3747 3975 l 3747 4005 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+5853 4995 m 5973 5025 l 5853 5055 l 6015 5055 l 6015 4995 l cp clip
+n 6000 5025 m 3600 5025 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 4995 m 5973 5025 l 5853 5055 l 5853 5025 l 5853 4995 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+3747 5280 m 3627 5250 l 3747 5220 l 3585 5220 l 3585 5280 l cp clip
+n 6000 5250 m 3600 5250 l gs col-1 s gr gr
+
+% arrowhead
+n 3747 5280 m 3627 5250 l 3747 5220 l 3747 5250 l 3747 5280 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7743 5745 m 7863 5775 l 7743 5805 l 7905 5805 l 7905 5745 l cp clip
+n 3600 5775 m 7890 5775 l gs col-1 s gr gr
+
+% arrowhead
+n 7743 5745 m 7863 5775 l 7743 5805 l 7743 5775 l 7743 5745 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+1347 6330 m 1227 6300 l 1347 6270 l 1185 6270 l 1185 6330 l cp clip
+n 6000 6300 m 1200 6300 l gs col-1 s gr gr
+
+% arrowhead
+n 1347 6330 m 1227 6300 l 1347 6270 l 1347 6300 l 1347 6330 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+n 7890 877 m 7890 6900 l gs col-1 s gr
+% Polyline
+gs clippath
+8037 2955 m 7917 2925 l 8037 2895 l 7875 2895 l 7875 2955 l cp clip
+n 9165 2925 m 7890 2925 l gs col-1 s gr gr
+
+% arrowhead
+n 8037 2955 m 7917 2925 l 8037 2895 l 8037 2925 l 8037 2955 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9108 2325 m 9228 2355 l 9108 2385 l 9270 2385 l 9270 2325 l cp clip
+n 7905 2355 m 9255 2355 l gs col-1 s gr gr
+
+% arrowhead
+n 9108 2325 m 9228 2355 l 9108 2385 l 9108 2355 l 9108 2325 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9048 6090 m 9168 6120 l 9048 6150 l 9210 6150 l 9210 6090 l cp clip
+n 9195 6120 m 7920 6120 l gs col-1 s gr gr
+
+% arrowhead
+n 9048 6090 m 9168 6120 l 9048 6150 l 9048 6120 l 9048 6090 l cp gs 0.00 setgray ef gr col-1 s
+/Times-Roman ff 180.00 scf sf
+3465 660 m
+gs 1 -1 sc (main) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5775 675 m
+gs 1 -1 sc (encoder) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8070 690 m
+gs 1 -1 sc (transport) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1095 660 m
+gs 1 -1 sc (user) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+1320 1035 m
+gs 1 -1 sc (megaco:cast/3) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3645 3690 m
+gs 1 -1 sc (EncMod:decode_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4050 4500 m
+gs 1 -1 sc (\(ack requested\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3675 4950 m
+gs 1 -1 sc (EncMod:encode_message) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5160 3045 m
+gs 1 -1 sc (megaco:recieve_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5100 1935 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2400 6210 m
+gs 1 -1 sc (UserMod:handle_trans_reply/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5115 5685 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+3645 1275 m
+gs 1 -1 sc (EncMod:encode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+7995 2790 m
+gs 1 -1 sc (recieve bytes\(2\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+7935 2280 m
+gs 1 -1 sc (send bytes\(1\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+7935 6000 m
+gs 1 -1 sc (send bytes\(3\)) col-1 sh gr
+showpage
+$F2psEnd
+rs
diff --git a/lib/megaco/doc/src/call_flow_cont.gif b/lib/megaco/doc/src/call_flow_cont.gif
new file mode 100644
index 0000000000..ff25cdc185
--- /dev/null
+++ b/lib/megaco/doc/src/call_flow_cont.gif
Binary files differ
diff --git a/lib/megaco/doc/src/call_flow_cont.ps b/lib/megaco/doc/src/call_flow_cont.ps
new file mode 100644
index 0000000000..835e6a6ba1
--- /dev/null
+++ b/lib/megaco/doc/src/call_flow_cont.ps
@@ -0,0 +1,271 @@
+%!PS-Adobe-2.0
+%%Title: call_flow_cont.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Fri Jun 15 13:06:10 2001
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 54 372 584 759
+%%Pages: 1
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+0.0 792.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+%%Page: 1 1
+7.500 slw
+% Polyline
+n 9600 952 m 9600 6975 l gs col-1 s gr
+% Polyline
+n 7200 877 m 7200 6900 l gs col-1 s gr
+% Polyline
+n 4800 952 m 4800 6975 l gs col-1 s gr
+% Polyline
+n 2400 877 m 2400 6975 l gs col-1 s gr
+% Polyline
+gs clippath
+2547 3930 m 2427 3900 l 2547 3870 l 2385 3870 l 2385 3930 l cp clip
+n 4800 3900 m 2400 3900 l gs col-1 s gr gr
+
+% arrowhead
+n 2547 3930 m 2427 3900 l 2547 3870 l 2547 3900 l 2547 3930 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4653 1470 m 4773 1500 l 4653 1530 l 4815 1530 l 4815 1470 l cp clip
+n 4800 1500 m 2400 1500 l gs col-1 s gr gr
+
+% arrowhead
+n 4653 1470 m 4773 1500 l 4653 1530 l 4653 1500 l 4653 1470 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4947 1905 m 4827 1875 l 4947 1845 l 4785 1845 l 4785 1905 l cp clip
+n 7200 1875 m 4800 1875 l gs col-1 s gr gr
+
+% arrowhead
+n 4947 1905 m 4827 1875 l 4947 1845 l 4947 1875 l 4947 1905 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7053 1620 m 7173 1650 l 7053 1680 l 7215 1680 l 7215 1620 l cp clip
+n 4800 1650 m 7200 1650 l gs col-1 s gr gr
+
+% arrowhead
+n 7053 1620 m 7173 1650 l 7053 1680 l 7053 1650 l 7053 1620 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9453 2370 m 9573 2400 l 9453 2430 l 9615 2430 l 9615 2370 l cp clip
+n 4800 2400 m 9600 2400 l gs col-1 s gr gr
+
+% arrowhead
+n 9453 2370 m 9573 2400 l 9453 2430 l 9453 2400 l 9453 2370 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4872 3480 m 4752 3450 l 4872 3420 l 4710 3420 l 4710 3480 l cp clip
+n 7125 3450 m 4725 3450 l gs col-1 s gr gr
+
+% arrowhead
+n 4872 3480 m 4752 3450 l 4872 3420 l 4872 3450 l 4872 3480 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7053 3195 m 7173 3225 l 7053 3255 l 7215 3255 l 7215 3195 l cp clip
+n 4800 3225 m 7200 3225 l gs col-1 s gr gr
+
+% arrowhead
+n 7053 3195 m 7173 3225 l 7053 3255 l 7053 3225 l 7053 3195 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+2253 5070 m 2373 5100 l 2253 5130 l 2415 5130 l 2415 5070 l cp clip
+n 1125 5100 m 2400 5100 l gs col-1 s gr gr
+
+% arrowhead
+n 2253 5070 m 2373 5100 l 2253 5130 l col-1 s
+% Polyline
+gs clippath
+1272 4380 m 1152 4350 l 1272 4320 l 1110 4320 l 1110 4380 l cp clip
+n 1125 4350 m 2400 4350 l gs col-1 s gr gr
+
+% arrowhead
+n 1272 4380 m 1152 4350 l 1272 4320 l 1272 4350 l 1272 4380 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+2547 3930 m 2427 3900 l 2547 3870 l 2385 3870 l 2385 3930 l cp clip
+n 4800 3900 m 2400 3900 l gs col-1 s gr gr
+
+% arrowhead
+n 2547 3930 m 2427 3900 l 2547 3870 l 2547 3900 l 2547 3930 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+2253 1245 m 2373 1275 l 2253 1305 l 2415 1305 l 2415 1245 l cp clip
+n 1125 1275 m 2400 1275 l gs col-1 s gr gr
+
+% arrowhead
+n 2253 1245 m 2373 1275 l 2253 1305 l col-1 s
+% Polyline
+gs clippath
+4962 6150 m 4842 6120 l 4962 6090 l 4800 6090 l 4800 6150 l cp clip
+n 7215 6120 m 4815 6120 l gs col-1 s gr gr
+
+% arrowhead
+n 4962 6150 m 4842 6120 l 4962 6090 l 4962 6120 l 4962 6150 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+7083 5865 m 7203 5895 l 7083 5925 l 7245 5925 l 7245 5865 l cp clip
+n 4830 5895 m 7230 5895 l gs col-1 s gr gr
+
+% arrowhead
+n 7083 5865 m 7203 5895 l 7083 5925 l 7083 5895 l 7083 5865 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4653 5415 m 4773 5445 l 4653 5475 l 4815 5475 l 4815 5415 l cp clip
+n 4800 5445 m 2400 5445 l gs col-1 s gr gr
+
+% arrowhead
+n 4653 5415 m 4773 5445 l 4653 5475 l 4653 5445 l 4653 5415 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4947 6795 m 4827 6765 l 4947 6735 l 4785 6735 l 4785 6795 l cp clip
+n 9600 6765 m 4800 6765 l gs col-1 s gr gr
+
+% arrowhead
+n 4947 6795 m 4827 6765 l 4947 6735 l 4947 6765 l 4947 6795 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+9423 6525 m 9543 6555 l 9423 6585 l 9585 6585 l 9585 6525 l cp clip
+n 4770 6555 m 9570 6555 l gs col-1 s gr gr
+
+% arrowhead
+n 9423 6525 m 9543 6555 l 9423 6585 l 9423 6555 l 9423 6525 l cp gs 0.00 setgray ef gr col-1 s
+% Polyline
+gs clippath
+4917 2625 m 4797 2595 l 4917 2565 l 4755 2565 l 4755 2625 l cp clip
+n 9570 2595 m 4770 2595 l gs col-1 s gr gr
+
+% arrowhead
+n 4917 2625 m 4797 2595 l 4917 2565 l 4917 2595 l 4917 2625 l cp gs 0.00 setgray ef gr col-1 s
+/Times-Roman ff 180.00 scf sf
+2145 690 m
+gs 1 -1 sc (transport) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+9420 660 m
+gs 1 -1 sc (user) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2475 1425 m
+gs 1 -1 sc (megaco:receive_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4875 3075 m
+gs 1 -1 sc (EncMod:encode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+6045 2295 m
+gs 1 -1 sc (UserMod:handle_trans_requeat/3) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4860 1575 m
+gs 1 -1 sc (EncMod:decode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+4860 5790 m
+gs 1 -1 sc (EncMod:decode_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2445 5385 m
+gs 1 -1 sc (megaco:receive_message/4) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+2475 3825 m
+gs 1 -1 sc (SendMod:send_message/2) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+900 4260 m
+gs 1 -1 sc (send bytes\(2\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+945 5010 m
+gs 1 -1 sc (receive bytes\(3\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+990 1155 m
+gs 1 -1 sc (receive bytes\(1\)) col-1 sh gr
+/Times-Roman ff 210.00 scf sf
+5970 6480 m
+gs 1 -1 sc (UserMod:handle_trans_ack/4) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6900 675 m
+gs 1 -1 sc (encoder) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4590 735 m
+gs 1 -1 sc (main) col-1 sh gr
+showpage
+$F2psEnd
+rs
diff --git a/lib/megaco/doc/src/definitions/cite.defs b/lib/megaco/doc/src/definitions/cite.defs
new file mode 100644
index 0000000000..41fffc1460
--- /dev/null
+++ b/lib/megaco/doc/src/definitions/cite.defs
@@ -0,0 +1,26 @@
+[
+{"4711","CCITT","CCITT, Red Book Vol.-FASCILE VIII.7, Recomm. X400-X.430, Geneva, 1985","jocke"},
+{"X.680","ITU-T X.680","ITU-T Recommendation X.680 (1994) | ISO/IEC 8824-1: 1995, Abstract Syntax Notation One (ASN.1): Specification of Basic Notation"},
+{"X.682","ITU-T X.682","ITU-T Recommendation X.682 (1994) | ISO/IEC 8824-3: 1995, Abstract Syntax Notation One (ASN.1): Constraint Specification"},
+{"X.690","ITU-T X.690","ITU-T Recommendation X.690 (1994) | ISO/IEC 8825-1: 1995, ASN.1 Encoding Rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)"},
+{"X.691","ITU-T X.691","ITU-T Recommendation X.691 (04/95) | ISO/IEC 8825-2: 1995, ASN.1 Encoding Rules: Specification of Packed Encoding Rules (PER)"},
+{"X.681","ITU-T X.681","ITU-T Recommendation X.681 (1994) | ISO/IEC 8824-2: 1995, Abstract Syntax Notation One (ASN.1): Information Object Specification"},
+{"X.683","ITU-T X.683","ITU-T Recommendation X.683 (1994) | ISO/IEC 8824-4: 1995, Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 Specifications"},
+{
+ "DUBUISSON",
+ "ASN.1 Communication between Heterogeneous Systems",
+ "Oliver Dubuisson, ASN.1 Communication between Heterogeneous Systems, "
+ "June 2000 ISBN 0-126333361-0", "nibe"
+ },
+ {
+ "erlbook2",
+ "Concurrent Programming in ERLANG",
+ "J. Armstrong, R. Virding, C. Wikstrom, M. Williams, "
+ "Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X",
+ "kent"
+ },
+ {"practsgml", "Practical SGML",
+ "Eric van Herwijnen: Practical SGML, Kluwer Academic Publishers, 1990.",
+ "peter"
+}
+].
diff --git a/lib/megaco/doc/src/definitions/cite.defs.xml b/lib/megaco/doc/src/definitions/cite.defs.xml
new file mode 100644
index 0000000000..e54251fa24
--- /dev/null
+++ b/lib/megaco/doc/src/definitions/cite.defs.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cites SYSTEM "cites.dtd">
+
+<cites>
+ <cite>
+ <id>4711</id>
+ <shortdef>CCITT</shortdef>
+ <def>
+CCITT, Red Book Vol.-FASCILE VIII.7, Recomm. X400-X.430, Geneva, 1985. </def>
+ <resp>jocke</resp>
+ </cite>
+ <cite>
+ <id>X.680</id>
+ <shortdef>ITU-T X.680</shortdef>
+ <def>
+ITU-T Recommendation X.680 (1994) | ISO/IEC 8824-1: 1995, Abstract Syntax Notation One (ASN.1): Specification of Basic Notation. </def>
+ </cite>
+ <cite>
+ <id>X.682</id>
+ <shortdef>ITU-T X.682</shortdef>
+ <def>
+ITU-T Recommendation X.682 (1994) | ISO/IEC 8824-3: 1995, Abstract Syntax Notation One (ASN.1): Constraint Specification. </def>
+ </cite>
+ <cite>
+ <id>X.690</id>
+ <shortdef>ITU-T X.690</shortdef>
+ <def>
+ITU-T Recommendation X.690 (1994) | ISO/IEC 8825-1: 1995, ASN.1 Encoding Rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER). </def>
+ </cite>
+ <cite>
+ <id>X.691</id>
+ <shortdef>ITU-T X.691</shortdef>
+ <def>
+ITU-T Recommendation X.691 (04/95) | ISO/IEC 8825-2: 1995, ASN.1 Encoding Rules: Specification of Packed Encoding Rules (PER). </def>
+ </cite>
+ <cite>
+ <id>X.681</id>
+ <shortdef>ITU-T X.681</shortdef>
+ <def>
+ITU-T Recommendation X.681 (1994) | ISO/IEC 8824-2: 1995, Abstract Syntax Notation One (ASN.1): Information Object Specification. </def>
+ </cite>
+ <cite>
+ <id>X.683</id>
+ <shortdef>ITU-T X.683</shortdef>
+ <def>
+ITU-T Recommendation X.683 (1994) | ISO/IEC 8824-4: 1995, Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 Specifications. </def>
+ </cite>
+ <cite>
+ <id>DUBUISSON</id>
+ <shortdef>ASN.1 Communication between Heterogeneous Systems</shortdef>
+ <def>
+Oliver Dubuisson, ASN.1 Communication between Heterogeneous Systems, June 2000 ISBN 0-126333361-0. </def>
+ <resp>nibe</resp>
+ </cite>
+ <cite>
+ <id>erlbook2</id>
+ <shortdef>Concurrent Programming in ERLANG</shortdef>
+ <def>
+J. Armstrong, R. Virding, C. Wikstrom, M. Williams, Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X. </def>
+ <resp>kent</resp>
+ </cite>
+ <cite>
+ <id>practsgml</id>
+ <shortdef>Practical SGML</shortdef>
+ <def>
+Eric van Herwijnen: Practical SGML, Kluwer Academic Publishers, 1990. </def>
+ <resp>peter</resp>
+ </cite>
+</cites>
+
diff --git a/lib/megaco/doc/src/definitions/term.defs b/lib/megaco/doc/src/definitions/term.defs
new file mode 100644
index 0000000000..f3d6f865d2
--- /dev/null
+++ b/lib/megaco/doc/src/definitions/term.defs
@@ -0,0 +1,215 @@
+[{"agent","agent","An entity that terminates a management protocol in the Network Element.","mbj"},
+{"API","API","Application Programming Interface. The interface towards an application. Usually this is a set of functions available, but can also be a set of messages sent to or from an application.","mbj"},
+{"application","application","A collection of resources which is required to offer a specific service.","mbj"},
+{"appmon","Application Monitor","A graphical node and application process tree viewer. See also appmon.","mbj"},
+{"Appmon","Appmon","Application name for the Application Monitor within Erlang/OTP. A graphical node and process viewer.","mbj"},
+{"app callback","application callback module","A module which is called when the application is started, and when it has stopped. Every application has one application callback module.","mbj"},
+{"AC","application controller","A process which coordinates all operations on applications.","mbj"},
+{"app master","application master","The application master is a process that monitors the application. It is provided by the Erlang run-time system. Every application has an application master process.","mbj"},
+{".app file","application resource file","Specifies the resources required by the application and how the application should be started. Every application has one application resource file, called AppName.app.","mbj"},
+{"arity","arity","Denotes the number of arguments to a function.","jocke"},
+{"ASN.1","ASN.1","Abstract Syntax Notation One - an ITU-T and ISO standard notation for describing data formats used in communication protocols.","kenneth"},
+{"ASN.1 Compiler","ASN.1 Compiler","The Erlang/OTP ASN.1 Compiler translates an ASN.1 module into a corresponding Erlang module with encode and decode functions.","kenneth"},
+{"atom","atom","An atom is a constant. Atoms always starts with a lower case letter (a-z) and are terminated by a non-alphanumeric character - otherwise they must be quoted (enclosed in \' \'). An atom is a data type in Erlang, used to enhance the legibility of programs.","kenneth"},
+{"atomicity","atomicity","Atomicity refers to the \"all or nothing\" property. If a transaction succeeds (i.e. commits), then all its effects on the data is captured in the database. If the transaction does not succeed (i.e. aborts), then none of its effect on the data is captured in the database. In other words, the transaction processing algorithm guarantees that the database will not reflect a partitial effect of a transaction.","hakan"},
+{"attach","attach","The debugger may attach to a process. When attached, the debugger may show process details, such as message queues and variable bindings.","olin"},
+{"behaviour","behaviour","A \"pattern of design\" which can be used to build applications and processes in an applications.","mbj"},
+{"BIF","BIF","Built-In Functions which perform operations that are impossible or inefficient to program in Erlang itself. Are defined in
+the module Erlang in the application kernel","kenneth"},
+{"binary","binary","A data type in Erlang which is used to store an area of untyped memory. Binaries are used for efficiently handling large quantities of untyped data.","kenneth"},
+{"boolean","boolean","A common data type in programming and specification languages. The value can be either true or false.","kenneth"},
+{"boot file","boot file","A binary file with extension .boot which is read during start of an Erlang node. See SASL User's Guide for more info.","kenneth"},
+{"break point","break point","By setting a break point using the debugger, the user specifies a position in the source code of a module where execution is to be suspended and control transferred to the debugger.","olin"},
+{"CAshort","CA","See Certification Authority.","helen"},
+{"CA certificate","CA certificate","A certificate containing a CA's public key. Network entities use this public key to verify certificates signed with the CA's private key.","helen"},
+{"callback function","callback function","A callback function is a function exported from a callback module, that a generic behaviour calls to perform a specific task.", "mbj"},
+{"callback module","callback module","A callback module is a module that implements the specific parts of a generic behaviour. The generic behaviour specifies which callback functions must be exported from the module.","mbj"},
+{"certificate","certificate","A file used for authenticating network entities under the SSL protocol. A certificate contains information about its owner (called the subject) and issuer, plus the owner's public key and a signature made by a CA. Network entities verify these signatures using CA certificates.","helen"},
+{"CAlong","Certification Authority (CA)","A trusted third party whose purpose is to sign certificates for network entities it has authenticated using secure means. Other network entities can check the signature to verify that a CA has authenticated the bearer of a certificate.","helen"},
+{"CSRlong","Certificate Signing Request (CSR)","An unsigned certificate for submission to a Certification Authority, which signs it with its private key. Once the CSR is signed, it becomes a certificate.","helen"},
+{"child","child","A supervised process. See also permanent, transient, temporary child.","mbj"},
+{"cipher","cipher","A system of encryption.","helen"},
+{"ClearCase","ClearCase","A configuration management system from Rational Software Corporation.","lars"},
+{"client-server model","client-server model","A model where there is a server, which manages some resource, and a number of clients which send requests to the server to access the resource. The client-server model is one of the basic programming techniques for coordinating the activities of several parallel processes.","mbj"},
+{"cover","Coverage Analyser","Module name for the coverage analyser tool, located in the Tools application.","gunilla"},
+{"CORBAlong","Common Object Request Broker Architecture (CORBA)","A specification of an architecture for a distributed object system","lars"},{"CORBA","Common Object Request Broker Architecture (CORBA)","A specification of an architecture for a distributed object system","lars"},
+{"compiler","compiler","A compiler is a translator. A common type of compilers are those who takes source code for a programming language and translates it into code that is executable on a specific platform. E.g. the Erlang compiler translates Erlang source code to an intermediary code that is executable by the Erlang Run Time System.","kenneth"},
+{"consistency","consistency","Consistency refers to the requirement that, given a consistent initial database state, the state of the database after the successful execution of a transaction is also consistent; that is, a transaction transforms the database from a consistent state to another consistent state. Database consistency may be defined as a set of rules or constraints. If the execution of a transaction causes the consistency constraints to be violated, the transaction is not accepted (and thus aborted) by the system.","hakan"},
+{"cookie","cookie","A magic cookie is a secret atom assigned to each Erlang node. The Erlang nodes in a distributed system must know each others cookies in order to authorize each other for communication","kenneth"},
+{"CORBAshort","CORBA","See Common Object RequestBroker Architecture.","lars"},
+{"Coverage Analyser","Coverage Analyser","A tool which provides a set of functions for coverage analysis of Erlang programs, i.e observing how many times each line or function are executed. See also cover.","olin"},
+{"coverage analysis","coverage analysis","The task of determining which lines, or how many lines of code, has actually been executed. Useful for determining the completeness of test suites.","olin"},
+{"cross reference tool","cross reference tool","A tool that can be used for finding dependencies between functions, modules, applications and releases. The Erlang/OTP cross reference tool is called xref and is part of the Tools application.","gunilla"},
+{"CSRshort","CSR","See Certificate Signing Request.","helen"},
+{"data type","data type","The data types in Erlang are numbers, atoms, tuples, lists, pids, funs, records, ports, references and binaries. The values of Erlang data types can be stored in variables.","kenneth"},
+{"DBMSlong","Database Management System (DBMS)","A database is a collection of data and a DBMS is a system which manages the database. Applications accesses the database through the database management system.","hakan"},
+{"DBMSshort","DBMS","See Database Management System.","hakan"},
+{"Debugger","Debugger","An Erlang/OTP tool which provides mechanisms which makes it possible to see what happens during the execution of code in specified modules, or when processes crash.","olin"},
+{"dets","dets","A module within the stdlib application, which provides a term storage, and which is used as the underlying file storage mechanism by the Mnesia DBMS.","hakan"},
+{"dirty operations","dirty operations","Functions which manipulate data in a DBMS, without using transactions.","hakan"},
+{"distributed application","distributed application","An application which runs on one of several nodes. May be restarted on another node. (See local application.)","mbj"},
+{"DNSshort","DNS","See Domain Name System.","lars"},
+{"Docbuilder","Docbuilder","The documentation system used in Erlang/OTP.","jocke"},
+{"DNSlong","Domain Name System (DNS)","DNS is a service that map names to internet addresses","lars"},
+{"DTD","DTD","Document Type Definition as defined in SGML.","jocke"},
+{"durability","durability","If a transaction succeeds, then its effect on the data is persistently captured, and will survive subsequent system failures resulting in loss of data in volatile memory. Durability is usually enforced by first writing modified data to some non-volatile memory (usually disc), before a transaction is allowed to commit. If there is a system failure, the state of the non-volatile memory must be recovered to reflect the effect of all and only committed transactions.","hakan"},
+{"Emacs","Emacs"," A widely used text editor which allows customization of its behaviour. An Erlang mode for Emacs is included in the Erlang deliverables.","kenneth"},
+{"Emacs for Erlang","Emacs for Erlang","A tool which provides a major mode for editing Erlang source files in Emacs.","olin"},
+{"encaps","encapsulation","Data can be encapsulated into another data element.","kent"},
+{"eprof","eprof","A module in the tools application. See Profiler.","olin"},
+{"erl","erl","The command which starts an Erlang run-time system.","kenneth"},
+{"erl_interface","erl_interface library","A thread safe library with C-functions which makes it possible to write a C-program which appears as one of the nodes in a system of distributed Erlang nodes.","kenneth"},
+{"Erlang","Erlang","Erlang is a functional programming language intended for designing large industrial soft real time systems.","kenneth"},
+{"Erlang emulator","Erlang emulator","Another word for Erlang Virtual Machine.","kenneth"},
+{"ERTSlong","Erlang Run Time System","A fundamental part of Erlang/OTP which contains the Erlang Virtual Machine, the kernel and stdlib applications. The Erlang Run Time System is a mandatory part which all other Erlang applications are dependent upon.","kenneth"},
+{"Erlang VM","Erlang Virtual Machine","The virtual machine, which makes Erlang/OTP work together with a specific OS/HW platform. The Erlang Virtual Machine is available on several different platforms. The Erlang Virtual Machine is the glue which makes it possible to run an Erlang application on any platform without change.","kenneth"},
+{"ERTSshort","ERTS","See Erlang Run Time System.","kenneth"},
+{"ETS","ETS","Erlang Term Storage tables.","olin"},
+{"EVAshort","EVA","See Event and Alarm handling application","mbj"},
+{"EVAlong","Event and Alarm handling application (EVA)","An application that consists of Fault Management functionality, such as sending and logging of events and alarms.","mbj"},
+{"event handler","event handler","A module exporting functions which can process events sent to an event manager process. The event handler is a behaviour of type gen_event.","mbj"},
+{"event manager","event manager","A process to which events of a certain category is sent. gen_event handler can be installed in the event manager.","mbj"},
+{"exit signal","exit signal","A signal which is sent from a terminating process to the processes and ports it is linked to. An EXIT signal has the following format: {'EXIT', Exiting_Process_Id, Reason}.","kent"},
+{"foo","foo","Algebraic place holder.","kent"},
+{"FSM","FSM","Finite State Machine.","kenneth"},
+{"fun","fun","A data type, introduced in Erlang 4.4, which represent functional objects.","kenneth"},
+{"function","function","Erlang programs are written entirely in terms of modules with functions. A function can have arguments and does always return a result. A function can be exported which makes it available for calls from other modules. Non exported functions can only be called internally within the module.","kenneth"},
+{"Gateway","gateway","A server which acts as an intermediary for some other server. Unlike a proxy, a gateway receives requests as if it were the origin server for the requested resource; the requesting client may not be aware that it is communicating with a gateway.","jocke"},
+{"gen_event","gen_event","A behaviour used for programming event handling mechanisms, such as alarm handlers, error loggers, and plug-and-play handlers.","mbj"},
+{"gen_fsm","gen_fsm","A behaviour used for programming finite state machines.","mbj"},
+{"gen_server","gen_server","A behaviour used for programming client-server processes.","mbj"},
+{"gterm","Global Glossary Database","A glossary database used to list common acronymns and defintions etc.","jocke"},
+{"xref","xref","A cross reference tool that can be used for finding dependencies between functions, modules, applications and releases. Part of the Tools application.","gunilla"},
+{"GSlong","Graphics System","A library module which provides a graphics interface for Erlang.","mbj"},
+{"grid","grid","A multi-column object which is used to display tables. (Graphics System.)","mbj"},
+{"GSshort","GS","See Graphics System.","olin"},
+{"GS Contributions","GS Contributions","Unsupported user supplied tools which are included with the Erlang/OTP software release.","olin"},
+{"GUI","GUI","Graphical User Interface","mbj"},
+{"Home Directory","Home Directory","The position of a user account in the file system. The Home Directory is automatically passed to the Erlang run-time system at startup. On Unix the contents of the environment variable \"HOME\" is passed. Om Win32 the concatenation of the environment variables \"HOMEDRIVE\" and \"HOMEPATH\" is passed, or if these variables are not set, the value returned by the Win32 API function \"GetWindowsDirectory\" is passed.","kenneth"},
+{"host name","host name","The name of a machine on a network, e.g. erlang.ericsson.se.","kent"},
+{"HTML","HTML","Hypertext Markup Language.","jocke"},
+{"HTTP","HTTP","Hypertext Transfer Protocol.","jocke"},
+{"HTTPS","HTTPS","The Hypertext Transport Protocol, Secure, the standard SSL communication mechanism of the World Wide Web.","helen"},
+{"IDLshort","IDL","See Interface Description Language.","lars"},
+{"IDLlong","Interface Description Language (IDL)","The interface specification language created by OMG.","lars"},
+{"indexing","indexing","Fast lookup using an (usually enumerated) key.","kent"},
+{"I1","INETS","The Internet Services application","jocke"},
+{"initial call","initial call","The first call to an interpreted function (when using the Interpreter).","kent"},
+{"instrumentation function","instrumentation function","A function used to implement a Managed Object, i.e. give access to the real resources behind an MO.","mbj"},
+{"IDLlong","Interface Description Language (IDL)","The interface specification language created by OMG.","lars"},
+{"interpreter","interpreter","An application which provides mechanisms which make it possible to see what happens during the execution of code in specified (interpreted) modules, or when processes crash.","kent"},
+{"isolation","isolation","A transaction executes as if no other concurrent transactions are executing, and thus its execution results are equivalent to those obtained by executing database transactions serially. A system which maintains transaction isolation is also said to be enforcing serializability.","hakan"},
+{"kernel","kernel","An application which contains file servers, code servers and other code necessary for the Erlang run-time system.","kenneth"},
+{"key","key","A file containing the value that must be fed into an algorithm in order to encrypt or decrypt a message.","helen"},
+{"key pair","key pair","A set of two keys used in public key cryptography. One is the public key used to encrypt data, and the other is the private key necessary to decrypt the same data.","helen"},
+{"list","list","Terms separated by commas and enclosed in square brackets [ ] are called lists. A list is a data type in Erlang, used for storing a variable number of terms. It is dynamically sized. The first element of the list is referred to as the head of the list, and the remainer of the list as the tail.","kenneth"},
+{"list box","list box ","A list of labels with optional scroll bars attached. (Graphics System.)","mbj"},
+{"lc","list comprehension","A language construct in Erlang which are analogous to set comprehensions in Zermelo-Frankel set theory. Analogous to the 'setof' and 'findall' predicates in Prolog.","kenneth"},
+{"local application","local application","An application which runs on one node and which are always started at the local node only. (See distributed application.)","mbj"},
+{"manager","manager","An entity that terminates a management protocol in the Network Management Station.","mbj"},
+{"Master Agent","Master Agent","The SNMP agent system consists of one Master Agent which terminates the SNMP protocol","mbj"}, {"MIB","Management Information Base (MIB)","An abstract definition of the management information available through a management interface in a system.","mbj"},
+{"matching","matching","See pattern matching.","kenneth"},
+{"message queue","message queue","The queue of not yet received messages that are in the mailbox of a process.","olin"},
+{"Mnemosyne","Mnemosyne","Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.","hakan"},
+{"Mnesia","Mnesia","Mnesia is a distributed Database Management System, appropriate for telecommunications applications and other applications with need of continuous operation and soft real-time properties.","hakan"},
+{"MIBshort","MIB","See Management Information Base.","mbj"},
+{"MIME","MIME","Multi-purpose Internet Mail Extensions.","jocke"},
+{"MOlong","Managed Object (MO)","The abstract management information defined in a MIB.","mbj"}, {"MO", "MO","Managed Object; The abstract management information defined in a MIB.","nibe"},
+{"MOshort","MO","See Managed Object.","mbj"},
+{"module","module","Module is the unit for compilation and for loading in Erlang. A Module contains a module declaration, export declarations and code representing the functions in the module.","kenneth"},
+{"NCSA","NCSA","The National Center for Supercomputing Applications.","jocke"},
+{"NEshort","NE","See Network Element.","mbj"},
+{"NElong", "Network Element","In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity.","mbj"}, {"NE", "NE","Network Element; In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity.","mbj"},
+{"NMSlong","Network Management Station (NMS)","The place where the operator manages the network.","mbj"}, {"NMS","NMS","Network Management Station; The place where the operator manages the network.","nibe"},
+{"NMSshort","NMS","See Network Management Station.","mbj"},
+{"node","node","An executing Erlang run-time system which can communicate with other Erlang run-time systems.","kenneth"},
+{"node name","node name","A node name is an atom constructed as the concatenation of a name supplied by the user, an \"@\" character, and the name of the host where the node is executing.","kenneth"},
+{"notation","notation","How things are written.","kent"},
+{"notification","notification","Information of an event.","kent"},
+{"NROFF","NROFF","A text formatting language for line printer quality output devices that runs on the UNIX operating system.","jocke"},
+{"number","number","A data type in Erlang. Are subdivided into integers, for storing natural numbers, or floats, for storing real numbers.","kenneth"},
+{"OMGlong","Object Managment Group (OMG)","A standardisation group for all specifications in the area of CORBA.","lars"},
+{"OMGshort","OMG","Object Managment Group.","lars"},
+{"OTP","OTP","Open Telecom Platform","mike"},
+{"os_mon","os_mon","An application which monitors the behaviour of the underlying operating system","mbj"},
+{"parser generator","parser generator","A tool for making compilers which takes a grammar description as input and generates a complete program (a parser) which recognizes input which complies with the grammar. YECC is a parser generator included in the Erlang/OTP.","kenneth"},
+{"pass phrase","pass phrase","The word or phrase which authenticates the user who is authorized to use private key file. The pass phrase prevents unauthorized users from starting, restarting, or reconfiguring the server.","helen"},
+{"pattern matching","pattern matching","A basic mechanism in Erlang for assigning values to variables and for controlling the flow of a program.","kenneth"},
+{"permanent child","permanent child","A supervised process which always is restarted when it dies.","mbj"},
+{"Pid","Pid","Process Identifier. A data type in Erlang for storing process references. The process identity of the process displayed in the line.","kenneth"},
+{"Pman","Pman","Module and application name for the Process Trace Tool.","olin"},
+{"point","point","A unit used to indicate the size of a typeface. Equal to 1/72 inches.","jocke"},
+{"pointer","pointer","A pointer tells where data is stored. Memory pointers are not used in Erlang.","kent"},
+{"port","port","A data type in Erlang. Ports provide the basic mechanism for communication with the external world.","peterl"},
+{"port controller","port controller","An Erlang process which controls a port program. A port has exactly one port controller.","peterl"},
+{"port program","port program","A program that runs as an external program in the operating system and which the Erlang run-time system can start and communicate with by means of the Erlang port mechanism.","kenneth"},
+{"PostScript","PostScript","A language describing a fully laid-out page in terms of fonts, lines, grey scales, and so on, in a way that is interpretable by a printer. The language was developed by Adobe Systems.","jocke"},
+{"pretty-printed","pretty-printed","Nicely formatted code or data, e.g. C or Erlang, with indents and tabs etc.","jocke"},
+{"primitive","primitive","The basic elements in a programming language.","kent"},
+{"private key","private key","The secret key in a pair, used to decrypt incoming messages and sign outgoing ones.","helen"},
+{"process","process","A process is a self-contained separate unit of execution which exists concurrently with other processes in the system. The BIF \"spawn/3\" creates and starts the execution of a new process.","kenneth"},
+{"process dictionary","process dictionary","Each process has an associated dictionary which provides the process with simple destructive storage capabilities.","kenneth"},
+{"Process Manager","Process Manager","Obsolete name for the Process Trace Tool.","olin"},
+{"Process Trace Tool","Process Trace Tool","A tool which gives an overview of the processes in the Erlang run-time system. See also Pman.","olin"},
+{"Profiler","Profiler","Another name for eprof, a tool used to profile a system in order to find out how much time is spent in various segments of a program.","olin"},
+{"program","program","Routines which can be executed by a computer.","kent"},
+{"Proxy","proxy","An intermediary program which acts as both a server and a client for the purpose of making requests on behalf of other clients.","jocke"},
+{"public key","public key","The publicly available key in a key pair, used to encrypt messages bound for its owner and to decrypt signatures made by its owner.","helen"},
+{"query","query","Queries are used for accessing the data in a Database Management System. The query specify a maybe complicated relation that should hold for all of the selected data. This could involve several tables as well as conditions like for instance less then and greater then.","hakan"},
+{"query language","query language","A language which is specially designed to express database queries. Examples of query languages are QLC and SQL.","hakan"},
+{"receive","receive","A primitive for message processing in Erlang, receives a message from a process.","kenneth"},
+{"record","record","A data structure intended for storing a fixed number of related Erlang terms, it is similar to a \"struct\" in C or a \"record\" in Pascal.","kenneth"},
+{"recursion","recursion","A function is recursive if it calls itself until the result desired is attained. Recursion is the heart of functional programming.","kenneth"},
+{"reference","reference","A data type in Erlang for storing system unique references.","kenneth"},
+{"release handler","release handler","A SASL process which handles software upgrade.","mbj"},
+{"relup","release upgrade script","A script with instructions to the release handler of how the release should be installed in the system.","mbj"},
+{"RPC","Remote Proceedure Call","A technique for evaluating a function transparently on a remote node.","kenneth"},
+{"resource","resource","The actual resource to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources.","mbj"},{"resources","resources","The actual resources to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources.","nibe"},
+{"RFC","RFC","A \"Request for Comments\" used as a proposed standard by IETF.","jocke"},
+{"SASLshort","SASL","See System Architecture Support Libraries.","mbj"},
+{"schema","schema","The schema contains the definitions and whereabouts for all tables. In Mnesia it is realized as a special table named \"schema\".","hakan"},
+{"schema functions","schema functions","The functions which are available for managing schemas.","hakan"},
+{"SDL","SDL","Specification and Description Language. A ITU-T standard specification language which is used to specify the behaviour of switching systems.","kenneth"},
+{"send","send","A primitive for message processing in Erlang, sends a message to a process.","kenneth"},
+{"shell","shell"," The shell is an interactive front-end to an Erlang node where Erlang expressions can be evaluated. ","kenneth"},
+{"shell prompt","shell prompt","The text or symbol shown on the screen when the shell is ready to receive commands.","kent"},
+{"SNMPEAlong","Simple Network Management Protocol Extensible Agent (SNMPEA).","An Erlang/OTP application that includes a bilingual extensible SNMP agent.","mbj"},
+{"single assignment","single assignment","Means that once a variable has been assigned a value, the value can never be changed. Erlang is a single assignment language.","kenneth"},
+{"single step","single step","Single stepping is a function provided by the debugger. By single stepping the developer may use the debugger to follow the execution of a process and see what actually happens at each function call.","olin"},
+{"slave","slave","Not in control, can never take over by himself.","kent"},
+{"SSLlong","Secure Sockets Layer (SSL)","A protocol created by Netscape Communications Corporation for authentication and encryption over TCP/IP networks, including Web.","helen"},
+{"signature","signature","An encrypted text block that validates a certificate or other file. A Certification Authority (CA) creates a signature by generating a hash of the public key embedded in a certificate, then encrypting the hash with its own private key. Only the CA's public key can decrypt the signature, verifying that the CA has authenticated the network entity that owns the certificate.","helen"},
+{"SNMPshort","SNMP","Simple Network Management Protocol.","mbj"},
+{"SNMPshort","SNMPEA","See Simple Network Management Protocol Extensible Agent.","mbj"},
+{"spawn","spawn","A primitive for multiprocessing in Erlang, that starts a parallel computation (called a process). The creation of a new process","kenneth"},
+{"SSLshort","SSL","See Secure Sockets Layer.","helen"},
+{"SSLeay","SSLeay","An SSL library developed by Eric Yong ([email protected]).","helen"},
+{"SSLTOP","SSLTOP","The path to your SSL directory, a subdirectory of ServerRoot.","helen"},
+{"start script","start script","A start script is a file with .script extension which is the source when a boot file is created. See SASL User's Guide for more info.","kenneth"},
+{"stdlib","stdlib","An application within Erlang/OTP which contains modules for manipulating lists, strings, files, etc.","kenneth"},
+{"sticky directory","sticky directory","A directory containing Erlang object code that is part of the runtime system.","kent"},
+{"sticky lock","sticky lock","A lock which lingers at a node after the transaction which first acquired the lock has terminated. Once a process has obtained a sticky lock on a node, subsequent locks acquired by processes on the same node, can be set without need of involving remote nodes.","hakan"},
+{"string","string","The ASCII or ISO-8859-1 representation of the list of characters occurring within quotation marks in Erlang code.","kent"},
+{"Subagent","Subagent","The SNMP agent system consists of one Master Agent (See Master Agent) and zero or more Subagents which can be used to distribute the SNMP agent system on several nodes.","mbj"},
+{"supervision tree","supervision tree","A hierarcial tree of processes used to program fault tolerant systems.","mbj"},
+{"supervisor","supervisor","A behaviour to stucture fault tolerant computations, and program supervision trees with.","mbj"},
+{"sup_bridge","supervisor bridge"," A behaviour used to connect a process, or subsystem, to a supervisor tree.","mbj"},
+{"SASLlong","System Architecture Support Libraries (SASL)","An Erlang/OTP application which contains services for error logging, release handling and report browsing.","mbj"}, {".config","system configuration file","A file which specifies configuration parameters for the applications in the system.","mbj"},
+{"table lock","table lock","Table locks are locks which are set on whole tables. They may either be read locks or write locks.","hakan"},
+{"Table Visualizer","Table Visualizer","A tool which enables the user to examine ETS and Mnesia tables.","olin"},
+{"temporary child","temporary child","A supervised process which is never restarted when it dies.","mbj"},
+{"term","term","The super type of all Erlang types.","kenneth"},
+{"Toolbar","Toolbar","A tool that provides an simplistic interface to the other various Erlang/OTP tools","olin"},
+{"tools","tools","An application within Erlang/OTP which contains the tools which are not applications themselves.","olin"},
+{"transaction","transaction","Transactions groups a set of database accesses into an atomic unit. All transactions has the ACID (atomicity, concistency, isolation and durability) properties.","hakan"},
+{"transient child","transient child","A supervised process which is restarted if it dies non-normally.","mbj"},
+{"trigger","trigger","The Interpreter. A break point that is reached by a process triggers if it is active, and the execution of the process is stopped.","olin"},
+{"tty","tty","tty is a simple command line interface program where keystrokes are collected and interpreted. Originally meant teletypewriter equipment. Now it usually means the user console/terminal/shell window.","kent"},
+{"tuple","tuple","A tuple is a data type in Erlang. Tuples are used as place holders for complex data structures. Tuples may contain anything of any size, and are written as sequences of terms separated by commas, and enclosed in curly brackets { }.","kenneth"},
+{"variable","variable","An alias for a memory position, in which a value can be put. Erlang variables always start with an upper case letter.","kenneth"},
+{"workers","workers","The lower nodes in a supervision tree. These are the processes that actually performs some real work, e.g. servers.","mbj"},
+{"YECC","YECC","A LALR-1 parser generator included in Erlang/OTP. It is written in Erlang and generates a parser as an Erlang module.","kenneth"}].
+
+
+
+
diff --git a/lib/megaco/doc/src/definitions/term.defs.xml b/lib/megaco/doc/src/definitions/term.defs.xml
new file mode 100644
index 0000000000..28ac0d6eaf
--- /dev/null
+++ b/lib/megaco/doc/src/definitions/term.defs.xml
@@ -0,0 +1,1525 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE terms SYSTEM "terms.dtd">
+
+<terms>
+ <term>
+ <id>agent</id>
+ <shortdef>agent</shortdef>
+ <def>
+An entity that terminates a management protocol in the Network Element. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>API</id>
+ <shortdef>API</shortdef>
+ <def>
+Application Programming Interface. The interface towards an application. Usually this is a set of functions available, but can also be a set of messages sent to or from an application. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>application</id>
+ <shortdef>application</shortdef>
+ <def>
+A collection of resources which is required to offer a specific service. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>appmon</id>
+ <shortdef>Application Monitor</shortdef>
+ <def>
+A graphical node and application process tree viewer. See also appmon. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>Appmon</id>
+ <shortdef>Appmon</shortdef>
+ <def>
+Application name for the Application Monitor within Erlang/OTP. A graphical node and process viewer. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>app callback</id>
+ <shortdef>application callback module</shortdef>
+ <def>
+A module which is called when the application is started, and when it has stopped. Every application has one application callback module. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>AC</id>
+ <shortdef>application controller</shortdef>
+ <def>
+A process which coordinates all operations on applications. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>app master</id>
+ <shortdef>application master</shortdef>
+ <def>
+The application master is a process that monitors the application. It is provided by the Erlang run-time system. Every application has an application master process. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>.app file</id>
+ <shortdef>application resource file</shortdef>
+ <def>
+Specifies the resources required by the application and how the application should be started. Every application has one application resource file, called AppName.app. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>arity</id>
+ <shortdef>arity</shortdef>
+ <def>
+Denotes the number of arguments to a function. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>ASN.1</id>
+ <shortdef>ASN.1</shortdef>
+ <def>
+Abstract Syntax Notation One - an ITU-T and ISO standard notation for describing data formats used in communication protocols. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>ASN.1 Compiler</id>
+ <shortdef>ASN.1 Compiler</shortdef>
+ <def>
+The Erlang/OTP ASN.1 Compiler translates an ASN.1 module into a corresponding Erlang module with encode and decode functions. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>atom</id>
+ <shortdef>atom</shortdef>
+ <def>
+An atom is a constant. Atoms always starts with a lower case letter (a-z) and are terminated by a non-alphanumeric character - otherwise they must be quoted (enclosed in ' '). An atom is a data type in Erlang, used to enhance the legibility of programs. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>atomicity</id>
+ <shortdef>atomicity</shortdef>
+ <def>
+Atomicity refers to the "all or nothing" property. If a transaction succeeds (i.e. commits), then all its effects on the data is captured in the database. If the transaction does not succeed (i.e. aborts), then none of its effect on the data is captured in the database. In other words, the transaction processing algorithm guarantees that the database will not reflect a partitial effect of a transaction. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>attach</id>
+ <shortdef>attach</shortdef>
+ <def>
+The debugger may attach to a process. When attached, the debugger may show process details, such as message queues and variable bindings. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>behaviour</id>
+ <shortdef>behaviour</shortdef>
+ <def>
+A "pattern of design" which can be used to build applications and processes in an applications. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>BIF</id>
+ <shortdef>BIF</shortdef>
+ <def>
+Built-In Functions which perform operations that are impossible or inefficient to program in Erlang itself. Are defined in the module Erlang in the application kernel </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>binary</id>
+ <shortdef>binary</shortdef>
+ <def>
+A data type in Erlang which is used to store an area of untyped memory. Binaries are used for efficiently handling large quantities of untyped data. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>boolean</id>
+ <shortdef>boolean</shortdef>
+ <def>
+A common data type in programming and specification languages. The value can be either true or false. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>boot file</id>
+ <shortdef>boot file</shortdef>
+ <def>
+A binary file with extension .boot which is read during start of an Erlang node. See SASL User's Guide for more info. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>break point</id>
+ <shortdef>break point</shortdef>
+ <def>
+By setting a break point using the debugger, the user specifies a position in the source code of a module where execution is to be suspended and control transferred to the debugger. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>CAshort</id>
+ <shortdef>CA</shortdef>
+ <def>
+See Certification Authority. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>CA certificate</id>
+ <shortdef>CA certificate</shortdef>
+ <def>
+A certificate containing a CA's public key. Network entities use this public key to verify certificates signed with the CA's private key. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>callback function</id>
+ <shortdef>callback function</shortdef>
+ <def>
+A callback function is a function exported from a callback module, that a generic behaviour calls to perform a specific task. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>callback module</id>
+ <shortdef>callback module</shortdef>
+ <def>
+A callback module is a module that implements the specific parts of a generic behaviour. The generic behaviour specifies which callback functions must be exported from the module. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>certificate</id>
+ <shortdef>certificate</shortdef>
+ <def>
+A file used for authenticating network entities under the SSL protocol. A certificate contains information about its owner (called the subject) and issuer, plus the owner's public key and a signature made by a CA. Network entities verify these signatures using CA certificates. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>CAlong</id>
+ <shortdef>Certification Authority (CA)</shortdef>
+ <def>
+A trusted third party whose purpose is to sign certificates for network entities it has authenticated using secure means. Other network entities can check the signature to verify that a CA has authenticated the bearer of a certificate. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>CSRlong</id>
+ <shortdef>Certificate Signing Request (CSR)</shortdef>
+ <def>
+An unsigned certificate for submission to a Certification Authority, which signs it with its private key. Once the CSR is signed, it becomes a certificate. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>child</id>
+ <shortdef>child</shortdef>
+ <def>
+A supervised process. See also permanent, transient, temporary child. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>cipher</id>
+ <shortdef>cipher</shortdef>
+ <def>
+A system of encryption. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>ClearCase</id>
+ <shortdef>ClearCase</shortdef>
+ <def>
+A configuration management system from Rational Software Corporation. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>client-server model</id>
+ <shortdef>client-server model</shortdef>
+ <def>
+A model where there is a server, which manages some resource, and a number of clients which send requests to the server to access the resource. The client-server model is one of the basic programming techniques for coordinating the activities of several parallel processes. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>cover</id>
+ <shortdef>Coverage Analyser</shortdef>
+ <def>
+Module name for the coverage analyser tool, located in the Tools application. </def>
+ <resp>gunilla</resp>
+ </term>
+ <term>
+ <id>CORBAlong</id>
+ <shortdef>Common Object Request Broker Architecture (CORBA)</shortdef>
+ <def>
+A specification of an architecture for a distributed object system </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>CORBA</id>
+ <shortdef>Common Object Request Broker Architecture (CORBA)</shortdef>
+ <def>
+A specification of an architecture for a distributed object system </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>compiler</id>
+ <shortdef>compiler</shortdef>
+ <def>
+A compiler is a translator. A common type of compilers are those who takes source code for a programming language and translates it into code that is executable on a specific platform. E.g. the Erlang compiler translates Erlang source code to an intermediary code that is executable by the Erlang Run Time System. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>consistency</id>
+ <shortdef>consistency</shortdef>
+ <def>
+Consistency refers to the requirement that, given a consistent initial database state, the state of the database after the successful execution of a transaction is also consistent; that is, a transaction transforms the database from a consistent state to another consistent state. Database consistency may be defined as a set of rules or constraints. If the execution of a transaction causes the consistency constraints to be violated, the transaction is not accepted (and thus aborted) by the system. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>cookie</id>
+ <shortdef>cookie</shortdef>
+ <def>
+A magic cookie is a secret atom assigned to each Erlang node. The Erlang nodes in a distributed system must know each others cookies in order to authorize each other for communication </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>CORBAshort</id>
+ <shortdef>CORBA</shortdef>
+ <def>
+See Common Object RequestBroker Architecture. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>Coverage Analyser</id>
+ <shortdef>Coverage Analyser</shortdef>
+ <def>
+A tool which provides a set of functions for coverage analysis of Erlang programs, i.e observing how many times each line or function are executed. See also cover. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>coverage analysis</id>
+ <shortdef>coverage analysis</shortdef>
+ <def>
+The task of determining which lines, or how many lines of code, has actually been executed. Useful for determining the completeness of test suites. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>cross reference tool</id>
+ <shortdef>cross reference tool</shortdef>
+ <def>
+A tool that can be used for finding dependencies between functions, modules, applications and releases. The Erlang/OTP cross reference tool is called xref and is part of the Tools application. </def>
+ <resp>gunilla</resp>
+ </term>
+ <term>
+ <id>CSRshort</id>
+ <shortdef>CSR</shortdef>
+ <def>
+See Certificate Signing Request. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>data type</id>
+ <shortdef>data type</shortdef>
+ <def>
+The data types in Erlang are numbers, atoms, tuples, lists, pids, funs, records, ports, references and binaries. The values of Erlang data types can be stored in variables. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>DBMSlong</id>
+ <shortdef>Database Management System (DBMS)</shortdef>
+ <def>
+A database is a collection of data and a DBMS is a system which manages the database. Applications accesses the database through the database management system. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>DBMSshort</id>
+ <shortdef>DBMS</shortdef>
+ <def>
+See Database Management System. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>Debugger</id>
+ <shortdef>Debugger</shortdef>
+ <def>
+An Erlang/OTP tool which provides mechanisms which makes it possible to see what happens during the execution of code in specified modules, or when processes crash. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>dets</id>
+ <shortdef>dets</shortdef>
+ <def>
+A module within the stdlib application, which provides a term storage, and which is used as the underlying file storage mechanism by the Mnesia DBMS. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>dirty operations</id>
+ <shortdef>dirty operations</shortdef>
+ <def>
+Functions which manipulate data in a DBMS, without using transactions. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>distributed application</id>
+ <shortdef>distributed application</shortdef>
+ <def>
+An application which runs on one of several nodes. May be restarted on another node. (See local application.) </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>DNSshort</id>
+ <shortdef>DNS</shortdef>
+ <def>
+See Domain Name System. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>Docbuilder</id>
+ <shortdef>Docbuilder</shortdef>
+ <def>
+The documentation system used in Erlang/OTP. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>DNSlong</id>
+ <shortdef>Domain Name System (DNS)</shortdef>
+ <def>
+DNS is a service that map names to internet addresses </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>DTD</id>
+ <shortdef>DTD</shortdef>
+ <def>
+Document Type Definition as defined in SGML. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>durability</id>
+ <shortdef>durability</shortdef>
+ <def>
+If a transaction succeeds, then its effect on the data is persistently captured, and will survive subsequent system failures resulting in loss of data in volatile memory. Durability is usually enforced by first writing modified data to some non-volatile memory (usually disc), before a transaction is allowed to commit. If there is a system failure, the state of the non-volatile memory must be recovered to reflect the effect of all and only committed transactions. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>Emacs</id>
+ <shortdef>Emacs</shortdef>
+ <def>
+A widely used text editor which allows customization of its behaviour. An Erlang mode for Emacs is included in the Erlang deliverables. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Emacs for Erlang</id>
+ <shortdef>Emacs for Erlang</shortdef>
+ <def>
+A tool which provides a major mode for editing Erlang source files in Emacs. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>encaps</id>
+ <shortdef>encapsulation</shortdef>
+ <def>
+Data can be encapsulated into another data element. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>eprof</id>
+ <shortdef>eprof</shortdef>
+ <def>
+A module in the tools application. See Profiler. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>erl</id>
+ <shortdef>erl</shortdef>
+ <def>
+The command which starts an Erlang run-time system. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>erl_interface</id>
+ <shortdef>erl_interface library</shortdef>
+ <def>
+A thread safe library with C-functions which makes it possible to write a C-program which appears as one of the nodes in a system of distributed Erlang nodes. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Erlang</id>
+ <shortdef>Erlang</shortdef>
+ <def>
+Erlang is a functional programming language intended for designing large industrial soft real time systems. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Erlang emulator</id>
+ <shortdef>Erlang emulator</shortdef>
+ <def>
+Another word for Erlang Virtual Machine. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>ERTSlong</id>
+ <shortdef>Erlang Run Time System</shortdef>
+ <def>
+A fundamental part of Erlang/OTP which contains the Erlang Virtual Machine, the kernel and stdlib applications. The Erlang Run Time System is a mandatory part which all other Erlang applications are dependent upon. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Erlang VM</id>
+ <shortdef>Erlang Virtual Machine</shortdef>
+ <def>
+The virtual machine, which makes Erlang/OTP work together with a specific OS/HW platform. The Erlang Virtual Machine is available on several different platforms. The Erlang Virtual Machine is the glue which makes it possible to run an Erlang application on any platform without change. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>ERTSshort</id>
+ <shortdef>ERTS</shortdef>
+ <def>
+See Erlang Run Time System. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>ETS</id>
+ <shortdef>ETS</shortdef>
+ <def>
+Erlang Term Storage tables. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>EVAshort</id>
+ <shortdef>EVA</shortdef>
+ <def>
+See Event and Alarm handling application </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>EVAlong</id>
+ <shortdef>Event and Alarm handling application (EVA)</shortdef>
+ <def>
+An application that consists of Fault Management functionality, such as sending and logging of events and alarms. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>event handler</id>
+ <shortdef>event handler</shortdef>
+ <def>
+A module exporting functions which can process events sent to an event manager process. The event handler is a behaviour of type gen_event. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>event manager</id>
+ <shortdef>event manager</shortdef>
+ <def>
+A process to which events of a certain category is sent. gen_event handler can be installed in the event manager. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>exit signal</id>
+ <shortdef>exit signal</shortdef>
+ <def>
+A signal which is sent from a terminating process to the processes and ports it is linked to. An EXIT signal has the following format: {'EXIT', Exiting_Process_Id, Reason}. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>foo</id>
+ <shortdef>foo</shortdef>
+ <def>
+Algebraic place holder. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>FSM</id>
+ <shortdef>FSM</shortdef>
+ <def>
+Finite State Machine. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>fun</id>
+ <shortdef>fun</shortdef>
+ <def>
+A data type, introduced in Erlang 4.4, which represent functional objects. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>function</id>
+ <shortdef>function</shortdef>
+ <def>
+Erlang programs are written entirely in terms of modules with functions. A function can have arguments and does always return a result. A function can be exported which makes it available for calls from other modules. Non exported functions can only be called internally within the module. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Gateway</id>
+ <shortdef>gateway</shortdef>
+ <def>
+A server which acts as an intermediary for some other server. Unlike a proxy, a gateway receives requests as if it were the origin server for the requested resource; the requesting client may not be aware that it is communicating with a gateway. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>gen_event</id>
+ <shortdef>gen_event</shortdef>
+ <def>
+A behaviour used for programming event handling mechanisms, such as alarm handlers, error loggers, and plug-and-play handlers. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>gen_fsm</id>
+ <shortdef>gen_fsm</shortdef>
+ <def>
+A behaviour used for programming finite state machines. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>gen_server</id>
+ <shortdef>gen_server</shortdef>
+ <def>
+A behaviour used for programming client-server processes. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>gterm</id>
+ <shortdef>Global Glossary Database</shortdef>
+ <def>
+A glossary database used to list common acronymns and defintions etc. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>xref</id>
+ <shortdef>xref</shortdef>
+ <def>
+A cross reference tool that can be used for finding dependencies between functions, modules, applications and releases. Part of the Tools application. </def>
+ <resp>gunilla</resp>
+ </term>
+ <term>
+ <id>GSlong</id>
+ <shortdef>Graphics System</shortdef>
+ <def>
+A library module which provides a graphics interface for Erlang. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>grid</id>
+ <shortdef>grid</shortdef>
+ <def>
+A multi-column object which is used to display tables. (Graphics System.) </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>GSshort</id>
+ <shortdef>GS</shortdef>
+ <def>
+See Graphics System. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>GS Contributions</id>
+ <shortdef>GS Contributions</shortdef>
+ <def>
+Unsupported user supplied tools which are included with the Erlang/OTP software release. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>GUI</id>
+ <shortdef>GUI</shortdef>
+ <def>
+Graphical User Interface </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>Home Directory</id>
+ <shortdef>Home Directory</shortdef>
+ <def>
+The position of a user account in the file system. The Home Directory is automatically passed to the Erlang run-time system at startup. On Unix the contents of the environment variable "HOME" is passed. Om Win32 the concatenation of the environment variables "HOMEDRIVE" and "HOMEPATH" is passed, or if these variables are not set, the value returned by the Win32 API function "GetWindowsDirectory" is passed. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>host name</id>
+ <shortdef>host name</shortdef>
+ <def>
+The name of a machine on a network, e.g. erlang.ericsson.se. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>HTML</id>
+ <shortdef>HTML</shortdef>
+ <def>
+Hypertext Markup Language. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>HTTP</id>
+ <shortdef>HTTP</shortdef>
+ <def>
+Hypertext Transfer Protocol. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>HTTPS</id>
+ <shortdef>HTTPS</shortdef>
+ <def>
+The Hypertext Transport Protocol, Secure, the standard SSL communication mechanism of the World Wide Web. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>IDLshort</id>
+ <shortdef>IDL</shortdef>
+ <def>
+See Interface Description Language. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>IDLlong</id>
+ <shortdef>Interface Description Language (IDL)</shortdef>
+ <def>
+The interface specification language created by OMG. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>indexing</id>
+ <shortdef>indexing</shortdef>
+ <def>
+Fast lookup using an (usually enumerated) key. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>I1</id>
+ <shortdef>INETS</shortdef>
+ <def>
+The Internet Services application </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>initial call</id>
+ <shortdef>initial call</shortdef>
+ <def>
+The first call to an interpreted function (when using the Interpreter). </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>instrumentation function</id>
+ <shortdef>instrumentation function</shortdef>
+ <def>
+A function used to implement a Managed Object, i.e. give access to the real resources behind an MO. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>IDLlong</id>
+ <shortdef>Interface Description Language (IDL)</shortdef>
+ <def>
+The interface specification language created by OMG. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>interpreter</id>
+ <shortdef>interpreter</shortdef>
+ <def>
+An application which provides mechanisms which make it possible to see what happens during the execution of code in specified (interpreted) modules, or when processes crash. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>isolation</id>
+ <shortdef>isolation</shortdef>
+ <def>
+A transaction executes as if no other concurrent transactions are executing, and thus its execution results are equivalent to those obtained by executing database transactions serially. A system which maintains transaction isolation is also said to be enforcing serializability. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>kernel</id>
+ <shortdef>kernel</shortdef>
+ <def>
+An application which contains file servers, code servers and other code necessary for the Erlang run-time system. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>key</id>
+ <shortdef>key</shortdef>
+ <def>
+A file containing the value that must be fed into an algorithm in order to encrypt or decrypt a message. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>key pair</id>
+ <shortdef>key pair</shortdef>
+ <def>
+A set of two keys used in public key cryptography. One is the public key used to encrypt data, and the other is the private key necessary to decrypt the same data. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>list</id>
+ <shortdef>list</shortdef>
+ <def>
+Terms separated by commas and enclosed in square brackets [ ] are called lists. A list is a data type in Erlang, used for storing a variable number of terms. It is dynamically sized. The first element of the list is referred to as the head of the list, and the remainer of the list as the tail. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>list box</id>
+ <shortdef>list box </shortdef>
+ <def>
+A list of labels with optional scroll bars attached. (Graphics System.) </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>lc</id>
+ <shortdef>list comprehension</shortdef>
+ <def>
+A language construct in Erlang which are analogous to set comprehensions in Zermelo-Frankel set theory. Analogous to the 'setof' and 'findall' predicates in Prolog. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>local application</id>
+ <shortdef>local application</shortdef>
+ <def>
+An application which runs on one node and which are always started at the local node only. (See distributed application.) </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>manager</id>
+ <shortdef>manager</shortdef>
+ <def>
+An entity that terminates a management protocol in the Network Management Station. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>Master Agent</id>
+ <shortdef>Master Agent</shortdef>
+ <def>
+The SNMP agent system consists of one Master Agent which terminates the SNMP protocol </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>MIB</id>
+ <shortdef>Management Information Base (MIB)</shortdef>
+ <def>
+An abstract definition of the management information available through a management interface in a system. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>matching</id>
+ <shortdef>matching</shortdef>
+ <def>
+See pattern matching. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>message queue</id>
+ <shortdef>message queue</shortdef>
+ <def>
+The queue of not yet received messages that are in the mailbox of a process. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>Mnemosyne</id>
+ <shortdef>Mnemosyne</shortdef>
+ <def>
+Mnemosyne was the query language of Mnesia up to the R11B release. Supersed by QLC.</def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>Mnesia</id>
+ <shortdef>Mnesia</shortdef>
+ <def>
+Mnesia is a distributed Database Management System, appropriate for telecommunications applications and other applications with need of continuous operation and soft real-time properties. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>MIBshort</id>
+ <shortdef>MIB</shortdef>
+ <def>
+See Management Information Base. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>MIME</id>
+ <shortdef>MIME</shortdef>
+ <def>
+Multi-purpose Internet Mail Extensions. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>MOlong</id>
+ <shortdef>Managed Object (MO)</shortdef>
+ <def>
+The abstract management information defined in a MIB. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>MO</id>
+ <shortdef>MO</shortdef>
+ <def>
+Managed Object; The abstract management information defined in a MIB. </def>
+ <resp>nibe</resp>
+ </term>
+ <term>
+ <id>MOshort</id>
+ <shortdef>MO</shortdef>
+ <def>
+See Managed Object. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>module</id>
+ <shortdef>module</shortdef>
+ <def>
+Module is the unit for compilation and for loading in Erlang. A Module contains a module declaration, export declarations and code representing the functions in the module. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>NCSA</id>
+ <shortdef>NCSA</shortdef>
+ <def>
+The National Center for Supercomputing Applications. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>NEshort</id>
+ <shortdef>NE</shortdef>
+ <def>
+See Network Element. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>NElong</id>
+ <shortdef>Network Element</shortdef>
+ <def>
+In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>NE</id>
+ <shortdef>NE</shortdef>
+ <def>
+Network Element; In OTP, the Network Element is the entire distributed OTP system, meaning that the distributed OTP system is managed as one entity. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>NMSlong</id>
+ <shortdef>Network Management Station (NMS)</shortdef>
+ <def>
+The place where the operator manages the network. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>NMS</id>
+ <shortdef>NMS</shortdef>
+ <def>
+Network Management Station; The place where the operator manages the network. </def>
+ <resp>nibe</resp>
+ </term>
+ <term>
+ <id>NMSshort</id>
+ <shortdef>NMS</shortdef>
+ <def>
+See Network Management Station. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>node</id>
+ <shortdef>node</shortdef>
+ <def>
+An executing Erlang run-time system which can communicate with other Erlang run-time systems. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>node name</id>
+ <shortdef>node name</shortdef>
+ <def>
+A node name is an atom constructed as the concatenation of a name supplied by the user, an "@" character, and the name of the host where the node is executing. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>notation</id>
+ <shortdef>notation</shortdef>
+ <def>
+How things are written. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>notification</id>
+ <shortdef>notification</shortdef>
+ <def>
+Information of an event. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>NROFF</id>
+ <shortdef>NROFF</shortdef>
+ <def>
+A text formatting language for line printer quality output devices that runs on the UNIX operating system. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>number</id>
+ <shortdef>number</shortdef>
+ <def>
+A data type in Erlang. Are subdivided into integers, for storing natural numbers, or floats, for storing real numbers. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>OMGlong</id>
+ <shortdef>Object Managment Group (OMG)</shortdef>
+ <def>
+A standardisation group for all specifications in the area of CORBA. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>OMGshort</id>
+ <shortdef>OMG</shortdef>
+ <def>
+Object Managment Group. </def>
+ <resp>lars</resp>
+ </term>
+ <term>
+ <id>OTP</id>
+ <shortdef>OTP</shortdef>
+ <def>
+Open Telecom Platform </def>
+ <resp>mike</resp>
+ </term>
+ <term>
+ <id>os_mon</id>
+ <shortdef>os_mon</shortdef>
+ <def>
+An application which monitors the behaviour of the underlying operating system </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>parser generator</id>
+ <shortdef>parser generator</shortdef>
+ <def>
+A tool for making compilers which takes a grammar description as input and generates a complete program (a parser) which recognizes input which complies with the grammar. YECC is a parser generator included in the Erlang/OTP. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>pass phrase</id>
+ <shortdef>pass phrase</shortdef>
+ <def>
+The word or phrase which authenticates the user who is authorized to use private key file. The pass phrase prevents unauthorized users from starting, restarting, or reconfiguring the server. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>pattern matching</id>
+ <shortdef>pattern matching</shortdef>
+ <def>
+A basic mechanism in Erlang for assigning values to variables and for controlling the flow of a program. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>permanent child</id>
+ <shortdef>permanent child</shortdef>
+ <def>
+A supervised process which always is restarted when it dies. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>Pid</id>
+ <shortdef>Pid</shortdef>
+ <def>
+Process Identifier. A data type in Erlang for storing process references. The process identity of the process displayed in the line. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Pman</id>
+ <shortdef>Pman</shortdef>
+ <def>
+Module and application name for the Process Trace Tool. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>point</id>
+ <shortdef>point</shortdef>
+ <def>
+A unit used to indicate the size of a typeface. Equal to 1/72 inches. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>pointer</id>
+ <shortdef>pointer</shortdef>
+ <def>
+A pointer tells where data is stored. Memory pointers are not used in Erlang. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>port</id>
+ <shortdef>port</shortdef>
+ <def>
+A data type in Erlang. Ports provide the basic mechanism for communication with the external world. </def>
+ <resp>peterl</resp>
+ </term>
+ <term>
+ <id>port controller</id>
+ <shortdef>port controller</shortdef>
+ <def>
+An Erlang process which controls a port program. A port has exactly one port controller. </def>
+ <resp>peterl</resp>
+ </term>
+ <term>
+ <id>port program</id>
+ <shortdef>port program</shortdef>
+ <def>
+A program that runs as an external program in the operating system and which the Erlang run-time system can start and communicate with by means of the Erlang port mechanism. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>PostScript</id>
+ <shortdef>PostScript</shortdef>
+ <def>
+A language describing a fully laid-out page in terms of fonts, lines, grey scales, and so on, in a way that is interpretable by a printer. The language was developed by Adobe Systems. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>pretty-printed</id>
+ <shortdef>pretty-printed</shortdef>
+ <def>
+Nicely formatted code or data, e.g. C or Erlang, with indents and tabs etc. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>primitive</id>
+ <shortdef>primitive</shortdef>
+ <def>
+The basic elements in a programming language. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>private key</id>
+ <shortdef>private key</shortdef>
+ <def>
+The secret key in a pair, used to decrypt incoming messages and sign outgoing ones. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>process</id>
+ <shortdef>process</shortdef>
+ <def>
+A process is a self-contained separate unit of execution which exists concurrently with other processes in the system. The BIF "spawn/3" creates and starts the execution of a new process. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>process dictionary</id>
+ <shortdef>process dictionary</shortdef>
+ <def>
+Each process has an associated dictionary which provides the process with simple destructive storage capabilities. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Process Manager</id>
+ <shortdef>Process Manager</shortdef>
+ <def>
+Obsolete name for the Process Trace Tool. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>Process Trace Tool</id>
+ <shortdef>Process Trace Tool</shortdef>
+ <def>
+A tool which gives an overview of the processes in the Erlang run-time system. See also Pman. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>Profiler</id>
+ <shortdef>Profiler</shortdef>
+ <def>
+Another name for eprof, a tool used to profile a system in order to find out how much time is spent in various segments of a program. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>program</id>
+ <shortdef>program</shortdef>
+ <def>
+Routines which can be executed by a computer. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>Proxy</id>
+ <shortdef>proxy</shortdef>
+ <def>
+An intermediary program which acts as both a server and a client for the purpose of making requests on behalf of other clients. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>public key</id>
+ <shortdef>public key</shortdef>
+ <def>
+The publicly available key in a key pair, used to encrypt messages bound for its owner and to decrypt signatures made by its owner. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>query</id>
+ <shortdef>query</shortdef>
+ <def>
+Queries are used for accessing the data in a Database Management System. The query specify a maybe complicated relation that should hold for all of the selected data. This could involve several tables as well as conditions like for instance less then and greater then. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>query language</id>
+ <shortdef>query language</shortdef>
+ <def>
+A language which is specially designed to express database queries. Examples of query languages are QLC and SQL. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>receive</id>
+ <shortdef>receive</shortdef>
+ <def>
+A primitive for message processing in Erlang, receives a message from a process. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>record</id>
+ <shortdef>record</shortdef>
+ <def>
+A data structure intended for storing a fixed number of related Erlang terms, it is similar to a "struct" in C or a "record" in Pascal. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>recursion</id>
+ <shortdef>recursion</shortdef>
+ <def>
+A function is recursive if it calls itself until the result desired is attained. Recursion is the heart of functional programming. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>reference</id>
+ <shortdef>reference</shortdef>
+ <def>
+A data type in Erlang for storing system unique references. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>release handler</id>
+ <shortdef>release handler</shortdef>
+ <def>
+A SASL process which handles software upgrade. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>relup</id>
+ <shortdef>release upgrade script</shortdef>
+ <def>
+A script with instructions to the release handler of how the release should be installed in the system. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>RPC</id>
+ <shortdef>Remote Proceedure Call</shortdef>
+ <def>
+A technique for evaluating a function transparently on a remote node. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>resource</id>
+ <shortdef>resource</shortdef>
+ <def>
+The actual resource to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>resources</id>
+ <shortdef>resources</shortdef>
+ <def>
+The actual resources to be managed. A resource is represented by a Managed Object. Each resource is mapped to one or several resources. </def>
+ <resp>nibe</resp>
+ </term>
+ <term>
+ <id>RFC</id>
+ <shortdef>RFC</shortdef>
+ <def>
+A "Request for Comments" used as a proposed standard by IETF. </def>
+ <resp>jocke</resp>
+ </term>
+ <term>
+ <id>SASLshort</id>
+ <shortdef>SASL</shortdef>
+ <def>
+See System Architecture Support Libraries. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>schema</id>
+ <shortdef>schema</shortdef>
+ <def>
+The schema contains the definitions and whereabouts for all tables. In Mnesia it is realized as a special table named "schema". </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>schema functions</id>
+ <shortdef>schema functions</shortdef>
+ <def>
+The functions which are available for managing schemas. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>SDL</id>
+ <shortdef>SDL</shortdef>
+ <def>
+Specification and Description Language. A ITU-T standard specification language which is used to specify the behaviour of switching systems. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>send</id>
+ <shortdef>send</shortdef>
+ <def>
+A primitive for message processing in Erlang, sends a message to a process. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>shell</id>
+ <shortdef>shell</shortdef>
+ <def>
+The shell is an interactive front-end to an Erlang node where Erlang expressions can be evaluated. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>shell prompt</id>
+ <shortdef>shell prompt</shortdef>
+ <def>
+The text or symbol shown on the screen when the shell is ready to receive commands. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>SNMPEAlong</id>
+ <shortdef>Simple Network Management Protocol Extensible Agent (SNMPEA).</shortdef>
+ <def>
+An Erlang/OTP application that includes a bilingual extensible SNMP agent. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>single assignment</id>
+ <shortdef>single assignment</shortdef>
+ <def>
+Means that once a variable has been assigned a value, the value can never be changed. Erlang is a single assignment language. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>single step</id>
+ <shortdef>single step</shortdef>
+ <def>
+Single stepping is a function provided by the debugger. By single stepping the developer may use the debugger to follow the execution of a process and see what actually happens at each function call. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>slave</id>
+ <shortdef>slave</shortdef>
+ <def>
+Not in control, can never take over by himself. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>SSLlong</id>
+ <shortdef>Secure Sockets Layer (SSL)</shortdef>
+ <def>
+A protocol created by Netscape Communications Corporation for authentication and encryption over TCP/IP networks, including Web. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>signature</id>
+ <shortdef>signature</shortdef>
+ <def>
+An encrypted text block that validates a certificate or other file. A Certification Authority (CA) creates a signature by generating a hash of the public key embedded in a certificate, then encrypting the hash with its own private key. Only the CA's public key can decrypt the signature, verifying that the CA has authenticated the network entity that owns the certificate. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>SNMPshort</id>
+ <shortdef>SNMP</shortdef>
+ <def>
+Simple Network Management Protocol. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>SNMPshort</id>
+ <shortdef>SNMPEA</shortdef>
+ <def>
+See Simple Network Management Protocol Extensible Agent. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>spawn</id>
+ <shortdef>spawn</shortdef>
+ <def>
+A primitive for multiprocessing in Erlang, that starts a parallel computation (called a process). The creation of a new process </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>SSLshort</id>
+ <shortdef>SSL</shortdef>
+ <def>
+See Secure Sockets Layer. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>SSLeay</id>
+ <shortdef>SSLeay</shortdef>
+ <def>
+An SSL library developed by Eric Yong ([email protected]). </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>SSLTOP</id>
+ <shortdef>SSLTOP</shortdef>
+ <def>
+The path to your SSL directory, a subdirectory of ServerRoot. </def>
+ <resp>helen</resp>
+ </term>
+ <term>
+ <id>start script</id>
+ <shortdef>start script</shortdef>
+ <def>
+A start script is a file with .script extension which is the source when a boot file is created. See SASL User's Guide for more info. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>stdlib</id>
+ <shortdef>stdlib</shortdef>
+ <def>
+An application within Erlang/OTP which contains modules for manipulating lists, strings, files, etc. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>sticky directory</id>
+ <shortdef>sticky directory</shortdef>
+ <def>
+A directory containing Erlang object code that is part of the runtime system. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>sticky lock</id>
+ <shortdef>sticky lock</shortdef>
+ <def>
+A lock which lingers at a node after the transaction which first acquired the lock has terminated. Once a process has obtained a sticky lock on a node, subsequent locks acquired by processes on the same node, can be set without need of involving remote nodes. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>string</id>
+ <shortdef>string</shortdef>
+ <def>
+The ASCII or ISO-8859-1 representation of the list of characters occurring within quotation marks in Erlang code. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>Subagent</id>
+ <shortdef>Subagent</shortdef>
+ <def>
+The SNMP agent system consists of one Master Agent (See Master Agent) and zero or more Subagents which can be used to distribute the SNMP agent system on several nodes. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>supervision tree</id>
+ <shortdef>supervision tree</shortdef>
+ <def>
+A hierarcial tree of processes used to program fault tolerant systems. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>supervisor</id>
+ <shortdef>supervisor</shortdef>
+ <def>
+A behaviour to stucture fault tolerant computations, and program supervision trees with. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>sup_bridge</id>
+ <shortdef>supervisor bridge</shortdef>
+ <def>
+A behaviour used to connect a process, or subsystem, to a supervisor tree. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>SASLlong</id>
+ <shortdef>System Architecture Support Libraries (SASL)</shortdef>
+ <def>
+An Erlang/OTP application which contains services for error logging, release handling and report browsing. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>.config</id>
+ <shortdef>system configuration file</shortdef>
+ <def>
+A file which specifies configuration parameters for the applications in the system. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>table lock</id>
+ <shortdef>table lock</shortdef>
+ <def>
+Table locks are locks which are set on whole tables. They may either be read locks or write locks. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>Table Visualizer</id>
+ <shortdef>Table Visualizer</shortdef>
+ <def>
+A tool which enables the user to examine ETS and Mnesia tables. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>temporary child</id>
+ <shortdef>temporary child</shortdef>
+ <def>
+A supervised process which is never restarted when it dies. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>term</id>
+ <shortdef>term</shortdef>
+ <def>
+The super type of all Erlang types. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>Toolbar</id>
+ <shortdef>Toolbar</shortdef>
+ <def>
+A tool that provides an simplistic interface to the other various Erlang/OTP tools </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>tools</id>
+ <shortdef>tools</shortdef>
+ <def>
+An application within Erlang/OTP which contains the tools which are not applications themselves. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>transaction</id>
+ <shortdef>transaction</shortdef>
+ <def>
+Transactions groups a set of database accesses into an atomic unit. All transactions has the ACID (atomicity, concistency, isolation and durability) properties. </def>
+ <resp>hakan</resp>
+ </term>
+ <term>
+ <id>transient child</id>
+ <shortdef>transient child</shortdef>
+ <def>
+A supervised process which is restarted if it dies non-normally. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>trigger</id>
+ <shortdef>trigger</shortdef>
+ <def>
+The Interpreter. A break point that is reached by a process triggers if it is active, and the execution of the process is stopped. </def>
+ <resp>olin</resp>
+ </term>
+ <term>
+ <id>tty</id>
+ <shortdef>tty</shortdef>
+ <def>
+tty is a simple command line interface program where keystrokes are collected and interpreted. Originally meant teletypewriter equipment. Now it usually means the user console/terminal/shell window. </def>
+ <resp>kent</resp>
+ </term>
+ <term>
+ <id>tuple</id>
+ <shortdef>tuple</shortdef>
+ <def>
+A tuple is a data type in Erlang. Tuples are used as place holders for complex data structures. Tuples may contain anything of any size, and are written as sequences of terms separated by commas, and enclosed in curly brackets { }. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>variable</id>
+ <shortdef>variable</shortdef>
+ <def>
+An alias for a memory position, in which a value can be put. Erlang variables always start with an upper case letter. </def>
+ <resp>kenneth</resp>
+ </term>
+ <term>
+ <id>workers</id>
+ <shortdef>workers</shortdef>
+ <def>
+The lower nodes in a supervision tree. These are the processes that actually performs some real work, e.g. servers. </def>
+ <resp>mbj</resp>
+ </term>
+ <term>
+ <id>YECC</id>
+ <shortdef>YECC</shortdef>
+ <def>
+A LALR-1 parser generator included in Erlang/OTP. It is written in Erlang and generates a parser as an Erlang module. </def>
+ <resp>kenneth</resp>
+ </term>
+</terms>
+
diff --git a/lib/megaco/doc/src/distr_node_config.gif b/lib/megaco/doc/src/distr_node_config.gif
new file mode 100644
index 0000000000..073e1eeaac
--- /dev/null
+++ b/lib/megaco/doc/src/distr_node_config.gif
Binary files differ
diff --git a/lib/megaco/doc/src/distr_node_config.ps b/lib/megaco/doc/src/distr_node_config.ps
new file mode 100644
index 0000000000..fbb5334bc6
--- /dev/null
+++ b/lib/megaco/doc/src/distr_node_config.ps
@@ -0,0 +1,20151 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: /clearcase/cslab/megaco/doc/src/distr_node_config.ps
+%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley
+%%BoundingBox: 11 236 537 605
+%%Pages: 1
+%%DocumentFonts:
+%%EndComments
+%%EndProlog
+
+%%Page: 1 1
+
+% remember original state
+/origstate save def
+
+% build a temporary dictionary
+20 dict begin
+
+% define string to hold a scanline's worth of data
+/pix 1773 string def
+
+% define space for color conversions
+/grays 591 string def % space for gray scale line
+/npixls 0 def
+/rgbindx 0 def
+
+% lower left corner
+11 236 translate
+
+% size of image (on paper, in 1/72inch coords)
+525.96000 368.92800 scale
+
+% define 'colorimage' if it isn't defined
+% ('colortogray' and 'mergeprocs' come from xwd2ps
+% via xgrab)
+/colorimage where % do we know about 'colorimage'?
+ { pop } % yes: pop off the 'dict' returned
+ { % no: define one
+ /colortogray { % define an RGB->I function
+ /rgbdata exch store % call input 'rgbdata'
+ rgbdata length 3 idiv
+ /npixls exch store
+ /rgbindx 0 store
+ 0 1 npixls 1 sub {
+ grays exch
+ rgbdata rgbindx get 20 mul % Red
+ rgbdata rgbindx 1 add get 32 mul % Green
+ rgbdata rgbindx 2 add get 12 mul % Blue
+ add add 64 idiv % I = .5G + .31R + .18B
+ put
+ /rgbindx rgbindx 3 add store
+ } for
+ grays 0 npixls getinterval
+ } bind def
+
+ % Utility procedure for colorimage operator.
+ % This procedure takes two procedures off the
+ % stack and merges them into a single procedure.
+
+ /mergeprocs { % def
+ dup length
+ 3 -1 roll
+ dup
+ length
+ dup
+ 5 1 roll
+ 3 -1 roll
+ add
+ array cvx
+ dup
+ 3 -1 roll
+ 0 exch
+ putinterval
+ dup
+ 4 2 roll
+ putinterval
+ } bind def
+
+ /colorimage { % def
+ pop pop % remove 'false 3' operands
+ {colortogray} mergeprocs
+ image
+ } bind def
+ } ifelse % end of 'false' case
+
+
+
+591 401 8 % dimensions of data
+[591 0 0 -401 0 401] % mapping matrix
+{currentfile pix readhexstring pop}
+false 3 colorimage
+
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000000000000000
+000000000000000000000000000000ffffffffffffffffff000000000000000000000000
+000000000000000000000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000000000000000000000000000000000
+000000000000ffffffffffffffffff000000000000000000000000000000000000000000
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000000000000000000000000000000000000000000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000000000000000
+000000000000000000000000000000ffffffffffffffffff000000000000000000000000
+000000000000000000000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000000000000000000000000000000000
+000000000000ffffffffffffffffff000000000000000000000000000000000000000000
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000000000000000000000000000000000000000000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffff000000000000000000ffffff000000
+ffffffffffffffffffffffffffffff000000000000000000ffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffff000000000000ffffffffffff000000ffffffffffffffffff000000000000
+ffffffffffffffffffffffff000000ffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff
+ffffff000000ffffff000000ffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000ffffffffffffffffff000000ffffff000000000000ffffffffffff
+ffffff000000000000000000ffffffffffffffffff000000000000ffffffffffffffffff
+000000ffffff000000000000ffffffffffff000000000000000000ffffff000000000000
+ffffffffffff000000000000ffffffffffff000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff
+ffffff000000ffffff000000ffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffff000000000000000000ffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000
+000000000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff
+ffffff000000ffffff000000ffffff000000ffffffffffffffffffffffff000000000000
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
+000000ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
+000000ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+000000000000ffffffffffff000000ffffffffffff000000ffffff000000ffffff000000
+ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
+000000000000000000ffffffffffff000000000000000000ffffff000000000000000000
+ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffffffffff
+000000ffffff000000000000ffffffffffffffffff000000000000ffffffffffffffffff
+000000000000ffffff000000ffffffffffff000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffff000000000000000000ffffffffffff000000
+ffffffffffff000000000000000000ffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffff000000000000
+ffffffffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff000000
+000000ffffff000000000000000000ffffffffffff000000000000000000000000ffffff
+000000000000000000ffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000ffffffffffffffffffffffffffffff000000000000000000ffffffffffff000000
+000000000000ffffff000000ffffffffffffffffffffffffffffff000000000000000000
+ffffff000000ffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffff000000000000ffffffffffff000000ffffff
+ffffffffffff000000000000ffffffffffffffffffffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffff
+000000000000ffffffffffffffffff000000ffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffff000000ffffffffffffffffff000000ffffff000000ffffff000000ffffffffffff
+ffffffffffff000000000000000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000000000ffffffffffffffffff000000
+000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffff000000ffffffffffff000000ffffff000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffff000000000000ffffff000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000ffffffffffff000000000000000000000000000000000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000ffffffffffff000000ffffffffffff000000000000000000ffffffffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+000000000000ffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+000000000000000000000000000000000000000000000000000000000000ffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
+000000000000ffffffffffff000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffff000000ffffff000000000000ffffff
+ffffffffffffffffff000000000000000000000000000000ffffff000000ffffffffffff
+000000ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffff000000000000000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffff000000000000000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffff000000000000ffffff000000
+000000000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffff000000ffffff
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffff000000000000000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffff000000ffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000
+000000000000ffffffffffffffffff000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000ffffffffffffffffffffffff000000000000
+000000ffffffffffff000000000000000000ffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffff000000000000000000ffffff000000000000
+000000ffffff000000000000000000000000000000ffffff000000000000000000000000
+000000000000ffffff000000000000000000ffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffff000000000000000000
+ffffff000000000000000000ffffffffffff000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000ffffff000000ffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000ffffffffffffffffffffffffffffff000000000000ffffff
+ffffffffffff000000ffffffffffffffffff000000000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+ffffff000000000000000000ffffffffffff000000000000ffffffffffffffffff000000
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffff000000ffffffffffffffffff000000ffffff000000ffffff
+ffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffff000000000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffff000000000000ffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffff000000ffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffffffffffffffff
+000000000000000000ffffffffffffffffff000000000000ffffffffffff000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffff000000ffffff000000000000ffffffffffffffffffffffff
+000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000ffffff000000000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000ffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffff000000000000000000ffffff000000000000000000ffffffffffff
+000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000ffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000000000
+000000ffffffffffff000000000000000000ffffffffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffff000000ffffff000000000000ffffffffffff
+ffffffffffff000000000000000000000000000000ffffff000000ffffffffffff000000
+ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000ffffffffffffffffff000000000000000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffff000000000000000000ffffffffffff000000ffffff
+ffffff000000ffffffffffffffffff000000ffffff000000000000ffffff000000000000
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000000000000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffff
+000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000ffffffffffffffffff000000000000000000
+ffffffffffffffffff000000000000ffffffffffffffffffffffff000000000000000000
+ffffffffffff000000000000000000ffffffffffffffffffffffff000000000000000000
+000000000000000000ffffffffffff000000000000000000ffffff000000000000000000
+ffffff000000000000000000000000000000ffffff000000000000000000000000000000
+000000ffffff000000000000000000ffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000000000
+000000000000000000000000000000000000ffffff000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffff000000ffffffffffffffffff000000000000ffffffffffffffffffffffff
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000000000ffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000000000000000ffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffff000000ffffffffffffffffff000000000000ffffffffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffff000000ffffff000000000000ffffffffffffffffff
+000000000000000000ffffff000000ffffff000000000000ffffffffffffffffffffffff
+000000000000000000ffffffffffffffffff000000ffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffff000000000000000000ffffff000000
+000000000000ffffff000000000000ffffffffffffffffff000000ffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000
+ffffffffffff000000ffffff000000000000000000ffffffffffff000000ffffff000000
+ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000000000000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+000000ffffff000000ffffffffffff000000ffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000000000000000ffffffffffff000000ffffffffffffffffff000000ffffff000000
+000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000000000ffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffff000000000000
+ffffffffffff000000000000000000ffffffffffff000000000000000000ffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000
+ffffffffffff000000ffffff000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000ffffffffffffffffff000000000000000000ffffffffffffffffffffffff
+000000000000000000000000000000000000000000ffffff000000000000000000000000
+000000000000ffffffffffff000000ffffff000000000000ffffffffffffffffffffffff
+000000000000000000ffffffffffff000000000000000000ffffffffffff000000000000
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffff000000ffffff
+ffffffffffffffffff000000000000ffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+000000000000000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffffffffff000000000000ffffffffffff000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000ffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff000000
+000000ffffff000000000000000000ffffffffffff000000000000000000000000ffffff
+000000000000000000ffffffffffffffffff000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffff000000000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+000000000000000000000000000000000000000000000000000000000000ffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
+000000000000ffffffffffff000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffff000000ffffff000000000000ffffff
+ffffffffffffffffff000000000000000000000000000000ffffff000000ffffffffffff
+000000ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffff000000000000000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffff000000000000000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffff000000000000ffffff000000
+000000000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000ffffff000000ffffffffffff
+ffffff000000000000ffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffff000000000000ffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffff000000ffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000
+000000000000ffffffffffffffffff000000000000ffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000ffffffffffffffffffffffff000000000000
+000000ffffffffffff000000000000000000ffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffff000000000000000000ffffff000000000000
+000000ffffff000000000000000000000000000000ffffff000000000000000000000000
+000000000000ffffff000000000000000000ffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffff000000000000000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000ffffff000000ffffffffffff
+ffffff000000000000ffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000000000000000000000ffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000000000ffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffff000000ffffffffffff
+ffffff000000000000ffffffffffffffffff000000ffffff000000000000ffffffffffff
+ffffff000000000000000000ffffff000000ffffff000000000000ffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffff000000ffffff000000000000000000
+000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000ffffffffffff000000000000000000ffffff
+000000000000000000ffffff000000000000ffffffffffffffffff000000ffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+000000ffffffffffff000000ffffff000000000000000000ffffffffffff000000ffffff
+000000ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffff000000000000000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffff000000ffffffffffff000000ffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000000000ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffff000000ffffffffffff
+000000ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffffffffff000000000000ffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffff000000000000ffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000ffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffff000000000000000000000000000000000000000000ffffff000000000000000000
+000000000000000000ffffffffffff000000ffffff000000000000ffffffffffffffffff
+ffffff000000000000000000ffffffffffff000000000000000000ffffffffffff000000
+000000ffffffffffffffffffffffffffffff000000000000000000000000000000000000
+ffffffffffffffffffffffff000000000000000000000000ffffffffffffffffff000000
+ffffffffffffffffffffffff000000000000ffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000000000000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000000000000000000000000000000000
+000000000000ffffffffffffffffff000000000000000000000000000000000000000000
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000000000000000000000000000000000000000000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000000000000000
+000000000000000000000000000000ffffffffffffffffff000000000000000000000000
+000000000000000000000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffff000000000000000000000000000000000000
+000000000000ffffffffffffffffff000000000000000000000000000000000000000000
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000000000000000000000000000000000000000000000ffffff
+ffffffffffff000000000000000000000000000000000000000000000000ffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff
+000000000000000000000000000000000000000000000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000000000000000
+000000000000000000000000000000ffffffffffffffffff000000000000000000000000
+000000000000000000000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+
+showpage
+
+% stop using temporary dictionary
+end
+
+% restore original state
+origstate restore
+
+%%Trailer
diff --git a/lib/megaco/doc/src/fascicules.xml b/lib/megaco/doc/src/fascicules.xml
new file mode 100644
index 0000000000..0678195e07
--- /dev/null
+++ b/lib/megaco/doc/src/fascicules.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
+
+<fascicules>
+ <fascicule file="part" href="part_frame.html" entry="no">
+ User's Guide
+ </fascicule>
+ <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
+ Reference Manual
+ </fascicule>
+ <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
+ Release Notes
+ </fascicule>
+ <fascicule file="" href="../../../../doc/print.html" entry="no">
+ Off-Print
+ </fascicule>
+</fascicules>
+
diff --git a/lib/megaco/doc/src/files.mk b/lib/megaco/doc/src/files.mk
new file mode 100644
index 0000000000..debc5d278d
--- /dev/null
+++ b/lib/megaco/doc/src/files.mk
@@ -0,0 +1,73 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+XML_APPLICATION_FILES = \
+ ref_man.xml
+
+XML_REF3_FILES = \
+ megaco.xml \
+ megaco_codec_meas.xml \
+ megaco_codec_mstone1.xml \
+ megaco_codec_mstone2.xml \
+ megaco_codec_transform.xml \
+ megaco_edist_compress.xml \
+ megaco_encoder.xml \
+ megaco_flex_scanner.xml \
+ megaco_user.xml \
+ megaco_tcp.xml \
+ megaco_transport.xml \
+ megaco_udp.xml
+
+XML_PART_FILES = \
+ part.xml \
+ part_notes.xml \
+ part_notes_history.xml
+
+XML_EXTRA_FILES = \
+ notes_history.xml
+
+XML_CHAPTER_FILES = \
+ megaco_intro.xml \
+ megaco_architecture.xml \
+ megaco_run.xml \
+ megaco_encode.xml \
+ megaco_transport_mechanisms.xml \
+ megaco_examples.xml \
+ megaco_performance.xml \
+ megaco_mib.xml \
+ megaco_debug.xml \
+ notes.xml
+
+BOOK_FILES = book.xml
+
+GIF_FILES = \
+ single_node_config.gif \
+ distr_node_config.gif \
+ megaco_sys_arch.gif \
+ user_guide.gif \
+ note.gif \
+ notes.gif \
+ ref_man.gif \
+ book.gif \
+ MG-startup_flow_noMID.gif \
+ MGC_startup_call_flow.gif \
+ MG_startup_call_flow.gif \
+ call_flow.gif \
+ call_flow_cont.gif \
+ mstone1.gif
diff --git a/lib/megaco/doc/src/index.html.src b/lib/megaco/doc/src/index.html.src
new file mode 100644
index 0000000000..4de3450f67
--- /dev/null
+++ b/lib/megaco/doc/src/index.html.src
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!-- This file is obsolete -->
+<HTML>
+<!--
+ ``The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved via the world wide web at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ AB. All Rights Reserved.''
+
+ $Id$
+-->
+<HEAD>
+<TITLE>Megaco %VSN%</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF">
+
+<CENTER>
+<A HREF="http://%ERLANG_SITE%">
+ <IMG ALT="Erlang/OTP" BORDER=0 SRC="html/min_head.gif">
+</A><BR>
+
+<FONT SIZE="-1">
+[<A HREF="%UP_ONE_LEVEL%">Up</A> |
+<A HREF="http://%ERLANG_SITE%">Erlang/OTP</A>]
+</FONT><BR>
+
+<P><FONT SIZE="+3">Megaco</FONT><BR>
+Version %VSN%
+</CENTER>
+
+<P><TABLE>
+<TR>
+<TD>
+<!-- IMG ALIGN=LEFT ALT="MEGACO" SRC="html/megaco.gif" -->
+</TD>
+
+<TD>
+ <p>The <STRONG>Megaco</STRONG> application is a framework
+for building applications on top of the Megaco/H.248 protocol.</p>
+</TD>
+</TR>
+</TABLE>
+
+<P><CENTER>
+<TABLE CELLPADDING=15>
+<TR>
+<TD ALIGN=CENTER>
+<A HREF="html/users_guide.html">
+ <IMG ALT="User's Guide" BORDER=0 SRC="html/user_guide.gif">
+</A>
+<BR>
+<FONT SIZE="-1">
+<A HREF="html/users_guide.html">User's Guide</A>
+</FONT>
+</TD>
+
+<TD ALIGN=CENTER>
+<A HREF="html/index.html">
+ <IMG ALT="Reference Manual" BORDER=0 SRC="html/ref_man.gif">
+</A>
+<BR>
+<FONT SIZE="-1">
+<A HREF="html/index.html">Reference Manual</A>
+</FONT>
+</TD>
+
+</TR>
+
+<TR>
+<TD ALIGN=CENTER>
+<A HREF="html/release_notes.html">
+ <IMG ALT="Release Notes" BORDER=0 SRC="html/notes.gif">
+</A>
+<BR>
+<FONT SIZE="-1">
+<A HREF="html/release_notes.html">Release Notes</A>
+</FONT>
+</TD>
+
+<TD ALIGN=CENTER>
+<A HREF="%OFF_PRINT%">
+ <IMG ALT="Off-Print" BORDER=0 SRC="html/book.gif">
+</A>
+<BR>
+<FONT SIZE="-1">
+<A HREF="%OFF_PRINT%">Off-Print</A>
+</FONT>
+</TD>
+</TR>
+</TABLE>
+</CENTER>
+
+<P><CENTER>
+<HR>
+<FONT SIZE="-1">
+Copyright &copy; 1991-2001
+<A HREF="http://www.erlang.se/">Ericsson Utvecklings AB</A>
+</FONT>
+</CENTER>
+</BODY>
+</HTML>
diff --git a/lib/megaco/doc/src/make.dep b/lib/megaco/doc/src/make.dep
new file mode 100644
index 0000000000..0e2040ab50
--- /dev/null
+++ b/lib/megaco/doc/src/make.dep
@@ -0,0 +1,59 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+# ----------------------------------------------------
+# >>>> Do not edit this file <<<<
+# This file was automaticly generated by
+# /home/otp/bin/docdepend
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# TeX files that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: book.tex megaco.tex megaco_architecture.tex \
+ megaco_codec_meas.tex \
+ megaco_codec_mstone1.tex megaco_codec_mstone2.tex \
+ megaco_codec_transform.tex \
+ megaco_debug.tex megaco_edist_compress.tex \
+ megaco_encode.tex megaco_encoder.tex megaco_examples.tex \
+ megaco_flex_scanner.tex megaco_intro.tex megaco_mib.tex \
+ megaco_performance.tex megaco_run.tex megaco_tcp.tex \
+ megaco_transport.tex megaco_transport_mechanisms.tex \
+ megaco_udp.tex megaco_user.tex part.tex ref_man.tex
+
+# ----------------------------------------------------
+# Source inlined when transforming from source to LaTeX
+# ----------------------------------------------------
+
+book.tex: ref_man.xml
+
+# ----------------------------------------------------
+# Pictures that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: call_flow.ps call_flow_cont.ps distr_node_config.ps \
+ megaco_sys_arch.ps single_node_config.ps
+
+book.dvi: mstone1.ps
+
+book.dvi: MG-startup_flow_noMID.ps MGC_startup_call_flow.ps \
+ MG_startup_call_flow.ps
+
diff --git a/lib/megaco/doc/src/meas.log b/lib/megaco/doc/src/meas.log
new file mode 100644
index 0000000000..6122e81e91
--- /dev/null
+++ b/lib/megaco/doc/src/meas.log
@@ -0,0 +1,132 @@
+
+Run meas on message package: time_test
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Megaco version: megaco-3.11-p08 (reentrant flex)
+ASN.1 version: 1.6.10
+
+measure using codec megaco_pretty_text_encoder []
+ msg01a[1][367] msg01b[1][367] msg02[1][393] msg03[1][178] msg04[1][225] msg05[1][169] msg06a[1][105] msg06b[1][105] msg07[1][104] msg08a[1][328] msg08b[1][357] msg09[1][209] msg10[1][345] msg11[1][290] msg12[1][511] msg13[1][228] msg14[1][309] msg15[1][148] msg16[1][181] msg17[1][104] msg18[1][165] msg19[1][109] msg20[1][266] msg21[1][215] msg22a[1][598] msg23a[1][181] msg23b[1][307] msg23c[1][329] msg23d[1][581] msg24[1][230] msg25[1][278] msg30a[1][62] msg30b[1][65] msg30c[1][402] msg30d[1][527] msg51a[2][203] msg51b[2][200] msg51c[2][207] msg51d[2][200] msg51e[2][196] msg51f[2][205] msg51g[2][205] msg51h[2][232] msg51i[2][313] msg52[2][181] msg53[2][205] msg54a[2][174] msg54b[2][169] msg54c[2][202] msg55[2][164] msg56[2][173] msg57[2][169] msg58a[2][447] msg58b[2][472] msg61a[2][215] msg61b[2][207] msg61c[2][194] msg71a[3][282] msg71b01[3][299] msg71b02[3][295] msg71b03[3][298] msg71b04[3][447] msg71b05[3][312] msg71b06[3][315] msg71b07[3][463] msg71b08[3][477] msg71b09[3][479] msg71b10[3][494] msg71b11[3][498] msg71b12[3][493] msg71b13[3][495] msg71b14[3][511] msg71b15[3][513] msg71b16[3][524] msg71b17[3][536] msg71b18[3][553] msg71b19[3][494] msg71b20[3][554] msg71b21[3][561] msg71b22[3][621] msg71c01[3][343] msg71c02[3][330] msg71c03[3][329] msg71c04[3][330] msg71c05[3][316] msg71c06[3][317] msg71c07[3][316] msg71c08[3][342] msg71c09[3][381] msg71c10[3][399] msg71c11[3][430] msg71c12[3][449] msg71c13[3][451] msg71c14[3][458] msg71c15[3][409] msg71d01[3][373] msg71d02[3][628] msg71d03[3][629] msg71d04[3][773] msg72a01[3][304] msg72a02[3][453] msg72a03[3][469] msg72b01[3][342] msg72b02[3][506] msg72b03[3][520] msg72b04[3][521] msg72c01[3][353] msg72c02[3][565] msg72c03[3][607] msg72c04[3][608] msg73a[3][261] msg73b01[3][198] msg73b02[3][228] msg73c01[3][314] msg73c02[3][314] msg74a01[3][185] msg74a02[3][181] msg74a03[3][211] msg74a04[3][207] msg74a05[3][359] msg74a06[3][363] msg75a01[3][234] msg75a02[3][256] msg76a01[3][319] msg76a02[3][366] msg76b01[3][222] msg77a01[3][209] msg78a01[3][434] msg78a02[3][430] msg78a03[3][434] msg78a04[3][511] msg78a05[3][480] msg78a06[3][597] msg78a07[3][625] msg78a08[3][915] msg78a09[3][1445] msg79a01[3][297] msg80a01[3][174] msg80a02[3][177] msg80a03[3][178] msg80b01[3][178] msg80b02[3][181] msg80b03[3][182] msg81a01[3][49] msg81a02[3][52] msg81a03[3][53] msg81b01[3][53] msg81b02[3][56] msg81b03[3][57]
+ Measurment on 149 messages:
+ Average size: 336 bytes,
+ encode: 22 microsec,
+ decode: 76 microsec
+
+measure using codec megaco_pretty_text_encoder [flex_scanner]
+ msg01a[1][367] msg01b[1][367] msg02[1][393] msg03[1][178] msg04[1][225] msg05[1][169] msg06a[1][105] msg06b[1][105] msg07[1][104] msg08a[1][332] msg08b[1][361] msg09[1][209] msg10[1][345] msg11[1][290] msg12[1][511] msg13[1][228] msg14[1][309] msg15[1][148] msg16[1][181] msg17[1][104] msg18[1][165] msg19[1][109] msg20[1][266] msg21[1][215] msg22a[1][598] msg23a[1][181] msg23b[1][307] msg23c[1][329] msg23d[1][581] msg24[1][230] msg25[1][278] msg30a[1][62] msg30b[1][65] msg30c[1][402] msg30d[1][527] msg51a[2][203] msg51b[2][200] msg51c[2][207] msg51d[2][200] msg51e[2][196] msg51f[2][205] msg51g[2][205] msg51h[2][232] msg51i[2][313] msg52[2][181] msg53[2][205] msg54a[2][174] msg54b[2][169] msg54c[2][202] msg55[2][164] msg56[2][173] msg57[2][169] msg58a[2][447] msg58b[2][472] msg61a[2][215] msg61b[2][207] msg61c[2][194] msg71a[3][282] msg71b01[3][299] msg71b02[3][295] msg71b03[3][298] msg71b04[3][447] msg71b05[3][312] msg71b06[3][315] msg71b07[3][463] msg71b08[3][477] msg71b09[3][479] msg71b10[3][494] msg71b11[3][498] msg71b12[3][493] msg71b13[3][495] msg71b14[3][511] msg71b15[3][513] msg71b16[3][524] msg71b17[3][536] msg71b18[3][553] msg71b19[3][494] msg71b20[3][554] msg71b21[3][561] msg71b22[3][621] msg71c01[3][343] msg71c02[3][330] msg71c03[3][329] msg71c04[3][330] msg71c05[3][316] msg71c06[3][317] msg71c07[3][316] msg71c08[3][342] msg71c09[3][381] msg71c10[3][399] msg71c11[3][430] msg71c12[3][449] msg71c13[3][451] msg71c14[3][458] msg71c15[3][409] msg71d01[3][373] msg71d02[3][628] msg71d03[3][629] msg71d04[3][773] msg72a01[3][304] msg72a02[3][453] msg72a03[3][469] msg72b01[3][342] msg72b02[3][506] msg72b03[3][520] msg72b04[3][521] msg72c01[3][353] msg72c02[3][565] msg72c03[3][607] msg72c04[3][608] msg73a[3][261] msg73b01[3][198] msg73b02[3][228] msg73c01[3][314] msg73c02[3][314] msg74a01[3][185] msg74a02[3][181] msg74a03[3][211] msg74a04[3][207] msg74a05[3][359] msg74a06[3][363] msg75a01[3][234] msg75a02[3][256] msg76a01[3][319] msg76a02[3][366] msg76b01[3][222] msg77a01[3][209] msg78a01[3][438] msg78a02[3][434] msg78a03[3][438] msg78a04[3][515] msg78a05[3][484] msg78a06[3][601] msg78a07[3][629] msg78a08[3][919] msg78a09[3][1449] msg79a01[3][297] msg80a01[3][174] msg80a02[3][177] msg80a03[3][178] msg80b01[3][178] msg80b02[3][181] msg80b03[3][182] msg81a01[3][49] msg81a02[3][52] msg81a03[3][53] msg81b01[3][53] msg81b02[3][56] msg81b03[3][57]
+ Measurment on 149 messages:
+ Average size: 336 bytes,
+ encode: 22 microsec,
+ decode: 41 microsec
+
+measure using codec megaco_compact_text_encoder []
+ msg01a[1][195] msg01b[1][195] msg02[1][209] msg03[1][104] msg04[1][94] msg05[1][71] msg06a[1][70] msg06b[1][70] msg07[1][68] msg08a[1][196] msg08b[1][210] msg09[1][123] msg10[1][196] msg11[1][198] msg12[1][246] msg13[1][143] msg14[1][183] msg15[1][104] msg16[1][107] msg17[1][68] msg18[1][90] msg19[1][74] msg20[1][125] msg21[1][90] msg22a[1][346] msg23a[1][107] msg23b[1][178] msg23c[1][186] msg23d[1][328] msg24[1][116] msg25[1][158] msg30a[1][32] msg30b[1][35] msg30c[1][302] msg30d[1][312] msg51a[2][93] msg51b[2][90] msg51c[2][86] msg51d[2][86] msg51e[2][85] msg51f[2][85] msg51g[2][85] msg51h[2][97] msg51i[2][114] msg52[2][96] msg53[2][98] msg54a[2][91] msg54b[2][86] msg54c[2][95] msg55[2][90] msg56[2][87] msg57[2][85] msg58a[2][184] msg58b[2][181] msg61a[2][113] msg61b[2][112] msg61c[2][109] msg71a[3][166] msg71b01[3][172] msg71b02[3][169] msg71b03[3][170] msg71b04[3][284] msg71b05[3][175] msg71b06[3][176] msg71b07[3][290] msg71b08[3][293] msg71b09[3][294] msg71b10[3][298] msg71b11[3][298] msg71b12[3][301] msg71b13[3][302] msg71b14[3][309] msg71b15[3][309] msg71b16[3][314] msg71b17[3][315] msg71b18[3][323] msg71b19[3][302] msg71b20[3][324] msg71b21[3][324] msg71b22[3][346] msg71c01[3][179] msg71c02[3][176] msg71c03[3][176] msg71c04[3][176] msg71c05[3][173] msg71c06[3][173] msg71c07[3][173] msg71c08[3][181] msg71c09[3][201] msg71c10[3][207] msg71c11[3][214] msg71c12[3][223] msg71c13[3][223] msg71c14[3][228] msg71c15[3][213] msg71d01[3][188] msg71d02[3][352] msg71d03[3][353] msg71d04[3][402] msg72a01[3][200] msg72a02[3][314] msg72a03[3][320] msg72b01[3][215] msg72b02[3][333] msg72b03[3][340] msg72b04[3][341] msg72c01[3][238] msg72c02[3][375] msg72c03[3][389] msg72c04[3][390] msg73a[3][154] msg73b01[3][92] msg73b02[3][100] msg73c01[3][165] msg73c02[3][165] msg74a01[3][94] msg74a02[3][93] msg74a03[3][105] msg74a04[3][104] msg74a05[3][140] msg74a06[3][141] msg75a01[3][103] msg75a02[3][107] msg76a01[3][117] msg76a02[3][146] msg76b01[3][89] msg77a01[3][103] msg78a01[3][241] msg78a02[3][241] msg78a03[3][241] msg78a04[3][260] msg78a05[3][249] msg78a06[3][280] msg78a07[3][284] msg78a08[3][343] msg78a09[3][461] msg79a01[3][164] msg80a01[3][76] msg80a02[3][79] msg80a03[3][80] msg80b01[3][78] msg80b02[3][81] msg80b03[3][82] msg81a01[3][37] msg81a02[3][40] msg81a03[3][41] msg81b01[3][39] msg81b02[3][42] msg81b03[3][43]
+ Measurment on 149 messages:
+ Average size: 181 bytes,
+ encode: 19 microsec,
+ decode: 63 microsec
+
+measure using codec megaco_compact_text_encoder [flex_scanner]
+ msg01a[1][195] msg01b[1][195] msg02[1][209] msg03[1][104] msg04[1][94] msg05[1][71] msg06a[1][70] msg06b[1][70] msg07[1][68] msg08a[1][196] msg08b[1][210] msg09[1][123] msg10[1][196] msg11[1][198] msg12[1][246] msg13[1][143] msg14[1][183] msg15[1][104] msg16[1][107] msg17[1][68] msg18[1][90] msg19[1][74] msg20[1][125] msg21[1][90] msg22a[1][346] msg23a[1][107] msg23b[1][178] msg23c[1][186] msg23d[1][328] msg24[1][116] msg25[1][158] msg30a[1][32] msg30b[1][35] msg30c[1][302] msg30d[1][312] msg51a[2][93] msg51b[2][90] msg51c[2][86] msg51d[2][86] msg51e[2][85] msg51f[2][85] msg51g[2][85] msg51h[2][97] msg51i[2][114] msg52[2][96] msg53[2][98] msg54a[2][91] msg54b[2][86] msg54c[2][95] msg55[2][90] msg56[2][87] msg57[2][85] msg58a[2][184] msg58b[2][181] msg61a[2][113] msg61b[2][112] msg61c[2][109] msg71a[3][166] msg71b01[3][172] msg71b02[3][169] msg71b03[3][170] msg71b04[3][284] msg71b05[3][175] msg71b06[3][176] msg71b07[3][290] msg71b08[3][293] msg71b09[3][294] msg71b10[3][298] msg71b11[3][298] msg71b12[3][301] msg71b13[3][302] msg71b14[3][309] msg71b15[3][309] msg71b16[3][314] msg71b17[3][315] msg71b18[3][323] msg71b19[3][302] msg71b20[3][324] msg71b21[3][324] msg71b22[3][346] msg71c01[3][179] msg71c02[3][176] msg71c03[3][176] msg71c04[3][176] msg71c05[3][173] msg71c06[3][173] msg71c07[3][173] msg71c08[3][181] msg71c09[3][201] msg71c10[3][207] msg71c11[3][214] msg71c12[3][223] msg71c13[3][223] msg71c14[3][228] msg71c15[3][213] msg71d01[3][188] msg71d02[3][352] msg71d03[3][353] msg71d04[3][402] msg72a01[3][200] msg72a02[3][314] msg72a03[3][320] msg72b01[3][215] msg72b02[3][333] msg72b03[3][340] msg72b04[3][341] msg72c01[3][238] msg72c02[3][375] msg72c03[3][389] msg72c04[3][390] msg73a[3][154] msg73b01[3][92] msg73b02[3][100] msg73c01[3][165] msg73c02[3][165] msg74a01[3][94] msg74a02[3][93] msg74a03[3][105] msg74a04[3][104] msg74a05[3][140] msg74a06[3][141] msg75a01[3][103] msg75a02[3][107] msg76a01[3][117] msg76a02[3][146] msg76b01[3][89] msg77a01[3][103] msg78a01[3][241] msg78a02[3][241] msg78a03[3][241] msg78a04[3][260] msg78a05[3][249] msg78a06[3][280] msg78a07[3][284] msg78a08[3][343] msg78a09[3][461] msg79a01[3][164] msg80a01[3][76] msg80a02[3][79] msg80a03[3][80] msg80b01[3][78] msg80b02[3][81] msg80b03[3][82] msg81a01[3][37] msg81a02[3][40] msg81a03[3][41] msg81b01[3][39] msg81b02[3][42] msg81b03[3][43]
+ Measurment on 149 messages:
+ Average size: 181 bytes,
+ encode: 19 microsec,
+ decode: 38 microsec
+
+measure using codec megaco_per_bin_encoder []
+ msg01a[1][141] msg01b[1][141] msg02[1][151] msg03[1][52] msg04[1][57] msg05[1][43] msg06a[1][26] msg06b[1][26] msg07[1][26] msg08a[1][123] msg08b[1][125] msg09[1][69] msg10[1][170] msg11[1][140] msg12[1][203] msg13[1][100] msg14[1][115] msg15[1][35] msg16[1][53] msg17[1][26] msg18[1][39] msg19[1][27] msg20[1][45] msg21[1][28] msg22a[1][291] msg23a[1][53] msg23b[1][92] msg23c[1][96] msg23d[1][174] msg24[1][41] msg25[1][85] msg30a[1][14] msg30b[1][16] msg30c[1][195] msg30d[1][205] msg51a[2][36] msg51b[2][36] msg51c[2][31] msg51d[2][31] msg51e[2][31] msg51f[2][31] msg51g[2][31] msg51h[2][40] msg51i[2][45] msg52[2][36] msg53[2][35] msg54a[2][33] msg54b[2][33] msg54c[2][36] msg55[2][31] msg56[2][33] msg57[2][32] msg58a[2][68] msg58b[2][66] msg61a[2][54] msg61b[2][54] msg61c[2][53] msg71a[3][87] msg71b01[3][88] msg71b02[3][88] msg71b03[3][88] msg71b04[3][114] msg71b05[3][89] msg71b06[3][89] msg71b07[3][114] msg71b08[3][115] msg71b09[3][115] msg71b10[3][118] msg71b11[3][118] msg71b12[3][118] msg71b13[3][118] msg71b14[3][126] msg71b15[3][127] msg71b16[3][130] msg71b17[3][134] msg71b18[3][133] msg71b19[3][118] msg71b20[3][133] msg71b21[3][126] msg71b22[3][141] msg71c01[3][88] msg71c02[3][88] msg71c03[3][88] msg71c04[3][88] msg71c05[3][88] msg71c06[3][88] msg71c07[3][88] msg71c08[3][92] msg71c09[3][104] msg71c10[3][106] msg71c11[3][108] msg71c12[3][110] msg71c13[3][110] msg71c14[3][112] msg71c15[3][108] msg71d01[3][89] msg71d02[3][146] msg71d03[3][146] msg71d04[3][162] msg72a01[3][141] msg72a02[3][167] msg72a03[3][167] msg72b01[3][145] msg72b02[3][171] msg72b03[3][174] msg72b04[3][174] msg72c01[3][170] msg72c02[3][208] msg72c03[3][215] msg72c04[3][215] msg73a[3][97] msg73b01[3][37] msg73b02[3][40] msg73c01[3][104] msg73c02[3][104] msg74a01[3][39] msg74a02[3][39] msg74a03[3][43] msg74a04[3][43] msg74a05[3][50] msg74a06[3][50] msg75a01[3][60] msg75a02[3][64] msg76a01[3][48] msg76a02[3][68] msg76b01[3][34] msg77a01[3][38] msg78a01[3][148] msg78a02[3][148] msg78a03[3][148] msg78a04[3][158] msg78a05[3][149] msg78a06[3][169] msg78a07[3][171] msg78a08[3][192] msg78a09[3][220] msg79a01[3][61] msg80a01[3][48] msg80a02[3][48] msg80a03[3][48] msg80b01[3][50] msg80b02[3][50] msg80b03[3][50] msg81a01[3][17] msg81a02[3][17] msg81a03[3][17] msg81b01[3][17] msg81b02[3][17] msg81b03[3][17]
+ Measurment on 149 messages:
+ Average size: 91 bytes,
+ encode: 63 microsec,
+ decode: 69 microsec
+
+measure using codec megaco_per_bin_encoder [driver]
+ msg01a[1][141] msg01b[1][141] msg02[1][151] msg03[1][52] msg04[1][57] msg05[1][43] msg06a[1][26] msg06b[1][26] msg07[1][26] msg08a[1][123] msg08b[1][125] msg09[1][69] msg10[1][170] msg11[1][140] msg12[1][203] msg13[1][100] msg14[1][115] msg15[1][35] msg16[1][53] msg17[1][26] msg18[1][39] msg19[1][27] msg20[1][45] msg21[1][28] msg22a[1][291] msg23a[1][53] msg23b[1][92] msg23c[1][96] msg23d[1][174] msg24[1][41] msg25[1][85] msg30a[1][14] msg30b[1][16] msg30c[1][195] msg30d[1][205] msg51a[2][36] msg51b[2][36] msg51c[2][31] msg51d[2][31] msg51e[2][31] msg51f[2][31] msg51g[2][31] msg51h[2][40] msg51i[2][45] msg52[2][36] msg53[2][35] msg54a[2][33] msg54b[2][33] msg54c[2][36] msg55[2][31] msg56[2][33] msg57[2][32] msg58a[2][68] msg58b[2][66] msg61a[2][54] msg61b[2][54] msg61c[2][53] msg71a[3][87] msg71b01[3][88] msg71b02[3][88] msg71b03[3][88] msg71b04[3][114] msg71b05[3][89] msg71b06[3][89] msg71b07[3][114] msg71b08[3][115] msg71b09[3][115] msg71b10[3][118] msg71b11[3][118] msg71b12[3][118] msg71b13[3][118] msg71b14[3][126] msg71b15[3][127] msg71b16[3][130] msg71b17[3][134] msg71b18[3][133] msg71b19[3][118] msg71b20[3][133] msg71b21[3][126] msg71b22[3][141] msg71c01[3][88] msg71c02[3][88] msg71c03[3][88] msg71c04[3][88] msg71c05[3][88] msg71c06[3][88] msg71c07[3][88] msg71c08[3][91] msg71c09[3][103] msg71c10[3][105] msg71c11[3][107] msg71c12[3][109] msg71c13[3][109] msg71c14[3][111] msg71c15[3][107] msg71d01[3][89] msg71d02[3][145] msg71d03[3][145] msg71d04[3][161] msg72a01[3][141] msg72a02[3][167] msg72a03[3][167] msg72b01[3][145] msg72b02[3][171] msg72b03[3][174] msg72b04[3][174] msg72c01[3][170] msg72c02[3][208] msg72c03[3][215] msg72c04[3][215] msg73a[3][97] msg73b01[3][37] msg73b02[3][40] msg73c01[3][104] msg73c02[3][104] msg74a01[3][39] msg74a02[3][39] msg74a03[3][43] msg74a04[3][43] msg74a05[3][50] msg74a06[3][50] msg75a01[3][60] msg75a02[3][63] msg76a01[3][48] msg76a02[3][68] msg76b01[3][34] msg77a01[3][38] msg78a01[3][148] msg78a02[3][148] msg78a03[3][148] msg78a04[3][158] msg78a05[3][149] msg78a06[3][169] msg78a07[3][170] msg78a08[3][190] msg78a09[3][218] msg79a01[3][61] msg80a01[3][48] msg80a02[3][48] msg80a03[3][48] msg80b01[3][49] msg80b02[3][49] msg80b03[3][49] msg81a01[3][17] msg81a02[3][17] msg81a03[3][17] msg81b01[3][17] msg81b02[3][17] msg81b03[3][17]
+ Measurment on 149 messages:
+ Average size: 91 bytes,
+ encode: 43 microsec,
+ decode: 45 microsec
+
+measure using codec megaco_per_bin_encoder [native]
+ msg01a[1][141] msg01b[1][141] msg02[1][151] msg03[1][52] msg04[1][57] msg05[1][43] msg06a[1][26] msg06b[1][26] msg07[1][26] msg08a[1][123] msg08b[1][125] msg09[1][69] msg10[1][170] msg11[1][140] msg12[1][203] msg13[1][100] msg14[1][115] msg15[1][35] msg16[1][53] msg17[1][26] msg18[1][39] msg19[1][27] msg20[1][45] msg21[1][28] msg22a[1][291] msg23a[1][53] msg23b[1][92] msg23c[1][96] msg23d[1][174] msg24[1][41] msg25[1][85] msg30a[1][14] msg30b[1][16] msg30c[1][195] msg30d[1][205] msg51a[2][36] msg51b[2][36] msg51c[2][31] msg51d[2][31] msg51e[2][31] msg51f[2][31] msg51g[2][31] msg51h[2][40] msg51i[2][45] msg52[2][36] msg53[2][35] msg54a[2][33] msg54b[2][33] msg54c[2][36] msg55[2][31] msg56[2][33] msg57[2][32] msg58a[2][68] msg58b[2][66] msg61a[2][54] msg61b[2][54] msg61c[2][53] msg71a[3][87] msg71b01[3][88] msg71b02[3][88] msg71b03[3][88] msg71b04[3][114] msg71b05[3][89] msg71b06[3][89] msg71b07[3][114] msg71b08[3][115] msg71b09[3][115] msg71b10[3][118] msg71b11[3][118] msg71b12[3][118] msg71b13[3][118] msg71b14[3][126] msg71b15[3][127] msg71b16[3][130] msg71b17[3][134] msg71b18[3][133] msg71b19[3][118] msg71b20[3][133] msg71b21[3][126] msg71b22[3][141] msg71c01[3][88] msg71c02[3][88] msg71c03[3][88] msg71c04[3][88] msg71c05[3][88] msg71c06[3][88] msg71c07[3][88] msg71c08[3][92] msg71c09[3][104] msg71c10[3][106] msg71c11[3][108] msg71c12[3][110] msg71c13[3][110] msg71c14[3][112] msg71c15[3][108] msg71d01[3][89] msg71d02[3][146] msg71d03[3][146] msg71d04[3][162] msg72a01[3][141] msg72a02[3][167] msg72a03[3][167] msg72b01[3][145] msg72b02[3][171] msg72b03[3][174] msg72b04[3][174] msg72c01[3][170] msg72c02[3][208] msg72c03[3][215] msg72c04[3][215] msg73a[3][97] msg73b01[3][37] msg73b02[3][40] msg73c01[3][104] msg73c02[3][104] msg74a01[3][39] msg74a02[3][39] msg74a03[3][43] msg74a04[3][43] msg74a05[3][50] msg74a06[3][50] msg75a01[3][60] msg75a02[3][64] msg76a01[3][48] msg76a02[3][68] msg76b01[3][34] msg77a01[3][38] msg78a01[3][148] msg78a02[3][148] msg78a03[3][148] msg78a04[3][158] msg78a05[3][149] msg78a06[3][169] msg78a07[3][171] msg78a08[3][192] msg78a09[3][220] msg79a01[3][61] msg80a01[3][48] msg80a02[3][48] msg80a03[3][48] msg80b01[3][50] msg80b02[3][50] msg80b03[3][50] msg81a01[3][17] msg81a02[3][17] msg81a03[3][17] msg81b01[3][17] msg81b02[3][17] msg81b03[3][17]
+ Measurment on 149 messages:
+ Average size: 91 bytes,
+ encode: 47 microsec,
+ decode: 51 microsec
+
+measure using codec megaco_per_bin_encoder [driver,native]
+ msg01a[1][141] msg01b[1][141] msg02[1][151] msg03[1][52] msg04[1][57] msg05[1][43] msg06a[1][26] msg06b[1][26] msg07[1][26] msg08a[1][123] msg08b[1][125] msg09[1][69] msg10[1][170] msg11[1][140] msg12[1][203] msg13[1][100] msg14[1][115] msg15[1][35] msg16[1][53] msg17[1][26] msg18[1][39] msg19[1][27] msg20[1][45] msg21[1][28] msg22a[1][291] msg23a[1][53] msg23b[1][92] msg23c[1][96] msg23d[1][174] msg24[1][41] msg25[1][85] msg30a[1][14] msg30b[1][16] msg30c[1][195] msg30d[1][205] msg51a[2][36] msg51b[2][36] msg51c[2][31] msg51d[2][31] msg51e[2][31] msg51f[2][31] msg51g[2][31] msg51h[2][40] msg51i[2][45] msg52[2][36] msg53[2][35] msg54a[2][33] msg54b[2][33] msg54c[2][36] msg55[2][31] msg56[2][33] msg57[2][32] msg58a[2][68] msg58b[2][66] msg61a[2][54] msg61b[2][54] msg61c[2][53] msg71a[3][87] msg71b01[3][88] msg71b02[3][88] msg71b03[3][88] msg71b04[3][114] msg71b05[3][89] msg71b06[3][89] msg71b07[3][114] msg71b08[3][115] msg71b09[3][115] msg71b10[3][118] msg71b11[3][118] msg71b12[3][118] msg71b13[3][118] msg71b14[3][126] msg71b15[3][127] msg71b16[3][130] msg71b17[3][134] msg71b18[3][133] msg71b19[3][118] msg71b20[3][133] msg71b21[3][126] msg71b22[3][141] msg71c01[3][88] msg71c02[3][88] msg71c03[3][88] msg71c04[3][88] msg71c05[3][88] msg71c06[3][88] msg71c07[3][88] msg71c08[3][91] msg71c09[3][103] msg71c10[3][105] msg71c11[3][107] msg71c12[3][109] msg71c13[3][109] msg71c14[3][111] msg71c15[3][107] msg71d01[3][89] msg71d02[3][145] msg71d03[3][145] msg71d04[3][161] msg72a01[3][141] msg72a02[3][167] msg72a03[3][167] msg72b01[3][145] msg72b02[3][171] msg72b03[3][174] msg72b04[3][174] msg72c01[3][170] msg72c02[3][208] msg72c03[3][215] msg72c04[3][215] msg73a[3][97] msg73b01[3][37] msg73b02[3][40] msg73c01[3][104] msg73c02[3][104] msg74a01[3][39] msg74a02[3][39] msg74a03[3][43] msg74a04[3][43] msg74a05[3][50] msg74a06[3][50] msg75a01[3][60] msg75a02[3][63] msg76a01[3][48] msg76a02[3][68] msg76b01[3][34] msg77a01[3][38] msg78a01[3][148] msg78a02[3][148] msg78a03[3][148] msg78a04[3][158] msg78a05[3][149] msg78a06[3][169] msg78a07[3][170] msg78a08[3][190] msg78a09[3][218] msg79a01[3][61] msg80a01[3][48] msg80a02[3][48] msg80a03[3][48] msg80b01[3][49] msg80b02[3][49] msg80b03[3][49] msg81a01[3][17] msg81a02[3][17] msg81a03[3][17] msg81b01[3][17] msg81b02[3][17] msg81b03[3][17]
+ Measurment on 149 messages:
+ Average size: 91 bytes,
+ encode: 26 microsec,
+ decode: 29 microsec
+
+measure using codec megaco_ber_bin_encoder []
+ msg01a[1][246] msg01b[1][246] msg02[1][262] msg03[1][98] msg04[1][100] msg05[1][83] msg06a[1][56] msg06b[1][56] msg07[1][56] msg08a[1][194] msg08b[1][204] msg09[1][120] msg10[1][298] msg11[1][227] msg12[1][352] msg13[1][163] msg14[1][198] msg15[1][70] msg16[1][100] msg17[1][57] msg18[1][82] msg19[1][58] msg20[1][102] msg21[1][64] msg22a[1][464] msg23a[1][100] msg23b[1][171] msg23c[1][178] msg23d[1][316] msg24[1][89] msg25[1][145] msg30a[1][33] msg30b[1][36] msg30c[1][378] msg30d[1][386] msg51a[2][75] msg51b[2][75] msg51c[2][69] msg51d[2][69] msg51e[2][71] msg51f[2][71] msg51g[2][71] msg51h[2][86] msg51i[2][100] msg52[2][73] msg53[2][72] msg54a[2][71] msg54b[2][71] msg54c[2][77] msg55[2][67] msg56[2][69] msg57[2][70] msg58a[2][132] msg58b[2][132] msg61a[2][106] msg61b[2][106] msg61c[2][103] msg71a[3][159] msg71b01[3][165] msg71b02[3][165] msg71b03[3][165] msg71b04[3][212] msg71b05[3][169] msg71b06[3][169] msg71b07[3][215] msg71b08[3][218] msg71b09[3][218] msg71b10[3][221] msg71b11[3][221] msg71b12[3][221] msg71b13[3][221] msg71b14[3][233] msg71b15[3][238] msg71b16[3][242] msg71b17[3][247] msg71b18[3][247] msg71b19[3][221] msg71b20[3][247] msg71b21[3][231] msg71b22[3][257] msg71c01[3][169] msg71c02[3][166] msg71c03[3][166] msg71c04[3][166] msg71c05[3][164] msg71c06[3][164] msg71c07[3][164] msg71c08[3][169] msg71c09[3][190] msg71c10[3][193] msg71c11[3][196] msg71c12[3][199] msg71c13[3][199] msg71c14[3][203] msg71c15[3][197] msg71d01[3][178] msg71d02[3][271] msg71d03[3][271] msg71d04[3][297] msg72a01[3][232] msg72a02[3][279] msg72a03[3][282] msg72b01[3][241] msg72b02[3][294] msg72b03[3][297] msg72b04[3][297] msg72c01[3][267] msg72c02[3][339] msg72c03[3][353] msg72c04[3][353] msg73a[3][169] msg73b01[3][75] msg73b02[3][83] msg73c01[3][185] msg73c02[3][185] msg74a01[3][76] msg74a02[3][76] msg74a03[3][80] msg74a04[3][80] msg74a05[3][98] msg74a06[3][98] msg75a01[3][106] msg75a02[3][108] msg76a01[3][101] msg76a02[3][127] msg76b01[3][70] msg77a01[3][75] msg78a01[3][236] msg78a02[3][236] msg78a03[3][236] msg78a04[3][254] msg78a05[3][238] msg78a06[3][271] msg78a07[3][273] msg78a08[3][318] msg78a09[3][372] msg79a01[3][110] msg80a01[3][86] msg80a02[3][87] msg80a03[3][88] msg80b01[3][88] msg80b02[3][89] msg80b03[3][90] msg81a01[3][35] msg81a02[3][36] msg81a03[3][37] msg81b01[3][37] msg81b02[3][38] msg81b03[3][39]
+ Measurment on 149 messages:
+ Average size: 165 bytes,
+ encode: 35 microsec,
+ decode: 42 microsec
+
+measure using codec megaco_ber_bin_encoder [driver]
+ msg01a[1][246] msg01b[1][246] msg02[1][262] msg03[1][98] msg04[1][100] msg05[1][83] msg06a[1][56] msg06b[1][56] msg07[1][56] msg08a[1][194] msg08b[1][204] msg09[1][120] msg10[1][298] msg11[1][227] msg12[1][352] msg13[1][163] msg14[1][198] msg15[1][70] msg16[1][100] msg17[1][57] msg18[1][82] msg19[1][58] msg20[1][102] msg21[1][64] msg22a[1][464] msg23a[1][100] msg23b[1][171] msg23c[1][178] msg23d[1][316] msg24[1][89] msg25[1][145] msg30a[1][33] msg30b[1][36] msg30c[1][378] msg30d[1][386] msg51a[2][75] msg51b[2][75] msg51c[2][69] msg51d[2][69] msg51e[2][71] msg51f[2][71] msg51g[2][71] msg51h[2][86] msg51i[2][100] msg52[2][73] msg53[2][72] msg54a[2][71] msg54b[2][71] msg54c[2][77] msg55[2][67] msg56[2][69] msg57[2][70] msg58a[2][132] msg58b[2][132] msg61a[2][106] msg61b[2][106] msg61c[2][103] msg71a[3][159] msg71b01[3][165] msg71b02[3][165] msg71b03[3][165] msg71b04[3][212] msg71b05[3][169] msg71b06[3][169] msg71b07[3][215] msg71b08[3][218] msg71b09[3][218] msg71b10[3][221] msg71b11[3][221] msg71b12[3][221] msg71b13[3][221] msg71b14[3][233] msg71b15[3][238] msg71b16[3][242] msg71b17[3][247] msg71b18[3][247] msg71b19[3][221] msg71b20[3][247] msg71b21[3][231] msg71b22[3][257] msg71c01[3][169] msg71c02[3][166] msg71c03[3][166] msg71c04[3][166] msg71c05[3][164] msg71c06[3][164] msg71c07[3][164] msg71c08[3][169] msg71c09[3][190] msg71c10[3][193] msg71c11[3][196] msg71c12[3][199] msg71c13[3][199] msg71c14[3][203] msg71c15[3][197] msg71d01[3][178] msg71d02[3][271] msg71d03[3][271] msg71d04[3][297] msg72a01[3][232] msg72a02[3][279] msg72a03[3][282] msg72b01[3][241] msg72b02[3][294] msg72b03[3][297] msg72b04[3][297] msg72c01[3][267] msg72c02[3][339] msg72c03[3][353] msg72c04[3][353] msg73a[3][169] msg73b01[3][75] msg73b02[3][83] msg73c01[3][185] msg73c02[3][185] msg74a01[3][76] msg74a02[3][76] msg74a03[3][80] msg74a04[3][80] msg74a05[3][98] msg74a06[3][98] msg75a01[3][106] msg75a02[3][108] msg76a01[3][101] msg76a02[3][127] msg76b01[3][70] msg77a01[3][75] msg78a01[3][236] msg78a02[3][236] msg78a03[3][236] msg78a04[3][254] msg78a05[3][238] msg78a06[3][271] msg78a07[3][273] msg78a08[3][318] msg78a09[3][372] msg79a01[3][110] msg80a01[3][86] msg80a02[3][87] msg80a03[3][88] msg80b01[3][88] msg80b02[3][89] msg80b03[3][90] msg81a01[3][35] msg81a02[3][36] msg81a03[3][37] msg81b01[3][37] msg81b02[3][38] msg81b03[3][39]
+ Measurment on 149 messages:
+ Average size: 165 bytes,
+ encode: 35 microsec,
+ decode: 37 microsec
+
+measure using codec megaco_ber_bin_encoder [native]
+ msg01a[1][246] msg01b[1][246] msg02[1][262] msg03[1][98] msg04[1][100] msg05[1][83] msg06a[1][56] msg06b[1][56] msg07[1][56] msg08a[1][194] msg08b[1][204] msg09[1][120] msg10[1][298] msg11[1][227] msg12[1][352] msg13[1][163] msg14[1][198] msg15[1][70] msg16[1][100] msg17[1][57] msg18[1][82] msg19[1][58] msg20[1][102] msg21[1][64] msg22a[1][464] msg23a[1][100] msg23b[1][171] msg23c[1][178] msg23d[1][316] msg24[1][89] msg25[1][145] msg30a[1][33] msg30b[1][36] msg30c[1][378] msg30d[1][386] msg51a[2][75] msg51b[2][75] msg51c[2][69] msg51d[2][69] msg51e[2][71] msg51f[2][71] msg51g[2][71] msg51h[2][86] msg51i[2][100] msg52[2][73] msg53[2][72] msg54a[2][71] msg54b[2][71] msg54c[2][77] msg55[2][67] msg56[2][69] msg57[2][70] msg58a[2][132] msg58b[2][132] msg61a[2][106] msg61b[2][106] msg61c[2][103] msg71a[3][159] msg71b01[3][165] msg71b02[3][165] msg71b03[3][165] msg71b04[3][212] msg71b05[3][169] msg71b06[3][169] msg71b07[3][215] msg71b08[3][218] msg71b09[3][218] msg71b10[3][221] msg71b11[3][221] msg71b12[3][221] msg71b13[3][221] msg71b14[3][233] msg71b15[3][238] msg71b16[3][242] msg71b17[3][247] msg71b18[3][247] msg71b19[3][221] msg71b20[3][247] msg71b21[3][231] msg71b22[3][257] msg71c01[3][169] msg71c02[3][166] msg71c03[3][166] msg71c04[3][166] msg71c05[3][164] msg71c06[3][164] msg71c07[3][164] msg71c08[3][169] msg71c09[3][190] msg71c10[3][193] msg71c11[3][196] msg71c12[3][199] msg71c13[3][199] msg71c14[3][203] msg71c15[3][197] msg71d01[3][178] msg71d02[3][271] msg71d03[3][271] msg71d04[3][297] msg72a01[3][232] msg72a02[3][279] msg72a03[3][282] msg72b01[3][241] msg72b02[3][294] msg72b03[3][297] msg72b04[3][297] msg72c01[3][267] msg72c02[3][339] msg72c03[3][353] msg72c04[3][353] msg73a[3][169] msg73b01[3][75] msg73b02[3][83] msg73c01[3][185] msg73c02[3][185] msg74a01[3][76] msg74a02[3][76] msg74a03[3][80] msg74a04[3][80] msg74a05[3][98] msg74a06[3][98] msg75a01[3][106] msg75a02[3][108] msg76a01[3][101] msg76a02[3][127] msg76b01[3][70] msg77a01[3][75] msg78a01[3][236] msg78a02[3][236] msg78a03[3][236] msg78a04[3][254] msg78a05[3][238] msg78a06[3][271] msg78a07[3][273] msg78a08[3][318] msg78a09[3][372] msg79a01[3][110] msg80a01[3][86] msg80a02[3][87] msg80a03[3][88] msg80b01[3][88] msg80b02[3][89] msg80b03[3][90] msg81a01[3][35] msg81a02[3][36] msg81a03[3][37] msg81b01[3][37] msg81b02[3][38] msg81b03[3][39]
+ Measurment on 149 messages:
+ Average size: 165 bytes,
+ encode: 19 microsec,
+ decode: 26 microsec
+
+measure using codec megaco_ber_bin_encoder [driver,native]
+ msg01a[1][246] msg01b[1][246] msg02[1][262] msg03[1][98] msg04[1][100] msg05[1][83] msg06a[1][56] msg06b[1][56] msg07[1][56] msg08a[1][194] msg08b[1][204] msg09[1][120] msg10[1][298] msg11[1][227] msg12[1][352] msg13[1][163] msg14[1][198] msg15[1][70] msg16[1][100] msg17[1][57] msg18[1][82] msg19[1][58] msg20[1][102] msg21[1][64] msg22a[1][464] msg23a[1][100] msg23b[1][171] msg23c[1][178] msg23d[1][316] msg24[1][89] msg25[1][145] msg30a[1][33] msg30b[1][36] msg30c[1][378] msg30d[1][386] msg51a[2][75] msg51b[2][75] msg51c[2][69] msg51d[2][69] msg51e[2][71] msg51f[2][71] msg51g[2][71] msg51h[2][86] msg51i[2][100] msg52[2][73] msg53[2][72] msg54a[2][71] msg54b[2][71] msg54c[2][77] msg55[2][67] msg56[2][69] msg57[2][70] msg58a[2][132] msg58b[2][132] msg61a[2][106] msg61b[2][106] msg61c[2][103] msg71a[3][159] msg71b01[3][165] msg71b02[3][165] msg71b03[3][165] msg71b04[3][212] msg71b05[3][169] msg71b06[3][169] msg71b07[3][215] msg71b08[3][218] msg71b09[3][218] msg71b10[3][221] msg71b11[3][221] msg71b12[3][221] msg71b13[3][221] msg71b14[3][233] msg71b15[3][238] msg71b16[3][242] msg71b17[3][247] msg71b18[3][247] msg71b19[3][221] msg71b20[3][247] msg71b21[3][231] msg71b22[3][257] msg71c01[3][169] msg71c02[3][166] msg71c03[3][166] msg71c04[3][166] msg71c05[3][164] msg71c06[3][164] msg71c07[3][164] msg71c08[3][169] msg71c09[3][190] msg71c10[3][193] msg71c11[3][196] msg71c12[3][199] msg71c13[3][199] msg71c14[3][203] msg71c15[3][197] msg71d01[3][178] msg71d02[3][271] msg71d03[3][271] msg71d04[3][297] msg72a01[3][232] msg72a02[3][279] msg72a03[3][282] msg72b01[3][241] msg72b02[3][294] msg72b03[3][297] msg72b04[3][297] msg72c01[3][267] msg72c02[3][339] msg72c03[3][353] msg72c04[3][353] msg73a[3][169] msg73b01[3][75] msg73b02[3][83] msg73c01[3][185] msg73c02[3][185] msg74a01[3][76] msg74a02[3][76] msg74a03[3][80] msg74a04[3][80] msg74a05[3][98] msg74a06[3][98] msg75a01[3][106] msg75a02[3][108] msg76a01[3][101] msg76a02[3][127] msg76b01[3][70] msg77a01[3][75] msg78a01[3][236] msg78a02[3][236] msg78a03[3][236] msg78a04[3][254] msg78a05[3][238] msg78a06[3][271] msg78a07[3][273] msg78a08[3][318] msg78a09[3][372] msg79a01[3][110] msg80a01[3][86] msg80a02[3][87] msg80a03[3][88] msg80b01[3][88] msg80b02[3][89] msg80b03[3][90] msg81a01[3][35] msg81a02[3][36] msg81a03[3][37] msg81b01[3][37] msg81b02[3][38] msg81b03[3][39]
+ Measurment on 149 messages:
+ Average size: 165 bytes,
+ encode: 19 microsec,
+ decode: 20 microsec
+
+measure using codec megaco_erl_dist_encoder []
+ msg01a[1][1070] msg01b[1][1070] msg02[1][1132] msg03[1][515] msg04[1][563] msg05[1][496] msg06a[1][367] msg06b[1][367] msg07[1][372] msg08a[1][953] msg08b[1][914] msg09[1][580] msg10[1][1180] msg11[1][945] msg12[1][1567] msg13[1][723] msg14[1][1031] msg15[1][484] msg16[1][518] msg17[1][372] msg18[1][516] msg19[1][370] msg20[1][773] msg21[1][493] msg22a[1][1587] msg23a[1][518] msg23b[1][866] msg23c[1][923] msg23d[1][1619] msg24[1][621] msg25[1][720] msg30a[1][182] msg30b[1][169] msg30c[1][1110] msg30d[1][1275] msg51a[2][596] msg51b[2][593] msg51c[2][548] msg51d[2][548] msg51e[2][639] msg51f[2][639] msg51g[2][639] msg51h[2][707] msg51i[2][716] msg52[2][509] msg53[2][501] msg54a[2][505] msg54b[2][500] msg54c[2][530] msg55[2][492] msg56[2][492] msg57[2][486] msg58a[2][1055] msg58b[2][1032] msg61a[2][544] msg61b[2][543] msg61c[2][551] msg71a[3][804] msg71b01[3][885] msg71b02[3][890] msg71b03[3][891] msg71b04[3][1273] msg71b05[3][877] msg71b06[3][878] msg71b07[3][1259] msg71b08[3][1252] msg71b09[3][1252] msg71b10[3][1250] msg71b11[3][1254] msg71b12[3][1243] msg71b13[3][1245] msg71b14[3][1295] msg71b15[3][1309] msg71b16[3][1304] msg71b17[3][1308] msg71b18[3][1301] msg71b19[3][1244] msg71b20[3][1302] msg71b21[3][1245] msg71b22[3][1303] msg71c01[3][928] msg71c02[3][936] msg71c03[3][936] msg71c04[3][936] msg71c05[3][944] msg71c06[3][944] msg71c07[3][944] msg71c08[3][928] msg71c09[3][1008] msg71c10[3][995] msg71c11[3][987] msg71c12[3][980] msg71c13[3][980] msg71c14[3][989] msg71c15[3][1005] msg71d01[3][1001] msg71d02[3][1502] msg71d03[3][1503] msg71d04[3][1485] msg72a01[3][1077] msg72a02[3][1459] msg72a03[3][1445] msg72b01[3][1089] msg72b02[3][1463] msg72b03[3][1454] msg72b04[3][1455] msg72c01[3][1109] msg72c02[3][1519] msg72c03[3][1525] msg72c04[3][1526] msg73a[3][735] msg73b01[3][627] msg73b02[3][667] msg73c01[3][884] msg73c02[3][884] msg74a01[3][557] msg74a02[3][553] msg74a03[3][547] msg74a04[3][543] msg74a05[3][525] msg74a06[3][529] msg75a01[3][586] msg75a02[3][578] msg76a01[3][795] msg76a02[3][878] msg76b01[3][582] msg77a01[3][525] msg78a01[3][1161] msg78a02[3][1157] msg78a03[3][1216] msg78a04[3][1303] msg78a05[3][1202] msg78a06[3][1441] msg78a07[3][1433] msg78a08[3][1710] msg78a09[3][1665] msg79a01[3][855] msg80a01[3][513] msg80a02[3][516] msg80a03[3][516] msg80b01[3][505] msg80b02[3][508] msg80b03[3][508] msg81a01[3][169] msg81a02[3][172] msg81a03[3][172] msg81b01[3][161] msg81b02[3][164] msg81b03[3][164]
+ Measurment on 149 messages:
+ Average size: 875 bytes,
+ encode: 5 microsec,
+ decode: 10 microsec
+
+measure using codec megaco_erl_dist_encoder [megaco_compressed]
+ msg01a[1][357] msg01b[1][357] msg02[1][389] msg03[1][175] msg04[1][162] msg05[1][158] msg06a[1][103] msg06b[1][103] msg07[1][103] msg08a[1][384] msg08b[1][378] msg09[1][210] msg10[1][380] msg11[1][339] msg12[1][519] msg13[1][236] msg14[1][373] msg15[1][171] msg16[1][178] msg17[1][103] msg18[1][167] msg19[1][106] msg20[1][251] msg21[1][146] msg22a[1][638] msg23a[1][178] msg23b[1][316] msg23c[1][337] msg23d[1][613] msg24[1][211] msg25[1][311] msg30a[1][41] msg30b[1][43] msg30c[1][444] msg30d[1][500] msg51a[2][177] msg51b[2][174] msg51c[2][153] msg51d[2][153] msg51e[2][170] msg51f[2][170] msg51g[2][170] msg51h[2][207] msg51i[2][224] msg52[2][156] msg53[2][149] msg54a[2][157] msg54b[2][152] msg54c[2][164] msg55[2][146] msg56[2][142] msg57[2][140] msg58a[2][311] msg58b[2][294] msg61a[2][200] msg61b[2][199] msg61c[2][196] msg71a[3][304] msg71b01[3][325] msg71b02[3][330] msg71b03[3][331] msg71b04[3][532] msg71b05[3][328] msg71b06[3][329] msg71b07[3][530] msg71b08[3][533] msg71b09[3][534] msg71b10[3][541] msg71b11[3][541] msg71b12[3][540] msg71b13[3][541] msg71b14[3][554] msg71b15[3][599] msg71b16[3][594] msg71b17[3][599] msg71b18[3][603] msg71b19[3][541] msg71b20[3][604] msg71b21[3][572] msg71b22[3][620] msg71c01[3][316] msg71c02[3][316] msg71c03[3][316] msg71c04[3][316] msg71c05[3][316] msg71c06[3][316] msg71c07[3][316] msg71c08[3][320] msg71c09[3][361] msg71c10[3][363] msg71c11[3][370] msg71c12[3][378] msg71c13[3][378] msg71c14[3][402] msg71c15[3][396] msg71d01[3][340] msg71d02[3][657] msg71d03[3][658] msg71d04[3][715] msg72a01[3][991] msg72a02[3][1373] msg72a03[3][1359] msg72b01[3][1003] msg72b02[3][1377] msg72b03[3][1368] msg72b04[3][1369] msg72c01[3][1023] msg72c02[3][1433] msg72c03[3][1439] msg72c04[3][1440] msg73a[3][320] msg73b01[3][184] msg73b02[3][202] msg73c01[3][798] msg73c02[3][798] msg74a01[3][186] msg74a02[3][182] msg74a03[3][191] msg74a04[3][187] msg74a05[3][224] msg74a06[3][228] msg75a01[3][191] msg75a02[3][199] msg76a01[3][230] msg76a02[3][257] msg76b01[3][166] msg77a01[3][164] msg78a01[3][469] msg78a02[3][469] msg78a03[3][491] msg78a04[3][523] msg78a05[3][477] msg78a06[3][568] msg78a07[3][572] msg78a08[3][685] msg78a09[3][799] msg79a01[3][769] msg80a01[3][427] msg80a02[3][430] msg80a03[3][430] msg80b01[3][419] msg80b02[3][422] msg80b03[3][422] msg81a01[3][83] msg81a02[3][86] msg81a03[3][86] msg81b01[3][75] msg81b02[3][78] msg81b03[3][78]
+ Measurment on 149 messages:
+ Average size: 405 bytes,
+ encode: 6 microsec,
+ decode: 7 microsec
+
+measure using codec megaco_erl_dist_encoder [compressed]
+ msg01a[1][465] msg01b[1][465] msg02[1][486] msg03[1][291] msg04[1][284] msg05[1][261] msg06a[1][212] msg06b[1][209] msg07[1][210] msg08a[1][408] msg08b[1][409] msg09[1][321] msg10[1][424] msg11[1][389] msg12[1][489] msg13[1][348] msg14[1][396] msg15[1][226] msg16[1][293] msg17[1][209] msg18[1][274] msg19[1][214] msg20[1][313] msg21[1][274] msg22a[1][543] msg23a[1][294] msg23b[1][309] msg23c[1][316] msg23d[1][334] msg24[1][262] msg25[1][306] msg30a[1][139] msg30b[1][139] msg30c[1][343] msg30d[1][350] msg51a[2][294] msg51b[2][292] msg51c[2][276] msg51d[2][276] msg51e[2][297] msg51f[2][297] msg51g[2][296] msg51h[2][325] msg51i[2][337] msg52[2][269] msg53[2][268] msg54a[2][268] msg54b[2][265] msg54c[2][280] msg55[2][262] msg56[2][261] msg57[2][258] msg58a[2][449] msg58b[2][442] msg61a[2][303] msg61b[2][305] msg61c[2][302] msg71a[3][310] msg71b01[3][318] msg71b02[3][320] msg71b03[3][318] msg71b04[3][368] msg71b05[3][321] msg71b06[3][318] msg71b07[3][368] msg71b08[3][367] msg71b09[3][367] msg71b10[3][373] msg71b11[3][376] msg71b12[3][373] msg71b13[3][369] msg71b14[3][398] msg71b15[3][413] msg71b16[3][416] msg71b17[3][415] msg71b18[3][417] msg71b19[3][373] msg71b20[3][419] msg71b21[3][390] msg71b22[3][432] msg71c01[3][333] msg71c02[3][333] msg71c03[3][334] msg71c04[3][335] msg71c05[3][334] msg71c06[3][333] msg71c07[3][332] msg71c08[3][334] msg71c09[3][372] msg71c10[3][374] msg71c11[3][380] msg71c12[3][379] msg71c13[3][379] msg71c14[3][389] msg71c15[3][389] msg71d01[3][348] msg71d02[3][470] msg71d03[3][470] msg71d04[3][500] msg72a01[3][409] msg72a02[3][465] msg72a03[3][464] msg72b01[3][421] msg72b02[3][477] msg72b03[3][482] msg72b04[3][482] msg72c01[3][442] msg72c02[3][512] msg72c03[3][534] msg72c04[3][533] msg73a[3][326] msg73b01[3][303] msg73b02[3][318] msg73c01[3][366] msg73c02[3][366] msg74a01[3][266] msg74a02[3][263] msg74a03[3][271] msg74a04[3][266] msg74a05[3][300] msg74a06[3][303] msg75a01[3][284] msg75a02[3][291] msg76a01[3][357] msg76a02[3][368] msg76b01[3][282] msg77a01[3][276] msg78a01[3][470] msg78a02[3][467] msg78a03[3][480] msg78a04[3][505] msg78a05[3][480] msg78a06[3][514] msg78a07[3][519] msg78a08[3][547] msg78a09[3][626] msg79a01[3][364] msg80a01[3][263] msg80a02[3][267] msg80a03[3][266] msg80b01[3][269] msg80b02[3][270] msg80b03[3][270] msg81a01[3][138] msg81a02[3][140] msg81a03[3][140] msg81b01[3][143] msg81b02[3][144] msg81b03[3][144]
+ Measurment on 149 messages:
+ Average size: 345 bytes,
+ encode: 86 microsec,
+ decode: 21 microsec
+
+measure using codec megaco_erl_dist_encoder [megaco_compressed,compressed]
+ msg01a[1][250] msg01b[1][250] msg02[1][272] msg03[1][131] msg04[1][133] msg05[1][120] msg06a[1][82] msg06b[1][80] msg07[1][82] msg08a[1][240] msg08b[1][244] msg09[1][163] msg10[1][223] msg11[1][204] msg12[1][278] msg13[1][160] msg14[1][210] msg15[1][94] msg16[1][136] msg17[1][81] msg18[1][126] msg19[1][84] msg20[1][139] msg21[1][110] msg22a[1][318] msg23a[1][136] msg23b[1][149] msg23c[1][153] msg23d[1][164] msg24[1][111] msg25[1][157] msg30a[1][41] msg30b[1][43] msg30c[1][240] msg30d[1][249] msg51a[2][129] msg51b[2][126] msg51c[2][112] msg51d[2][113] msg51e[2][121] msg51f[2][121] msg51g[2][121] msg51h[2][139] msg51i[2][152] msg52[2][122] msg53[2][118] msg54a[2][121] msg54b[2][115] msg54c[2][122] msg55[2][114] msg56[2][110] msg57[2][109] msg58a[2][212] msg58b[2][205] msg61a[2][159] msg61b[2][158] msg61c[2][153] msg71a[3][145] msg71b01[3][169] msg71b02[3][174] msg71b03[3][175] msg71b04[3][188] msg71b05[3][174] msg71b06[3][175] msg71b07[3][189] msg71b08[3][192] msg71b09[3][196] msg71b10[3][203] msg71b11[3][203] msg71b12[3][196] msg71b13[3][199] msg71b14[3][203] msg71b15[3][245] msg71b16[3][234] msg71b17[3][236] msg71b18[3][248] msg71b19[3][202] msg71b20[3][248] msg71b21[3][230] msg71b22[3][258] msg71c01[3][152] msg71c02[3][153] msg71c03[3][154] msg71c04[3][154] msg71c05[3][152] msg71c06[3][154] msg71c07[3][154] msg71c08[3][155] msg71c09[3][181] msg71c10[3][183] msg71c11[3][189] msg71c12[3][196] msg71c13[3][196] msg71c14[3][216] msg71c15[3][211] msg71d01[3][180] msg71d02[3][268] msg71d03[3][272] msg71d04[3][312] msg72a01[3][382] msg72a02[3][435] msg72a03[3][434] msg72b01[3][395] msg72b02[3][450] msg72b03[3][454] msg72b04[3][452] msg72c01[3][413] msg72c02[3][483] msg72c03[3][505] msg72c04[3][503] msg73a[3][187] msg73b01[3][136] msg73b02[3][143] msg73c01[3][336] msg73c02[3][336] msg74a01[3][132] msg74a02[3][128] msg74a03[3][136] msg74a04[3][132] msg74a05[3][176] msg74a06[3][182] msg75a01[3][155] msg75a02[3][158] msg76a01[3][159] msg76a02[3][163] msg76b01[3][125] msg77a01[3][126] msg78a01[3][277] msg78a02[3][277] msg78a03[3][296] msg78a04[3][307] msg78a05[3][281] msg78a06[3][313] msg78a07[3][314] msg78a08[3][340] msg78a09[3][425] msg79a01[3][333] msg80a01[3][232] msg80a02[3][236] msg80a03[3][236] msg80b01[3][237] msg80b02[3][240] msg80b03[3][240] msg81a01[3][83] msg81a02[3][85] msg81a03[3][86] msg81b01[3][75] msg81b02[3][78] msg81b03[3][78]
+ Measurment on 149 messages:
+ Average size: 200 bytes,
+ encode: 71 microsec,
+ decode: 12 microsec
+
+Started: 2009:05:28 10:59:25 4686
+Finished: 2009:05:28 12:24:03 428
+ 1 hour 24 min 38 sec
+
+
+storing:
+ creating message_size.xls
+ creating decode_time.xls
+ creating encode_time.xls
+ creating total_time.xls
+
diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml
new file mode 100644
index 0000000000..0fb9d5aac6
--- /dev/null
+++ b/lib/megaco/doc/src/megaco.xml
@@ -0,0 +1,2173 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco.xml</file>
+ </header>
+ <module>megaco</module>
+ <modulesummary>Main API of the Megaco application</modulesummary>
+ <description>
+ <p>Interface module for the Megaco application</p>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+action_request() = #'ActionRequest'{}
+action_reply() = #'ActionReply'{}
+error_desc() = #'ErrorDescriptor'{}
+transaction_reply() = #'TransactionReply'{}
+segment_no() = integer()
+
+resend_indication() = flag | boolean()
+
+property_parm() = #'PropertyParm'{}
+property_group() = [property_parm()]
+property_groups() = [property_group()]
+
+sdp() = sdp_c() | sdp_o() | sdp_s() | sdp_i() | sdp_u() |
+ sdp_e() | sdp_p() | sdp_b() | sdp_z() | sdp_k() |
+ sdp_a() | sdp_a_rtpmap() | sdp_a_ptime() |
+ sdp_t() | sdp_r() | sdp_m()
+sdp_v() = #megaco_sdp_v{} (Protocol version)
+sdp_o() = #megaco_sdp_o{} (Owner/creator and session identifier)
+sdp_s() = #megaco_sdp_s{} (Session name)
+sdp_i() = #megaco_sdp_i{} (Session information)
+sdp_u() = #megaco_sdp_u{} (URI of description)
+sdp_e() = #megaco_sdp_e{} (Email address)
+sdp_p() = #megaco_sdp_p{} (Phone number)
+sdp_c() = #megaco_sdp_c{} (Connection information)
+sdp_b() = #megaco_sdp_b{} (Bandwidth information)
+sdp_k() = #megaco_sdp_k{} (Encryption key)
+sdp_a() = #megaco_sdp_a{} (Session attribute)
+sdp_a_rtpmap() = #megaco_sdp_a_rtpmap{}
+sdp_a_ptime() = #megaco_sdp_a_ptime{}
+sdp_a_quality() = #megaco_sdp_a_quality{}
+sdp_a_fmtp() = #megaco_sdp_a_fmtp{}
+sdp_z() = #megaco_sdp_z{} (Time zone adjustment)
+sdp_t() = #megaco_sdp_t{} (Time the session is active)
+sdp_r() = #megaco_sdp_r{} (Repeat times)
+sdp_m() = #megaco_sdp_m{} (Media name and transport address)
+sdp_property_parm() = sdp() | property_parm()
+sdp_property_group() = [sdp_property_parm()]
+sdp_property_groups() = [sdp_property_group()]
+
+megaco_timer() = infinity | integer() >= 0 | megaco_incr_timer()
+megaco_incr_timer() = #megaco_incr_timer{}
+ ]]></code>
+ <p>The record <c><![CDATA[megaco_incr_timer]]></c> contains the following fields: </p>
+ <taglist>
+ <tag><c><![CDATA[wait_for = integer() >= 0]]></c></tag>
+ <item>
+ <p>The actual timer time.</p>
+ </item>
+ <tag><c><![CDATA[factor = integer() >= 0]]></c></tag>
+ <item>
+ <p>The factor when calculating the new timer time
+ (<c><![CDATA[wait_for]]></c>).</p>
+ </item>
+ <tag><c><![CDATA[incr = integer()]]></c></tag>
+ <item>
+ <p>The increment value when calculating the new timer time
+ (<c><![CDATA[wait_for]]></c>). Note that this value <em>can</em> be negative
+ and that a timer restart can therefor lead to a <c><![CDATA[wait_for]]></c>
+ value of zero! It is up to the user to be aware of the
+ consequences of a <c><![CDATA[wait_for]]></c> value of zero. </p>
+ </item>
+ <tag><c><![CDATA[max_retries = infinity | infinity_restartable | integer() >= 0]]></c></tag>
+ <item>
+ <p>The maximum number of repetitions of the timer.</p>
+ <p>There is a special case for this field. When the
+ <c><![CDATA[max_retries]]></c> has the value <c><![CDATA[infinity_restartable]]></c>,
+ it means that the timer is restartable as long as some
+ external event occurs (e.g. receipt of a pending
+ message for instance). But the timer will never be
+ restarted "by itself", i.e. when the timer expires
+ (whatever the timeout time), so does the timer.
+ Whenever the timer is restarted, the timeout time will
+ be calculated in the usual way! Also, as mentioned
+ above, beware the consequences of setting the value to
+ <c><![CDATA[infinity]]></c> if <em>incr</em> has been set to an
+ negative value.</p>
+ </item>
+ </taglist>
+
+ <marker id="start"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>start() -> ok | {error, Reason}</name>
+ <fsummary>Starts the Megaco application</fsummary>
+ <type>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Starts the Megaco application</p>
+ <p>Users may either explicitly be registered with
+ megaco:start_user/2 and/or be statically configured by
+ setting the application environment variable 'users' to a
+ list of {UserMid, Config} tuples. See the function
+ megaco:start_user/2 for details.</p>
+
+ <marker id="stop"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>stop() -> ok | {error, Reason}</name>
+ <fsummary>Stops the Megaco application</fsummary>
+ <type>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Stops the Megaco application</p>
+
+ <marker id="start_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_user(UserMid, Config) -> ok | {error, Reason}</name>
+ <fsummary>Initial configuration of a user</fsummary>
+ <type>
+ <v>UserMid = megaco_mid()</v>
+ <v>Config = [{user_info_item(), user_info_value()}]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Initial configuration of a user</p>
+ <p>Requires the megaco application to be started. A user is
+ either a Media Gateway (MG) or a Media Gateway Controller
+ (MGC). One Erlang node may host many users.</p>
+ <p>A user is identified by its UserMid, which must be a legal
+ Megaco MID.</p>
+ <p>Config is a list of {Item, Value} tuples. See
+ megaco:user_info/2 about which items and values that are valid.</p>
+
+ <marker id="stop_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>stop_user(UserMid) -> ok | {error, Reason}</name>
+ <fsummary>Delete the configuration of a user</fsummary>
+ <type>
+ <v>UserMid = megaco_mid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete the configuration of a user</p>
+ <p>Requires that the user does not have any active connection.</p>
+
+ <marker id="user_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>user_info(UserMid) -> [{Item, Value}]</name>
+ <name>user_info(UserMid, Item) -> Value | exit(Reason)</name>
+ <fsummary>Lookup user information</fsummary>
+ <type>
+ <v>Handle = user_info_handle()</v>
+ <v>UserMid = megaco_mid() </v>
+ <v>Item = user_info_item()</v>
+ <v>Value = user_info_value()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Lookup user information</p>
+ <p>The following Item's are valid:</p>
+ <marker id="ui_connections"></marker>
+ <taglist>
+ <tag><c><![CDATA[connections]]></c></tag>
+ <item>
+ <p>Lists all active connections for this user. Returns a
+ list of megaco_conn_handle records.</p>
+ <marker id="ui_receive_handle"></marker>
+ </item>
+
+ <tag><c><![CDATA[receive_handle]]></c></tag>
+ <item>
+ <p>Construct a megaco_receive_handle record from user config</p>
+
+ <marker id="ui_trans_id"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_id]]></c></tag>
+ <item>
+ <p>Current transaction id. </p>
+ <p>A positive integer or the atom
+ <c><![CDATA[undefined_serial]]></c> (in case no messages has been sent).</p>
+
+ <marker id="ui_min_trans_id"></marker>
+ </item>
+
+ <tag><c><![CDATA[min_trans_id]]></c></tag>
+ <item>
+ <p>First trans id. </p>
+ <p>A positive integer, defaults to 1.</p>
+
+ <marker id="ui_max_trans_id"></marker>
+ </item>
+
+ <tag><c><![CDATA[max_trans_id]]></c></tag>
+ <item>
+ <p>Last trans id. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>.</p>
+
+ <marker id="ui_request_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[request_timer]]></c></tag>
+ <item>
+ <p>Wait for reply. </p>
+ <p>The timer is cancelled when a reply is received. </p>
+ <p>When a pending message is received, the timer is
+ cancelled and the <c><![CDATA[long_request_timer]]></c> is started instead
+ (see below). No resends will be performed from this point
+ (since we now know that the other side has received the
+ request). </p>
+ <p>When the timer reaches an intermediate expire, the request
+ is resent and the timer is restarted. </p>
+ <p>When the timer reaches the final expire, either the function
+ <c><![CDATA[megaco:call]]></c> will return with <c><![CDATA[{error, timeout}]]></c>
+ or the callback function <c><![CDATA[handle_trans_reply]]></c> will be
+ called with <c><![CDATA[UserReply = {error, timeout}]]></c> (if
+ <c><![CDATA[megaco:cast]]></c> was used).</p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to <c><![CDATA[#megaco_incr_timer{}]]></c>.</p>
+
+ <marker id="ui_long_request_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[long_request_timer]]></c></tag>
+ <item>
+ <p>Wait for reply after having received a pending message. </p>
+ <p>When the timer reaches an intermediate expire, the timer
+ is restarted. </p>
+ <p>When a pending message is received, and the
+ <c><![CDATA[long_request_timer]]></c>
+ is <em>not</em> "on its final leg", the timer will be
+ restarted, and, if <c><![CDATA[long_request_resend = true]]></c>, the
+ request will be re-sent. </p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to <c><![CDATA[60 seconds]]></c>.</p>
+
+ <marker id="ui_long_request_resend"></marker>
+ </item>
+
+ <tag><c><![CDATA[long_request_resend]]></c></tag>
+ <item>
+ <p>This option indicates weather the request should be
+ resent until the reply is received,
+ <em>even</em> though a pending message has been received. </p>
+ <p>Normally, after a pending message has been received,
+ the request is not resent
+ (since a pending message is an indication that the
+ request has been received). But since the reply (to the
+ request) can be lost, this behaviour has its values.</p>
+ <p>It is of course pointless to set this value to <em>true</em>
+ unless the <c><![CDATA[long_request_timer]]></c> (see above) is also set
+ to an incremental timer (<c><![CDATA[#megaco_incr_timer{}]]></c>). </p>
+ <p>A <c><![CDATA[boolean]]></c>,
+ defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ui_reply_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[reply_timer]]></c></tag>
+ <item>
+ <p>Wait for an ack. </p>
+ <p>When a request is received, some info
+ related to the reply is store internally (e.g. the
+ binary of the reply). This info will live until either
+ an ack is received or this timer expires. For instance,
+ if the same request is received again (e.g. a request
+ with the same transaction id), the (stored) reply will
+ be (re-) sent automatically by megaco.</p>
+ <p>If the timer is of type <c><![CDATA[#megaco_incr_timer{}]]></c>,
+ then for each intermediate timout, the reply will be resent
+ (this is valid until the ack is received or
+ the timer expires). </p>
+ <p>A Megaco Timer (see explanation above), defaults to 30000.</p>
+
+ <marker id="ui_request_keep_alive_timeout"></marker>
+ </item>
+
+ <tag><c><![CDATA[request_keep_alive_timeout]]></c></tag>
+ <item>
+ <p>Specifies the timeout time for the request-keep-alive timer. </p>
+ <p>This timer is started when the <em>first</em> reply to an asynchroneous
+ request (issued using the
+ <seealso marker="megaco#cast">megaco:cast/3</seealso> function)
+ arrives. As long as this timer is running, replies will
+ be delivered via the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function, with their "arrival number"
+ (see <c><![CDATA[UserReply]]></c> of the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function). </p>
+ <p>Replies arriving after the timer has expired, will be
+ delivered using the
+ <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans/3,4</seealso>
+ callback function. </p>
+ <p>The timeout time can have the values:
+ <c><![CDATA[plain | integer() >= 0]]></c>. </p>
+ <p>Defaults to <c><![CDATA[plain]]></c>.</p>
+
+ <marker id="ui_call_proxy_gc_timeout"></marker>
+ </item>
+
+ <tag><c><![CDATA[call_proxy_gc_timeout]]></c></tag>
+ <item>
+ <p>Timeout time for the call proxy. </p>
+ <p>When a request is sent using the
+ <seealso marker="megaco#call">call/3</seealso> function,
+ a proxy process is started to handle
+ all replies. When the reply has been received and delivered
+ to the user, the proxy process continue to exist for as long
+ as this option specifies. Any received messages, is passed on
+ to the user via the
+ <seealso marker="megaco_user#handle_unexpected_trans">handle_unexpected_trans</seealso>
+ callback function. </p>
+ <p>The timeout time is in milliseconds. A value of 0 (zero) means
+ that the proxy process will exit directly after the reply has
+ been delivered. </p>
+ <p>An integer >= 0, defaults to 5000 (= 5 seconds).</p>
+
+ <marker id="ui_auto_ack"></marker>
+ </item>
+
+ <tag><c><![CDATA[auto_ack]]></c></tag>
+ <item>
+ <p>Automatic send transaction ack when the transaction
+ reply has been received (see <c><![CDATA[trans_ack]]></c> below). </p>
+ <p>This is used for <em>three-way-handshake</em>.</p>
+ <p>A <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ui_trans_ack"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_ack]]></c></tag>
+ <item>
+ <p>Shall ack's be accumulated or not. </p>
+ <p>This property is only valid if <c><![CDATA[auto_ack]]></c> is true.</p>
+ <p>If <c><![CDATA[auto_ack]]></c> is true, then if <c><![CDATA[trans_ack]]></c> is
+ <c><![CDATA[false]]></c>, ack's will be sent immediately.
+ If <c><![CDATA[trans_ack]]></c> is <c><![CDATA[true]]></c>, then
+ ack's will instead be sent to the transaction
+ sender process for accumulation and later sending
+ (see <c><![CDATA[trans_ack_maxcount]]></c>, <c><![CDATA[trans_req_maxcount]]></c>,
+ <c><![CDATA[trans_req_maxsize]]></c>, <c><![CDATA[trans_ack_maxcount]]></c> and
+ <c><![CDATA[trans_timer]]></c>). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info.</p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ui_trans_ack_maxcount"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_ack_maxcount]]></c></tag>
+ <item>
+ <p>Maximum number of accumulated ack's. At most this many ack's
+ will be accumulated by the transaction sender (if started and
+ configured to accumulate ack's).</p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 10.</p>
+
+ <marker id="ui_trans_req"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_req]]></c></tag>
+ <item>
+ <p>Shall requests be accumulated or not. </p>
+ <p>If <c><![CDATA[trans_req]]></c> is <c><![CDATA[false]]></c>, then request(s)
+ will be sent immediately (in its own message).</p>
+ <p>If <c><![CDATA[trans_req]]></c> is true, then request(s) will
+ instead be sent to the transaction sender process for
+ accumulation and later sending
+ (see <c><![CDATA[trans_ack_maxcount]]></c>, <c><![CDATA[trans_req_maxcount]]></c>,
+ <c><![CDATA[trans_req_maxsize]]></c>, <c><![CDATA[trans_ack_maxcount]]></c> and
+ <c><![CDATA[trans_timer]]></c>). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ui_trans_req_maxcount"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_req_maxcount]]></c></tag>
+ <item>
+ <p>Maximum number of accumulated requests. At most this many
+ requests will be accumulated by the transaction sender
+ (if started and configured to accumulate requests). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info.</p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 10.</p>
+ <marker id="ui_trans_req_maxsize"></marker>
+ </item>
+ <tag><c><![CDATA[trans_req_maxsize]]></c></tag>
+ <item>
+ <p>Maximum size of the accumulated requests. At most this much
+ requests will be accumulated by the transaction sender
+ (if started and configured to accumulate requests).</p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info.</p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 2048.</p>
+
+ <marker id="ui_trans_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_timer]]></c></tag>
+ <item>
+ <p>Transaction sender timeout time. Has two functions. First, if
+ the value is 0, then transactions will not be accumulated
+ (e.g. the transaction sender process will not be started).
+ Second, if the value is greater then 0 and <c><![CDATA[auto_ack]]></c>
+ and <c><![CDATA[trans_ack]]></c> are both true or
+ if <c><![CDATA[trans_req]]></c> is true,
+ then transaction sender will be started and transactions
+ (which is depending on the values of <c><![CDATA[auto_ack]]></c>,
+ <c><![CDATA[trans_ack]]></c> and <c><![CDATA[trans_req]]></c>) will be accumulated,
+ for later sending. </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 0.</p>
+
+ <marker id="ui_pending_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[pending_timer]]></c></tag>
+ <item>
+ <p>Automatically send pending if the timer expires before a
+ transaction reply has been sent. This timer is also called
+ provisional response timer. </p>
+ <p>A Megaco Timer (see explanation above), defaults to 30000.</p>
+
+ <marker id="ui_sent_pending_limit"></marker>
+ </item>
+
+ <tag><c><![CDATA[sent_pending_limit]]></c></tag>
+ <item>
+ <p>Sent pending limit (see the MGOriginatedPendingLimit
+ and the MGCOriginatedPendingLimit of the megaco root package).
+ This parameter specifies how many pending messages that can
+ be sent (for a given received transaction request).
+ When the limit is exceeded, the transaction is aborted
+ (see <seealso marker="megaco_user#request_abort">handle_trans_request_abort</seealso>) and an error message
+ is sent to the other side. </p>
+ <p>Note that this has no effect on the actual sending of
+ pending transactions. This is either implicit (e.g. when
+ receiving a re-sent transaction request for a request which
+ is being processed) or controlled by the pending_timer,
+ see above. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>.</p>
+
+ <marker id="ui_recv_pending_limit"></marker>
+ </item>
+
+ <tag><c><![CDATA[recv_pending_limit]]></c></tag>
+ <item>
+ <p>Receive pending limit (see the MGOriginatedPendingLimit
+ and the MGCOriginatedPendingLimit of the megaco root package).
+ This parameter specifies how many pending messages that can
+ be received (for a sent transaction request).
+ When the limit is exceeded, the transaction is considered
+ lost, and an error returned to the user (through the call-back
+ function <em>handle_trans_reply</em>). </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>. </p>
+
+ <marker id="ui_send_mod"></marker>
+ </item>
+
+ <tag><c><![CDATA[send_mod]]></c></tag>
+ <item>
+ <p>Send callback module which exports send_message/2. The
+ function SendMod:send_message(SendHandle, Binary) is
+ invoked when the bytes needs to be transmitted to the
+ remote user. </p>
+ <p>An <c><![CDATA[atom]]></c>, defaults to <c><![CDATA[megaco_tcp]]></c>.</p>
+
+ <marker id="ui_encoding_mod"></marker>
+ </item>
+
+ <tag><c><![CDATA[encoding_mod]]></c></tag>
+ <item>
+ <p>Encoding callback module which exports encode_message/2
+ and decode_message/2. The function
+ EncodingMod:encode_message(EncodingConfig,
+ MegacoMessage) is invoked whenever a 'MegacoMessage'
+ record needs to be translated into an Erlang binary. The
+ function EncodingMod:decode_message(EncodingConfig,
+ Binary) is invoked whenever an Erlang binary needs to be
+ translated into a 'MegacoMessage' record. </p>
+ <p>An <c><![CDATA[atom]]></c>, defaults to <c><![CDATA[megaco_pretty_text_encoder]]></c>.</p>
+
+ <marker id="ui_encoding_config"></marker>
+ </item>
+
+ <tag><c><![CDATA[encoding_config]]></c></tag>
+ <item>
+ <p>Encoding module config. </p>
+ <p>A <c><![CDATA[list]]></c>, defaults to <c><![CDATA[[]]]></c>.</p>
+
+ <marker id="ui_protocol_version"></marker>
+ </item>
+
+ <tag><c><![CDATA[protocol_version]]></c></tag>
+ <item>
+ <p>Actual protocol version. </p>
+ <p>An <c><![CDATA[integer]]></c>, default is 1.</p>
+
+ <marker id="ui_strict_version"></marker>
+ </item>
+
+ <tag><c><![CDATA[strict_version]]></c></tag>
+ <item>
+ <p>Strict version control, i.e. when a message is received,
+ verify that the version is that which was negotiated. </p>
+ <p>An <c><![CDATA[boolean]]></c>, default is true.</p>
+
+ <marker id="ui_reply_data"></marker>
+ </item>
+
+ <tag><c><![CDATA[reply_data]]></c></tag>
+ <item>
+ <p>Default reply data. </p>
+ <p>Any term, defaults to the atom <c><![CDATA[undefined]]></c>.</p>
+
+ <marker id="ui_user_mod"></marker>
+ </item>
+
+ <tag><c><![CDATA[user_mod]]></c></tag>
+ <item>
+ <p>Name of the user callback module. See the the reference
+ manual for megaco_user for more info.</p>
+
+ <marker id="ui_user_args"></marker>
+ </item>
+
+ <tag><c><![CDATA[user_args]]></c></tag>
+ <item>
+ <p>List of extra arguments to the user callback
+ functions. See the the reference manual for megaco_user
+ for more info.</p>
+
+ <marker id="ui_threaded"></marker>
+ </item>
+
+ <tag><c><![CDATA[threaded]]></c></tag>
+ <item>
+ <p>If a received message contains several transaction requests,
+ this option indicates whether the requests should be handled
+ sequentially in the same process (<c><![CDATA[false]]></c>), or if each
+ request should be handled by its own process (<c><![CDATA[true]]></c>
+ i.e. a separate process is spawned for each request). </p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>. </p>
+
+ <marker id="ui_resend_indication"></marker>
+ </item>
+
+ <tag><c><![CDATA[resend_indication]]></c></tag>
+ <item>
+ <p>This option indicates weather the transport module
+ should be told if a message send is a resend or not. </p>
+ <p>If <em>false</em>, megaco messages are sent using the
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function. </p>
+ <p>If <em>true</em>, megaco message <em>re-sends</em> are made using the
+ <seealso marker="megaco_transport#resend_message">resend_message</seealso>
+ function. The initial message send is still done using the
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function. </p>
+ <p>The special value <em>flag</em> instead indicates that the
+ function
+ <seealso marker="megaco_transport#send_message">send_message/3</seealso>
+ shall be used. </p>
+ <p>A <c>resend_indication()</c>,
+ defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ui_segment_reply_ind"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_reply_ind]]></c></tag>
+ <item>
+ <p>This option specifies if the user shall be notified of received
+ segment replies or not. </p>
+ <p>See
+ <seealso marker="megaco_user#segment_reply">handle_segment_reply</seealso>
+ callback function for more information. </p>
+ <p>A <c><![CDATA[boolean]]></c>,
+ defaults to <c><![CDATA[false]]></c>. </p>
+
+ <marker id="ui_segment_recv_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_recv_timer]]></c></tag>
+ <item>
+ <p>This timer is started when the segment indicated by the
+ <c><![CDATA[segmentation complete token]]></c> is received, but all
+ segments has not yet been received.</p>
+ <p>When the timer finally expires, a "megaco segments not
+ received" (459) error message is sent to the other side
+ and the user is notified with a <c><![CDATA[segment timeout]]></c><c><![CDATA[UserReply]]></c> in either the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso> callback function or
+ the return value of the
+ <seealso marker="megaco#call">call</seealso> function. </p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to <c><![CDATA[10000]]></c>. </p>
+
+ <marker id="ui_segment_send"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_send]]></c></tag>
+ <item>
+ <p>Shall outgoing messages be segmented or not: </p>
+ <taglist>
+ <tag><c><![CDATA[none]]></c></tag>
+ <item>
+ <p>Do not segment outgoing reply messages. This is usefull when
+ either it is known that messages are never to large or
+ that the transport protocol can handle such things
+ on its own (e.g. TCP or SCTP).</p>
+ </item>
+ <tag><c><![CDATA[integer() > 0]]></c></tag>
+ <item>
+ <p>Outgoing reply messages will be segmented as needed
+ (see <c><![CDATA[max_pdu_size]]></c> below). This value, K, indicate
+ the outstanding window, i.e. how many segments can be
+ outstanding (not acknowledged) at any given time. </p>
+ </item>
+ <tag><c><![CDATA[infinity]]></c></tag>
+ <item>
+ <p>Outgoing reply messages will be segmented as needed
+ (see <c><![CDATA[max_pdu_size]]></c> below). Segment messages
+ are sent all at once (i.e. no acknowledgement awaited
+ before sending the next segment). </p>
+ </item>
+ </taglist>
+ <p>Defaults to <c><![CDATA[none]]></c>. </p>
+
+ <marker id="ui_max_pdu_size"></marker>
+ </item>
+
+ <tag><c><![CDATA[max_pdu_size]]></c></tag>
+ <item>
+ <p>Max message size. If the encoded message (PDU) exceeds
+ this size, the message should be segmented, and then
+ encoded. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>. </p>
+ </item>
+ </taglist>
+
+ <marker id="update_user_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_user_info(UserMid, Item, Value) -> ok | {error, Reason}</name>
+ <fsummary>Update information about a user</fsummary>
+ <type>
+ <v>UserMid = megaco_mid() </v>
+ <v>Item = user_info_item()</v>
+ <v>Value = user_info_value()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Update information about a user</p>
+ <p>Requires that the user is started. See megaco:user_info/2
+ about which items and values that are valid.</p>
+
+ <marker id="conn_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>conn_info(ConnHandle) -> [{Item, Value}]</name>
+ <name>conn_info(ConnHandle, Item) -> Value | exit(Reason)</name>
+ <fsummary>Lookup information about an active connection</fsummary>
+ <type>
+ <v>ConnHandle = #megaco_conn_handle{}</v>
+ <v>Item = conn_info_item()</v>
+ <v>Value = conn_info_value()</v>
+ <v>Reason = {no_such_connection, ConnHandle} | term()</v>
+ </type>
+ <desc>
+ <p>Lookup information about an active connection</p>
+ <p>Requires that the connection is active.</p>
+ <marker id="ci_control_pid"></marker>
+ <taglist>
+
+ <tag><c><![CDATA[control_pid]]></c></tag>
+ <item>
+ <p>The process identifier of the controlling process for a
+ connection.</p>
+
+ <marker id="ci_send_handle"></marker>
+ </item>
+
+ <tag><c><![CDATA[send_handle]]></c></tag>
+ <item>
+ <p>Opaque send handle whose contents is internal for the
+ send module. May be any term.</p>
+
+ <marker id="ci_local_mid"></marker>
+ </item>
+
+ <tag><c><![CDATA[local_mid]]></c></tag>
+ <item>
+ <p>The local mid (of the connection, i.e. the own mid).
+ <c><![CDATA[megaco_mid()]]></c>.</p>
+
+ <marker id="ci_remote_mid"></marker>
+ </item>
+
+ <tag><c><![CDATA[remote_mid]]></c></tag>
+ <item>
+ <p>The remote mid (of the connection).
+ <c><![CDATA[megaco_mid()]]></c>.</p>
+
+ <marker id="ci_receive_handle"></marker>
+ </item>
+
+ <tag><c><![CDATA[receive_handle]]></c></tag>
+ <item>
+ <p>Construct a megaco_receive_handle record.</p>
+
+ <marker id="ci_trans_id"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_id]]></c></tag>
+ <item>
+ <p>Next transaction id. A positive integer or the atom
+ <c><![CDATA[undefined_serial]]></c> (only in case of error). </p>
+ <p>Note that transaction id's are (currently) maintained
+ on a per user basis so there is no way to be sure that
+ the value returned will actually be used for a transaction
+ sent on this connection (in case a user has several
+ connections, which is not at all unlikely). </p>
+
+ <marker id="ci_max_trans_id"></marker>
+ </item>
+
+ <tag><c><![CDATA[max_trans_id]]></c></tag>
+ <item>
+ <p>Last trans id. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>.</p>
+
+ <marker id="ci_request_time"></marker>
+ </item>
+
+ <tag><c><![CDATA[request_timer]]></c></tag>
+ <item>
+ <p>Wait for reply. </p>
+ <p>The timer is cancelled when a reply is received. </p>
+ <p>When a pending message is received, the timer is
+ cancelled and the <c><![CDATA[long_request_timer]]></c> is started instead
+ (see below). No resends will be performed from this point
+ (since we now know that the other side has received the
+ request). </p>
+ <p>When the timer reaches an intermediate expire, the request
+ is resent and the timer is restarted. </p>
+ <p>When the timer reaches the final expire, either the function
+ <c><![CDATA[megaco:call]]></c> will return with <c><![CDATA[{error, timeout}]]></c>
+ or the callback function <c><![CDATA[handle_trans_reply]]></c> will be
+ called with <c><![CDATA[UserReply = {error, timeout}]]></c> (if
+ <c><![CDATA[megaco:cast]]></c> was used).</p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to #megaco_incr_timer{}.</p>
+
+ <marker id="ci_long_request_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[long_request_timer]]></c></tag>
+ <item>
+ <p>Wait for reply after having received a pending message. </p>
+ <p>When the timer reaches an intermediate expire, the timer
+ restarted. </p>
+ <p>When a pending message is received, and the
+ <c><![CDATA[long_request_timer]]></c>
+ is <em>not</em> "on its final leg", the timer will be
+ restarted, and, if <c><![CDATA[long_request_resend = true]]></c>, the
+ request will be re-sent. </p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to <c><![CDATA[60 seconds]]></c>.</p>
+
+ <marker id="ci_request_keep_alive_timeout"></marker>
+ </item>
+
+ <tag><c><![CDATA[request_keep_alive_timeout]]></c></tag>
+ <item>
+ <p>Specifies the timeout time for the request-keep-alive timer. </p>
+ <p>This timer is started when the <em>first</em> reply to an asynchroneous
+ request (issued using the
+ <seealso marker="megaco#cast">megaco:cast/3</seealso> function)
+ arrives. As long as this timer is running, replies will
+ be delivered via the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function, with their "arrival number"
+ (see <c><![CDATA[UserReply]]></c> of the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function). </p>
+ <p>Replies arriving after the timer has expired, will be
+ delivered using the
+ <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans/3,4</seealso>
+ callback function. </p>
+ <p>The timeout time can have the values:
+ <c><![CDATA[plain | integer() >= 0]]></c>. </p>
+ <p>Defaults to <c><![CDATA[plain]]></c>.</p>
+
+ <marker id="ci_long_request_resend"></marker>
+ </item>
+
+ <tag><c><![CDATA[long_request_resend]]></c></tag>
+ <item>
+ <p>This option indicates weather the request should be
+ resent until the reply is received,
+ <em>even</em> though a pending message has been received. </p>
+ <p>Normally, after a pending message has been received,
+ the request is not resent
+ (since a pending message is an indication that the
+ request has been received). But since the reply (to the
+ request) can be
+ lost, this behaviour has its values.</p>
+ <p>It is of course pointless to set this value to <em>true</em>
+ unless the <c><![CDATA[long_request_timer]]></c> (see above) is also set
+ to an incremental timer (<c><![CDATA[#megaco_incr_timer{}]]></c>). </p>
+ <p>A <c><![CDATA[boolean]]></c>,
+ defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ci_reply_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[reply_timer]]></c></tag>
+ <item>
+ <p>Wait for an ack. </p>
+ <p>When a request is received, some info
+ related to the reply is store internally (e.g. the
+ binary of the reply). This info will live until either
+ an ack is received or this timer expires. For instance,
+ if the same request is received again (e.g. a request
+ with the same transaction id), the (stored) reply will
+ be (re-) sent automatically by megaco.</p>
+ <p>If the timer is of type <c><![CDATA[#megaco_incr_timer{}]]></c>,
+ then for each intermediate timout, the reply will be resent
+ (this is valid until the ack is received or
+ the timer expires). </p>
+ <p>A Megaco Timer (see explanation above), defaults to 30000.</p>
+
+ <marker id="ci_call_proxy_gc_timeout"></marker>
+ </item>
+
+ <tag><c><![CDATA[call_proxy_gc_timeout]]></c></tag>
+ <item>
+ <p>Timeout time for the call proxy. </p>
+ <p>When a request is sent using the
+ <seealso marker="megaco#call">call/3</seealso> function,
+ a proxy process is started to handle
+ all replies. When the reply has been received and delivered
+ to the user, the proxy process continue to exist for as long
+ as this option specifies. Any received messages, is passed on
+ to the user via the
+ <seealso marker="megaco_user#handle_unexpected_trans">handle_unexpected_trans</seealso>
+ callback function. </p>
+ <p>The timeout time is in milliseconds. A value of 0 (zero) means
+ that the proxy process will exit directly after the reply has
+ been delivered. </p>
+ <p>An integer >= 0, defaults to 5000 (= 5 seconds).</p>
+ <marker id="ci_auto_ack"></marker>
+ </item>
+
+ <tag><c><![CDATA[auto_ack]]></c></tag>
+ <item>
+ <p>Automatic send transaction ack when the transaction
+ reply has been received (see <c><![CDATA[trans_ack]]></c> below). </p>
+ <p>This is used for <em>three-way-handshake</em>. </p>
+ <p>A <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ci_trans_ack"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_ack]]></c></tag>
+ <item>
+ <p>Shall ack's be accumulated or not. </p>
+ <p>This property is only valid if <c><![CDATA[auto_ack]]></c> is true. </p>
+ <p>If <c><![CDATA[auto_ack]]></c> is true, then if <c><![CDATA[trans_ack]]></c> is
+ <c><![CDATA[false]]></c>, ack's will be sent immediately.
+ If <c><![CDATA[trans_ack]]></c> is
+ <c><![CDATA[true]]></c>, then ack's will instead be sent to the transaction
+ sender process for accumulation and later sending
+ (see <c><![CDATA[trans_ack_maxcount]]></c>, <c><![CDATA[trans_req_maxcount]]></c>,
+ <c><![CDATA[trans_req_maxsize]]></c>, <c><![CDATA[trans_ack_maxcount]]></c> and
+ <c><![CDATA[trans_timer]]></c>). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ci_trans_ack_maxcount"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_ack_maxcount]]></c></tag>
+ <item>
+ <p>Maximum number of accumulated ack's. At most this many ack's
+ will be accumulated by the transaction sender (if started and
+ configured to accumulate ack's).</p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info.</p>
+ <p>An integer, defaults to 10.</p>
+
+ <marker id="ci_trans_req"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_req]]></c></tag>
+ <item>
+ <p>Shall requests be accumulated or not. </p>
+ <p>If <c><![CDATA[trans_req]]></c> is <c><![CDATA[false]]></c>, then request(s)
+ will be sent immediately (in its own message). </p>
+ <p>If <c><![CDATA[trans_req]]></c> is true, then request(s) will
+ instead be sent to the transaction sender process for
+ accumulation and later sending
+ (see <c><![CDATA[trans_ack_maxcount]]></c>, <c><![CDATA[trans_req_maxcount]]></c>,
+ <c><![CDATA[trans_req_maxsize]]></c>, <c><![CDATA[trans_ack_maxcount]]></c> and
+ <c><![CDATA[trans_timer]]></c>). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>.</p>
+
+ <marker id="ci_trans_req_maxcount"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_req_maxcount]]></c></tag>
+ <item>
+ <p>Maximum number of accumulated requests. At most this many
+ requests will be accumulated by the transaction sender
+ (if started and configured to accumulate requests). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 10.</p>
+
+ <marker id="ci_trans_req_maxsize"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_req_maxsize]]></c></tag>
+ <item>
+ <p>Maximum size of the accumulated requests. At most this much
+ requests will be accumulated by the transaction sender
+ (if started and configured to accumulate requests). </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 2048.</p>
+
+ <marker id="ci_trans_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[trans_timer]]></c></tag>
+ <item>
+ <p>Transaction sender timeout time. Has two functions. First, if
+ the value is 0, then transactions will not be accumulated
+ (e.g. the transaction sender process will not be started).
+ Second, if the value is greater then 0 and <c><![CDATA[auto_ack]]></c>
+ and <c><![CDATA[trans_ack]]></c> is true or if <c><![CDATA[trans_req]]></c> is true,
+ then transaction sender will be started and transactions
+ (which is depending on the values of <c><![CDATA[auto_ack]]></c>,
+ <c><![CDATA[trans_ack]]></c> and <c><![CDATA[trans_req]]></c>) will be accumulated,
+ for later sending. </p>
+ <p>See also <seealso marker="megaco_run#transaction_sender">transaction sender</seealso> for more info. </p>
+ <p>An <c><![CDATA[integer]]></c>, defaults to 0.</p>
+
+ <marker id="ci_pending_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[pending_timer]]></c></tag>
+ <item>
+ <p>Automatic send transaction pending if the timer expires
+ before a transaction reply has been sent. This timer is
+ also called provisional response timer. </p>
+ <p>A Megaco Timer (see explanation above), defaults to 30000.</p>
+
+ <marker id="ci_sent_pending_limit"></marker>
+ </item>
+
+ <tag><c><![CDATA[sent_pending_limit]]></c></tag>
+ <item>
+ <p>Sent pending limit (see the MGOriginatedPendingLimit
+ and the MGCOriginatedPendingLimit of the megaco root package).
+ This parameter specifies how many pending messages that can
+ be sent (for a given received transaction request).
+ When the limit is exceeded, the transaction is aborted
+ (see <seealso marker="megaco_user#request_abort">handle_trans_request_abort</seealso>) and an error message
+ is sent to the other side. </p>
+ <p>Note that this has no effect on the actual sending of
+ pending transactions. This is either implicit (e.g. when
+ receiving a re-sent transaction request for a request which
+ is being processed) or controlled by the pending_timer,
+ see above. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>.</p>
+
+ <marker id="ci_recv_pending_limit"></marker>
+ </item>
+
+ <tag><c><![CDATA[recv_pending_limit]]></c></tag>
+ <item>
+ <p>Receive pending limit (see the MGOriginatedPendingLimit
+ and the MGCOriginatedPendingLimit of the megaco root package).
+ This parameter specifies how many pending messages that can
+ be received (for a sent transaction request).
+ When the limit is exceeded, the transaction is considered
+ lost, and an error returned to the user (through the call-back
+ function <em>handle_trans_reply</em>). </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>.</p>
+
+ <marker id="ci_send_mod"></marker>
+ </item>
+
+ <tag><c><![CDATA[send_mod]]></c></tag>
+ <item>
+ <p>Send callback module which exports send_message/2. The
+ function SendMod:send_message(SendHandle, Binary) is
+ invoked when the bytes needs to be transmitted to
+ the remote user. </p>
+ <p>An <c><![CDATA[atom]]></c>, defaults to <c><![CDATA[megaco_tcp]]></c>.</p>
+
+ <marker id="ci_encoding_mod"></marker>
+ </item>
+
+ <tag><c><![CDATA[encoding_mod]]></c></tag>
+ <item>
+ <p>Encoding callback module which exports encode_message/2
+ and decode_message/2. The function
+ EncodingMod:encode_message(EncodingConfig, MegacoMessage)
+ is invoked whenever a 'MegacoMessage' record needs to be
+ translated into an Erlang binary. The function
+ EncodingMod:decode_message(EncodingConfig, Binary) is
+ invoked whenever an Erlang binary needs to be translated
+ into a 'MegacoMessage' record. </p>
+ <p>An <c><![CDATA[atom]]></c>,
+ defaults to <c><![CDATA[megaco_pretty_text_encoder]]></c>.</p>
+
+ <marker id="ci_encoding_confi"></marker>
+ </item>
+
+ <tag><c><![CDATA[encoding_config]]></c></tag>
+ <item>
+ <p>Encoding module config. </p>
+ <p>A <c><![CDATA[list]]></c>, defaults to [].</p>
+
+ <marker id="ci_protocol_version"></marker>
+ </item>
+
+ <tag><c><![CDATA[protocol_version]]></c></tag>
+ <item>
+ <p>Actual protocol version. </p>
+ <p>An positive integer, Current default is 1.</p>
+ <marker id="ci_strict_version"></marker>
+ </item>
+ <tag><c><![CDATA[strict_version]]></c></tag>
+ <item>
+ <p>Strict version control, i.e. when a message is received,
+ verify that the version is that which was negotiated. </p>
+ <p>An <c><![CDATA[boolean]]></c>, default is true.</p>
+ <marker id="ci_reply_data"></marker>
+ </item>
+ <tag><c><![CDATA[reply_data]]></c></tag>
+ <item>
+ <p>Default reply data. </p>
+ <p>Any term, defaults to the atom <c><![CDATA[undefined]]></c>.</p>
+
+ <marker id="ci_threaded"></marker>
+ </item>
+
+ <tag><c><![CDATA[threaded]]></c></tag>
+ <item>
+ <p>If a received message contains several transaction requests,
+ this option indicates whether the requests should be handled
+ sequentially in the same process (<c><![CDATA[false]]></c>), or if each
+ request should be handled by its own process (<c><![CDATA[true]]></c>
+ i.e. a separate process is spawned for each request). </p>
+ <p>An <c><![CDATA[boolean]]></c>, defaults to <c><![CDATA[false]]></c>. </p>
+ <marker id="ci_resend_indication"></marker>
+ </item>
+ <tag><c><![CDATA[resend_indication]]></c></tag>
+ <item>
+ <p>This option indicates weather the transport module
+ should be told if a message send is a resend or not. </p>
+ <p>If <em>false</em>, megaco messages are sent using the
+ <seealso marker="megaco_transport#send_message">send_message/2</seealso>
+ function. </p>
+ <p>If <em>true</em>, megaco message <em>re-sends</em> are made using the
+ <seealso marker="megaco_transport#resend_message">resend_message</seealso>
+ function. The initial message send is still done using the
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function. </p>
+ <p>The special value <em>flag</em> instead indicates that the
+ function
+ <seealso marker="megaco_transport#send_message">send_message/3</seealso>
+ shall be used. </p>
+ <p>A <c>resend_indication()</c>,
+ defaults to <c><![CDATA[false]]></c>.</p>
+ <marker id="ci_segment_reply_ind"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_reply_ind]]></c></tag>
+ <item>
+ <p>This option specifies if the user shall be notified of received
+ segment replies or not. </p>
+ <p>See
+ <seealso marker="megaco_user#segment_reply">handle_segment_reply</seealso>
+ callback function for more information. </p>
+ <p>A <c><![CDATA[boolean]]></c>,
+ defaults to <c><![CDATA[false]]></c>. </p>
+
+ <marker id="ci_segment_recv_timer"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_recv_timer]]></c></tag>
+ <item>
+ <p>This timer is started when the segment indicated by the
+ <c><![CDATA[segmentation complete token]]></c> (e.g. the last of the segment
+ which makes up the reply) is received, but all
+ segments has not yet been received.</p>
+ <p>When the timer finally expires, a "megaco segments not
+ received" (459) error message is sent to the other side
+ and the user is notified with a
+ <c><![CDATA[segment timeout]]></c><c><![CDATA[UserReply]]></c> in either the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>
+ callback function or
+ the return value of the
+ <seealso marker="megaco#call">call</seealso> function. </p>
+ <p>A Megaco Timer (see explanation above),
+ defaults to <c><![CDATA[10000]]></c>. </p>
+
+ <marker id="ci_segment_send"></marker>
+ </item>
+
+ <tag><c><![CDATA[segment_send]]></c></tag>
+ <item>
+ <p>Shall outgoing messages be segmented or not: </p>
+ <taglist>
+ <tag><c><![CDATA[none]]></c></tag>
+ <item>
+ <p>Do not segment outgoing reply messages. This is usefull when
+ either it is known that messages are never to large or
+ that the transport protocol can handle such things
+ on its own (e.g. TCP or SCTP).</p>
+ </item>
+ <tag><c><![CDATA[integer() > 0]]></c></tag>
+ <item>
+ <p>Outgoing reply messages will be segmented as needed
+ (see <c><![CDATA[max_pdu_size]]></c> below). This value, K, indicate
+ the outstanding window, i.e. how many segments can be
+ outstanding (not acknowledged) at any given time. </p>
+ </item>
+ <tag><c><![CDATA[infinity]]></c></tag>
+ <item>
+ <p>Outgoing reply messages will be segmented as needed
+ (see <c><![CDATA[max_pdu_size]]></c> below). Segment messages
+ are sent all at once (i.e. no acknowledgement awaited
+ before sending the next segment). </p>
+ </item>
+ </taglist>
+ <p>Defaults to <c><![CDATA[none]]></c>. </p>
+ <marker id="ci_max_pdu_size"></marker>
+ </item>
+
+ <tag><c><![CDATA[max_pdu_size]]></c></tag>
+ <item>
+ <p>Max message size. If the encoded message (PDU) exceeds
+ this size, the message should be segmented, and then
+ encoded. </p>
+ <p>A positive integer or <c><![CDATA[infinity]]></c>,
+ defaults to <c><![CDATA[infinity]]></c>. </p>
+ </item>
+ </taglist>
+
+ <marker id="update_conn_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_conn_info(ConnHandle, Item, Value) -> ok | {error, Reason}</name>
+ <fsummary>Update information about an active connection</fsummary>
+ <type>
+ <v>ConnHandle = #megaco_conn_handle{}</v>
+ <v>Item = conn_info_item()</v>
+ <v>Value = conn_info_value()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Update information about an active connection</p>
+ <p>Requires that the connection is activated. See
+ megaco:conn_info/2 about which items and values that are
+ valid.</p>
+
+ <marker id="system_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>system_info() -> [{Item, Value}] | exit(Reason)</name>
+ <name>system_info(Item) -> Value | exit(Reason)</name>
+ <fsummary>Lookup system information</fsummary>
+ <type>
+ <v>Item = system_info_item()</v>
+ </type>
+ <desc>
+ <p>Lookup system information</p>
+ <p>The following items are valid:</p>
+ <taglist>
+ <tag><c><![CDATA[text_config]]></c></tag>
+ <item>
+ <p>The text encoding config.</p>
+ </item>
+ <tag><c><![CDATA[connections]]></c></tag>
+ <item>
+ <p>Lists all active connections. Returns a list of
+ megaco_conn_handle records.</p>
+ </item>
+ <tag><c><![CDATA[users]]></c></tag>
+ <item>
+ <p>Lists all active users. Returns a list of
+ megaco_mid()'s.</p>
+ </item>
+ <tag><c><![CDATA[n_active_requests]]></c></tag>
+ <item>
+ <p>Returns an integer representing the number of requests
+ that has originated from this Erlang node and still are
+ active (and therefore consumes system resources).</p>
+ </item>
+ <tag><c><![CDATA[n_active_replies]]></c></tag>
+ <item>
+ <p>Returns an integer representing the number of replies
+ that has originated from this Erlang node and still are
+ active (and therefore consumes system resources).</p>
+ </item>
+ <tag><c><![CDATA[n_active_connections]]></c></tag>
+ <item>
+ <p>Returns an integer representing the number of active
+ connections.</p>
+ </item>
+ </taglist>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>info() -> Info</name>
+ <fsummary>All the information of the application</fsummary>
+ <type>
+ <v>Info = [{Key, Value}]</v>
+ </type>
+ <desc>
+ <p>This function produces a list of information about the megaco
+ application. Such as users and their config, connections
+ and their config, statistics and so on.</p>
+
+ <p>This information can be produced by the functions
+ <seealso marker="#user_info">user_info</seealso>,
+ <seealso marker="#conn_info">conn_info</seealso>,
+ <seealso marker="#system_info">system_info</seealso> and
+ <seealso marker="#get_stats">get_stats</seealso>
+ but this is a simple way to get it all at once.</p>
+
+ <marker id="connect"></marker> <!-- Belongs to NEXT function(s) -->
+ </desc>
+ </func>
+
+ <func>
+ <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) -> {ok, ConnHandle} | {error, Reason}</name>
+ <name>connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra) -> {ok, ConnHandle} | {error, Reason}</name>
+ <fsummary>Establish a "virtual" connection</fsummary>
+ <type>
+ <v>ReceiveHandle = #megaco_receive_handle{}</v>
+ <v>RemoteMid = preliminary_mid | megaco_mid()</v>
+ <v>SendHandle = term()</v>
+ <v>ControlPid = pid()</v>
+ <v>ConnHandle = #megaco_conn_handle{}</v>
+ <v>Reason = connect_reason() | handle_connect_reason() | term()</v>
+ <v>connect_reason() = {no_such_user, LocalMid} | {already_connected, ConnHandle} | term()</v>
+ <v>handle_connect_error() = {connection_refused, ConnData, ErrorInfo} | term()</v>
+ <v>LocalMid = megaco_mid()</v>
+ <v>ConnData = term()</v>
+ <v>ErrorInfo = term()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Establish a "virtual" connection</p>
+ <p>Activates a connection to a remote user. When this is done
+ the connection can be used to send messages (with
+ SendMod:send_message/2). The ControlPid is the identifier
+ of a process that controls the connection. That process will
+ be supervised and if it dies, this will be detected and the
+ UserMod:handle_disconnect/2 callback function will be
+ invoked. See the megaco_user module for more info about the
+ callback arguments. The connection may also explicitly be
+ deactivated by invoking megaco:disconnect/2.</p>
+ <p>The ControlPid may be the identity of a process residing on
+ another Erlang node. This is useful when you want to
+ distribute a user over several Erlang nodes. In such a case
+ one of the nodes has the physical connection. When a user
+ residing on one of the other nodes needs to send a request
+ (with megaco:call/3 or megaco:cast/3), the message will
+ encoded on the originating Erlang node, and then be
+ forwarded to the node with the physical connection. When the
+ reply arrives, it will be forwarded back to the originator.
+ The distributed connection may explicitly be deactivated by
+ a local call to megaco:disconnect/2 or implicitly when
+ the physical connection is deactivated (with megaco:disconnect/2,
+ killing the controlling process, halting the other node, ...).</p>
+ <p>The call of this function will trigger the callback
+ function UserMod:handle_connect/2 to be invoked. See the
+ megaco_user module for more info about the callback
+ arguments.</p>
+ <p>A connection may be established in several ways:</p>
+ <taglist>
+ <tag><c><![CDATA[provisioned MID]]></c></tag>
+ <item>
+ <p>The MG may explicitly invoke megaco:connect/4 and use
+ a provisioned MID of the MGC as the RemoteMid.</p>
+ </item>
+ <tag><c><![CDATA[upgrade preliminary MID]]></c></tag>
+ <item>
+ <p>The MG may explicitly invoke megaco:connect/4 with the
+ atom 'preliminary_mid' as a temporary MID of the MGC,
+ send an intial message, the Service Change Request, to
+ the MGC and then wait for an initial message, the
+ Service Change Reply. When the reply arrives, the Megaco
+ application will pick the MID of the MGC from the
+ message header and automatically upgrade the connection
+ to be a "normal" connection. By using this method of
+ establishing the connection, the callback function
+ UserMod:handle_connect/2 to be invoked twice. First with
+ a ConnHandle with the remote_mid-field set to
+ preliminary_mid, and then when the connection upgrade is
+ done with the remote_mid-field set to the actual MID of
+ the MGC.</p>
+ </item>
+ <tag><c><![CDATA[automatic]]></c></tag>
+ <item>
+ <p>When the MGC receives its first message, the Service
+ Change Request, the Megaco application will
+ automatically establish the connection by using the MG
+ MID found in the message header as remote mid.</p>
+ </item>
+ <tag><c><![CDATA[distributed]]></c></tag>
+ <item>
+ <p>When a user (MG/MGC) is distributed over several nodes,
+ it is required that the node hosting the connection
+ already has activated the connection and that it is
+ in the "normal" state. The RemoteMid must be a real
+ Megaco MID and not a preliminary_mid.</p>
+ </item>
+ </taglist>
+ <p>An initial megaco_receive_handle record may be obtained
+ with megaco:user_info(UserMid, receive_handle)</p>
+ <p>The send handle is provided by the preferred transport
+ module, e.g. megaco_tcp, megaco_udp. Read the documentation
+ about each transport module about the details.</p>
+
+ <p>The connect is done in two steps: first an internal
+ <c>connection setup</c> and then by calling the user
+ <seealso marker="megaco_user#connect">handle_connect</seealso>
+ callback function. The first step could result in
+ an error with <c>Reason = connect_reason()</c> and the second
+ an error with <c>Reason = handle_connect_reason()</c>: </p>
+
+ <taglist>
+ <tag><c>connect_reason()</c></tag>
+ <item>
+ <p>An error with this reason is generated by the
+ megaco application itself.</p>
+ </item>
+
+ <tag><c>handle_connect_reason()</c></tag>
+ <item>
+ <p>An error with this reason is caused by the user
+ <seealso marker="megaco_user#connect">handle_connect</seealso>
+ callback function either returning an error
+ or an invalid value.</p>
+ </item>
+
+ </taglist>
+
+ <p><c><![CDATA[Extra]]></c> can be any <c><![CDATA[term()]]></c>
+ except the atom <c><![CDATA[ignore_extra]]></c>.
+ It is passed (back) to the user via the callback function
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>. </p>
+
+ <marker id="disconnect"></marker> <!-- Belongs to NEXT function(s) -->
+ </desc>
+ </func>
+
+ <func>
+ <name>disconnect(ConnHandle, DiscoReason) -> ok | {error, ErrReason}</name>
+ <fsummary>Tear down a "virtual" connection</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>DiscoReason = term()</v>
+ <v>ErrReason = term()</v>
+ </type>
+ <desc>
+ <p>Tear down a "virtual" connection</p>
+ <p>Causes the UserMod:handle_disconnect/2 callback function to
+ be invoked. See the megaco_user module for more info about
+ the callback arguments.</p>
+
+ <marker id="call"></marker> <!-- Belongs to NEXT function(s) -->
+ </desc>
+ </func>
+
+ <func>
+ <name>call(ConnHandle, Actions, Options) -> {ProtocolVersion, UserReply}</name>
+ <fsummary>Sends one or more transaction request(s) and waits for the reply</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>Actions = action_reqs() | [action_reqs()]</v>
+ <v>action_reqs() = binary() | [action_request()]</v>
+ <v>Options = [send_option()]</v>
+ <v>send_option() = {request_timer, megaco_timer()} | {long_request_timer, megaco_timer()} | {send_handle, term()} | {protocol_version, integer()} | {call_proxy_gc_timeout, call_proxy_gc_timeout()}</v>
+ <v>ProtocolVersion = integer()</v>
+ <v>UserReply = user_reply() | [user_reply()]</v>
+ <v>user_reply() = success() | failure()</v>
+ <v>success() = {ok, result()} | {ok, result(), extra()}</v>
+ <v>result() = message_result() | segment_result()</v>
+ <v>message_result() = action_reps()</v>
+ <v>segment_result() = segments_ok()</v>
+ <v>failure() = {error, reason()} | {error, reason(), extra()}</v>
+ <v>reason() = message_reason() | segment_reason() | user_cancel_reason() | send_reason() | other_reason()</v>
+ <v>message_reason() = error_desc()</v>
+ <v>segment_reason() = {segment, segments_ok(), segments_err()} | {segment_timeout, missing_segments(), segments_ok(), segments_err()}</v>
+ <v>segments_ok() = [segment_ok()]</v>
+ <v>segment_ok() = {segment_no(), action_reps()}</v>
+ <v>segments_err() = [segment_err()]</v>
+ <v>segment_err() = {segment_no(), error_desc()}</v>
+ <v>missing_segments() = [segment_no()]</v>
+ <v>user_cancel_reason() = {user_cancel, reason_for_user_cancel()}</v>
+ <v>reason_for_user_cancel() = term()</v>
+ <v>send_reason() = send_cancelled_reason() | send_failed_reason()</v>
+ <v>send_cancelled_reason() = {send_message_cancelled, reason_for_send_cancel()}</v>
+ <v>reason_for_send_cancel() = term()</v>
+ <v>send_failed_reason() = {send_message_failed, reason_for_send_failure()}</v>
+ <v>reason_for_send_failure() = term()</v>
+ <v>other_reason() = {wrong_mid, WrongMid, RightMid, TR} | term()</v>
+ <v>WrongMid = mid()</v>
+ <v>RightMid = mid()</v>
+ <v>TR = transaction_reply()</v>
+ <v>action_reps() = [action_reply()]</v>
+ <v>call_proxy_gc_timeout() = integer() >= 0</v>
+ <v>extra() = term()</v>
+ </type>
+ <desc>
+ <p>Sends one or more transaction request(s) and waits for the
+ reply.</p>
+ <p>When sending one transaction in a message, <c><![CDATA[Actions]]></c> should be
+ <c><![CDATA[action_reqs()]]></c> (<c><![CDATA[UserReply]]></c> will then be
+ <c><![CDATA[user_reply()]]></c>). When sending several transactions in a message,
+ <c><![CDATA[Actions]]></c> should be <c><![CDATA[[action_reqs()]]]></c> (<c><![CDATA[UserReply]]></c>
+ will then be <c><![CDATA[[user_reply()]]]></c>). Each element of the list is
+ part of one transaction.</p>
+ <p>For some of <em>our</em> codecs (not binary), it is also possible
+ to pre-encode the actions, in which case <c><![CDATA[Actions]]></c> will be
+ either a <c><![CDATA[binary()]]></c> or <c><![CDATA[[binary()]]]></c>.</p>
+ <p>The function returns when the reply arrives, when the
+ request timer eventually times out or when the outstanding
+ requests are explicitly cancelled.</p>
+ <p>The default values of the send options are obtained by
+ <c><![CDATA[megaco:conn_info(ConnHandle, Item)]]></c>. But the send options
+ above, may explicitly be overridden.</p>
+ <p>The <c><![CDATA[ProtocolVersion]]></c> version is the version actually encoded
+ in the reply message.</p>
+ <p>At <c><![CDATA[success()]]></c>, the <c><![CDATA[UserReply]]></c> contains a list of
+ 'ActionReply' records possibly containing error indications.</p>
+ <p>A <c><![CDATA[message_error()]]></c>, indicates that the remote user has
+ replied with an explicit transactionError.</p>
+ <p>A <c><![CDATA[user_cancel_error()]]></c>, indicates that the request has been
+ canceled by the user. <c><![CDATA[reason_for_user_cancel()]]></c> is the reason
+ given in the call to the <seealso marker="#cancel">cancel</seealso>
+ function. </p>
+ <p>A <c><![CDATA[send_error()]]></c>, indicates that the send function of the
+ megaco transport callback module failed to send the request.
+ There are two separate cases: <c><![CDATA[send_cancelled_reason()]]></c> and
+ <c><![CDATA[send_failed_reason()]]></c>.
+ The first is the result of the send function returning
+ <c><![CDATA[{cancel, Reason}]]></c> and the second is some other kind of
+ erroneous return value. See the
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function for more info. </p>
+ <p>An <c><![CDATA[other_error()]]></c>, indicates some other error such as
+ timeout.</p>
+
+ <p>For more info about the <c>extra()</c> part of the
+ result, see the
+ <seealso marker="megaco_user#extra_argument">note</seealso>
+ in the user callback module documentation. </p>
+
+
+
+ <marker id="cast"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>cast(ConnHandle, Actions, Options) -> ok | {error, Reason}</name>
+ <fsummary>Sends one or more transaction request(s) but does NOT wait for a reply</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>Actions = action_reqs() | [action_reqs()]</v>
+ <v>action_reqs() = binary() | [action_request()]</v>
+ <v>Options = [send_option()]</v>
+ <v>send_option() = {request_keep_alive_timeout, request_keep_alive_timeout()} | {request_timer, megaco_timer()} | {long_request_timer, megaco_timer()} | {send_handle, term()} | {reply_data, reply_data()} | {protocol_version, integer()}</v>
+ <v>request_keep_alive_timeout() = plain | integer() >= 0</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Sends one or more transaction request(s) but does NOT wait for a reply</p>
+ <p>When sending one transaction in a message, <c><![CDATA[Actions]]></c> should be
+ <c><![CDATA[action_reqs()]]></c>. When sending several transactions in a message,
+ <c><![CDATA[Actions]]></c> should be <c><![CDATA[[action_reqs()]]]></c>. Each element of the
+ list is part of one transaction.</p>
+ <p>For some of <em>our</em> codecs (not binary), it is also possible
+ to pre-encode the actions, in which case <c><![CDATA[Actions]]></c> will be
+ either a <c><![CDATA[binary()]]></c> or <c><![CDATA[[binary()]]]></c>.</p>
+ <p>The default values of the send options are obtained by
+ megaco:conn_info(ConnHandle, Item). But the send options above,
+ may explicitly be overridden.</p>
+ <p>The ProtocolVersion version is the version actually encoded
+ in the reply message.</p>
+ <p>The callback function UserMod:handle_trans_reply/4 is invoked
+ when the reply arrives, when the request timer eventually
+ times out or when the outstanding requests are explicitly
+ cancelled. See the megaco_user module for more info about
+ the callback arguments.</p>
+ <p>Given as UserData argument to UserMod:handle_trans_reply/4.</p>
+
+ <marker id="encode_actions"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>encode_actions(ConnHandle, Actions, Options) -> {ok, BinOrBins} | {error, Reason}</name>
+ <fsummary>Encode action requests for one or more transaction request(s)</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>Actions = action_reqs() | [action_reqs()]</v>
+ <v>action_reqs() = [#'ActionRequest'{}]</v>
+ <v>Options = [send_option()]</v>
+ <v>send_option() = {request_timer, megaco_timer()} | {long_request_timer, megaco_timer()} | {send_handle, term()} | {protocol_version, integer()}</v>
+ <v>BinOrBins = binary() | [binary()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Encodes lists of action requests for one or more transaction
+ request(s).</p>
+ <p>When encoding action requests for one transaction,
+ <c><![CDATA[Actions]]></c> should be <c><![CDATA[action_reqs()]]></c>.
+ When encoding action requests for several transactions,
+ <c><![CDATA[Actions]]></c> should be <c><![CDATA[[action_reqs()]]]></c>. Each element
+ of the list is part of one transaction.</p>
+
+ <marker id="token_tag2string"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>token_tag2string(Tag) -> Result</name>
+ <name>token_tag2string(Tag, EncoderMod) -> Result</name>
+ <name>token_tag2string(Tag, EncoderMod, Version) -> Result</name>
+ <fsummary>Convert a token tag to a string</fsummary>
+ <type>
+ <v>Tag = atom()</v>
+ <v>EncoderMod = pretty | compact | encoder_module()</v>
+ <v>encoder_module() = megaco_pretty_text_encoder | megaco_compact_text_encoder | atom()</v>
+ <v>Version = int_version() | atom_version()</v>
+ <v>int_version() = 1 | 2 | 3</v>
+ <v>atom_version() = v1 | v2 | v3 | prev3c | prev3b</v>
+ <v>Result = string() | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Convert a token tag to a string</p>
+ <p>If no encoder module is given, the default is used
+ (which is pretty).</p>
+ <p>If no or an unknown version is given,
+ the <em>best</em> version is used (which is v3).</p>
+ <p>If no match is found for <c><![CDATA[Tag]]></c>, <c><![CDATA[Result]]></c> will be the
+ empty string (<c><![CDATA[[]]]></c>).</p>
+
+ <marker id="cancel"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>cancel(ConnHandle, CancelReason) -> ok | {error, ErrReason}</name>
+ <fsummary>Cancel all outstanding messages for this connection</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>CancelReason = term()</v>
+ <v>ErrReason = term()</v>
+ </type>
+ <desc>
+ <p>Cancel all outstanding messages for this connection</p>
+ <p>This causes outstanding megaco:call/3 requests to return.
+ The callback functions UserMod:handle_reply/4 and
+ UserMod:handle_trans_ack/4 are also invoked where it
+ applies. See the megaco_user module for more info about the
+ callback arguments.</p>
+
+ <marker id="process_received_message"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
+ <name>process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
+ <fsummary>Process a received message</fsummary>
+ <type>
+ <v>ReceiveHandle = #megaco_receive_handle{}</v>
+ <v>ControlPid = pid()</v>
+ <v>SendHandle = term()</v>
+ <v>BinMsg = binary()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Process a received message</p>
+
+ <p>This function is intended to be invoked by some
+ transport modules when get an incoming message. Which
+ transport that actually is used is up to the user to
+ choose.</p>
+
+ <p>The message is delivered as an Erlang binary and is decoded
+ by the encoding module stated in the receive handle together
+ with its encoding config (also in the receive
+ handle). Depending of the outcome of the decoding various
+ callback functions will be invoked. See megaco_user for more
+ info about the callback arguments.</p>
+
+ <p>The argument <c>Extra</c> is just an opaque data structure passed to the user
+ via the callback functions in the
+ <seealso marker="megaco_user">user callback module</seealso>.
+ Note however that if <c>Extra</c> has the value
+ <c>extra_undefined</c> the argument will be ignored (same as if
+ <c>process_received_message/4</c> had been called).
+ See the documentation for the behaviour of the callback module,
+ <seealso marker="megaco_user">megaco_user</seealso>, for more info. </p>
+ <p>Note that all processing is done in the context of the calling
+ process. A transport module could call this function via one of the
+ <c><![CDATA[spawn]]></c> functions (e.g. <c><![CDATA[spawn_opt]]></c>). See also
+ <c><![CDATA[receive_message/4,5]]></c>.
+ </p>
+ <p>If the message cannot be decoded the following callback
+ function will be invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_syntax_error/3</p>
+ </item>
+ </list>
+ <p>If the decoded message instead of transactions contains a
+ message error, the following callback function will be
+ invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_message_error/3</p>
+ </item>
+ </list>
+ <p>If the decoded message happens to be received before the
+ connection is established, a new "virtual" connection is
+ established. This is typically the case for the Media
+ Gateway Controller (MGC) upon the first Service Change.
+ When this occurs the following callback function will be
+ invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_connect/2</p>
+ </item>
+ </list>
+ <p>For each transaction request in the decoded message the
+ following callback function will be invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_trans_request/3</p>
+ </item>
+ </list>
+ <p>For each transaction reply in the decoded message the reply
+ is returned to the user. Either the originating function
+ megaco:call/3 will return. Or in case the originating
+ function was megaco:case/3 the following callback function
+ will be invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_trans_reply/4</p>
+ </item>
+ </list>
+ <p>When a transaction acknowledgement is received it is
+ possible that user has decided not to bother about the
+ acknowledgement. But in case the return value from
+ UserMod:handle_trans_request/3 indicates that the
+ acknowledgement is important the following callback function
+ will be invoked:</p>
+ <list type="bulleted">
+ <item>
+ <p>UserMod:handle_trans_ack/4</p>
+ </item>
+ </list>
+ <p>See the megaco_user module for more info about the callback
+ arguments.</p>
+
+ <marker id="receive_message"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) -> ok</name>
+ <name>receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) -> ok</name>
+ <fsummary>Process a received message</fsummary>
+ <type>
+ <v>ReceiveHandle = #megaco_receive_handle{}</v>
+ <v>ControlPid = pid()</v>
+ <v>SendHandle = term()</v>
+ <v>BinMsg = binary()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Process a received message</p>
+ <p>This is a callback function intended to be invoked by some
+ transport modules when get an incoming message. Which
+ transport that actually is used is up to the user to
+ choose.</p>
+ <p>In principle, this function calls the
+ <c><![CDATA[process_received_message/4]]></c> function via a <c><![CDATA[spawn]]></c> to
+ perform the actual processing.</p>
+ <p>For further information see the
+ <seealso marker="#process_received_message">process_received_message/4</seealso>
+ function.</p>
+
+ <marker id="parse_digit_map"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>parse_digit_map(DigitMapBody) -> {ok, ParsedDigitMap} | {error, Reason}</name>
+ <fsummary>Parses a digit map body</fsummary>
+ <type>
+ <v>DigitMapBody = string()</v>
+ <v>ParsedDigitMap = parsed_digit_map()</v>
+ <v>parsed_digit_map() = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Parses a digit map body</p>
+ <p>Parses a digit map body, represented as a list of
+ characters, into a list of state transitions suited to
+ be evaluated by megaco:eval_digit_map/1,2.</p>
+
+ <marker id="eval_digit_map"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>eval_digit_map(DigitMap) -> {ok, MatchResult} | {error, Reason}</name>
+ <name>eval_digit_map(DigitMap, Timers) -> {ok, MatchResult} | {error, Reason}</name>
+ <fsummary>Collect digit map letters according to the digit map</fsummary>
+ <type>
+ <v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v>
+ <v>parsed_digit_map() = term()</v>
+ <v>ParsedDigitMap = term()</v>
+ <v>Timers = ignore() | reject()</v>
+ <v>ignore() = ignore | {ignore, digit_map_value()}</v>
+ <v>reject() = reject | {reject, digit_map_value()} | digit_map_value()</v>
+ <v>MatchResult = {Kind, Letters} | {Kind, Letters, Extra}</v>
+ <v>Kind = kind()</v>
+ <v>kind() = full | unambiguous</v>
+ <v>Letters = [letter()]</v>
+ <v>letter() = $0..$9 | $a .. $k</v>
+ <v>Extra = letter()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Collect digit map letters according to the digit map.</p>
+ <p>When evaluating a digit map, a state machine waits for
+ timeouts and letters reported by
+ megaco:report_digit_event/2. The length of the various
+ timeouts are defined in the digit_map_value() record.</p>
+ <p>When a complete sequence of valid events has been received,
+ the result is returned as a list of letters.</p>
+ <p>There are two options for handling syntax errors (that is
+ when an unexpected event is received when the digit map
+ evaluator is expecting some other event). The unexpected
+ events may either be ignored or rejected. The latter means
+ that the evaluation is aborted and an error is returned. </p>
+
+ <marker id="report_digit_event"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>report_digit_event(DigitMapEvalPid, Events) -> ok | {error, Reason}</name>
+ <fsummary>Send one or more events to the event collector process</fsummary>
+ <type>
+ <v>DigitMapEvalPid = pid()</v>
+ <v>Events = Event | [Event]</v>
+ <v>Event = letter() | pause() | cancel()</v>
+ <v>letter() = $0..$9 | $a .. $k | $A .. $K</v>
+ <v>pause() = one_second() | ten_seconds()</v>
+ <v>one_second() = $s | $S</v>
+ <v>ten_seconds() = $l | $L</v>
+ <v>cancel() = $z | $Z | cancel</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Send one or more events to the event collector process.</p>
+ <p>Send one or more events to a process that is evaluating a
+ digit map, that is a process that is executing
+ megaco:eval_digit_map/1,2.</p>
+ <p>Note that the events <c><![CDATA[$s | $S]]></c>, <c><![CDATA[l | $L]]></c> and
+ <c><![CDATA[$z | $Z]]></c> has nothing to do with the timers using
+ the same characters.</p>
+
+ <marker id="test_digit_event"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>test_digit_event(DigitMap, Events) -> {ok, Kind, Letters} | {error, Reason}</name>
+ <fsummary>Feed digit map collector with events and return the result</fsummary>
+ <type>
+ <v>DigitMap = #'DigitMapValue'{} | parsed_digit_map()</v>
+ <v>parsed_digit_map() = term()</v>
+ <v>ParsedDigitMap = term()</v>
+ <v>Timers = ignore() | reject()</v>
+ <v>ignore() = ignore | {ignore, digit_map_value()}</v>
+ <v>reject() = reject | {reject, digit_map_value()} | digit_map_value()</v>
+ <v>DigitMapEvalPid = pid()</v>
+ <v>Events = Event | [Event]</v>
+ <v>Event = letter() | pause() | cancel()</v>
+ <v>Kind = kind()</v>
+ <v>kind() = full | unambiguous</v>
+ <v>Letters = [letter()]</v>
+ <v>letter() = $0..$9 | $a .. $k | $A .. $K</v>
+ <v>pause() = one_second() | ten_seconds()</v>
+ <v>one_second() = $s | $S</v>
+ <v>ten_seconds() = $l | $L</v>
+ <v>cancel () = $z | $Z | cancel</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Feed digit map collector with events and return the result</p>
+ <p>This function starts the evaluation of a digit map with
+ megaco:eval_digit_map/1 and sends a sequence of events to it
+ megaco:report_digit_event/2 in order to simplify testing of
+ digit maps.</p>
+
+ <marker id="encode_sdp"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>encode_sdp(SDP) -> {ok, PP} | {error, Reason}</name>
+ <fsummary>Encode an SDP construct</fsummary>
+ <type>
+ <v>SDP = sdp_property_parm() | sdp_property_group() | sdp_property_groups() | asn1_NOVALUE</v>
+ <v>PP = property_parm() | property_group() | property_groups() | asn1_NOVALUE</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Encode (generate) an SDP construct.</p>
+ <p>If a <c><![CDATA[property_parm()]]></c> is found as part of the input
+ (<c><![CDATA[SDP]]></c>) then it is left unchanged.</p>
+ <p>This function performs the following transformation:</p>
+ <list type="bulleted">
+ <item>
+ <p>sdp() -&gt; property_parm()</p>
+ </item>
+ <item>
+ <p>sdp_property_group() -&gt; property_group()</p>
+ </item>
+ <item>
+ <p>sdp_property_groups() -&gt; property_groups()</p>
+ </item>
+ </list>
+
+ <marker id="decode_sdp"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>decode_sdp(PP) -> {ok, SDP} | {error, Reason}</name>
+ <fsummary>Decode an property parameter construct</fsummary>
+ <type>
+ <v>PP = property_parm() | property_group() | property_groups() | asn1_NOVALUE</v>
+ <v>SDP = sdp() | decode_sdp_property_group() | decode_sdp_property_groups() | asn1_NOVALUE</v>
+ <v>decode_sdp() = sdp() | {property_parm(), DecodeError}</v>
+ <v>decode_sdp_property_group() = [decode_sdp()]</v>
+ <v>decode_sdp_property_groups() = [decode_sdp_property_group()]</v>
+ <v>DecodeError = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Decode (parse) a property parameter construct.</p>
+ <p>When decoding <c><![CDATA[property_group()]]></c> or
+ <c><![CDATA[property_groups()]]></c>,
+ those property parameter constructs that cannot be decoded
+ (either because of decode error or because they are unknown),
+ will be returned as a two-tuple. The first element of which
+ will be the (undecoded) property parameter and the other the
+ actual reason.
+ This means that the caller of this function has to expect not
+ only sdp-records, but also this two-tuple construct.</p>
+ <p>This function performs the following transformation:</p>
+ <list type="bulleted">
+ <item>
+ <p>property_parm() -&gt; sdp()</p>
+ </item>
+ <item>
+ <p>property_group() -&gt; sdp_property_group()</p>
+ </item>
+ <item>
+ <p>property_groups() -&gt; sdp_property_groups()</p>
+ </item>
+ </list>
+
+ <marker id="get_sdp_record_from_PG"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_sdp_record_from_PropertGroup(Type, PG) -> [sdp()]</name>
+ <fsummary>Get all sdp records of a certain type from a property group</fsummary>
+ <type>
+ <v>Type = v | c | m | o | a | b | t | r | z | k | s | i | u | e | p</v>
+ <v>PG = sdp_property_group()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retreive all the sdp records of type <c>Type</c> from the
+ property group <c>PG</c>.</p>
+
+ <marker id="versions1"></marker>
+ <marker id="versions2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>versions1() -> {ok, VersionInfo} | {error, Reason}</name>
+ <name>versions2() -> {ok, Info} | {error, Reason}</name>
+ <fsummary>Retreive various system and application info</fsummary>
+ <type>
+ <v>VersionInfo = [version_info()]</v>
+ <v>version_info() = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Utility functions used to retrieve some system and
+ application info.</p>
+ <p>The difference between the two functions is in how they get
+ the modules to check. <c><![CDATA[versions1]]></c> uses the
+ app-file and <c><![CDATA[versions2]]></c> uses the function
+ <c><![CDATA[application:get_key]]></c>.</p>
+
+ <marker id="print_version_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>print_version_info() -> void()</name>
+ <name>print_version_info(VersionInfo) -> void()</name>
+ <fsummary>Formated print of result of the versions functions</fsummary>
+ <type>
+ <v>VersionInfo = [version_info()]</v>
+ <v>version_info() = term()</v>
+ </type>
+ <desc>
+ <p>Utility function to produce a formated printout of the versions
+ info generated by the <c><![CDATA[versions1]]></c> and <c><![CDATA[versions2]]></c>
+ functions.</p>
+ <p>The function print_version_info/0 uses the result of function
+ version1/0 as <c><![CDATA[VersionInfo]]></c>.</p>
+ <p>Example: </p>
+ <pre>
+ {ok, V} = megaco:versions1(), megaco:format_versions(V).
+ </pre>
+ <marker id="enable_trace"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>enable_trace(Level, Destination) -> void()</name>
+ <fsummary>Start megaco tracing</fsummary>
+ <type>
+ <v>Level = max | min | 0 &lt;= integer() &lt;= 100</v>
+ <v>Destination = File | Port | HandlerSpec | io</v>
+ <v>File = string()</v>
+ <v>Port = integer()</v>
+ <v>HandleSpec = {HandlerFun, Data}</v>
+ <v>HandleFun = fun() (two arguments)</v>
+ <v>Data = term()</v>
+ </type>
+ <desc>
+ <p>This function is used to start megaco tracing at a given
+ <c><![CDATA[Level]]></c> and direct result to the given <c><![CDATA[Destination]]></c>.</p>
+ <p>It starts a tracer server and then sets the proper match spec
+ (according to <c><![CDATA[Level]]></c>).</p>
+ <p>In the case when <c><![CDATA[Destination]]></c> is <c><![CDATA[File]]></c>, the printable
+ megaco trace events will be printed to the file <c><![CDATA[File]]></c> using
+ plain <c><![CDATA[io:format/2]]></c>. </p>
+ <p>In the case when <c><![CDATA[Destination]]></c> is <c><![CDATA[io]]></c>, the printable
+ megaco trace events will be printed on stdout using plain
+ <c><![CDATA[io:format/2]]></c>. </p>
+ <p>See <c><![CDATA[dbg]]></c> for further information.</p>
+ <marker id="disable_trace"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>disable_trace() -> void()</name>
+ <fsummary>Stop megaco tracing</fsummary>
+ <desc>
+ <p>This function is used to stop megaco tracing.</p>
+ <marker id="set_trace"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>set_trace(Level) -> void()</name>
+ <fsummary>Change megaco trace level</fsummary>
+ <type>
+ <v>Level = max | min | 0 &lt;= integer() &lt;= 100</v>
+ </type>
+ <desc>
+ <p>This function is used to change the megaco trace level.</p>
+ <p>It is assumed that tracing has already been enabled (see
+ <c><![CDATA[enable_trace]]></c> above).</p>
+
+ <marker id="stats"></marker>
+ <marker id="get_stats"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name>get_stats(GlobalCounter) -> {ok, CounterStats} | {error, Reason}</name>
+ <name>get_stats(ConnHandle) -> {ok, ConnHandleStats} | {error, Reason}</name>
+ <name>get_stats(ConnHandle, Counter) -> {ok, integer()} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TotalStats = [total_stats()]</v>
+ <v>total_stats() = {conn_handle(), [stats()]} | {global_counter(), integer()}</v>
+ <v>GlobalCounter = global_counter()</v>
+ <v>GlobalCounterStats = integer()</v>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ConnHandleStats = [stats()]</v>
+ <v>stats() = {counter(), integer()}</v>
+ <v>Counter = counter()</v>
+ <v>counter() = medGwyGatewayNumTimerRecovery | medGwyGatewayNumErrors</v>
+ <v>global_counter() = medGwyGatewayNumErrors</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retreive the (SNMP) statistic counters maintained by the
+ megaco application. The global
+ counters handle events that cannot be attributed to
+ a single connection (e.g. protocol errors that occur
+ before the connection has been properly setup).</p>
+ <marker id="reset_stats"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>reset_stats() -> void()</name>
+ <name>reset_stats(ConnHandle) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ </type>
+ <desc>
+ <p>Reset all related (SNMP) statistics counters.</p>
+ <marker id="test_request"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>test_request(ConnHandle, Version, EncodingMod, EncodingConfig, Actions) -> {MegaMsg, EncodeRes}</name>
+ <fsummary>Tests if the Actions argument is correct</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>Version = integer()</v>
+ <v>EncodingMod = atom()</v>
+ <v>EncodingConfig = Encoding configuration</v>
+ <v>Actions = A list</v>
+ <v>MegaMsg = #'MegacoMessage'{}</v>
+ <v>EncodeRes = {ok, Bin} | {error, Reason}</v>
+ <v>Bin = binary()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Tests if the Actions argument is correctly composed.</p>
+ <p>This function is only intended for testing purposes. It's
+ supposed to have a same kind of interface as the <seealso marker="#call">call</seealso> or <seealso marker="#cast">cast</seealso> functions (with the additions
+ of the <c><![CDATA[EncodingMod]]></c> and <c><![CDATA[EncodingConfig]]></c>
+ arguments). It composes a complete megaco message end
+ attempts to encode it. The return value, will be a tuple of
+ the composed megaco message and the encode result. </p>
+
+ <marker id="test_reply"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) -> {MegaMsg, EncodeRes}</name>
+ <fsummary>Tests if the Reply argument is correct</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>Version = integer()</v>
+ <v>EncodingMod = atom()</v>
+ <v>EncodingConfig = A list</v>
+ <v>Reply = actual_reply()</v>
+ <v>MegaMsg = #'MegacoMessage'{}</v>
+ <v>EncodeRes = {ok, Bin} | {error, Reason}</v>
+ <v>Bin = binary()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Tests if the Reply argument is correctly composed.</p>
+ <p>This function is only intended for testing purposes. It's
+ supposed to test the <c><![CDATA[actual_reply()]]></c> return value of
+ the callback functions
+ <seealso marker="megaco_user#trans_request">handle_trans_request</seealso>
+ and
+ <seealso marker="megaco_user#trans_long_request">handle_trans_long_request</seealso>
+ functions (with the additions of the <c><![CDATA[EncodingMod]]></c> and
+ <c><![CDATA[EncodingConfig]]></c> arguments). It composes a complete
+ megaco message end attempts to encode it. The return value,
+ will be a tuple of the composed megaco message and the
+ encode result.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_architecture.xml b/lib/megaco/doc/src/megaco_architecture.xml
new file mode 100644
index 0000000000..aeea17c5cf
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_architecture.xml
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Architecture</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_architecture.xml</file>
+ </header>
+
+ <section>
+ <title>Network view</title>
+ <p>Megaco is a (master/slave) protocol for control of gateway functions at
+ the edge of the packet network. Examples of this is IP-PSTN trunking
+ gateways and analog line gateways. The main function of Megaco is to
+ allow gateway decomposition into a call agent (call control) part (known
+ as Media Gateway Controller, MGC) - master, and an gateway interface
+ part (known as Media Gateway, MG) - slave. The MG has no call control
+ knowledge and only handle making the connections and simple
+ configurations.</p>
+ <p>SIP and H.323 are peer-to-peer protocols for call control (valid only
+ for some of the protocols within H.323), or more generally multi-media
+ session protocols. They both operate at a different level (call control)
+ from Megaco in a decomposed network, and are therefor not aware of
+ whether or not Megaco is being used underneath.</p>
+ <image file="megaco_sys_arch.gif">
+ <icaption>Network architecture</icaption>
+ </image>
+ <p>Megaco and peer protocols are complementary in nature and entirely
+ compatible within the same system. At a system level, Megaco allows
+ for</p>
+ <list type="bulleted">
+ <item>
+ <p>overall network cost and performance optimization</p>
+ </item>
+ <item>
+ <p>protection of investment by isolation of changes at the call
+ control layer</p>
+ </item>
+ <item>
+ <p>freedom to geographically distribute both call function and
+ gateway function</p>
+ </item>
+ <item>
+ <p>adaption of legacy equipment</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>General</title>
+ <p>This Erlang/OTP application supplies a framework for building
+ applications that needs to utilize the Megaco/H.248 protocol.</p>
+ <p>We have introduced the term "user" as a generic term for either
+ an MG or an MGC, since most of the functionality we support, is
+ common for both MG's and MGC's. A (local) user may be configured
+ in various ways and it may establish any number of connections
+ to its counterpart, the remote user. Once a connection has been
+ established, the connection is supervised and it may be used for
+ the purpose of sending messages. N.B. according to the standard
+ an MG is connected to at most one MGC, while an MGC may be
+ connected to any number of MG's.</p>
+ <p>For the purpose of managing "virtual MG's", one Erlang node may
+ host any number of MG's. In fact it may host a mix of MG's and
+ MGC's. You may say that an Erlang node may host any number of
+ "users".</p>
+ <p>The protocol engine uses callback modules to handle various
+ things:</p>
+ <list type="bulleted">
+ <item>
+ <p>encoding callback modules - handles the encoding and
+ decoding of messages. Several modules for handling different
+ encodings are included, such as ASN.1 BER, pretty well
+ indented text, compact text and some others. Others may be
+ written by you.</p>
+ </item>
+ <item>
+ <p>transport callback modules - handles sending and receiving
+ of messages. Transport modules for TCP/IP and UDP/IP are
+ included and others may be written by you.</p>
+ </item>
+ <item>
+ <p>user callback modules - the actual implementation of an MG
+ or MGC. Most of the functions are intended for handling of a
+ decoded transaction (request, reply, acknowledgement), but
+ there are others that handles connect, disconnect and
+ errors cases.</p>
+ </item>
+ </list>
+ <p>Each connection may have its own configuration of callback
+ modules, re-send timers, transaction id ranges etc. and they may
+ be re-configured on-the-fly.</p>
+ <p>In the API of Megaco, a user may explicitly send action
+ requests, but generation of transaction identifiers, the
+ encoding and actual transport of the message to the remote user
+ is handled automatically by the protocol engine according to the
+ actual connection configuration. Megaco messages are not exposed
+ in the API.</p>
+ <p>On the receiving side the transport module receives the message
+ and forwards it to the protocol engine, which decodes it and
+ invokes user callback functions for each transaction. When a
+ user has handled its action requests, it simply returns a list
+ of action replies (or a message error) and the protocol engine
+ uses the encoding module and transport module to compose and
+ forward the message to the originating user.</p>
+ <p>The protocol stack does also handle things like automatic
+ sending of acknowledgements, pending transactions, re-send of
+ messages, supervision of connections etc.</p>
+ <p>In order to provide a solution for scalable implementations of
+ MG's and MGC's, a user may be distributed over several Erlang
+ nodes. One of the Erlang nodes is connected to the physical
+ network interface, but messages may be sent from other nodes and
+ the replies are automatically forwarded back to the originating
+ node.</p>
+ </section>
+
+ <section>
+ <title>Single node config</title>
+ <p>Here a system configuration with an MG and MGC residing
+ in one Erlang node each is outlined:</p>
+ <image file="single_node_config.gif">
+ <icaption>Single node config</icaption>
+ </image>
+ </section>
+
+ <section>
+ <title>Distributed config</title>
+ <p>In a larger system with a user (in this case an MGC)
+ distributed over several Erlang nodes, it looks a little bit
+ different. Here the encoding is performed on the originating
+ Erlang node (1) and the binary is forwarded to the node (2) with
+ the physical network interface. When the potential message reply
+ is received on the interface on node (2), it is decoded there
+ and then different actions will be taken for each transaction in
+ the message. The transaction reply will be forwarded in its
+ decoded form to the originating node (1) while the other types
+ of transactions will be handled locally on node (2).</p>
+ <p>Timers and re-send of messages will be handled on locally on
+ one node, that is node(1), in order to avoid unnecessary
+ transfer of data between the Erlang nodes.
+ </p>
+ <p></p>
+ <image file="distr_node_config.gif">
+ <icaption>Distributes node config</icaption>
+ </image>
+ </section>
+
+ <section>
+ <title>Message round-trip call flow</title>
+ <p>The typical round-trip of a message can be viewed as
+ follows. Firstly we view the call flow on the originating
+ side:</p>
+ <image file="call_flow.gif">
+ <icaption>Message Call Flow (originating side)</icaption>
+ </image>
+ <p>Then we continue with the call flow on the destination
+ side:</p>
+ <image file="call_flow_cont.gif">
+ <icaption>Message Call Flow (destination side)</icaption>
+ </image>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_codec_meas.xml b/lib/megaco/doc/src/megaco_codec_meas.xml
new file mode 100644
index 0000000000..68d0326239
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_codec_meas.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_codec_meas</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_codec_meas.xml</file>
+ </header>
+ <module>megaco_codec_meas</module>
+ <modulesummary>This module implements a simple megaco codec measurement tool.</modulesummary>
+ <description>
+ <p>This module implements a simple megaco codec measurement tool.</p>
+ <p>Results are written to file (excel compatible text files) and on stdout.</p>
+ <p><em>Note</em> that this module is <em>not</em> included in the runtime part of
+ the application.</p>
+ </description>
+
+ <funcs>
+ <func>
+ <name>start() -> void()</name>
+ <name>start(MessagePackage) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackageRaw = message_package()</v>
+ <v>message_package() = atom()</v>
+ </type>
+ <desc>
+ <p>This function runs the measurement on all the <em>official</em> codecs;
+ pretty, compact, ber, per and erlang.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_codec_mstone1.xml b/lib/megaco/doc/src/megaco_codec_mstone1.xml
new file mode 100644
index 0000000000..5b0b410641
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_codec_mstone1.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_codec_mstone1</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2009-05-27</date>
+ <rev>%VSN%</rev>
+ <file>megaco_codec_mstone1.xml</file>
+ </header>
+ <module>megaco_codec_mstone1</module>
+ <modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary>
+ <description>
+ <p>This module implements the <em>mstone1</em> tool,
+ a simple megaco codec-based performance tool.</p>
+ <p>The results, the mstone value(s), are written to stdout.</p>
+ <p><em>Note</em> that this module is <em>not</em> included in the runtime part of
+ the application.</p>
+ </description>
+
+ <funcs>
+ <func>
+ <name>start() -> void()</name>
+ <name>start(MessagePackage) -> void()</name>
+ <name>start(MessagePackage, Factor) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = message_package()</v>
+ <v>message_package() = atom()</v>
+ <v>Factor() = integer() > 0</v>
+ </type>
+ <desc>
+ <p>This function starts the <em>mstone1</em> performance test with all codec configs.
+ <c>Factor</c> (defaults to <c>1</c>) processes are started for every supported
+ codec config. </p>
+ <p>Each process encodes and decodes their messages.
+ The number of messages processed in total (for all processes) is the mstone value.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_flex() -> void()</name>
+ <name>start_flex(MessagePackage) -> void()</name>
+ <name>start_flex(MessagePackage, Factor) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = message_package()</v>
+ <v>message_package() = atom()</v>
+ <v>Factor() = integer() > 0</v>
+ </type>
+ <desc>
+ <p>This function starts the <em>mstone1</em> performance test with only the
+ flex codec configs (i.e. <c>pretty</c> and <c>compact</c> with <c>flex</c>).
+ The same number of processes are started as when running the standard
+ test (using the <c>start/0,1</c> function).
+ Each process encodes and decodes their messages.
+ The number of messages processed in total (for all processes) is the mstone value.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_only_drv() -> void()</name>
+ <name>start_only_drv(MessagePackage) -> void()</name>
+ <name>start_only_drv(MessagePackage, Factor) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = message_package()</v>
+ <v>message_package() = atom()</v>
+ <v>Factor() = integer() > 0</v>
+ </type>
+ <desc>
+ <p>This function starts the <em>mstone1</em> performance test with only the
+ driver using codec configs (i.e. <c>pretty</c> and <c>compact</c>
+ with <c>flex</c>, and <c>ber</c> and <c>per</c> with <c>driver</c>
+ and <c>erlang</c> with <c>compressed</c>).
+ The same number of processes are started as when running the standard
+ test (using the <c>start/0,1</c> function).
+ Each process encodes and decodes their messages.
+ The number of messages processed in total (for all processes) is the mstone value.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_no_drv() -> void()</name>
+ <name>start_no_drv(MessagePackage) -> void()</name>
+ <name>start_no_drv(MessagePackage, Factor) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = message_package()</v>
+ <v>message_package() = atom()</v>
+ <v>Factor() = integer() > 0</v>
+ </type>
+ <desc>
+ <p>This function starts the <em>mstone1</em> performance test with codec configs
+ not using any drivers (i.e. <c>pretty</c> and <c>compact</c> without
+ <c>flex</c>, <c>ber</c> and <c>per</c> without <c>driver</c> and
+ <c>erlang</c> without <c>compressed</c>).
+ The same number of processes are started as when running the standard
+ test (using the <c>start/0,1</c> function).
+ Each process encodes and decodes their messages.
+ The number of messages processed in total (for all processes) is the mstone value.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_codec_mstone2.xml b/lib/megaco/doc/src/megaco_codec_mstone2.xml
new file mode 100644
index 0000000000..778e125a75
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_codec_mstone2.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_codec_mstone2</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2009-05-27</date>
+ <rev>%VSN%</rev>
+ <file>megaco_codec_mstone2.xml</file>
+ </header>
+ <module>megaco_codec_mstone2</module>
+ <modulesummary>This module implements a simple megaco codec-based performance tool.</modulesummary>
+ <description>
+ <p>This module implements the <em>mstone2</em> tool,
+ a simple megaco codec-based performance tool.</p>
+ <p>The results, the mstone value(s), are written to stdout.</p>
+ <p><em>Note</em> that this module is <em>not</em> included in the runtime part of
+ the application.</p>
+ </description>
+
+ <funcs>
+ <func>
+ <name>start() -> void()</name>
+ <name>start(MessagePackage) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = message_package()</v>
+ <v>message_package() = atom()</v>
+ </type>
+ <desc>
+ <p>This function starts the <em>mstone2</em> performance test with all codec configs.
+ Processes are created dynamically. Each process make <em>one</em> run
+ through their messages (decoding and encoding messages) and then exits.
+ When one process exits, a new is created with the same codec config and set
+ of messages. </p>
+ <p>The number of messages processed in total (for all processes) is the mstone value.</p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_codec_transform.xml b/lib/megaco/doc/src/megaco_codec_transform.xml
new file mode 100644
index 0000000000..71f7fc689f
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_codec_transform.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_codec_transform</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_codec_transform.xml</file>
+ </header>
+ <module>megaco_codec_transform</module>
+ <modulesummary>Megaco message transformation utility.</modulesummary>
+
+ <description>
+ <p>This module implements a simple megaco message transformation utility.</p>
+ <p><em>Note</em> that this module is <em>not</em> included in the runtime part of
+ the application.</p>
+
+ <marker id="export_messages"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>export_messages() -> void()</name>
+ <name>export_messages(MessagePackage) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>MessagePackage = atom()</v>
+ </type>
+ <desc>
+ <p>Export the messages in the <c>MessagePackage</c> (default is <c>time_test</c>). </p>
+ <p>The out produced by this function is a directory structure with the
+ following structure: </p>
+ <code type="none"><![CDATA[
+\011 <message package>/pretty/<message-files>
+\011 compact/<message-files>
+\011 per/<message-files>
+\011 ber/<message-files>
+\011 erlang/<message-files>
+ ]]></code>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_debug.xml b/lib/megaco/doc/src/megaco_debug.xml
new file mode 100644
index 0000000000..1b99985341
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_debug.xml
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Testing and tools</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_debug.xml</file>
+ </header>
+
+ <section>
+ <title>Tracing</title>
+ <p>We have instrumented our code in order to enable
+ tracing. Running the application with tracing deactivated,
+ causes a negligible performance overhead (an external call to a
+ function which returns an atom). Activation of tracing does not
+ require any recompilation of the code, since we rely on
+ Erlang/OTP's built in support for dynamic trace activation. In
+ our case tracing of calls to a given external function.</p>
+ <p>Event traces can be viewed in a generic message sequence chart
+ tool, <c>et</c>, or as standard output (events are written to stdio). </p>
+ <p>See <seealso marker="megaco#enable_trace">enable_trace</seealso>,
+ <seealso marker="megaco#disable_trace">disable_trace</seealso> and
+ <seealso marker="megaco#set_trace">set_trace</seealso> for
+ more info. </p>
+ </section>
+
+ <section>
+ <title>Measurement and transformation</title>
+ <p>We have included some simple tool(s) for codec measurement (meas),
+ performance tests (mstone1 and mstone2) and message transformation.</p>
+ <p>The tool(s) are located in the example/meas directory.</p>
+
+ <section>
+ <title>Requirement</title>
+ <list type="bulleted">
+ <item>
+ <p>Erlang/OTP, version R13B01 or later.</p>
+ </item>
+ <item>
+ <p>Version 3.11 or later of <em>this</em> application.</p>
+ </item>
+ <item>
+ <p>Version 1.6.10 or later of the <em>asn1</em> application. </p>
+ </item>
+ <item>
+ <p>The flex libraries. Without it, the flex powered codecs cannot
+ be used.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Meas results</title>
+ <p>The results from the measurement run (meas) is four
+ excel-compatible textfiles: </p>
+ <list type="bulleted">
+ <item>
+ <p>decode_time.xls -&gt; Decoding result</p>
+ </item>
+ <item>
+ <p>encode_time.xls -&gt; Encoding result</p>
+ </item>
+ <item>
+ <p>total_time.xls -&gt; Total (Decoding+encoding) result</p>
+ </item>
+ <item>
+ <p>message_size.xls -&gt; Message size</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Instruction</title>
+ <p>The tool contain four things:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>The transformation module</p>
+ </item>
+ <item>
+ <p>The measurement (meas) module(s)</p>
+ </item>
+ <item>
+ <p>The mstone (mstone1 and mstone2) module(s)</p>
+ </item>
+ <item>
+ <p>The basic message file</p>
+ </item>
+ </list>
+
+ <section>
+ <title>Message Transformation</title>
+ <p>The messages used by the different tools are contained in
+ single message package file (see below for more info). The messages
+ in this file is encoded with just one codec. During
+ measurement initiation, the messages are read and then transformed to all
+ codec formats used in the measurement. </p>
+ <p>The message transformation is done by the transformation module.
+ It is used to transform a set of messages encoded with one codec
+ into the other base codec's.</p>
+ </section>
+
+ <section>
+ <title>Measurement(s)</title>
+ <p>There are two different measurement tools: </p>
+ <list type="bulleted">
+ <item>
+ <p><em>meas</em>: </p>
+ <p>Used to perform codec measurements. That is, to see what
+ kind of performance can be expected by the different codecs
+ provided by the megaco application. </p>
+ <p>The measurement is done by iterating over the decode/encode
+ function for approx 2 seconds per message and counting
+ the number of decodes/encodes.</p>
+ <p>Is best run by modifying the meas.sh.skel skeleton script
+ provided by the tool.</p>
+ <p>To run it manually do the following: </p>
+ <code type="none"><![CDATA[
+ % erl -pa <path-megaco-ebin-dir> -pa <path-to-meas-module-dir>
+ Erlang (BEAM) emulator version 5.6 [source]
+
+ Eshell V5.7.1 (abort with ^G)
+ 1> megaco_codec_meas:start().
+ ...
+ 2> halt().
+ ]]></code>
+ <p>or to make it even easier, assuming a measure shall be
+ done on all the codecs (as above):</p>
+ <code type="none"><![CDATA[
+ % erl -noshell -pa <path-megaco-ebin-dir> \\
+ -pa <path-to-meas-module-dir> \\
+ -s megaco_codec_meas -s init stop
+ ]]></code>
+ <p>When run as above (this will take some time), the measurement
+ process is done as follows:</p>
+ <pre>
+\011 For each codec:
+\011 For each message:
+\011 Read the message from the file
+\011 Detect message version
+\011 Measure decode
+ Measure encode
+ Write results, encode, decode and total, to file
+ </pre>
+ </item>
+
+ <item>
+ <p><em>mstone1 and mstone2</em>: </p>
+ <p>These are two different SMP performance monitoring tool(s). </p>
+ <p><em>mstone1</em> creates a process for each codec config supported by
+ the megaco application and let them run for a specific
+ time (all at the same time), encoding and decoding
+ megaco messages. The number of messages processed in total
+ is the mstone1(1) value. </p>
+ <p>There are different ways to run the mstone1 tool, e.g. with or without
+ the use of drivers, with <em>only</em> flex-empowered configs. </p>
+ <p>Is best run by modifying the mstone1.sh.skel skeleton script
+ provided by the tool.</p>
+ <p>The <em>mstone2</em> is similar to the <em>mstone1</em> tool,
+ but in this case, each created process makes only <em>one</em> run
+ through the messages and then exits. A soon as a process exits,
+ a new process (with the same config and messages) is created to takes
+ its place.
+ The number of messages processed in total
+ is the mstone2(1) value. </p>
+ </item>
+ </list>
+
+ <p>Both these tools use the message package (time_test.msgs) provided
+ with the tool(s), although it can run on any message package as long as
+ it has the same structure. </p>
+ </section>
+
+ <section>
+ <title>Message package file</title>
+ <p>This is simply an erlang compatible text-file with the following
+ structure: <c>{codec_name(), messages_list()}</c>. </p>
+
+<pre>
+codec_name() = pretty | compact | ber | per | erlang (how the messages are encoded)
+messages_list() = [{message_name(), message()}]
+message_name() = atom()
+message() = binary()
+</pre>
+
+ <p>The codec name is the name of the codec with which all messages in
+ the <c>message_list()</c> has been encoded. </p>
+
+ <p>This file can be <c>exported</c> to a file structure by calling the
+ <seealso marker="megaco_codec_transform#export_messages">export_messages</seealso>
+ function. This can be usefull if a measurement shall be done with
+ an external tool. Exporting the messages creates a directory tree
+ with the following structure:
+ </p>
+ <code type="none"><![CDATA[
+\011 <message package>/pretty/<message-files>
+\011 compact/
+\011 per/
+\011 ber/<message-files>
+\011 erlang/
+ ]]></code>
+ <p>The file includes both version 1, 2 and version 3 messages.</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Notes</title>
+
+ <section>
+ <title>Binary codecs</title>
+ <p>There are two basic ways to use the binary encodings:
+ With package related name and termination id transformation
+ (the 'native' encoding config) or without. This transformation
+ converts package related names and termination id's to a more
+ convenient internal form (equivalent with the decoded text message).</p>
+ <p>The transformation is done _after_ the actual decode has been
+ done.</p>
+ <p>Furthermore, it is possible to make use of a linked in driver that
+ performs some of the decode/encode, decode for ber and encode for per
+ (the 'driver' encoding config).</p>
+ <p>Therefor in the tests, binary codecs are tested with four
+ different encoding configs to determine exactly how the
+ different options effect the performance: with transformation and
+ without driver ([]), without transformation and without driver
+ ([native]), with transformation and with driver ([driver]) and
+ finally without transformation and with driver ([driver,native]).</p>
+ </section>
+
+ <section>
+ <title>Included test messages</title>
+ <p>Some of these messages are ripped from the call flow examples
+ in an old version of the RFC and others are created to test
+ a specific feature of megaco. </p>
+ </section>
+
+ <section>
+ <title>Measurement tool directory name</title>
+ <p>Be sure <em>not</em> no name the directory containing the measurement
+ binaries starting with 'megaco-', e.g. megaco-meas. This will
+ confuse the erlang application loader (erlang applications
+ are named, e.g. megaco-1.0.2).</p>
+ </section>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_edist_compress.xml b/lib/megaco/doc/src/megaco_edist_compress.xml
new file mode 100644
index 0000000000..43e124ad3a
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_edist_compress.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2007</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_encoder</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_edist_compress.xml</file>
+ </header>
+ <module>megaco_edist_compress</module>
+ <modulesummary>Megaco erlang dist compress behaviour.</modulesummary>
+ <description>
+ <p>The following functions should be exported from a
+ <c><![CDATA[megaco_edist_compress]]></c> callback module:</p>
+ </description>
+ <funcs>
+ <func>
+ <name>Module:encode(R, Version) -> T</name>
+ <fsummary>Encode (compress) a megaco component.</fsummary>
+ <type>
+ <v>R = megaco_message() | transaction() | action_reply() | action_request() | command_request()</v>
+ <v>Version = integer()</v>
+ <v>T = term()</v>
+ </type>
+ <desc>
+ <p>Compress a megaco component. The erlang dist encoder makes no
+ assumption on the how or even if the component is compressed. </p>
+ </desc>
+ </func>
+ <func>
+ <name>Module:decode(T, Version) -> R</name>
+ <fsummary>Decode (decompress) a megaco component.</fsummary>
+ <type>
+ <v>T = term()</v>
+ <v>Version = integer()</v>
+ <v>R = megaco_message() | transaction() | action_reply() | action_request() | command_request()</v>
+ </type>
+ <desc>
+ <p>Decompress a megaco component. </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_encode.xml b/lib/megaco/doc/src/megaco_encode.xml
new file mode 100644
index 0000000000..410e4f3b31
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_encode.xml
@@ -0,0 +1,498 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Internal form and its encodings</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_encode.xml</file>
+ </header>
+ <p>This version of the stack is compliant with: </p>
+ <list type="bulleted">
+ <item>
+ <p>Megaco/H.248 version 1 (RFC3525)
+ updated according to Implementors Guide version 10-13.</p>
+ </item>
+ <item>
+ <p>Megaco/H.248 version 2 as defined by
+ draft-ietf-megaco-h248v2-04
+ updated according to Implementors Guide version 10-13.</p>
+ </item>
+ <item>
+ <p>Megaco/H.248 version 3 as defined by
+ ITU H.248.1 (09/2005).</p>
+ </item>
+ </list>
+
+ <section>
+ <title>Internal form of messages</title>
+ <p>We use the same internal form for both the binary and text
+ encoding. Our internal form of Megaco/H.248 messages is heavily
+ influenced by the internal format used by ASN.1
+ encoders/decoders:</p>
+ <list type="bulleted">
+ <item>
+ <p>"SEQUENCE OF" is represented as a list.</p>
+ </item>
+ <item>
+ <p>"CHOICE" is represented as a tagged tuple with size 2.</p>
+ </item>
+ <item>
+ <p>"SEQUENCE" is represented as a record, defined in
+ "megaco/include/megaco_message_v1.hrl".</p>
+ </item>
+ <item>
+ <p>"OPTIONAL" is represented as an ordinary field in a
+ record which defaults to 'asn1_NOVALUE', meaning that the
+ field has no value.</p>
+ </item>
+ <item>
+ <p>"OCTET STRING" is represented as a list of unsigned integers.</p>
+ </item>
+ <item>
+ <p>"ENUMERATED" is represented as a single atom.</p>
+ </item>
+ <item>
+ <p>"BIT STRING" is represented as a list of atoms.</p>
+ </item>
+ <item>
+ <p>"BOOLEAN" is represented as the atom 'true' or 'false'.</p>
+ </item>
+ <item>
+ <p>"INTEGER" is represented as an integer.</p>
+ </item>
+ <item>
+ <p>"IA5String" is represented as a list of integers,
+ where each integer is the ASCII value of the corresponding
+ character.</p>
+ </item>
+ <item>
+ <p>"NULL" is represented as the atom 'NULL'.</p>
+ </item>
+ </list>
+ <p>In order to fully understand the internal form you must get
+ hold on a ASN.1 specification for the Megaco/H.248 protocol,
+ and apply the rules above.
+ Please, see the documentation of the ASN.1 compiler in
+ Erlang/OTP for more details of the semantics in mapping between
+ ASN.1 and the corresponding internal form.</p>
+ <p>Observe that the 'TerminationId' record is not used in the
+ internal form. It has been replaced with a megaco_term_id record
+ (defined in "megaco/include/megaco.hrl").</p>
+ </section>
+
+ <section>
+ <title>The different encodings</title>
+ <p>The Megaco/H.248 standard defines both a plain text encoding
+ and a binary encoding (ASN.1 BER) and we have implemented
+ encoders and decoders for both. We do in fact supply five
+ different encoding/decoding modules.</p>
+ <p>In the text encoding, implementors have the choice of using a
+ mix of short and long keywords. It is also possible to add white
+ spaces to improve readability. We use the term compact for text
+ messages with the shortest possible keywords and no optional
+ white spaces, and the term pretty for a well indented text
+ format using long keywords and an indentation style like the
+ text examples in the Megaco/H.248 specification).</p>
+ <p>Here follows an example of a text message to give a feeling
+ of the difference between the pretty and compact versions of
+ text messages. First the pretty, well indented version with long
+ keywords:</p>
+ <pre>
+ MEGACO/1 [124.124.124.222]
+ Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1,
+ Reason = "901 Cold Boot"
+ }
+ }
+ }
+ } </pre>
+ <p>Then the compact version without indentation and with short keywords:</p>
+ <pre>
+
+ !/1 [124.124.124.222]
+ T=9998{C=-{SC=ROOT{SV{MT=RS,AD=55555,PF=ResGW/1,RE="901 Cold Boot"}}}} </pre>
+ <p>And the programmers view of the same message.
+ First a list of ActionRequest records are constructed and
+ then it is sent with one of the send functions in the API:</p>
+ <pre>
+ Prof = #'ServiceChangeProfile'{profileName = "resgw", version = 1},
+ Parm = #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeAddress = {portNumber, 55555},
+ serviceChangeReason = "901 Cold Boot",
+ serviceChangeProfile = Prof},
+ Req = #'ServiceChangeRequest'{terminationID = [?megaco_root_termination_id],
+ serviceChangeParms = Parm},
+ Actions = [#'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = {serviceChangeReq, Req}}],
+ megaco:call(ConnHandle, Actions, Config). </pre>
+ <p>And finally a print-out of the entire internal form:</p>
+ <pre>
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 1,
+ {ip4Address,{'IP4Address', [124,124,124,222], asn1_NOVALUE}},
+ {transactions,
+ [
+ {transactionRequest,
+ {'TransactionRequest',
+ 9998,
+ [{'ActionRequest',
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [
+ {'CommandRequest',
+ {serviceChangeReq,
+ {'ServiceChangeRequest',
+ [
+ {megaco_term_id, false, ["root"]}],
+ {'ServiceChangeParm',
+ restart,
+ {portNumber, 55555},
+ asn1_NOVALUE,
+ {'ServiceChangeProfile', "resgw", version = 1},
+ "901 MG Cold Boot",
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ asn1_NOVALUE
+ }
+ }
+ },
+ asn1_NOVALUE,
+ asn1_NOVALUE
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ } </pre>
+ <p>The following encoding modules are provided:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>megaco_pretty_text_encoder - encodes messages into
+ pretty text format, decodes both pretty as well as compact
+ text.</p>
+ </item>
+ <item>
+ <p>megaco_compact_text_encoder - encodes messages into
+ compact text format, decodes both pretty as well as compact
+ text.</p>
+ </item>
+ <item>
+ <p>megaco_binary_encoder - encode/decode ASN.1 BER messages.
+ This encoder implements the fastest of the BER encoders/decoders.
+ Recommended binary codec.</p>
+ </item>
+ <item>
+ <p>megaco_ber_encoder - encode/decode ASN.1 BER
+ messages.</p>
+ </item>
+ <item>
+ <p>megaco_ber_bin_encoder - encode/decode ASN.1 BER
+ messages. This encoder uses ASN.1 ber_bin which
+ has been optimized using the bit syntax.</p>
+ </item>
+ <item>
+ <p>megaco_per_encoder - encode/decode ASN.1 PER
+ messages. N.B. that this format is not included in the
+ Megaco standard.</p>
+ </item>
+ <item>
+ <p>megaco_per_bin_encoder - encode/decode ASN.1 PER
+ messages. N.B. that this format is not included in the
+ Megaco standard. This encoder uses ASN.1 per_bin which
+ has been optimized using the bit syntax.</p>
+ </item>
+ <item>
+ <p>megaco_erl_dist_encoder - encodes messages into Erlangs
+ distribution format. It is rather verbose but encoding and
+ decoding is blinding fast. N.B. that this format is not
+ included in the Megaco standard.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="erl_dist_config"></marker>
+ <title>Configuration of Erlang distribution encoding module</title>
+ <p>The encoding_config of the megaco_erl_dist_encoder module
+ may be one of these:</p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[[]]]></c> - Encodes the messages to the standard distribution
+ format. It is rather verbose but encoding and decoding is
+ blinding fast.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[megaco_compressed]]]></c> - Encodes the messages to the
+ standard distribution format after an internal transformation.
+ It is less verbose, but the total time of the encoding and
+ decoding will on the other hand be somewhat slower (see the
+ <seealso marker="megaco_performance">performance</seealso>
+ chapter for more info).</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[{megaco_compressed, Module}]]]></c> - Works in the same
+ way as the megaco_compressed config parameter, only here the
+ user provide their own compress module. This module must
+ implement the
+ <seealso marker="megaco_edist_compress">megaco_edist_compress</seealso>
+ behaviour.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[compressed]]]></c> - Encodes the messages to a compressed
+ form of the standard distribution format. It is less
+ verbose, but the encoding and decoding will on the other
+ hand be slower.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="text_config"></marker>
+ <title>Configuration of text encoding module(s)</title>
+ <p>When using text encoding(s), there is actually two different
+ configs controlling what software to use:</p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[[]]]></c> - An empty list indicates that the erlang
+ scanner should be used.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[{flex, port()}]]]></c> - Use the flex scanner when
+ decoding (not optimized for SMP). See
+ <seealso marker="megaco_run#initial_config">initial configuration</seealso>
+ for more info.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[{flex, ports()}]]]></c> - Use the flex scanner when
+ decoding (optimized for SMP). See
+ <seealso marker="megaco_run#initial_config">initial configuration</seealso>
+ for more info.</p>
+ </item>
+ </list>
+ <p>The Flex scanner is a Megaco scanner written as a linked in driver
+ (in C). There are two ways to get this working:</p>
+ <list type="bulleted">
+ <item>
+ <p>Let the Megaco stack start the flex scanner
+ (load the driver).</p>
+ <p>To make this happen the megaco stack has to be configured: </p>
+ <list type="bulleted">
+ <item>
+ <p>Add the <c><![CDATA[{scanner, flex}]]></c> (or similar) directive to an
+ Erlang system config file for the megaco app (see
+ <seealso marker="megaco_run#initial_config">initial configuration</seealso>
+ chapter for details). </p>
+ </item>
+ <item>
+ <p>Retrieve the encoding-config using the
+ <seealso marker="megaco#system_info">system_info</seealso>
+ function (with <c>Item = text_config</c>). </p>
+ </item>
+ <item>
+ <p>Update the receive handle with the encoding-config
+ (the <c>encoding_config</c> field). </p>
+ </item>
+ </list>
+ <p>The benefit of this is that Megaco handles the starting, holding
+ and the supervision of the driver and port.</p>
+ </item>
+ <item>
+ <p>The Megaco client (user) starts the flex scanner (load the driver).</p>
+ <p>When starting the flex scanner a port to the linked in driver is
+ created. This port has to be owned by a process. This process must not
+ die. If it does the port will also terminate. Therefor:</p>
+ <p></p>
+ <list type="bulleted">
+ <item>
+ <p>Create a permanent process. Make sure this process is
+ supervised (so that if it does die, this will be noticed).</p>
+ </item>
+ <item>
+ <p>Let this process start the flex scanner by calling the
+ <c><![CDATA[megaco_flex_scanner:start/0,1]]></c> function.</p>
+ </item>
+ <item>
+ <p>Retrieve the encoding-config and when initiating
+ the <c><![CDATA[megaco_receive_handle]]></c>, set the
+ field <c>encoding_config</c> accordingly.</p>
+ </item>
+ <item>
+ <p>Pass the <c><![CDATA[megaco_receive_handle]]></c> to the
+ transport module.</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="binary_config"></marker>
+ <title>Configuration of binary encoding module(s)</title>
+ <p>When using binary encoding, the structure of the termination id's
+ needs to be specified.</p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[[driver|_]]]></c> - make use of the asn1 driver for decode
+ (ber_bin) and encode (per_bin). This option is only available for
+ encoding modules: <c><![CDATA[megaco_binary_encoder]]></c>,
+ <c><![CDATA[megaco_ber_bin_encoder]]></c> and <c><![CDATA[megaco_per_bin_encoder]]></c>.</p>
+ <p>If this option is present in the encoding config, it <em>must</em>
+ to be the <em>first</em>, unless the
+ <seealso marker="#handling_versions">version3</seealso> encoding
+ config is present, in which case it must come second, after
+ the version3 encoding config,
+ e.g. <c><![CDATA[[{version3,prev3b},driver]]]></c>.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[native]]]></c> - skips the transformation phase, i.e.
+ the decoded message(s) will not be transformed into our internal
+ form.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[[integer()]]]></c> - A list containing the size (the number
+ of bits) of each level. Example: <c><![CDATA[[3,8,5,8]]]></c>.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[integer()]]></c> - Number of one byte (8 bits) levels.
+ N.B. This is currently converted into the previous config.
+ Example: <c><![CDATA[3]]></c> (<c><![CDATA[[8,8,8]]]></c>).</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="handling_versions"></marker>
+ <title>Handling megaco versions</title>
+ <p>Since the version 3 implemented, in this version of the Megaco
+ application, is preliminary, it is necessary to have a way
+ to handle different version 3 implementations. For this reason
+ the encoding config option <c><![CDATA[{version3, version3()}]]></c> has been
+ introduced. This option, if present, has to be <em>first</em> in the
+ encoding config list. Version 1 and 2 codec's ignore this option, if
+ found. </p>
+ <code type="none"><![CDATA[
+version3() -> prev3a | prev3b | prev3c | v3 ]]></code>
+ <list type="bulleted">
+ <item>
+ <p><em>prev3a</em></p>
+ <p>Preliminary version 3, based on TD-33</p>
+ </item>
+ <item>
+ <p><em>prev3b</em></p>
+ <p>Preliminary version 3, based on TD-33, but text encoding
+ updated with the final solution for priority in
+ <c><![CDATA[contextProperty]]></c> (which is backward compatible with v2).</p>
+ </item>
+ <item>
+ <p><em>prev3c</em></p>
+ <p>Preliminary version 3, based on the final version of the
+ v3-standard, but <em>excluding</em> segments!</p>
+ </item>
+ <item>
+ <p><em>v3</em></p>
+ <p>Full version 3. Including segmentation. This is the default
+ version 3 variant (i.e. if a version 3 messages is to be
+ encoded/decoded and no version3 encoding config is found,
+ then v3 is assumed).</p>
+ </item>
+ </list>
+ <p>There are two ways to handle the different megaco encoding versions.
+ Either using <em>dynamic version detection</em> (only valid for
+ for incoming messages) or by <em>explicit version</em> setting in
+ the connection info.</p>
+ <p>For incoming messages:</p>
+ <list type="bulleted">
+ <item>
+ <p>Dynamic version detection</p>
+ <p>Set the protocol version in the megaco_receive_handle to
+ <c><![CDATA[dynamic]]></c> (this is the default).
+ <br></br>This works for those codecs that support partial decode of the
+ version, currently <em>text</em>, and ber_bin
+ (<c><![CDATA[megaco_binary_encoder]]></c> and <c><![CDATA[megaco_ber_bin_encoder]]></c>).
+ <br></br>This way the decoder will detect which version is used and
+ then use the proper decoder. </p>
+ </item>
+ <item>
+ <p>Explicit version</p>
+ <p>Explicitly set the actual protocol version in the
+ megaco_receive_handle.
+ <br></br>Start with version 1. When the initial service change has been
+ performed and version 2 has been negotiated, upgrade the
+ megaco_receive_handle of the transport process (control_pid) to
+ version 2.
+ See
+ <seealso marker="megaco_tcp#upgrade_receive_handle">megaco_tcp</seealso>
+ and
+ <seealso marker="megaco_udp#upgrade_receive_handle">megaco_udp</seealso>.
+ <br></br>Note that if <c><![CDATA[udp]]></c> is used, the same transport process
+ could be used for several connections. This could make upgrading
+ impossible.
+ <br></br>For codecs that does not support partial decode of the version,
+ currently <c><![CDATA[megaco_ber_encoder]]></c>, <c><![CDATA[megaco_per_encoder]]></c>
+ and <c><![CDATA[megaco_per_bin_encoder]]></c>, <c><![CDATA[dynamic]]></c> will revert to
+ version 1.</p>
+ </item>
+ </list>
+ <p>For outgoing messages:</p>
+ <list type="bulleted">
+ <item>
+ <p>Update the connection info protocol_version.</p>
+ </item>
+ <item>
+ <p>Override protocol version when sending a message by adding the
+ item <c><![CDATA[{protocol_version, integer()}]]></c> to the Options.
+ See
+ <seealso marker="megaco#call">call</seealso> or
+ <seealso marker="megaco#cast">cast</seealso>.
+ <br></br>Note that this does not effect the messages that are sent
+ autonomously by the stack. They use the protocol_version of the
+ connection info.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Encoder callback functions</title>
+ <p>The encoder callback interface is defined by the <c><![CDATA[megaco_encoder]]></c>
+ behaviour, see <seealso marker="megaco_encoder">megaco_encoder</seealso>.</p>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_encoder.xml b/lib/megaco/doc/src/megaco_encoder.xml
new file mode 100644
index 0000000000..07e5091f74
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_encoder.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_encoder</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_encoder.xml</file>
+ </header>
+ <module>megaco_encoder</module>
+ <modulesummary>Megaco encoder behaviour.</modulesummary>
+ <description>
+ <p>The following functions should be exported from a
+ <c><![CDATA[megaco_encoder]]></c> callback module:</p>
+
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+megaco_message() = #'MegacoMessage{}'
+transaction() = {transactionRequest, transaction_request()} |
+ {transactionPending, transaction_reply()} |
+ {transactionReply, transaction_pending()} |
+ {transactionResponseAck, transaction_response_ack()} |
+ {segmentReply, segment_reply()}
+transaction_request() = #'TransactionRequest'{}
+transaction_pending() = #'TransactionPending'{}
+transaction_reply() = #'TransactionReply'{}
+transaction_response_ack() = [transaction_ack()]
+transaction_ack() = #'TransactionAck'{}
+segment_reply() = #'SegmentReply'{}
+action_request() = #'ActionRequest'{}
+action_reply() = #'ActionReply'{}
+ ]]></code>
+
+ <marker id="encode_message"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:encode_message(EncodingConfig, Version, Message) -> {ok, Bin} | Error</name>
+ <fsummary>Encode a megaco message.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer()</v>
+ <v>Message = megaco_message()</v>
+ <v>Bin = binary()</v>
+ <v>Error = term()</v>
+ </type>
+ <desc>
+ <p>Encode a megaco message.</p>
+
+ <marker id="decode_message"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:decode_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
+ <fsummary>Decode a megaco message.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer() | dynamic</v>
+ <v>Message = megaco_message()</v>
+ <v>Bin = binary()</v>
+ <v>Error = term()</v>
+ </type>
+ <desc>
+ <p>Decode a megaco message. </p>
+ <p>Note that if the Version argument is <c><![CDATA[dynamic]]></c>, the
+ decoder should try to figure out the actual version from the
+ message itself and then use the proper decoder, e.g. version 1.
+ <br></br>If on the other hand the Version argument is an integer,
+ it means that this is the expected version of the message and
+ the decoder for that version should be used.</p>
+
+ <marker id="decode_mini_message"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:decode_mini_message(EncodingConfig, Version, Bin) -> {ok, Message} | Error</name>
+ <fsummary>Perform a minimal decode of a megaco message.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer() | dynamic</v>
+ <v>Message = megaco_message()</v>
+ <v>Bin = binary()</v>
+ <v>Error = term()</v>
+ </type>
+ <desc>
+ <p>Perform a minimal decode of a megaco message. </p>
+ <p>The purpose of this function is to do a minimal decode of
+ Megaco message. A successfull result is a <c><![CDATA['MegacoMessage']]></c>
+ in which only version and mid has been initiated. This function
+ is used by the megaco_messenger module when the
+ <c><![CDATA[decode_message/3]]></c> function fails to figure out the mid
+ (the actual sender) of the message.</p>
+ <p>Note again that a successfull decode only returns a
+ partially initiated message.</p>
+
+ <marker id="encode_transaction"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:encode_transaction(EncodingConfig, Version, Transaction) -> OK | Error</name>
+ <fsummary>Encode a megaco transaction.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer()</v>
+ <v>Transaction = transaction()</v>
+ <v>OK = {ok, Bin}</v>
+ <v>Bin = binary()</v>
+ <v>Error = {error, Reason}</v>
+ <v>Reason = not_implemented | OtherReason</v>
+ <v>OtherReason = term()</v>
+ </type>
+ <desc>
+ <p>Encode a megaco transaction. If this, for whatever reason,
+ is not supported, the function should return the error reason
+ <c>not_implemented</c>. </p>
+
+ <p>This functionality is used both when the transaction sender is
+ used and for segmentation. So, for either of those to work, this
+ function <em>must</em> be fully supported! </p>
+
+ <marker id="encode_action_requests"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:encode_action_requests(EncodingConfig, Version, ARs) -> OK | Error</name>
+ <fsummary>Encode megaco action requests.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer()</v>
+ <v>ARs = action_requests()</v>
+ <v>action_requests() = [action_request()]</v>
+ <v>OK = {ok, Bin}</v>
+ <v>Bin = binary()</v>
+ <v>Error = {error, Reason}</v>
+ <v>Reason = not_implemented | OtherReason</v>
+ <v>OtherReason = term()</v>
+ </type>
+ <desc>
+ <p>Encode megaco action requests. This function is called when
+ the user calls the function
+ <seealso marker="megaco#encode_actions">encode_actions/3</seealso>.
+ If that function is never used or if the codec cannot support this
+ (the encoding of individual actions), then return with error reason
+ <c>not_implemented</c>. </p>
+
+ <marker id="encode_action_reply"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:encode_action_reply(EncodingConfig, Version, AR) -> OK | Error</name>
+ <fsummary>Encode a megaco action reply.</fsummary>
+ <type>
+ <v>EncodingConfig = list()</v>
+ <v>Version = integer()</v>
+ <v>AR = action_reply()</v>
+ <v>OK = {ok, Bin}</v>
+ <v>Bin = binary()</v>
+ <v>Error = {error, Reason}</v>
+ <v>Reason = not_implemented | OtherReason</v>
+ <v>OtherReason = term()</v>
+ </type>
+ <desc>
+ <p>Encode a megaco action reply. If this, for whatever reason,
+ is not supported, the function should return the error reason
+ <c>not_implemented</c>. </p>
+
+ <p>This function is used when segmentation has been configured.
+ So, for this to work, this function <em>must</em> be fully
+ supported! </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_examples.xml b/lib/megaco/doc/src/megaco_examples.xml
new file mode 100644
index 0000000000..8c85c1a0b4
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_examples.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Implementation examples</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_examples.xml</file>
+ </header>
+
+ <section>
+ <title>A simple Media Gateway Controller</title>
+ <p>In megaco/examples/simple/megaco_simple_mgc.erl there is an
+ example of a simple MGC that listens on both text and binary
+ standard ports and is prepared to handle a Service Change
+ Request message to arrive either via TCP/IP or UDP/IP. Messages
+ received on the text port are decoded using a text decoder and
+ messages received on the binary port are decoded using a binary
+ decoder.</p>
+ <p>The Service Change Reply is encoded in the same way as the
+ request and sent back to the MG with the same transport
+ mechanism UDP/IP or TCP/IP.</p>
+ <p>After this initial service change message the connection
+ between the MG and MGC is fully established and supervised.</p>
+ <p>The MGC, with its four listeners, may be started with:</p>
+ <pre>
+ cd megaco/examples/simple
+ erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+ megaco_simple_mgc:start().
+ </pre>
+ <p>or simply 'gmake mgc'.</p>
+ <p>The -s megaco_filter option to erl implies, the event tracing
+ mechanism to be enabled and an interactive sequence chart tool
+ to be started. This may be quite useful in order to visualize
+ how your MGC interacts with the Megaco/H.248 protocol stack.</p>
+ <p>The event traces may alternatively be directed to a file for
+ later analyze. By default the event tracing is disabled, but it
+ may dynamically be enabled without any need for re-compilation
+ of the code.
+ </p>
+ </section>
+
+ <section>
+ <title>A simple Media Gateway</title>
+ <p>In megaco/examples/simple/megaco_simple_mg.erl there is an
+ example of a simple MG that connects to an MGC, sends a Service
+ Change Request and waits synchronously for a reply.</p>
+ <p>After this initial service change message the connection
+ between the MG and MGC is fully established and supervised.</p>
+ <p>Assuming that the MGC is started on the local host, four
+ different MG's, using text over TCP/IP, binary over TCP/IP, text
+ over UDP/IP and binary over UDP/IP may be started on the same
+ Erlang node with:</p>
+ <pre>
+ cd megaco/examples/simple
+ erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+ megaco_simple_mg:start().
+ </pre>
+ <p>or simply 'gmake mg'.</p>
+ <p>If you "only" want to start a single MG which tries to connect
+ an MG on a host named "baidarka", you may use one of these
+ functions (instead of the megaco_simple_mg:start/0 above):</p>
+ <pre>
+ megaco_simple_mg:start_tcp_text("baidarka", []).
+ megaco_simple_mg:start_tcp_binary("baidarka", []).
+ megaco_simple_mg:start_udp_text("baidarka", []).
+ megaco_simple_mg:start_udp_binary("baidarka", []).
+ </pre>
+ <p>The -s megaco_filter option to erl implies, the event tracing
+ mechanism to be enabled and an interactive sequence chart tool
+ to be started. This may be quite useful in order to visualize
+ how your MG interacts with the Megaco/H.248 protocol stack.</p>
+ <p>The event traces may alternatively be directed to a file for
+ later analyze. By default the event tracing is disabled, but it
+ may dynamically be enabled without any need for re-compilation
+ of the code.
+ </p>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_flex_scanner.xml b/lib/megaco/doc/src/megaco_flex_scanner.xml
new file mode 100644
index 0000000000..eb206e5d13
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_flex_scanner.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_flex_scanner</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2009-05-04</date>
+ <rev>%VSN%</rev>
+ <file>megaco_flex_scanner.xml</file>
+ </header>
+ <module>megaco_flex_scanner</module>
+ <modulesummary>Interface module to the flex scanner linked in driver.</modulesummary>
+ <description>
+ <p>This module contains the public interface to the flex scanner
+ linked in driver. The flex scanner performs the scanning phase
+ of text message decoding.</p>
+
+ <p>The flex scanner is written using a tool called <em>flex</em>.
+ In order to be able to compile the flex scanner driver, this
+ tool has to be available. </p>
+
+ <p>By default the flex scanner reports line-number of an error.
+ But it can be built without line-number reporting. Instead
+ token number is used. This will speed up the scanning some
+ 5-10%. Use <c><![CDATA[--disable-megaco-flex-scanner-lineno]]></c> when
+ configuring the application.</p>
+
+ <p>The scanner will, by default, be built as a reentrant scanner <em>if</em> the
+ flex utility supports this (it depends on the version of flex).
+ It is possible to explicitly disable this even when flex support this.
+ Use <c><![CDATA[--disable-megaco-reentrant-flex-scanner]]></c> when
+ configuring the application.</p>
+
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+
+megaco_ports() = term()
+megaco_version() = integer() >= 1
+
+ ]]></code>
+
+ <marker id="start"></marker>
+ </section>
+
+
+ <funcs>
+ <func>
+ <name>start() -> {ok, PortOrPorts} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>PortOrPorts = megaco_ports()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This function is used to start the flex scanner.
+ It locates the library and loads the linked in driver.</p>
+
+ <p>On a single core system or if it's a non-reentrant scanner,
+ a single port is created. On a multi-core system with a reentrant
+ scanner, several ports will be created (one for each scheduler). </p>
+
+ <p>Note that the process that calls this function <em>must</em>
+ be permanent. If it dies, the port(s) will exit and the driver unload.</p>
+
+ <marker id="stop"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>stop(PortOrPorts) -> stopped</name>
+ <fsummary></fsummary>
+ <type>
+ <v>PortOrPorts = megaco_ports()</v>
+ </type>
+ <desc>
+ <p>This function is used to stop the flex scanner. It also
+ unloads the driver.</p>
+
+ <marker id="is_reentrant_enabled"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>is_reentrant_enabled() -> Boolean</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Boolean = boolean()</v>
+ </type>
+ <desc>
+ <p>Is the flex scanner reentrant or not.</p>
+
+ <marker id="is_scanner_port"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>is_scanner_port(Port, PortOrPorts) -> Boolean</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Port = port()</v>
+ <v>PortOrPorts = megaco_ports()</v>
+ <v>Boolean = boolean()</v>
+ </type>
+ <desc>
+ <p>Checks if a port is a flex scanner port or not (usefull when
+ if a port exits). </p>
+
+ <marker id="scan"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>scan(Binary, PortOrPorts) -> {ok, Tokens, Version, LatestLine} | {error, Reason, LatestLine} </name>
+ <fsummary></fsummary>
+ <type>
+ <v>Binary = binary()</v>
+ <v>PortOrPorts = megaco_ports()</v>
+ <v>Tokens = list()</v>
+ <v>Version = megaco_version()</v>
+ <v>LatestLine = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Scans a megaco message and generates a token list to be passed on the parser. </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_intro.xml b/lib/megaco/doc/src/megaco_intro.xml
new file mode 100644
index 0000000000..507271bcd8
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_intro.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Introduction</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_intro.xml</file>
+ </header>
+ <p>Megaco/H.248 is a protocol for control of elements in a
+ physically decomposed multimedia gateway, enabling separation of
+ call control from media conversion. A Media Gateway Controller
+ (MGC) controls one or more Media Gateways (MG).</p>
+ <p>This version of the stack supports version 1, 2 and 3 as
+ defined by:</p>
+ <list type="bulleted">
+ <item>
+ <p>version 1 - RFC 3525 and H.248-IG (v10-v13)</p>
+ </item>
+ <item>
+ <p>version 2 - draft-ietf-megaco-h248v2-04 &amp; H.248.1
+ v2 Corrigendum 1 (03/2004)</p>
+ </item>
+ <item>
+ <p>version 3: </p>
+ <list type="bulleted">
+ <item>
+ <p>prev3a - as defined by TD-33 (except segments)</p>
+ </item>
+ <item>
+ <p>prev3b - TD-33 updated to be backward compatible with v2
+ (except segments)</p>
+ </item>
+ <item>
+ <p>prev3c - As defined by ITU H.248.1 (09/2005)
+ (except segments)</p>
+ </item>
+ <item>
+ <p>v3 - Full version 3 as defined by ITU H.248.1 (09/2005)
+ (including segments)</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>The semantics of the protocol has jointly been defined by two
+ standardization bodies:</p>
+ <list type="bulleted">
+ <item>
+ <p>IETF - which calls the protocol Megaco</p>
+ </item>
+ <item>
+ <p>ITU - which calls the protocol H.248</p>
+ </item>
+ </list>
+
+ <section>
+ <title>Scope and Purpose</title>
+ <p>This manual describes the Megaco application, as a component
+ of the Erlang/Open Telecom Platform development environment. It
+ is assumed that the reader is familiar with the Erlang
+ Development Environment, which is described in a separate User's
+ Guide.</p>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>The following prerequisites is required for understanding the
+ material in the Megaco User's Guide:</p>
+ <list type="bulleted">
+ <item>
+ <p>the basics of the Megaco/H.248 protocol</p>
+ </item>
+ <item>
+ <p>the basics of the Abstract Syntax Notation One (ASN.1)</p>
+ </item>
+ <item>
+ <p>familiarity with the Erlang system and Erlang programming</p>
+ </item>
+ </list>
+ <p>The application requires Erlang/OTP release R10B or later.</p>
+ </section>
+
+ <section>
+ <title>About This Manual</title>
+ <p>In addition to this introductory chapter, the Megaco User's
+ Guide contains the following chapters:</p>
+ <list type="bulleted">
+ <item>
+ <p>Chapter 2: "Architecture" describes the architecture
+ and typical usage of the application.</p>
+ </item>
+ <item>
+ <p>Chapter 3: "Internal form and its encodings" describes
+ the internal form of Megaco/H.248 messages and its various
+ encodings.</p>
+ </item>
+ <item>
+ <p>Chapter 4: "Transport mechanisms" describes how
+ different mechanisms can be used to transport the
+ Megaco/H.248 messages.</p>
+ </item>
+ <item>
+ <p>Chapter 5: "Debugging" describes tracing and debugging.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Where to Find More Information</title>
+ <p>Refer to the following documentation for more information about
+ Megaco/H.248 and about the Erlang/OTP development system:</p>
+ <list type="bulleted">
+ <item>
+ <p><url href="http://www.erlang.org/project/megaco/standard/rfc3525.txt">version 1, RFC 3525</url></p>
+ </item>
+ <item>
+ <p><url href="http://www.ietf.org/rfc/rfc3015.txt">old version 1, RFC 3015</url></p>
+ </item>
+ <item>
+ <p><url href="http://www.erlang.org/project/megaco/standard/H.248.1-Corr1-200403.doc">Version 2 Corrigendum 1</url></p>
+ </item>
+ <item>
+ <p><url href="http://www.erlang.org/project/megaco/standard/draft-ietf-megaco-h248v2-04.txt">version 2, draft-ietf-megaco-h248v2-04</url></p>
+ </item>
+ <item>
+ <p><url href="http://www.itu.int/">TD-33 (Draft H.248.1 version 3)</url></p>
+ </item>
+ <item>
+ <p><url href="http://www.itu.int/">H.248.1 version 3</url></p>
+ </item>
+ <item>
+ <p>the ASN.1 application User's Guide</p>
+ </item>
+ <item>
+ <p>the Megaco application Reference Manual</p>
+ </item>
+ <item>
+ <p>Concurrent Programming in Erlang, 2nd Edition (1996),
+ Prentice-Hall, ISBN 0-13-508301-X.</p>
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_mib.xml b/lib/megaco/doc/src/megaco_mib.xml
new file mode 100644
index 0000000000..3c0a549590
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_mib.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco mib</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_mib.xml</file>
+ </header>
+
+ <section>
+ <title>Intro</title>
+ <p>The Megaco mib is as of yet not standardized and our
+ implementation is based on
+ <em>draft-ietf-megaco-mib-04.txt</em>. Almost all of the mib
+ cannot easily be implemented by the megaco application. Instead
+ these things should be implemented by a user (of the megaco
+ application). </p>
+ <p>So what part of the mib is implemented? Basically the relevant
+ statistic counters of the <em>MedGwyGatewayStatsEntry</em>.</p>
+ </section>
+
+ <section>
+ <title>Statistics counters</title>
+ <p>The implementation of the statistic counters is
+ lightweight. I.e. the statistic counters are handled
+ separately by different entities of the application. For
+ instance our two transport module(s) (see <seealso marker="megaco_tcp#stats">megaco_tcp</seealso> and <seealso marker="megaco_udp#stats">megaco_udp</seealso>) maintain their
+ own counters and the application engine (see <seealso marker="megaco#stats">megaco</seealso>) maintain it's own
+ counters.</p>
+ <p>This also means that if a user implement their own transport
+ service then it has to maintain it's own statistics.</p>
+ </section>
+
+ <section>
+ <title>Distribution</title>
+ <p>Each megaco application maintains it's own set of counters. So
+ in a large (distributed) MG/MGC it could be necessary to
+ collect the statistics from several nodes (each) running the
+ megaco application (only one of them with the transport).</p>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_performance.xml b/lib/megaco/doc/src/megaco_performance.xml
new file mode 100644
index 0000000000..b34ee4f389
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_performance.xml
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Performance comparison</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_performance.xml</file>
+ </header>
+
+ <section>
+ <title>Comparison of encoder/decoders</title>
+ <p>The Megaco/H.248 standard defines both a plain text encoding and a
+ binary encoding (ASN.1 BER) and we have implemented encoders and
+ decoders for both. We do supply a bunch of different encoding/decoding
+ modules and the user may in fact implement their own (like our erl_dist
+ module). Using a non-standard encoding format has its obvious drawbacks,
+ but may be useful in some configurations.</p>
+
+ <p>We have made four different measurements of our Erlang/OTP
+ implementation of the Megaco/H.248 protocol stack, in order to compare
+ our different encoders/decoders. The result of each one is summarized
+ in the table below.</p>
+
+ <p>The result above are the fastest
+ of these configurations for each codec. The figures presented are
+ the average of all used messages.</p>
+
+ <p>For comparison, also included are performance figures
+ where the flex driver was built as <c>non-reentrant</c> flex
+ (figures within parenthesis). </p>
+
+ <table>
+ <row>
+ <cell align="left" valign="middle"><em>Codec and config</em></cell>
+ <cell align="center" valign="middle"><em>Size</em></cell>
+ <cell align="center" valign="middle"><em>Encode</em></cell>
+ <cell align="center" valign="middle"><em>Decode</em></cell>
+ <cell align="center" valign="middle"><em>Total</em></cell>
+ </row>
+
+ <!-- PRETTY -->
+ <row>
+ <cell align="left" valign="middle">pretty</cell>
+ <cell align="right" valign="middle">336</cell>
+ <cell align="right" valign="middle">22</cell>
+ <cell align="right" valign="middle">76</cell>
+ <cell align="right" valign="middle">98</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">pretty [flex]</cell>
+ <cell align="right" valign="middle">336</cell>
+ <cell align="right" valign="middle">22 (22)</cell>
+ <cell align="right" valign="middle">41 (40)</cell>
+ <cell align="right" valign="middle">63 (62)</cell>
+ </row>
+
+ <!-- COMPACT -->
+ <row>
+ <cell align="left" valign="middle">compact</cell>
+ <cell align="right" valign="middle">181</cell>
+ <cell align="right" valign="middle">19</cell>
+ <cell align="right" valign="middle">63</cell>
+ <cell align="right" valign="middle">82</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">compact [flex]</cell>
+ <cell align="right" valign="middle">181</cell>
+ <cell align="right" valign="middle">19 (19)</cell>
+ <cell align="right" valign="middle">38 (36)</cell>
+ <cell align="right" valign="middle">57 (55)</cell>
+ </row>
+
+ <!-- PER -->
+ <row>
+ <cell align="left" valign="middle">per bin</cell>
+ <cell align="right" valign="middle">91</cell>
+ <cell align="right" valign="middle">63</cell>
+ <cell align="right" valign="middle">69</cell>
+ <cell align="right" valign="middle">132</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">per bin [driver]</cell>
+ <cell align="right" valign="middle">91</cell>
+ <cell align="right" valign="middle">43</cell>
+ <cell align="right" valign="middle">45</cell>
+ <cell align="right" valign="middle">88</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">per bin [native]</cell>
+ <cell align="right" valign="middle">91</cell>
+ <cell align="right" valign="middle">47</cell>
+ <cell align="right" valign="middle">51</cell>
+ <cell align="right" valign="middle">99</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">per bin [driver,native]</cell>
+ <cell align="right" valign="middle">91</cell>
+ <cell align="right" valign="middle">26</cell>
+ <cell align="right" valign="middle">29</cell>
+ <cell align="right" valign="middle">55</cell>
+ </row>
+
+ <!-- BER -->
+ <row>
+ <cell align="left" valign="middle">ber bin</cell>
+ <cell align="right" valign="middle">165</cell>
+ <cell align="right" valign="middle">35</cell>
+ <cell align="right" valign="middle">42</cell>
+ <cell align="right" valign="middle">77</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">ber bin [driver]</cell>
+ <cell align="right" valign="middle">165</cell>
+ <cell align="right" valign="middle">35</cell>
+ <cell align="right" valign="middle">37</cell>
+ <cell align="right" valign="middle">72</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">ber bin [native]</cell>
+ <cell align="right" valign="middle">165</cell>
+ <cell align="right" valign="middle">19</cell>
+ <cell align="right" valign="middle">26</cell>
+ <cell align="right" valign="middle">45</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">ber bin [driver,native]</cell>
+ <cell align="right" valign="middle">165</cell>
+ <cell align="right" valign="middle">19</cell>
+ <cell align="right" valign="middle">20</cell>
+ <cell align="right" valign="middle">39</cell>
+ </row>
+
+ <!-- ERLANG -->
+ <row>
+ <cell align="left" valign="middle">erl_dist</cell>
+ <cell align="right" valign="middle">875</cell>
+ <cell align="right" valign="middle">5</cell>
+ <cell align="right" valign="middle">10</cell>
+ <cell align="right" valign="middle">15</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">erl_dist [megaco_compressed]</cell>
+ <cell align="right" valign="middle">405</cell>
+ <cell align="right" valign="middle">6</cell>
+ <cell align="right" valign="middle">7</cell>
+ <cell align="right" valign="middle">13</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">erl_dist [compressed]</cell>
+ <cell align="right" valign="middle">345</cell>
+ <cell align="right" valign="middle">86</cell>
+ <cell align="right" valign="middle">21</cell>
+ <cell align="right" valign="middle">107</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">erl_dist [megaco_compressed,compressed]</cell>
+ <cell align="right" valign="middle">200</cell>
+ <cell align="right" valign="middle">71</cell>
+ <cell align="right" valign="middle">12</cell>
+ <cell align="right" valign="middle">83</cell>
+ </row>
+
+ <tcaption>Codec performance</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>System performance characteristics</title>
+ <p>This is primarily a way to show the effects of using the
+ reentrant flex scanner instead of the non-reentrant. </p>
+ <p>As can be seen from the figures above there is no real difference
+ between a non-reentrant and an reentrant flex scanner when it
+ comes to the decode times of an individual message. </p>
+ <p>The real difference is instead in system characteristics, which
+ is best shown with the mstone1 test. </p>
+ <p>When running SMP erlang on a multi-core machine the "throughput"
+ is significantly higher. The mstone1 test is an extreme test,
+ but it shows what is gained by using the reentrant flex-scanner. </p>
+ <image file="mstone1.gif">
+ <icaption>MStone1 with mstone1.sh -d flex -s 8</icaption>
+ </image>
+ </section>
+
+ <section>
+ <title>Description of encoders/decoders</title>
+ <p>In Appendix A of the Megaco/H.248 specification (RFC 3525), there are
+ about 30 messages that shows a representative call flow. We have also
+ added a few extra version 1, version 2 and version 3 messages.
+ We have used these messages as basis for our measurements.
+ Our figures have not been weighted in regard to how frequent
+ the different kinds of messages that are sent between the media
+ gateway and its controller.</p>
+ <p>The test compares the following encoder/decoders:</p>
+ <list type="bulleted">
+ <item>
+ <p><em>pretty</em> - pretty printed text. In the text encoding,
+ the protocol stack implementors have the choice of using a
+ mix of short and long keywords. It is also possible to add
+ white spaces to improve readability. The pretty text encoding
+ utilizes long keywords and an indentation style like the
+ text examples in the Megaco/H.248 specification.</p>
+ </item>
+ <item>
+ <p><em>compact</em> - the compact text encoding uses the shortest
+ possible keywords and no optional white spaces.</p>
+ </item>
+ <item>
+ <p><em>ber</em> - ASN.1 BER.</p>
+ </item>
+ <item>
+ <p><em>per</em> - ASN.1 PER. Not standardized as a valid
+ Megaco/H.248 encoding, but included for the matter of completeness
+ as its encoding is extremely compact.</p>
+ </item>
+ <item>
+ <p><em>erl_dist</em> - Erlang's native distribution format. Not
+ standardized as a valid Megaco/H.248 encoding, but included
+ as a reference due to its well known performance characteristics.
+ Erlang is a dynamically typed language and any Erlang data
+ structure may be serialized to the erl_dist format by using
+ built-in functions.</p>
+ </item>
+ </list>
+ <p>The actual encoded messages have been collected in one directory per
+ encoding type, containing one file per encoded message.</p>
+ <p>Here follows an example of a text message to give a feeling of the
+ difference between the pretty and compact versions of text messages.
+ First the pretty printed, well indented version with long keywords:</p>
+ <p></p>
+ <pre>
+MEGACO/1 [124.124.124.222]
+ Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ \011Services {
+ \011 Method = Restart,
+ \011 ServiceChangeAddress = 55555,
+ \011 Profile = ResGW/1,
+ \011 Reason = "901 MG Cold Boot"
+ \011}
+ }
+ }
+ } </pre>
+ <p>Then the compact text version without indentation and with short
+ keywords:</p>
+ <pre>
+!/1 [124.124.124.222] T=9998{
+ C=-{SC=ROOT{SV{MT=RS,AD=55555,PF=ResGW/1,RE="901 MG Cold Boot"}}}} </pre>
+ </section>
+
+ <section>
+ <title>Setup</title>
+ <p>The measurements has been performed on a
+ Dell PowerEdge 1950iii with
+ 2* Intel Xeon L5430 @ 2.66 GHz, with 8 GB memory and
+ running SLES 10 SP2 x86_64, kernel 2.6.16.60-0.34-smp.
+ Software versions was open source OTP R13B and megaco-3.11.</p>
+ </section>
+
+ <section>
+ <title>Summary</title>
+ <p>In our measurements we have seen that there are no significant
+ differences in message sizes between ASN.1 BER and the compact
+ text format. Some care should be taken when using the pretty text
+ style (which is used in all the examples included in the protocol
+ specification and preferred during debugging sessions) since the
+ messages can then be quite large. If the message size really is a
+ serious issue, our per encoder should be used, as the ASN.1 PER
+ format is much more compact than all the other alternatives. Its
+ major drawback is that it is has not been approved as a valid
+ Megaco/H.248 message encoding.</p>
+
+ <p>When it comes to pure encode/decode performance, it turns out that:</p>
+ <list type="bulleted">
+ <item>
+ <p>our fastest binary encoder (ber) is about equal
+ to our fastest text encoder (compact). </p>
+ </item>
+ <item>
+ <p>our fastest binary decoder (ber) is about 47% (44%) faster than our
+ fastest text decoder (compact). </p>
+ </item>
+ </list>
+
+ <p>If the pure encode/decode performance really is a serious issue, our
+ erl_dist encoder could be used, as the encoding/decoding of the
+ erlang distribution format is much faster than all the other
+ alternatives. Its major drawback is that it is has not been approved
+ as a valid Megaco/H.248 message encoding.</p>
+
+ <p>There is no performance advantage of building (and using) a
+ non-reentrant flex scanner over a reentrant flex scanner (if flex
+ supports building such a scanner). </p>
+
+ <note>
+ <p>Please, observe that these performance figures are related to our
+ implementation in Erlang/OTP. Measurements of other implementations
+ using other tools and techniques may of course result in other
+ figures. </p>
+ </note>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_run.xml b/lib/megaco/doc/src/megaco_run.xml
new file mode 100644
index 0000000000..3afc638bcf
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_run.xml
@@ -0,0 +1,373 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Running the stack</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_run.xml</file>
+ </header>
+
+ <section>
+ <marker id="starting"></marker>
+ <title>Starting</title>
+ <p>A user may have a number of "virtual" connections to other
+ users. An MG is connected to at most one MGC, while an MGC may
+ be connected to any number of MG's. For each connection the user
+ selects a transport service, an encoding scheme and a user
+ callback module.</p>
+ <p>An MGC must initiate its transport service in order to listen
+ to MG's trying to connect. How the actual transport is initiated
+ is outside the scope of this application. However a send handle
+ (typically a socket id or host and port) must be provided from
+ the transport service in order to enable us to send the message
+ to the correct destination. We do however not assume anything
+ about this, from our point of view, opaque handle. Hopefully it
+ is rather small since it will passed around the system between
+ processes rather frequently.</p>
+ <p>A user may either be statically configured in a .config file
+ according to the application concept of Erlang/OTP or
+ dynamically started with the configuration settings as arguments
+ to megaco:start_user/2. These configuration settings may be
+ updated later on with megaco:update_conn_info/2.</p>
+ <p>The function megaco:connect/4 is used to tell the Megaco
+ application about which control process it should supervise,
+ which MID the remote user has, which callback module it should
+ use to send messages etc. When this "virtual" connection is
+ established the user may use megaco:call/3 and megaco:cast/3 in
+ order to send messages to the other side. Then it is up to the
+ MG to send its first Service Change Request message after
+ applying some clever algorithm in order to fight the problem
+ with startup avalanche (as discussed in the RFC).</p>
+ <p>The originating user will wait for a reply or a timeout
+ (defined by the request_timer). When it receives the reply this
+ will optionally be acknowledged (regulated by auto_ack), and
+ forwarded to the user. If an interim pending reply is received,
+ the long_request_timer will be used instead of the usual
+ request_timer, in order to enable avoidance of spurious re-sends
+ of the request.</p>
+ <p>On the destination side the transport service waits for
+ messages. Each message is forwarded to the Megaco application
+ via the megaco:receive_message/4 callback function. The
+ transport service may or may not provide means for blocking and
+ unblocking the reception of the incoming messages.</p>
+ <p></p>
+ <p>If a message is received before the "virtual" connection has
+ been established, the connection will be setup automatically. An
+ MGC may be real open minded and dynamically decide which
+ encoding and transport service to use depending on how the
+ transport layer contact is performed. For IP transports two
+ ports are standardized, one for textual encoding and one for
+ binary encoding. If for example an UDP packet was received on
+ the text port it would be possible to decide encoding and
+ transport on the fly.</p>
+ <p>After decoding a message various user callback functions are
+ invoked in order to allow the user to act properly. See the
+ megaco_user module for more info about the callback
+ arguments.</p>
+ <p>When the user has processed a transaction request in its
+ callback function, the Megaco application assembles a
+ transaction reply, encodes it using the selected encoding module
+ and sends the message back by invoking the callback
+ function:</p>
+ <list type="bulleted">
+ <item>
+ <p>SendMod:send_message(SendHandle, ErlangBinary)</p>
+ </item>
+ </list>
+ <p>Re-send of messages, handling pending transactions,
+ acknowledgements etc. is handled automatically by the Megaco
+ application but the user is free to override the default
+ behaviour by the various configuration possibilities. See
+ megaco:update_user_info/2 and megaco:update_conn_info/2 about
+ the possibilities.</p>
+ <p>When connections gets broken (that is explicitly by
+ megaco:disconnect/2 or when its controlling process dies) a user
+ callback function is invoked in order to allow the user to
+ re-establish the connection. The internal state of kept
+ messages, re-send timers etc. is not affected by this. A few
+ re-sends will of course fail while the connection is down, but
+ the automatic re-send algorithm does not bother about this and
+ eventually when the connection is up and running the messages
+ will be delivered if the timeouts are set to be long enough. The
+ user has the option of explicitly invoking megaco:cancel/2 to
+ cancel all messages for a connection.</p>
+ </section>
+
+ <section>
+ <marker id="mgc_startup_call_flow"></marker>
+ <title>MGC startup call flow</title>
+ <p>In order to prepare the MGC for the reception of the initial
+ message, hopefully a Service Change Request, the following needs
+ to be done:</p>
+ <list type="bulleted">
+ <item>
+ <p>Start the Megaco application.</p>
+ </item>
+ <item>
+ <p>Start the MGC user. This may either be done explicitly
+ with megaco:start_user/2 or implicitly by providing the -megaco
+ users configuration parameter.</p>
+ </item>
+ <item>
+ <p>Initiate the transport service and provide it with a
+ receive handle obtained from megaco:user_info/2.</p>
+ </item>
+ </list>
+ <p>When the initial message arrives the transport service
+ forwards it to the protocol engine which automatically
+ sets up the connection and invokes UserMod:handle_connect/2
+ before it invokes UserMod:handle_trans_request/3 with
+ the Service Change Request like this:</p>
+ <image file="MGC_startup_call_flow.gif">
+ <icaption>MGC Startup Call Flow</icaption>
+ </image>
+ </section>
+
+ <section>
+ <marker id="mg_startup_call_flow"></marker>
+ <title>MG startup call flow</title>
+ <p>In order to prepare the MG for the sending of the initial
+ message, hopefully a Service Change Request, the following needs
+ to be done:</p>
+ <list type="bulleted">
+ <item>
+ <p>Start the Megaco application.</p>
+ </item>
+ <item>
+ <p>Start the MG user. This may either be done explicitly
+ with megaco:start_user/2 or implicitly by providing the -megaco
+ users configuration parameter.</p>
+ </item>
+ <item>
+ <p>Initiate the transport service and provide it with a
+ receive handle obtained from megaco:user_info/2.</p>
+ </item>
+ <item>
+ <p>Setup a connection to the MGC with megaco:connect/4 and
+ provide it with a receive handle obtained from
+ megaco:user_info/2.</p>
+ </item>
+ </list>
+ <p>If the MG has been provisioned with the MID of the MGC it can
+ be given as the RemoteMid parameter to megaco:connect/4 and the
+ call flow will look like this:</p>
+ <image file="MG_startup_call_flow.gif">
+ <icaption>MG Startup Call Flow</icaption>
+ </image>
+ <p>If the MG cannot be provisioned with the MID of the MGC, the
+ MG can use the atom 'preliminary_mid' as the RemoteMid parameter
+ to megaco:connect/4 and the call flow will look like this:</p>
+ <image file="MG-startup_flow_noMID.gif">
+ <icaption>MG Startup Call Flow (no MID)</icaption>
+ </image>
+ </section>
+
+ <section>
+ <marker id="config_megaco"></marker>
+ <title>Configuring the Megaco stack</title>
+ <p>There are three kinds of configuration:</p>
+ <list type="bulleted">
+ <item>
+ <p>User info - Information related to megaco users. Read/Write. </p>
+ <p>A User is an entity identified by a MID, e.g. a MGC or a MG. </p>
+ <p>This information can be retrieved using
+ <seealso marker="megaco#user_info">megaco:user_info</seealso>. </p>
+ </item>
+ <item>
+ <p>Connection info - Information regarding connections. Read/Write.</p>
+ <p>This information can be retrieved using
+ <seealso marker="megaco#conn_info">megaco:conn_info</seealso>. </p>
+ </item>
+ <item>
+ <p>System info - System wide information. Read only.</p>
+ <p>This information can be retrieved using
+ <seealso marker="megaco#system_info">megaco:system_info</seealso>. </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="initial_config"></marker>
+ <title>Initial configuration</title>
+ <p>The initial configuration of the Megaco should be defined in the
+ Erlang system configuration file. The following configured parameters
+ are defined for the Megaco application:</p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[users = [{Mid, [user_config()]}].]]></c></p>
+ <p>Each user is represented by a tuple with the Mid of the user and a
+ list of config parameters (each parameter is in turn a tuple:
+ <c><![CDATA[{Item, Value}]]></c>).</p>
+ </item>
+ <item>
+ <p><c><![CDATA[scanner = flex | {Module, Function, Arguments, Modules}]]></c></p>
+<!--
+ For future use
+ <p><c><![CDATA[scanner = flex | {flex, Opts} | {Module, Function, Arguments, Modules}]]></c></p>
+-->
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[flex]]></c> will result in the start of the flex scanner with default
+ options.</p>
+ </item>
+<!--
+ For future use
+ <item>
+ <p><c><![CDATA[{flex, Opts}]]></c> will result in the start of the flex scanner with the
+ specified options. <c>Opts</c> is two-tuple list where the only allowed option is
+ <c>{smp, boolean()}</c>, with default value being <c>false</c> and the value of
+ <c>true</c> resulting in a start of an smp-optimized scanner. </p>
+ </item>
+-->
+ <item>
+ <p>The MFA alternative makes it possible for Megaco to start and
+ supervise a scanner written by the user (see
+ <c><![CDATA[supervisor:start_child]]></c> for an explanation of the
+ parameters).</p>
+ </item>
+ </list>
+ </item>
+ </list>
+ <p>See also <seealso marker="megaco_encode#text_config">Configuration of text encoding module(s)</seealso>
+ for more info. </p>
+ </section>
+
+ <section>
+ <marker id="changing_config"></marker>
+ <title>Changing the configuration</title>
+ <p>The configuration can be changed during runtime. This is done with
+ the functions <seealso marker="megaco#update_user_info">megaco:update_user_info</seealso> and
+ <seealso marker="megaco#update_conn_info">megaco:update_conn_info</seealso></p>
+ </section>
+
+ <section>
+ <marker id="transaction_sender"></marker>
+ <title>The transaction sender</title>
+ <p>The transaction sender is a process (one per connection), which handle
+ all transaction sending, if so configured (see
+ <seealso marker="megaco#user_info">megaco:user_info</seealso> and
+ <seealso marker="megaco#conn_info">megaco:conn_info</seealso>).</p>
+ <p>The purpose of the transaction sender is to accumulate transactions
+ for a more efficient message sending. The transactions that are
+ accumulated are transaction request and transaction ack. For
+ transaction ack's the benefit is quite large, since the transactions
+ are small and it is possible to have ranges (which means that
+ transaction acks for transactions 1, 2, 3 and 4 can be sent as a
+ range 1-4 in one transaction ack, instead of four separate
+ transactions). </p>
+ <p>There are a number of configuration parameter's that control the
+ operation of the transaction sender. In principle, a message with
+ everything stored (ack's and request's) is sent from the process
+ when:</p>
+ <list type="bulleted">
+ <item>
+ <p>When <c><![CDATA[trans_timer]]></c> expires.</p>
+ </item>
+ <item>
+ <p>When <c><![CDATA[trans_ack_maxcount]]></c> number of ack's has been
+ received.</p>
+ </item>
+ <item>
+ <p>When <c><![CDATA[trans_req_maxcount]]></c> number of requests's has
+ been received.</p>
+ </item>
+ <item>
+ <p>When the size of all received requests exceeds
+ <c><![CDATA[trans_req_maxsize]]></c>.</p>
+ </item>
+ <item>
+ <p>When a reply transaction is sent.</p>
+ </item>
+ <item>
+ <p>When a pending transaction is sent.</p>
+ </item>
+ </list>
+ <p>When something is to be sent, everything is packed into one message,
+ unless the trigger was a reply transaction and the added size of the
+ reply and all the requests is greater then
+ <c><![CDATA[trans_req_maxsize]]></c>, in which case the stored
+ transactions are sent first in a separate message and the reply in
+ another message.</p>
+ <p>When the transaction sender receives a request which is already
+ "in storage" (indicated by the transaction id) it is assumed to
+ be a resend and everything stored is sent. This could happen if
+ the values of the <c><![CDATA[trans_timer]]></c> and the
+ <c><![CDATA[request_timer]]></c> is not properly choosen.</p>
+ </section>
+
+ <section>
+ <marker id="segment_reply"></marker>
+ <title>Segmentation of transaction replies</title>
+ <p>In version 3 of the megaco standard the Segmentation package was
+ introduced. Simply, this package defines a procedure to segment
+ megaco messages (transaction replies) when using a transport that
+ does not automatically do this (e.g. UDP). See also
+ <seealso marker="megaco_encode#handling_versions">version3</seealso>.</p>
+ <p>Although it would be both pointless and counterproductive to use
+ segmentation on a transport that already does this (e.g. TCP), the
+ megaco application does not check this. Instead, it is up to the
+ user to configure this properly. </p>
+ <list type="bulleted">
+ <item>
+ <p>Receiving segmented messages: </p>
+ <p>This is handled automatically by the megaco application.
+ There is however one thing that need to be configured by the user,
+ the
+ <seealso marker="megaco#user_info">segment_recv_timer</seealso>
+ option. </p>
+ <p>Note that the segments are delivered to the user differently
+ depending on which function is used to issue the original request.
+ When issuing the request using the
+ <seealso marker="megaco#cast">megaco:cast</seealso> function,
+ the segments are delivered to the user via the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>
+ callback function one at a time, as they arrive. But this obviously
+ doe not work for the
+ <seealso marker="megaco#call">megaco:call</seealso> function.
+ In this case, the segments are accumulated and then delivered
+ all at once as the function returns.</p>
+ </item>
+ <item>
+ <p>Sending segmented messages: </p>
+ <p>This is also handled automatically by the megaco application.
+ First of all, segmentation is only attempted if so configured, see
+ the <seealso marker="megaco#user_info">segment_send</seealso> option.
+ Secondly, megaco relies on the ability of the used codec to
+ encode action replies, which is the smallest component the
+ megaco application handles when segmenting. Thirdly, the
+ reply will be segmented only if the sum of the size of the
+ action replies (plus an arbitrary message header size) are greater
+ then the specified max message size (see the
+ <seealso marker="megaco#user_info">max_pdu_size</seealso> option).
+ Finally, if segmentation is decided, then each action reply
+ will make up it's own (segment) message.</p>
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_sys_arch.gif b/lib/megaco/doc/src/megaco_sys_arch.gif
new file mode 100644
index 0000000000..961afb148f
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_sys_arch.gif
Binary files differ
diff --git a/lib/megaco/doc/src/megaco_sys_arch.ps b/lib/megaco/doc/src/megaco_sys_arch.ps
new file mode 100644
index 0000000000..b25035aadf
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_sys_arch.ps
@@ -0,0 +1,18674 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: /clearcase/cslab/megaco/doc/src/megaco_sys_arch.ps
+%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley
+%%BoundingBox: 57 194 539 647
+%%Pages: 1
+%%DocumentFonts:
+%%EndComments
+%%EndProlog
+
+%%Page: 1 1
+
+% remember original state
+/origstate save def
+
+% build a temporary dictionary
+20 dict begin
+
+% define string to hold a scanline's worth of data
+/pix 1446 string def
+
+% define space for color conversions
+/grays 482 string def % space for gray scale line
+/npixls 0 def
+/rgbindx 0 def
+
+% lower left corner
+57 194 translate
+
+% size of image (on paper, in 1/72inch coords)
+481.96800 453.02400 scale
+
+% define 'colorimage' if it isn't defined
+% ('colortogray' and 'mergeprocs' come from xwd2ps
+% via xgrab)
+/colorimage where % do we know about 'colorimage'?
+ { pop } % yes: pop off the 'dict' returned
+ { % no: define one
+ /colortogray { % define an RGB->I function
+ /rgbdata exch store % call input 'rgbdata'
+ rgbdata length 3 idiv
+ /npixls exch store
+ /rgbindx 0 store
+ 0 1 npixls 1 sub {
+ grays exch
+ rgbdata rgbindx get 20 mul % Red
+ rgbdata rgbindx 1 add get 32 mul % Green
+ rgbdata rgbindx 2 add get 12 mul % Blue
+ add add 64 idiv % I = .5G + .31R + .18B
+ put
+ /rgbindx rgbindx 3 add store
+ } for
+ grays 0 npixls getinterval
+ } bind def
+
+ % Utility procedure for colorimage operator.
+ % This procedure takes two procedures off the
+ % stack and merges them into a single procedure.
+
+ /mergeprocs { % def
+ dup length
+ 3 -1 roll
+ dup
+ length
+ dup
+ 5 1 roll
+ 3 -1 roll
+ add
+ array cvx
+ dup
+ 3 -1 roll
+ 0 exch
+ putinterval
+ dup
+ 4 2 roll
+ putinterval
+ } bind def
+
+ /colorimage { % def
+ pop pop % remove 'false 3' operands
+ {colortogray} mergeprocs
+ image
+ } bind def
+ } ifelse % end of 'false' case
+
+
+
+482 453 8 % dimensions of data
+[482 0 0 -453 0 453] % mapping matrix
+{currentfile pix readhexstring pop}
+false 3 colorimage
+
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0000000000000
+000000000000c0c0c0000000000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0000000000000000000000000
+c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000c0c0c0c0c0c0000000000000000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000c0c0c0c0c0c0000000000000000000000000c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000000000000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000000000c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000000000000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000000000000000c0c0c0000000000000c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0000000000000000000000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeee996666c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0eeeeeeeeeeeeccccccbbbbbbccccccddddddeeeeeeeeeeeec0c0c0
+eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+eeeeeec0c0c0c0c0c0ddddddbbbbbbbbbbbbaaaaaaaaaaaa888888ddddddeeeeeeeeeeee
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0eeeeeebbbbbbaaaaaaaaaaaaaaaaaaaaaaaa888888777777c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0eeeeeeaaaaaadddddd999999aaaaaaaaaaaaaaaaaa777777777777ccccccc0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0ccccccbbbbbbccccccaaaaaa999999bbbbbb888888777777666666888888cccccc
+ccccccddddddeeeeeeeeeeeeeeeeeeeeeeeec0c0c0eeeeeeeeeeeeeeeeeec0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0ccccccaaaaaacc9999999999999999aaaaaa999999996666777777777777bbbbbb
+aaaaaa999999bbbbbbccccccbbbbbb999999aaaaaabbbbbbbbbbbbaaaaaa999999aaaaaa
+cccc99aaaaaaaaaaaabbbbbbbbbbbbaaaaaaaaaaaaccccccccccccccccccbbbbbbcccccc
+ccccccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ddddddbbbbbbaaaaaabbbbbbcc9999999999aaaaaaaaaaaa996666555555888888bbbbbb
+999966999999999999ccccccbbbbbb999999aaaaaabbbbbbcccc99888888999999aaaaaa
+aaaaaaddddddddddddddddddccccccaaaaaa999999aaaaaabbbbbbcc9999bbbbbb999999
+aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+aaaaaa888888ccccccbbbbbb999999888888aaaaaa999999777777777777666666aaaaaa
+999999888888999999aaaaaabbbbbb999966aaaaaaaaaaaabbbbbb888888996666888888
+999999999999999999aaaaaabbbbbbbbbbbb888888aaaaaa999999bbbbbbaaaaaa888888
+999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0dddddd
+777777666666888888999999aaaaaa888888999999888888666666444444666666888888
+666666996666999999999999777777777777aaaaaa666666999999bbbbbbaaaaaa999999
+aaaaaa999966996666ccccccbbbbbbaaaaaaaaaaaa888888888888aaaaaa996666999999
+999999bbbbbbc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000000000000000000000
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999999
+777777777777999999aaaaaaaaaaaa999999999999999999999966666633666666aaaaaa
+999966888888996699bbbbbb888888888888888888777777888888888888996666888888
+cc9999888888666666bbbbbbaaaaaabbbbbb999999888888888888bbbbbb888888777777
+888888aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0aaaaaa
+666666888888999999aaaaaa999999888888aaaaaa888888777777666666666666999999
+996666996666777777888888999999999999999999999999999966888888999999aaaaaa
+aaaaaa999966999999ccccccbbbbbb999999999999888888999999bbbbbb999999999999
+888888aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999999
+9966668888888888889999999999999999999999cc888888666666555555777777777777
+996666996666555555666666777777996666777777777777999999999999bbbbbbbbbbbb
+bbbbbbbbbbbbccccccccccccccccccddddddaaaaaabbbbbbcccccccccccc999966888888
+999999aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeee999999
+666666777777888888aaaaaaaaaaaa999999999999888888996666555555666666888888
+888888aaaaaa666666999999999999999966999999999999aaaaaacc9999777777aaaaaa
+999999cc9999bbbbbbbbbbbb999999bbbbbbdddddd999999aaaaaacccc99999966996666
+777777999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0666699663366bbbbbb663333888888
+996666666666555555999999999999888888999999888888888888555555555555888888
+888888996666777777444444888888777777999999999999999999999999888888999999
+bbbbbbaaaaaa666666999999bbbbbbcccc99999966888888cccccccccccc999966777777
+777777aaaaaaddddddffff66c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0aaaaaa999999
+555555666666777777999966999999777777999999888888996666444444996666888888
+888888666666666666999999777777666666777777777777999999999999999999999999
+aaaaaabbbbbb999999aaaaaa99cccccc9999999999777777bbbbbbcccc99999999996666
+777777888888aaaaaaddddddc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c09999ccaaaaaa
+777777666666888888aaaaaa999999996666999999669999888888555555666666888888
+996666888888777777555555888888777777999999777777888888bbbbbbaaaaaaaaaaaa
+bbbbbbaaaaaabbbbbb777777aaaaaacccccc999966cc9999ccccccbbbbbb999966666666
+666666888888c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999999888888
+888888666666888888999999aaaaaa888888999999666666999999555555666633666666
+996666666666444444666666666666666666666666888888888888999999999999aaaaaa
+ccccccaaaaaa888888999999aaaaaacc9999999999999999bbbbbbcccccc999966996666
+666666999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0aaaaaa999999
+777777777777666666999966bbbbbb777777777777777777888888444444666666777777
+888888777777996666555555777777999966777777666666888888999966999966aaaaaa
+bbbbbbbbbbbbbbbbbb999999aaaaaabbbbbb999999aaaaaabbbbbbbbbbbb777777666666
+777777999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0dddddd888888
+666666666666666666aaaaaa999999996666888888666666888888444444666633777777
+777777888888666666444444777777666666555555777777777777666666996666666666
+666666777777666666666666666666777777777777666666666666999999888888996666
+666666999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeeaaaaaa
+aaaaaa999999777777aaaaaaaaaaaa996666666666666666888888555555666633777777
+777777777777666633666666666666666633555555666666777777777777666666555555
+777777666666666633555555666666777777777777777777666666888888888888666666
+555555777777c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0bbbbbb
+996666999999555555aaaaaa999999777777666666666666888888555555666633777777
+888888666666663333555555888888777777666666666666666666777777999966666666
+777777666666555555555555444444666666996666996666777777777777999999666666
+555555999999c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeee
+996666777777555555aaaaaa888888777777777777777777777777444444666666555555
+777777666666666666555555666666777777555555555555888888666633666666666666
+666666666666996666777777555555666666999966666633555555888888777777666666
+555555aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+999999996666888888aaaaaa999999666666666666666666666666555555666633555555
+666666555555555555555555555555666666555555555555777777666666555555555555
+777777666666666666555555555555888888999966996666666666777777777777666666
+555555aaaaaac0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0000000000000000000000000000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+eeeeee999966777777999999888888666666666666555555666666444444555555666666
+666666aaaaaaaaaaaa888888555555999966666666777777555555999966888888555555
+888888888888996666666633555555888888888888666666777777999999888888777777
+555555ccccccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0dddddd444444888888aaaaaa888888666666555555666666555555666666555555
+777777666666666666555555444444666666666633666633555555666666888888444444
+777777666666996666666666666666666666777777999966555555777777666699666666
+666633eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+000000c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0bbbbbb666666777777888888666666555555444444555555444444444444
+555555666666663333444444555555444444555555666633444444666666555555555555
+555555666666555555555555555555555555666666666666555555777777555555777777
+666633eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0
+000000c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0cccccc666666444444555555999999cc9999eeeeeeeeeeee
+eeeeeeeeeeeeeeeeeeddddddeeeeeeeeeeeeeeeeeeeeeeeeddddddeeeeeeeeeeeecccccc
+eeeeeeeeeeeeeeeeeeddddddddddddeeeeeeeeeeeeeeeeeeddddddbbbbbbdddddddddddd
+eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999966eeeeeec0c0c0eeeeeec0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0000000000000000000000000000000000000c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0000000c0c0c0000000
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000
+c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000000000c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0eeeeee444444663333c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0eeeeee444444663333c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0333333ffffccffffccffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0333333ffffccffffccffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ffff99ffff99ffcc99ffffccffffccffff99777777ffffccffffcceeeeeec0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ffff99ffff99ffcc99ffffccffffccffff99777777ffffccffffcceeeeeec0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ff9999
+ffcc66cccc99ffcc99663333663333666633ffffcccc99cc9999cc9999ccddddddc0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ff9999
+ffcc66cccc99ffcc99663333663333666633ffffcccc99cc9999cc9999ccddddddc0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0ffcc99cc9966
+cc9966aaaaaa444444ffcc99ffff99ffff99dddddd9999cc9999cc9999cc9999cccccccc
+c0c0c0ffffccffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0ffcc99cc9966
+cc9966aaaaaa444444ffcc99ffff99ffff99dddddd9999cc9999cc9999cc9999cccccccc
+c0c0c0ffffccffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeeeeeeeecc9933cc9966cc9933
+996666666633cc9966ff9966ffff99cccc66cccc99666633ffcc99cccc99ffffccffffcc
+ff9966ff9966ffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0eeeeeeeeeeeecc9933cc9966cc9933
+996666666633cc9966ff9966ffff99cccc66cccc99666633ffcc99cccc99ffffccffffcc
+ff9966ff9966ffffccc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999966996633999933996633999933996666
+663333cc9966cc9933cc9966663333ffcc99999966ffcc99ffff99ffff99ffff99cc9999
+cc9966663333eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0999966996633999933996633999933996666
+663333cc9966cc9933cc9966663333ffcc99999966ffcc99ffff99ffff99ffff99cc9999
+cc9966663333eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0eeeeee999933ffffccc0c0c0666633666633666633663333
+996633cccc66996633996633ffcc99cccc66cccc99996666ffcc66ffcc66cc9966996633
+333333333333c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0eeeeee999933ffffccc0c0c0666633666633666633663333
+996633cccc66996633996633ffcc99cccc66cccc99996666ffcc66ffcc66cc9966996633
+333333333333c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0666633c0c0c0c0c0c0c0c0c0666633333333444444333333
+996633996633cc9933cccc66996633ffcc99666633ffcc99cc9966996633663333333333
+333333444444c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0666633c0c0c0c0c0c0c0c0c0666633333333444444333333
+996633996633cc9933cccc66996633ffcc99666633ffcc99cc9966996633663333333333
+333333444444c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0ddddddffccccc0c0c0c0c0c0dddddd663333333333333333663333
+663333cccc33996633999933ffcc99996633cccc66999933993333333333333333333333
+cccc99c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0ddddddffccccc0c0c0c0c0c0dddddd663333333333333333663333
+663333cccc33996633999933ffcc99996633cccc66999933993333333333333333333333
+cccc99c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0cccc99c0c0c099cccc996633663333333333666633dddddd
+cccc66666633996633cc9966996633999933996633663333333333333333999966c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0cccc99c0c0c099cccc996633663333333333666633dddddd
+cccc66666633996633cc9966996633999933996633663333333333333333999966c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0ffffcccccc66c0c0c0ffffcccccc66663333666633663333
+666633996633cc9966666633996633663333333333333333cccc99c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0ffffcccccc66c0c0c0ffffcccccc66663333666633663333
+666633996633cc9966666633996633663333333333333333cccc99c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ccff99996633
+66333366333366663366663333333333333399cc66c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ccff99996633
+66333366333366663366663333333333333399cc66c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ffffcc996633666633333333996633eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ffffcc996633666633333333996633eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0eeeeeec0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0
+
+showpage
+
+% stop using temporary dictionary
+end
+
+% restore original state
+origstate restore
+
+%%Trailer
diff --git a/lib/megaco/doc/src/megaco_tcp.xml b/lib/megaco/doc/src/megaco_tcp.xml
new file mode 100644
index 0000000000..f4ccd97cee
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_tcp.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_tcp</title>
+ <prepared>Lars Thors&eacute;n</prepared>
+ <responsible>Lars Thors&eacute;n</responsible>
+ <docno></docno>
+ <approved>Lars Thors&eacute;n</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_tcp.xml</file>
+ </header>
+ <module>megaco_tcp</module>
+ <modulesummary>Interface module to TPKT transport protocol for Megaco/H.248.</modulesummary>
+ <description>
+ <p>This module contains the public interface to the TPKT (TCP/IP) version
+ transport protocol for Megaco/H.248.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>start_transport() -> {ok, TransportRef}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TransportRef = pid()</v>
+ </type>
+ <desc>
+ <p>This function is used for starting the TCP/IP transport service.
+ Use exit(TransportRef, Reason) to stop the transport service.</p>
+ </desc>
+ </func>
+ <func>
+ <name>listen(TransportRef, ListenPortSpecList) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TransportRef = pid() | regname()</v>
+ <v>OptionListPerPort = [Option]</v>
+ <v>Option = {port, integer()} |{options, list()} |{receive_handle, term()}</v>
+ </type>
+ <desc>
+ <p>This function is used for starting new TPKT listening socket
+ for TCP/IP. The option list contains the socket
+ definitions.</p>
+ </desc>
+ </func>
+ <func>
+ <name>connect(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TransportRef = pid() | regname()</v>
+ <v>OptionList = [Option]</v>
+ <v>Option = {host, Ipaddr} | {port, integer()} |{options, list()} |{receive_handle, term()} |{module, atom()}</v>
+ <v>Handle = socket_handle()</v>
+ <v>ControlPid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This function is used to open a TPKT connection.</p>
+ <p>The <c><![CDATA[module]]></c> option makes it possible for the user to provide
+ their own callback module. The <c><![CDATA[receive_message/4]]></c> or
+ <c><![CDATA[process_received_message/4]]></c> functions of this module is called
+ when a new message is received (which one depends on the size of the
+ message; small - receive_message, large - process_received_message).
+ Default value is <em>megaco</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>close(Handle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ </type>
+ <desc>
+ <p>This function is used for closing an active TPKT connection.</p>
+ </desc>
+ </func>
+ <func>
+ <name>socket(Handle) -> Socket</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ <v>Socket = inet_socket()</v>
+ </type>
+ <desc>
+ <p>This function is used to convert a socket_handle() to
+ a inet_socket(). inet_socket() is a plain socket,
+ see the inet module for more info.</p>
+ </desc>
+ </func>
+ <func>
+ <name>send_message(Handle, Message) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ <v>Message = binary() | iolist()</v>
+ </type>
+ <desc>
+ <p>Sends a message on a connection.</p>
+ </desc>
+ </func>
+ <func>
+ <name>block(Handle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ </type>
+ <desc>
+ <p>Stop receiving incoming messages on the socket.</p>
+ </desc>
+ </func>
+ <func>
+ <name>unblock(Handle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ </type>
+ <desc>
+ <p>Starting to receive incoming messages from the socket again.</p>
+ <marker id="upgrade_receive_handle"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>upgrade_receive_handle(ControlPid) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>ControlPid = pid()</v>
+ </type>
+ <desc>
+ <p>Update the receive handle of the control process (e.g. after
+ having changed protocol version).</p>
+ <marker id="stats"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
+ <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TotalStats = [send_handle_stats()]</v>
+ <v>total_stats() = {send_handle(), [stats()]}</v>
+ <v>SendHandle = send_handle()</v>
+ <v>SendHandleStats = [stats()]</v>
+ <v>Counter = tcp_stats_counter()</v>
+ <v>CounterStats = integer()</v>
+ <v>stats() = {tcp_stats_counter(), integer()}</v>
+ <v>tcp_stats_counter() = medGwyGatewayNumInMessages | medGwyGatewayNumInOctets | medGwyGatewayNumOutMessages | medGwyGatewayNumOutOctets | medGwyGatewayNumErrors</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retreive the TCP related (SNMP) statistics counters.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reset_stats() -> void()</name>
+ <name>reset_stats(SendHandle) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>SendHandle = send_handle()</v>
+ </type>
+ <desc>
+ <p>Reset all TCP related (SNMP) statistics counters.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_transport.xml b/lib/megaco/doc/src/megaco_transport.xml
new file mode 100644
index 0000000000..66ef85ff25
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_transport.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_transport</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>Micael Karlberg</responsible>
+ <docno></docno>
+ <approved>Micael Karlberg</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_transport.xml</file>
+ </header>
+ <module>megaco_transport</module>
+ <modulesummary>Megaco transport behaviour.</modulesummary>
+ <description>
+ <p>The following functions should be exported from a
+ <c><![CDATA[megaco_transport]]></c> callback module:</p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#send_message">send_message/2</seealso> [<c><![CDATA[mandatory]]></c>]</p>
+ </item>
+ <item>
+ <p><seealso marker="#send_message">send_message/3</seealso> [<c>optional</c>]</p>
+ </item>
+ <item>
+ <p><seealso marker="#resend_message">resend_message/2</seealso> [<c><![CDATA[optional]]></c>]</p>
+ </item>
+ <item>
+ </item>
+ </list>
+ <marker id="send_message"></marker>
+ </description>
+ <funcs>
+ <func>
+ <name>Module:send_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
+ <name>Module:send_message(Handle, Msg, Resend) -> ok | {cancel, Reason} | Error</name>
+ <fsummary>Send a megaco message.</fsummary>
+ <type>
+ <v>Handle = term()</v>
+ <v>Msg = binary() | iolist()</v>
+ <v>Resend = boolean()</v>
+ <v>Reason = term()</v>
+ <v>Error = term()</v>
+ </type>
+ <desc>
+ <p>Send a megaco message. </p>
+ <p>If the function returns <c><![CDATA[{cancel, Reason}]]></c>,
+ this means the transport module decided not to send the message.
+ This is <em>not</em> an error. No error messages will be issued
+ and no error counters incremented.
+ What actions this will result in depends on what kind of
+ message was sent.
+ </p>
+ <p>In the case of requests, megaco will cancel the message in much
+ the same way as if <c><![CDATA[megaco:cancel]]></c> had been called
+ (after a successfull send). The information will be propagated
+ back to the user differently depending on how the request(s) where
+ issued: For requests issued using
+ <seealso marker="megaco#call">megaco:call</seealso>, the info
+ will be delivered in the return value. For requests issued
+ using <c><![CDATA[megaco:cast]]></c> the info will be delivered
+ via a call to the callback function
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>. </p>
+ <p>In the case of reply, megaco will cancel the reply and information
+ of this will be returned to the user via a call to the
+ callback function
+ <seealso marker="megaco_user#trans_ack">handle_trans_ack</seealso>. </p>
+
+ <p>The function <c>send_message/3</c> will only be called if the
+ <seealso marker="megaco#ui_resend_indication">resend_indication</seealso>
+ config option has been set to the value <c>flag</c>. The third
+ argument, <c>Resend</c> then indicates if the message send is
+ a resend or not. </p>
+
+ <marker id="resend_message"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:resend_message(Handle, Msg) -> ok | {cancel, Reason} | Error</name>
+ <fsummary>Re-send a megaco message.</fsummary>
+ <type>
+ <v>Handle = term()</v>
+ <v>Msg = binary() | iolist()</v>
+ <v>Reason = term()</v>
+ <v>Error = term()</v>
+ </type>
+ <desc>
+ <p>Re-send a megaco message. </p>
+ <p>Note that this function will only be called if the user has set the
+ <seealso marker="megaco#ui_resend_indication">resend_indication</seealso>
+ config option to <c><![CDATA[true]]></c><em>and</em> it is in fact a message
+ resend. If not <em>both</em> of these condition's are meet,
+ <c><![CDATA[send_message]]></c> will be called. </p>
+ <p>If the function returns <c><![CDATA[{cancel, Reason}]]></c>, this means the
+ transport module decided not to send the message.
+ This is <em>not</em> an error. No error messages will be issued
+ and no error counters incremented.
+ What actions this will result in depends on what kind of
+ message was sent. </p>
+ <p>In the case of requests, megaco will cancel the message in much
+ the same way as if <c><![CDATA[megaco:cancel]]></c> had been called
+ (after a successfull send). The information will be propagated
+ back to the user differently depending on how the request(s) where
+ issued: For requests issued using
+ <seealso marker="megaco#call">megaco:call</seealso>, the info
+ will be delivered in the return value. For requests issued
+ using <c><![CDATA[megaco:cast]]></c> the info will be delivered via a call
+ to the callback function
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>. </p>
+ <p>In the case of reply, megaco will cancel the reply and information
+ of this will be returned to the user via a call to the
+ callback function
+ <seealso marker="megaco_user#trans_ack">handle_trans_ack</seealso>. </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_transport_mechanisms.xml b/lib/megaco/doc/src/megaco_transport_mechanisms.xml
new file mode 100644
index 0000000000..f384280561
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_transport_mechanisms.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Transport mechanisms</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_transport_mechanisms.xml</file>
+ </header>
+
+ <section>
+ <title>Callback interface</title>
+ <p>The callback interface of the transport module contains several
+ functions. Some of which are mandatory while others are only
+ optional: </p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[send_message]]></c> - Send a message. <em>Mandatory</em></p>
+ </item>
+ <item>
+ <p><c><![CDATA[block]]></c> - Block the transport. <em>Optional</em></p>
+ <p>This function is usefull for flow control.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[unblock]]></c> - Unblock the transport. <em>Optional</em></p>
+ </item>
+ </list>
+ <p>For more detail, see the
+ <seealso marker="megaco_transport">megaco_transport</seealso>
+ behaviour definition.</p>
+ </section>
+
+ <section>
+ <title>Examples</title>
+ <p>The Megaco/H.248 application contains implementations
+ for the two protocols specified by the Megaco/H.248 standard;
+ UDP, see <seealso marker="megaco_udp">megaco_udp</seealso>,
+ and TCP/TPKT, see <seealso marker="megaco_tcp">megaco_tcp</seealso>. </p>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/megaco_udp.xml b/lib/megaco/doc/src/megaco_udp.xml
new file mode 100644
index 0000000000..ed554659b7
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_udp.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_udp</title>
+ <prepared>Lars Thors&eacute;n</prepared>
+ <responsible>Lars Thors&eacute;n</responsible>
+ <docno></docno>
+ <approved>Lars Thors&eacute;n</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_udp.xml</file>
+ </header>
+ <module>megaco_udp</module>
+ <modulesummary>Interface module to UDP transport protocol for Megaco/H.248.</modulesummary>
+ <description>
+ <p>This module contains the public interface to the UDP/IP version
+ transport protocol for Megaco/H.248.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>start_transport() -> {ok, TransportRef}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TransportRef = pid()</v>
+ </type>
+ <desc>
+ <p>This function is used for starting the UDP/IP transport service.
+ Use exit(TransportRef, Reason) to stop the transport service.</p>
+ </desc>
+ </func>
+ <func>
+ <name>open(TransportRef, OptionList) -> {ok, Handle, ControlPid} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TransportRef = pid() | regname()</v>
+ <v>OptionList = [option()]</v>
+ <v>option() = {port, integer()} |{options, list()} |{receive_handle, receive_handle()} |{module, atom()}</v>
+ <v>Handle = socket_handle()</v>
+ <v>receive_handle() = term()</v>
+ <v>ControlPid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This function is used to open an UDP/IP socket.</p>
+ <p>The <c><![CDATA[module]]></c> option makes it possible for the user to provide
+ their own callback module. The functions <c><![CDATA[receive_message/4]]></c> or
+ <c><![CDATA[process_received_message/4]]></c> of this module is called when a new
+ message is received (which one depends on the size of the message;
+ small - receive_message, large - process_received_message).
+ Default value is <em>megaco</em>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>close(Handle, Msg) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ <v>Msg</v>
+ </type>
+ <desc>
+ <p>This function is used for closing an active UDP socket.</p>
+ </desc>
+ </func>
+ <func>
+ <name>socket(Handle) -> Socket</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ <v>Socket = inet_socket()</v>
+ </type>
+ <desc>
+ <p>This function is used to convert a socket_handle() to
+ a inet_socket(). inet_socket() is a plain socket,
+ see the inet module for more info.</p>
+ </desc>
+ </func>
+ <func>
+ <name>create_send_handle(Handle, Host, Port) -> send_handle()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ <v>Host = {A,B,C,D} | string()</v>
+ <v>Port = integer()</v>
+ </type>
+ <desc>
+ <p>Creates a send handle from a transport handle. The send
+ handle is intended to be used by megaco_udp:send_message/2.</p>
+ </desc>
+ </func>
+ <func>
+ <name>send_message(SendHandle, Msg) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>SendHandle = send_handle()</v>
+ <v>Message = binary() | iolist()</v>
+ </type>
+ <desc>
+ <p>Sends a message on a socket. The send handle is obtained by
+ megaco_udp:create_send_handle/3. Increments the NumOutMessages
+ and NumOutOctets counters if message successfully sent. In case
+ of a failure to send, the NumErrors counter is <em>not</em>
+ incremented. This is done elsewhere in the megaco app.</p>
+ </desc>
+ </func>
+ <func>
+ <name>block(Handle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ </type>
+ <desc>
+ <p>Stop receiving incoming messages on the socket.</p>
+ </desc>
+ </func>
+ <func>
+ <name>unblock(Handle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>Handle = socket_handle()</v>
+ </type>
+ <desc>
+ <p>Starting to receive incoming messages from the socket again.</p>
+ <marker id="upgrade_receive_handle"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>upgrade_receive_handle(ControlPid, NewHandle) -> ok</name>
+ <fsummary></fsummary>
+ <type>
+ <v>ControlPid = pid()</v>
+ <v>NewHandle = receive_handle()</v>
+ <v>receive_handle() = term()</v>
+ </type>
+ <desc>
+ <p>Update the receive handle of the control process (e.g. after
+ having changed protocol version).</p>
+ <marker id="stats"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>get_stats() -> {ok, TotalStats} | {error, Reason}</name>
+ <name>get_stats(SendHandle) -> {ok, SendHandleStats} | {error, Reason}</name>
+ <name>get_stats(SendHandle, Counter) -> {ok, CounterStats} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>TotalStats = [total_stats()]</v>
+ <v>total_stats() = {send_handle(), [stats()]}</v>
+ <v>SendHandle = send_handle()</v>
+ <v>SendHandleStats = [stats()]</v>
+ <v>Counter = udp_stats_counter()</v>
+ <v>CounterStats = integer()</v>
+ <v>stats() = {udp_stats_counter(), integer()}</v>
+ <v>tcp_stats_counter() = medGwyGatewayNumInMessages | medGwyGatewayNumInOctets | medGwyGatewayNumOutMessages | medGwyGatewayNumOutOctets | medGwyGatewayNumErrors</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retreive the UDP related (SNMP) statistics counters.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reset_stats() -> void()</name>
+ <name>reset_stats(SendHandle) -> void()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>SendHandle = send_handle()</v>
+ </type>
+ <desc>
+ <p>Reset all TCP related (SNMP) statistics counters.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/megaco_user.xml b/lib/megaco/doc/src/megaco_user.xml
new file mode 100644
index 0000000000..37942007bc
--- /dev/null
+++ b/lib/megaco/doc/src/megaco_user.xml
@@ -0,0 +1,738 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>megaco_user</title>
+ <prepared>H&aring;kan Mattsson</prepared>
+ <responsible>H&aring;kan Mattsson</responsible>
+ <docno></docno>
+ <approved>H&aring;kan Mattsson</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>megaco_user.xml</file>
+ </header>
+ <module>megaco_user</module>
+ <modulesummary>Callback module for users of the Megaco application</modulesummary>
+ <description>
+ <p>This module defines the callback behaviour of Megaco users. A
+ megaco_user compliant callback module must export the following
+ functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#connect">handle_connect/2,3</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#disconnect">handle_disconnect/3</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#syntax_error">handle_syntax_error/3,4</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#message_error">handle_message_error/3,4</seealso></p>
+ </item>
+
+<!--
+ <item>
+ <p><seealso marker="#segment_error">handle_segment_error/4,5</seealso></p>
+ </item>
+-->
+
+ <item>
+ <p><seealso marker="#trans_request">handle_trans_request/3,4</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#trans_long_request">handle_trans_long_request/3,4</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#trans_reply">handle_trans_reply/4,5</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#trans_ack">handle_trans_ack/4,5</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#unexpected_trans">handle_unexpected_trans/3,4</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#request_abort">handle_trans_request_abort/4,5</seealso></p>
+ </item>
+
+ <item>
+ <p><seealso marker="#segment_reply">handle_segment_reply/5,6</seealso></p>
+ </item>
+ </list>
+
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>The <c><![CDATA[user_args]]></c> configuration parameter which may be used to
+ extend the argument list of the callback functions. For example,
+ the handle_connect function takes by default two arguments:</p>
+ <code type="none"><![CDATA[
+ handle_connect(Handle, Version)
+ ]]></code>
+ <p>but if the <c><![CDATA[user_args]]></c> parameter is set to a longer
+ list, such as <c><![CDATA[[SomePid,SomeTableRef]]]></c>, the callback
+ function is expected to have these (in this case two) extra
+ arguments last in the argument list:</p>
+ <code type="none"><![CDATA[
+ handle_connect(Handle, Version, SomePid, SomeTableRef)
+ ]]></code>
+
+ <marker id="extra_argument"></marker>
+ <note>
+ <p>Must of the functions below has an optional <c>Extra</c> argument (e.g.
+ <seealso marker="#unexpected_trans">handle_unexpected_trans/4</seealso>).
+ The functions which takes this argument will be called if and only if one
+ of the functions
+ <seealso marker="megaco#receive_message">receive_message/5</seealso> or
+ <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
+ was called with the <c>Extra</c> argument different than
+ <c>ignore_extra</c>. </p>
+ </note>
+
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+action_request() = #'ActionRequest'{}
+action_reply() = #'ActionReply'{}
+error_desc() = #'ErrorDescriptor'{}
+segment_no() = integer()
+ ]]></code>
+ <code type="none"><![CDATA[
+conn_handle() = #megaco_conn_handle{} ]]></code>
+ <p>The record initially returned by <c><![CDATA[megaco:connect/4,5]]></c>.
+ It identifies a "virtual" connection and may be reused after a
+ reconnect (disconnect + connect).</p>
+ <code type="none"><![CDATA[
+protocol_version() = integer() ]]></code>
+ <p>Is the actual protocol version. In most cases the protocol
+ version is retrieved from the processed message, but there
+ are exceptions:</p>
+ <p></p>
+ <list type="bulleted">
+ <item>
+ <p>When <c><![CDATA[handle_connect/2,3]]></c> is triggered by an
+ explicit call to <c><![CDATA[megaco:connect/4,5]]></c>.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[handle_disconnect/3]]></c></p>
+ </item>
+ <item>
+ <p><c><![CDATA[handle_syntax_error/3]]></c></p>
+ </item>
+ </list>
+ <p>In these cases, the ProtocolVersion default
+ version is obtained from the static connection
+ configuration:</p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[megaco:conn_info(ConnHandle, protocol_version)]]></c>.</p>
+ </item>
+ </list>
+ <marker id="connect"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>handle_connect(ConnHandle, ProtocolVersion) -> ok | error | {error,ErrorDescr}</name>
+ <name>handle_connect(ConnHandle, ProtocolVersion, Extra]) -> ok | error | {error,ErrorDescr}</name>
+ <fsummary>Invoked when a new connection is established</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>ErrorDescr = error_desc()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a new connection is established</p>
+ <p>Connections may either be established by an explicit call to
+ megaco:connect/4 or implicitly at the first invocation of
+ megaco:receive_message/3.</p>
+ <p>Normally a Media Gateway (MG) connects explicitly while a Media
+ Gateway Controller (MGC) connects implicitly.</p>
+ <p>At the Media Gateway Controller (MGC) side it is possible to reject
+ a connection request (and send a message error reply to the gateway)
+ by returning <c><![CDATA[{error, ErrorDescr}]]></c> or simply <c><![CDATA[error]]></c> which
+ generates an error descriptor with code 402 (unauthorized) and
+ reason "Connection refused by user" (this is also the case for all
+ unknown results, such as exit signals or throw).</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_message_error/4</c>. </p>
+
+ <p><c><![CDATA[handle_connect/3]]></c> (with <c><![CDATA[Extra]]></c>)
+ can also be called as a result of a call to the
+ <seealso marker="megaco#connect">megaco:connect/5</seealso> function
+ (if that function is called with the
+ <c>Extra</c> argument different than <c>ignore_extra</c>. </p>
+
+ <marker id="disconnect"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_disconnect(ConnHandle, ProtocolVersion, Reason) -> ok</name>
+ <fsummary>Invoked when a connection is teared down</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a connection is teared down</p>
+ <p>The disconnect may either be made explicitly by a call to
+ megaco:disconnect/2 or implicitly when the control process
+ of the connection dies.</p>
+
+ <marker id="syntax_error"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
+ <name>handle_syntax_error(ReceiveHandle, ProtocolVersion, DefaultED, Extra) -> reply | {reply, ED} | no_reply | {no_reply, ED} </name>
+ <fsummary>Invoked when a received message had syntax errors</fsummary>
+ <type>
+ <v>ReceiveHandle = receive_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>DefaultED = error_desc()</v>
+ <v>ED = error_desc()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a received message had syntax errors</p>
+ <p>Incoming messages is delivered by megaco:receive_message/4
+ and normally decoded successfully. But if the decoding
+ failed this function is called in order to decide if the
+ originator should get a reply message (reply) or if the reply
+ silently should be discarded (no_reply).</p>
+ <p>Syntax errors are detected locally on this side of the
+ protocol and may have many causes, e.g. a malfunctioning
+ transport layer, wrong encoder/decoder selected, bad
+ configuration of the selected encoder/decoder etc.</p>
+ <p>The error descriptor defaults to <c><![CDATA[DefaultED]]></c>,
+ but can be overridden with an alternate one by
+ returning <c><![CDATA[{reply,ED}]]></c> or <c><![CDATA[{no_reply,ED}]]></c>
+ instead of <c><![CDATA[reply]]></c> and <c><![CDATA[no_reply]]></c> respectively.
+ </p>
+ <p>Any other return values (including exit signals or throw) and the
+ <c><![CDATA[DefaultED]]></c> will be used. </p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_syntax_error/4</c>. </p>
+
+ <marker id="message_error"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr) -> ok</name>
+ <name>handle_message_error(ConnHandle, ProtocolVersion, ErrorDescr, Extra) -> ok</name>
+ <fsummary>Invoked when a received message just contains an error</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>ErrorDescr = error_desc()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a received message just contains an error
+ instead of a list of transactions.</p>
+ <p>Incoming messages is delivered by megaco:receive_message/4
+ and successfully decoded. Normally a message contains a list
+ of transactions, but it may instead contain an
+ ErrorDescriptor on top level of the message.</p>
+ <p>Message errors are detected remotely on the other side of
+ the protocol. And you probably don't want to reply to it,
+ but it may indicate that you have outstanding transactions
+ that not will get any response (request -&gt; reply; reply -&gt;
+ ack).</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_message_error/4</c>. </p>
+
+<!-- <marker id="segment_error"></marker> -->
+ <marker id="trans_request"></marker>
+ </desc>
+ </func>
+
+<!--
+ <func>
+ <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError) -> ok</name>
+ <name>handle_segment_error(ConnHandle, ProtocolVersion, TransId, SegmentError, Extra) -> ok</name>
+ <fsummary>Invoked when a segment error has been detected</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>TransId = integer()</v>
+ <v>SegmentError = {missing_segments, [integer()]}</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a segment error has been detected.</p>
+ <p><c><![CDATA[missing_segments]]></c> means that one or more
+ segments of a segmented message was not received in time.</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_segment_error/5</c>. </p>
+
+ <marker id="trans_request"></marker>
+ </desc>
+ </func>
+-->
+
+ <func>
+ <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) -> pending() | reply() | ignore_trans_request</name>
+ <name>handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) -> pending() | reply() | ignore_trans_request</name>
+ <fsummary>Invoked for each transaction request</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>ActionRequests = [action_request()]</v>
+ <v>Extra = term()</v>
+ <v>pending() = {pending, req_data()}</v>
+ <v>req_data() = term()</v>
+ <v>reply() = {ack_action(), actual_reply()} | {ack_action(), actual_reply(), send_options()} </v>
+ <v>ack_action() = discard_ack | {handle_ack, ack_data()} | {handle_pending_ack, ack_data()} | {handle_sloppy_ack, ack_data()}</v>
+ <v>actual_reply() = [action_reply()] | error_desc()</v>
+ <v>ack_data() = term()</v>
+ <v>send_options() = [send_option()]</v>
+ <v>send_option() = {reply_timer, megaco_timer()} | {send_handle, term()} | {protocol_version, integer()}</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked for each transaction request</p>
+ <p>Incoming messages is delivered by megaco:receive_message/4
+ and successfully decoded. Normally a message contains a list
+ of transactions and this function is invoked for each
+ TransactionRequest in the message.</p>
+ <p>This function takes a list of 'ActionRequest' records and
+ has three main options:</p>
+ <taglist>
+ <tag><c><![CDATA[Return ignore_trans_request]]></c></tag>
+ <item>
+ <p>Decide that these action requests shall be ignored
+ completely.</p>
+ </item>
+ <tag><c><![CDATA[Return pending()]]></c></tag>
+ <item>
+ <p>Decide that the processing of these action requests
+ will take a long time and that the originator should get
+ an immediate 'TransactionPending' reply as interim
+ response. The actual processing of these action requests
+ instead should be delegated to the the
+ handle_trans_long_request/3 callback function with the
+ req_data() as one of its arguments. </p>
+ </item>
+ <tag><c><![CDATA[Return reply()]]></c></tag>
+ <item>
+ <p>Process the action requests and either return an
+ error_descr() indicating some fatal error or a list of
+ action replies (wildcarded or not). </p>
+ <p>If for some reason megaco is unable to deliver the reply,
+ the reason for this will be passed to the user via a call
+ to the callback function
+ <seealso marker="#trans_ack">handle_trans_ack</seealso>,
+ unless <c><![CDATA[ack_action() = discard_ack]]></c>. </p>
+ <p>The ack_action() is either:</p>
+ <taglist>
+ <tag><c><![CDATA[discard_ack]]></c></tag>
+ <item>
+ <p>Meaning that you don't care if the reply is
+ acknowledged or not.</p>
+ </item>
+ <tag><c><![CDATA[{handle_ack, ack_data()} | {handle_ack, ack_data(), send_options()}]]></c></tag>
+ <item>
+ <p>Meaning that you want an immediate acknowledgement
+ when the other part receives this transaction
+ reply. When the acknowledgement eventually is
+ received, the handle_trans_ack/4 callback function
+ will be invoked with the ack_data() as one of its
+ arguments. ack_data() may be any Erlang term.</p>
+ </item>
+ <tag><c><![CDATA[{handle_pending_ack, ack_data()} | {handle_pending_ack, ack_data(), send_options()}]]></c></tag>
+ <item>
+ <p>This has the same effect as the above,
+ <em>if and only if</em> megaco has sent at least one
+ pending message for this request (during the processing
+ of the request). If no pending message has been sent, then
+ immediate acknowledgement will <em>not</em> be
+ requested. </p>
+ <p>Note that this only works as specified if the
+ <c><![CDATA[sent_pending_limit]]></c> config option has been set to
+ an integer value. </p>
+ </item>
+ <tag><c><![CDATA[{handle_sloppy_ack, ack_data()}| {handle_sloppy_ack, ack_data(), send_options()}]]></c></tag>
+ <item>
+ <p>Meaning that you want an acknowledgement <em>sometime</em>.
+ When the acknowledgement eventually is received, the
+ handle_trans_ack/4 callback function will be invoked with
+ the ack_data() as one of its arguments. ack_data() may be
+ any Erlang term.</p>
+ </item>
+ </taglist>
+ </item>
+ </taglist>
+ <p>Any other return values (including exit signals or throw) will
+ result in an error descriptor with code 500 (internal gateway error)
+ and the module name (of the callback module) as reason. </p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_trans_request/4</c>. </p>
+
+ <marker id="trans_long_request"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) -> reply()</name>
+ <name>handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra) -> reply()</name>
+ <fsummary>Optionally invoked for a time consuming transaction request</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>ReqData = req_data()</v>
+ <v>Extra = term()</v>
+ <v>req_data() = term()</v>
+ <v>reply() = {ack_action(), actual_reply()} | {ack_action(), actual_reply(), send_options()}</v>
+ <v>ack_action() = discard_ack | {handle_ack, ack_data()} | {handle_sloppy_ack, ack_data()}</v>
+ <v>actual_reply() = [action_reply()] | error_desc()</v>
+ <v>ack_data() = term()</v>
+ <v>send_options() = [send_option()]</v>
+ <v>send_option() = {reply_timer, megaco_timer()} | {send_handle, term()} | {protocol_version, integer()}</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Optionally invoked for a time consuming transaction request</p>
+ <p>If this function gets invoked or not is controlled by the
+ reply from the preceding call to handle_trans_request/3.
+ The handle_trans_request/3 function may decide to process
+ the action requests itself or to delegate the processing to
+ this function.</p>
+ <p>The req_data() argument to this function is the Erlang term
+ returned by handle_trans_request/3.</p>
+ <p></p>
+ <p>Any other return values (including exit signals or throw) will
+ result in an error descriptor with code 500 (internal gateway error)
+ and the module name (of the callback module) as reason. </p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_trans_long_request/4</c>. </p>
+
+ <marker id="trans_reply"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData) -> ok</name>
+ <name>handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, ReplyData, Extra) -> ok</name>
+ <fsummary>Optionally invoked for a transaction reply</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>UserReply = success() | failure()</v>
+ <v>success() = {ok, result()} </v>
+ <v>result() = transaction_result() | segment_result()</v>
+ <v>transaction_result() = action_reps()</v>
+ <v>segment_result() = {segment_no(), last_segment(), action_reps()}</v>
+ <v>action_reps() = [action_reply()]</v>
+ <v>failure() = {error, reason()}</v>
+ <v>reason() = transaction_reason() | segment_reason() | user_cancel_reason() | send_reason() | other_reason()</v>
+ <v>transaction_reason() = error_desc()</v>
+ <v>segment_reason() = {segment_no(), last_segment(), error_desc()}</v>
+ <v>other_reason() = timeout | {segment_timeout, missing_segments()} | exceeded_recv_pending_limit | term()</v>
+ <v>last_segment() = bool()</v>
+ <v>missing_segments() = [segment_no()]</v>
+ <v>user_cancel_reason() = {user_cancel, reason_for_user_cancel()}</v>
+ <v>reason_for_user_cancel() = term()</v>
+ <v>send_reason() = send_cancelled_reason() | send_failed_reason()</v>
+ <v>send_cancelled_reason() = {send_message_cancelled, reason_for_send_cancel()}</v>
+ <v>reason_for_send_cancel() = term()</v>
+ <v>send_failed_reason() = {send_message_failed, reason_for_send_failure()}</v>
+ <v>reason_for_send_failure() = term()</v>
+ <v>ReplyData = reply_data()</v>
+ <v>reply_data() = term()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Optionally invoked for a transaction reply</p>
+ <p>The sender of a transaction request has the option of
+ deciding, whether the originating Erlang process should
+ synchronously wait (<c><![CDATA[megaco:call/3]]></c>) for a reply or if the
+ message should be sent asynchronously (<c><![CDATA[megaco:cast/3]]></c>) and
+ the processing of the reply should be delegated this
+ callback function.</p>
+ <p>Note that if the reply is segmented (split into several smaller
+ messages; segments), then some extra info, segment number and
+ an indication if all segments of a reply has been received or
+ not, is also included in the <c><![CDATA[UserReply]]></c>. </p>
+ <p>The <c><![CDATA[ReplyData]]></c> defaults to
+ <c><![CDATA[megaco:lookup(ConnHandle, reply_data)]]></c>,
+ but may be explicitely overridden by a
+ <c><![CDATA[megaco:cast/3]]></c> option in order to forward info about the
+ calling context of the originating process.</p>
+ <p>At <c><![CDATA[success()]]></c>, the <c><![CDATA[UserReply]]></c> either contains:</p>
+ <list type="bulleted">
+ <item>
+ <p>A list of 'ActionReply' records possibly containing
+ error indications.</p>
+ </item>
+ <item>
+ <p>A tuple of size three containing:
+ the segment number,
+ the <c><![CDATA[last segment indicator]]></c> and finally
+ a list of 'ActionReply' records possibly containing error
+ indications. This is of course only possible if the
+ reply was segmented. </p>
+ </item>
+ </list>
+ <p><c><![CDATA[failure()]]></c> indicates an local or external error and
+ can be one of the following: </p>
+ <list type="bulleted">
+ <item>
+ <p>A <c><![CDATA[transaction_reason()]]></c>, indicates that the remote
+ user has replied with an explicit transactionError.</p>
+ </item>
+ <item>
+ <p>A <c><![CDATA[segment_reason()]]></c>, indicates that the remote user
+ has replied with an explicit transactionError for this
+ segment. This is of course only possible if the reply was
+ segmented. </p>
+ </item>
+ <item>
+ <p>A <c><![CDATA[user_cancel_reason()]]></c>, indicates that the request
+ has been canceled by the user. <c><![CDATA[reason_for_user_cancel()]]></c>
+ is the reason given in the call to the
+ <seealso marker="megaco#cancel">cancel</seealso>
+ function.</p>
+ </item>
+ <item>
+ <p>A <c><![CDATA[send_reason()]]></c>, indicates that the transport module
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function did not send the message. The reason for this can be: </p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[send_cancelled_reason()]]></c> - the message sending was
+ deliberately cancelled. <c><![CDATA[reason_for_send_cancel()]]></c>
+ is the reason given in the <c><![CDATA[cancel]]></c> return
+ from the
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ function. </p>
+ </item>
+ <item>
+ <p><c><![CDATA[send_failed_reason()]]></c> - an error occurred while attempting to
+ send the message. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p>An <c><![CDATA[other_reason()]]></c>, indicates some other error such
+ as: </p>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[timeout]]></c> - the reply failed to arrive before the
+ request timer expired.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[{segment_timeout, missing_segments()}]]></c> -
+ one or more segments
+ was not delivered before the expire of the segment
+ timer.</p>
+ </item>
+ <item>
+ <p><c><![CDATA[exceeded_recv_pending_limit]]></c> - the pending
+ limit was exceeded for this request.</p>
+ </item>
+ </list>
+ </item>
+ </list>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_trans_reply/5</c>. </p>
+
+ <marker id="trans_ack"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) -> ok</name>
+ <name>handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) -> ok</name>
+ <fsummary>Optionally invoked for a transaction acknowledgement</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>AckStatus = ok | {error, reason()}</v>
+ <v>reason() = user_cancel_reason() | send_reason() | other_reason()</v>
+ <v>user_cancel_reason() = {user_cancel, reason_for_user_cancel()}</v>
+ <v>send_reason() = send_cancelled_reason() | send_failed_reason()</v>
+ <v>send_cancelled_reason() = {send_message_cancelled, reason_for_send_cancel()}</v>
+ <v>reason_for_send_cancel() = term()</v>
+ <v>send_failed_reason() = {send_message_failed, reason_for_send_failure()}</v>
+ <v>reason_for_send_failure() = term()</v>
+ <v>other_reason() = term()</v>
+ <v>AckData = ack_data()</v>
+ <v>ack_data() = term()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Optionally invoked for a transaction acknowledgement</p>
+ <p>If this function gets invoked or not, is controlled by the
+ reply from the preceding call to handle_trans_request/3.
+ The handle_trans_request/3 function may decide to return
+ {handle_ack, ack_data()} or {handle_sloppy_ack, ack_data()}
+ meaning that you need an immediate acknowledgement of the
+ reply and that this function should be invoked to handle the
+ acknowledgement.</p>
+ <p>The ack_data() argument to this function is the Erlang term
+ returned by handle_trans_request/3.</p>
+ <p></p>
+ <p>If the AckStatus is ok, it is indicating that this is a
+ true acknowledgement of the transaction reply.</p>
+ <p>If the AckStatus is {error, Reason}, it is an indication that the
+ acknowledgement or even the reply (for which this is an
+ acknowledgement) was not delivered, but there is no point in
+ waiting any longer for it to arrive. This happens when: </p>
+ <taglist>
+ <tag><c><![CDATA[reply_timer]]></c></tag>
+ <item>
+ <p>The <c><![CDATA[reply_timer]]></c> eventually times out.</p>
+ </item>
+ <tag>reply send failure</tag>
+ <item>
+ <p>When megaco fails to send the reply (see
+ <seealso marker="#trans_reply">handle_trans_reply</seealso>),
+ for whatever reason. </p>
+ </item>
+ <tag>cancel</tag>
+ <item>
+ <p>The user has explicitly cancelled the wait
+ (megaco:cancel/2).</p>
+ </item>
+ </taglist>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_trans_ack/5</c>. </p>
+
+ <marker id="unexpected_trans"></marker>
+ <marker id="handle_unexpected_trans"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) -> ok</name>
+ <name>handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) -> ok</name>
+ <fsummary>Invoked when an unexpected message is received</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>Trans = #'TransactionPending'{} | #'TransactionReply'{} | #'TransactionResponseAck'{}</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a unexpected message is received</p>
+ <p>If a reply to a request is not received in time, the
+ megaco stack removes all info about the request from
+ it's tables. If a reply should arrive after this has been
+ done the app has no way of knowing where to send this message.
+ The message is delivered to the "user" by calling this
+ function on the local node (the node which has the link).</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_unexpected_trans/4</c>. </p>
+
+ <marker id="request_abort"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid) -> ok</name>
+ <name>handle_trans_request_abort(ConnHandle, ProtocolVersion, TransNo, Pid, Extra) -> ok</name>
+ <fsummary>Invoked when an transaction request has been aborted</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>TransNo = integer()</v>
+ <v>Pid = undefined | pid()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Invoked when a transaction request has been aborted</p>
+ <p>This function is invoked if the originating pending limit
+ has been exceeded. This usually means that a request has taken
+ abnormally long time to complete.</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_trans_request_abort/5</c>. </p>
+
+ <marker id="segment_reply"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl) -> ok</name>
+ <name>handle_segment_reply(ConnHandle, ProtocolVersion, TransNo, SegNo, SegCompl, Extra) -> ok</name>
+ <fsummary>Segment Reply Indication</fsummary>
+ <type>
+ <v>ConnHandle = conn_handle()</v>
+ <v>ProtocolVersion = protocol_version()</v>
+ <v>TransNo = integer()</v>
+ <v>SegNo = integer()</v>
+ <v>SegCompl = asn1_NOVALUE | 'NULL'</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>This function is called when a segment reply has been received
+ if the
+ <seealso marker="megaco#conn_info">segment_reply_ind</seealso>
+ config option has been set to true.</p>
+ <p>This is in effect a progress report.</p>
+
+ <p>See <seealso marker="#extra_argument">note</seealso>
+ above about the <c>Extra</c> argument in
+ <c>handle_segment_reply/6</c>. </p>
+
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/megaco/doc/src/mstone1-s8flex.log b/lib/megaco/doc/src/mstone1-s8flex.log
new file mode 100644
index 0000000000..d9d28399f3
--- /dev/null
+++ b/lib/megaco/doc/src/mstone1-s8flex.log
@@ -0,0 +1,234 @@
+
+---------------------------------------------
+Factor 01
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 01 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [16] ................ done
+ * await runners ready ................ done
+ * now snooze
+ * release them
+
+16 runners
+Runner heap size data:
+ Min: 75025
+ Max: 1682835
+ Avg: 582577
+Runner reductions data:
+ Min: 927126711
+ Max: 5292487523
+ Avg: 1929935038
+
+MStone: 63283727
+
+---------------------------------------------
+Factor 02
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 02 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [32] ................................ done
+ * await runners ready ................................ done
+ * now snooze
+ * release them
+
+32 runners
+Runner heap size data:
+ Min: 75025
+ Max: 1346269
+ Avg: 388569
+Runner reductions data:
+ Min: 645498054
+ Max: 2774469009
+ Avg: 943407719
+
+MStone: 61441342
+
+---------------------------------------------
+Factor 04
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 04 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [64] ................................................................ done
+ * await runners ready ................................................................ done
+ * now snooze
+ * release them
+
+64 runners
+Runner heap size data:
+ Min: 75025
+ Max: 1682835
+ Avg: 462690
+Runner reductions data:
+ Min: 395464832
+ Max: 916378232
+ Avg: 507760636
+
+MStone: 66958216
+
+---------------------------------------------
+Factor 08
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 08 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [128] ................................................................................................................................ done
+ * await runners ready ................................................................................................................................ done
+ * now snooze
+ * release them
+
+128 runners
+Runner heap size data:
+ Min: 75025
+ Max: 832040
+ Avg: 173900
+Runner reductions data:
+ Min: 236710819
+ Max: 457961244
+ Avg: 269562568
+
+MStone: 72098418
+
+---------------------------------------------
+Factor 16
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 16 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [256] ................................................................................................................................................................................................................................................................ done
+ * await runners ready ................................................................................................................................................................................................................................................................ done
+ * now snooze
+ * release them
+
+256 runners
+Runner heap size data:
+ Min: 75025
+ Max: 317811
+ Avg: 131652
+Runner reductions data:
+ Min: 134104991
+ Max: 163429204
+ Avg: 142654707
+
+MStone: 77139535
+
+---------------------------------------------
+Factor 32
+
+erl -noshell -smp +S 8 -pa /ldisk/bmk/pgm/otp-r13b-m311p08-re/lib/erlang/lib/megaco-3.11/examples/meas -s megaco_codec_mstone1 start_flex time_test 32 -s init stop
+
+OS: unix-linux: 2.6.16
+System architecture: x86_64-unknown-linux-gnu
+OTP release: R13B
+System version: Erlang R13B (erts-5.7.1) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]
+Heap type: private
+Global heap size: 0
+Thread support: true
+Thread pool size: 0
+Process limit: 32768
+SMP support: true
+Num schedulers: 8
+Scheduler bindings: {0,1,4,5,2,3,6,7}
+Scheduler bind type: thread_no_node_processor_spread
+Cpu topology: [{processor,[{core,{logical,0}},{core,{logical,4}},{core,{logical,2}},{core,{logical,6}}]},{processor,[{core,{logical,1}},{core,{logical,5}},{core,{logical,3}},{core,{logical,7}}]}]
+Megaco version: megaco-3.11-p08
+ASN.1 version: 1.6.10
+
+ * starting runners [512] ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ done
+ * await runners ready ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ done
+ * now snooze
+ * release them
+
+512 runners
+Runner heap size data:
+ Min: 75025
+ Max: 196418
+ Avg: 107328
+Runner reductions data:
+ Min: 71186547
+ Max: 74170110
+ Avg: 72380653
+
+MStone: 78820851
diff --git a/lib/megaco/doc/src/mstone1.gif b/lib/megaco/doc/src/mstone1.gif
new file mode 100644
index 0000000000..54c9c5514c
--- /dev/null
+++ b/lib/megaco/doc/src/mstone1.gif
Binary files differ
diff --git a/lib/megaco/doc/src/mstone1.jpg b/lib/megaco/doc/src/mstone1.jpg
new file mode 100644
index 0000000000..b417429a08
--- /dev/null
+++ b/lib/megaco/doc/src/mstone1.jpg
Binary files differ
diff --git a/lib/megaco/doc/src/mstone1.png b/lib/megaco/doc/src/mstone1.png
new file mode 100644
index 0000000000..19af210abc
--- /dev/null
+++ b/lib/megaco/doc/src/mstone1.png
Binary files differ
diff --git a/lib/megaco/doc/src/mstone1.ps b/lib/megaco/doc/src/mstone1.ps
new file mode 100644
index 0000000000..6436a4eb43
--- /dev/null
+++ b/lib/megaco/doc/src/mstone1.ps
@@ -0,0 +1,1959 @@
+%!PS-Adobe-3.0
+%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
+%%Title: mstone1_html_m5496b992.ps
+%%CreationDate: Fri May 29 19:07:25 2009
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 14 14 476 247
+%%EndComments
+%%BeginProlog
+% Use own dictionary to avoid conflicts
+10 dict begin
+%%EndProlog
+%%Page: 1 1
+% Translate for offset
+14.173228346456694 14.173228346456694 translate
+% Translate to begin of first scanline
+0 231.99920747433686 translate
+460.99842519685041 -231.99920747433686 scale
+% Image geometry
+461 232 8
+% Transformation matrix
+[ 461 0 0 232 0 0 ]
+% Strings to hold RGB-samples per scanline
+/rstr 461 string def
+/gstr 461 string def
+/bstr 461 string def
+{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
+true 3
+%%BeginData: 120502 ASCII Bytes
+colorimage
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+i;[-^"<[I>jo>>[s!S-Pn#nhl!"q57bl%G=s7lKks8;orq>UEis7ZKkpAapfqu?Nmr:^0\rj;e)
+s8Dutrr<#nq!DD]s0Gl?!Ao]1s8;oe!<;Hd"Sr)ls7>sarVlfr/b/l@q#CBds82ck([qD(r;Z+-
+8G3#_q>X&-q#CBlrVZ]fs7lWkrV6<jq"ssfrrVrprVcaFr<)rsrr)lpo`#!n$31)/s8VZin5BJi
+oDZ*k&-j;?o`+scYV-/(\,61)<Vugjs8VP@2$sI+9X"<ms7ZKmo_\Zn>9<i*IeWm8s8W#ss6a>7
+!'%(Ss5mc1$9F^WqXX[`s7QE7?l9"V-$I''!:^$grVccn!WW2js8VWhoDeR_rsA5qr;V'f!%3Qh
+rVnG1s8W&:BG^ja+`,[)rrEc4s7u]mq>Wh_s8Vrqr;ZWnp](3as8)ckq>^KXrr35rs8Vlns8W)t
+ruq.6s7?$[s8VurqZ$9hs7--bmf3=ap\k-lp1<7`r;Zfpir=N~>
+i;[-^"<[I>jo>>[s!S-Pn#nhl!"q57bl%G=s7lKks8;orq>UEis7ZKkpAapfqu?Nmr:^0\rj;e)
+s8Dutrr<#nq!DD]s0Gl?!Ao]1s8;oe!<;Hd"Sr)ls7>sarVlfr/b/l@q#CBds82ck([qD(r;Z+-
+8G3#_q>X&-q#CBlrVZ]fs7lWkrV6<jq"ssfrrVrprVcaFr<)rsrr)lpo`#!n$31)/s8VZin5BJi
+oDZ*k&-j;?o`+scYV-/(\,61)<Vugjs8VP@2$sI+9X"<ms7ZKmo_\Zn>9<i*IeWm8s8W#ss6a>7
+!'%(Ss5mc1$9F^WqXX[`s7QE7?l9"V-$I''!:^$grVccn!WW2js8VWhoDeR_rsA5qr;V'f!%3Qh
+rVnG1s8W&:BG^ja+`,[)rrEc4s7u]mq>Wh_s8Vrqr;ZWnp](3as8)ckq>^KXrr35rs8Vlns8W)t
+ruq.6s7?$[s8VurqZ$9hs7--bmf3=ap\k-lp1<7`r;Zfpir=N~>
+i;[-^"<[I>jo>>[s!S-Pn#nhl!"q57bl%G=s7lKks8;orq>UEis7ZKkpAapfqu?Nmr:^0\rj;e)
+s8Dutrr<#nq!DD]s0Gl?!Ao]1s8;oe!<;Hd"Sr)ls7>sarVlfr/b/l@q#CBds82ck([qD(r;Z+-
+8G3#_q>X&-q#CBlrVZ]fs7lWkrV6<jq"ssfrrVrprVcaFr<)rsrr)lpo`#!n$31)/s8VZin5BJi
+oDZ*k&-j;?o`+scYV-/(\,61)<Vugjs8VP@2$sI+9X"<ms7ZKmo_\Zn>9<i*IeWm8s8W#ss6a>7
+!'%(Ss5mc1$9F^WqXX[`s7QE7?l9"V-$I''!:^$grVccn!WW2js8VWhoDeR_rsA5qr;V'f!%3Qh
+rVnG1s8W&:BG^ja+`,[)rrEc4s7u]mq>Wh_s8Vrqr;ZWnp](3as8)ckq>^KXrr35rs8Vlns8W)t
+ruq.6s7?$[s8VurqZ$9hs7--bmf3=ap\k-lp1<7`r;Zfpir=N~>
+iVtA&rr<bBqu6Wds4%SZs+<S^q"W^NJ3s8@meQb[r9s[crVuors69R`q#::FqZ$Qjrr<#ks/l_1
+r;Z`qs8N&ns8Pa:s7KNEj7gnuGk1l7O91hXnc8^Ws6ose')2G)!<<)is8VZas8VrqrrE)krVmPV
+&W6Sfs*kU(s7G^Ys8;ors8V]hrsAN$rqZTir;ZforVm9("8i,tnGE7bp'gKjs%rUhq>]s9#70bt
+s'(TAs2e'#me,NGYlD]_]Dqa-s8)]oRic.Ls6/p>1H44gs7ZKls7'<Ae,7KeMuWhJs7>OU'qaXY
+Q!44a2h^2\T3:=UruCM-s-G.0iqhZ[?qLA7s8VoprVuI#kl(P[k5Y)Prr`3!o'ZMW0P!u3s56>%
+pAY*cs7lVu-^WlnhTC"&s7lX)XnMbos8C%?!<<)ts8N&js8VQes8)]o"nMKhs7,aYrs/&nq"+Oc
+qY^?m%efr!rr;lqo()MSr;ZHQrr3?"s8C2KpAP$krq5=OJ,~>
+iVtA&rr<bBqu6Wds4%SZs+<S^q"W^NJ3s8@meQb[r9s[crVuors69R`q#::FqZ$Qjrr<#ks/l_1
+r;Z`qs8N&ns8Pa:s7KNEj7gnuGk1l7O91hXnc8^Ws6ose')2G)!<<)is8VZas8VrqrrE)krVmPV
+&W6Sfs*kU(s7G^Ys8;ors8V]hrsAN$rqZTir;ZforVm9("8i,tnGE7bp'gKjs%rUhq>]s9#70bt
+s'(TAs2e'#me,NGYlD]_]Dqa-s8)]oRic.Ls6/p>1H44gs7ZKls7'<Ae,7KeMuWhJs7>OU'qaXY
+Q!44a2h^2\T3:=UruCM-s-G.0iqhZ[?qLA7s8VoprVuI#kl(P[k5Y)Prr`3!o'ZMW0P!u3s56>%
+pAY*cs7lVu-^WlnhTC"&s7lX)XnMbos8C%?!<<)ts8N&js8VQes8)]o"nMKhs7,aYrs/&nq"+Oc
+qY^?m%efr!rr;lqo()MSr;ZHQrr3?"s8C2KpAP$krq5=OJ,~>
+iVtA&rr<bBqu6Wds4%SZs+<S^q"W^NJ3s8@meQb[r9s[crVuors69R`q#::FqZ$Qjrr<#ks/l_1
+r;Z`qs8N&ns8Pa:s7KNEj7gnuGk1l7O91hXnc8^Ws6ose')2G)!<<)is8VZas8VrqrrE)krVmPV
+&W6Sfs*kU(s7G^Ys8;ors8V]hrsAN$rqZTir;ZforVm9("8i,tnGE7bp'gKjs%rUhq>]s9#70bt
+s'(TAs2e'#me,NGYlD]_]Dqa-s8)]oRic.Ls6/p>1H44gs7ZKls7'<Ae,7KeMuWhJs7>OU'qaXY
+Q!44a2h^2\T3:=UruCM-s-G.0iqhZ[?qLA7s8VoprVuI#kl(P[k5Y)Prr`3!o'ZMW0P!u3s56>%
+pAY*cs7lVu-^WlnhTC"&s7lX)XnMbos8C%?!<<)ts8N&js8VQes8)]o"nMKhs7,aYrs/&nq"+Oc
+qY^?m%efr!rr;lqo()MSr;ZHQrr3?"s8C2KpAP$krq5=OJ,~>
+iVsMdrr>bfrr;ors%6/hq@)lhn,E=ko(;q^s8)9bru_14rVuWlqZ$Tcs7cE_s7lWorV?Kn!&)Lr
+r;Z`qs8N#t.'ZYLmeleYs82cG/-#GF7K>jVr"Sl)p@SC]pAb'j)>O7*s8;osp%\Od(]aO7s8DZk
+s)AFjq8OP?nGiIerU]p`s5<nV%JTntp\jaaoDejOs7Q9grs&E(qu?Zqqu6UQ!<;cmo`+C[rV/$r
+$Ma5lo)J[grSmnXnR7@Ts8Rmls8W)unGfm(c27P*s8;QiK1>k?q"Odf!:]se$J-*hkPtP]s-Irp
+rr4S:s+4_[rVuTks7u]ap]&\`dIcf*s7?9jli@"`l2UY\rrE)lrVuoos8Dull2:Q%q#:`hrr;HX
+!WVlnnGi%.&^(.JoDeF^rVua+<^-N_)#aJ;:`9!,nG`I\s8V`hs8VZimf2kXs7QBk(ARe,qu?Hk
+s7lWks8V9^lhUDWs8)ZfqYq*#s8Duis8V]j>.4G(r;ZHMs*t~>
+iVsMdrr>bfrr;ors%6/hq@)lhn,E=ko(;q^s8)9bru_14rVuWlqZ$Tcs7cE_s7lWorV?Kn!&)Lr
+r;Z`qs8N#t.'ZYLmeleYs82cG/-#GF7K>jVr"Sl)p@SC]pAb'j)>O7*s8;osp%\Od(]aO7s8DZk
+s)AFjq8OP?nGiIerU]p`s5<nV%JTntp\jaaoDejOs7Q9grs&E(qu?Zqqu6UQ!<;cmo`+C[rV/$r
+$Ma5lo)J[grSmnXnR7@Ts8Rmls8W)unGfm(c27P*s8;QiK1>k?q"Odf!:]se$J-*hkPtP]s-Irp
+rr4S:s+4_[rVuTks7u]ap]&\`dIcf*s7?9jli@"`l2UY\rrE)lrVuoos8Dull2:Q%q#:`hrr;HX
+!WVlnnGi%.&^(.JoDeF^rVua+<^-N_)#aJ;:`9!,nG`I\s8V`hs8VZimf2kXs7QBk(ARe,qu?Hk
+s7lWks8V9^lhUDWs8)ZfqYq*#s8Duis8V]j>.4G(r;ZHMs*t~>
+iVsMdrr>bfrr;ors%6/hq@)lhn,E=ko(;q^s8)9bru_14rVuWlqZ$Tcs7cE_s7lWorV?Kn!&)Lr
+r;Z`qs8N#t.'ZYLmeleYs82cG/-#GF7K>jVr"Sl)p@SC]pAb'j)>O7*s8;osp%\Od(]aO7s8DZk
+s)AFjq8OP?nGiIerU]p`s5<nV%JTntp\jaaoDejOs7Q9grs&E(qu?Zqqu6UQ!<;cmo`+C[rV/$r
+$Ma5lo)J[grSmnXnR7@Ts8Rmls8W)unGfm(c27P*s8;QiK1>k?q"Odf!:]se$J-*hkPtP]s-Irp
+rr4S:s+4_[rVuTks7u]ap]&\`dIcf*s7?9jli@"`l2UY\rrE)lrVuoos8Dull2:Q%q#:`hrr;HX
+!WVlnnGi%.&^(.JoDeF^rVua+<^-N_)#aJ;:`9!,nG`I\s8V`hs8VZimf2kXs7QBk(ARe,qu?Hk
+s7lWks8V9^lhUDWs8)ZfqYq*#s8Duis8V]j>.4G(r;ZHMs*t~>
+hu>A1^]NWns8UpUgAq7!D=RZ+n,!(^!XA]1qu=Z&&kLmDs7cu%,760Ys8Mqh.K^9HrVmB&!W;ur
+s8W)uqu8sss8)`p./i`:k5bP^F=I8:JGoQKrrBGN!B&+$!!!$$s7QDa0-1[tp&>$ls6ose+nu"/
+/bh7Ss8VWhSfo'pRf<?bb<$_4_Z0Z5!j*[M9Z?]'s#p;_qu?Zqs6T4S!;$6im/Qq^potP)!<<&j
+s7H?hs61U)ru9Php&!_is76-gs6(<As6+D9(1oI>r(2A7rr4,.p&FgUs7bF]s8W#ss6)5Xs7uTm
+rr5gAlMpMVrr;]_rr3@+L]@DRs8Mrjmf*:brsIui$2sc%!!WE/kl(Miq=4LTs8NAjs8VcZ)?'S!
+k5SDNs8)cqpAb*knc&U.$0_Efp?`1<!;ZQmndM'D"XDHk*"4[RqY'shXY^#%PlLafMEq4nc^?0]
+1u/'/ruAa=*'MXCrs[:"2Xh6@s6fle']f;88cSDXs8DoWs*t~>
+hu>A1^]NWns8UpUgAq7!D=RZ+n,!(^!XA]1qu=Z&&kLmDs7cu%,760Ys8Mqh.K^9HrVmB&!W;ur
+s8W)uqu8sss8)`p./i`:k5bP^F=I8:JGoQKrrBGN!B&+$!!!$$s7QDa0-1[tp&>$ls6ose+nu"/
+/bh7Ss8VWhSfo'pRf<?bb<$_4_Z0Z5!j*[M9Z?]'s#p;_qu?Zqs6T4S!;$6im/Qq^potP)!<<&j
+s7H?hs61U)ru9Php&!_is76-gs6(<As6+D9(1oI>r(2A7rr4,.p&FgUs7bF]s8W#ss6)5Xs7uTm
+rr5gAlMpMVrr;]_rr3@+L]@DRs8Mrjmf*:brsIui$2sc%!!WE/kl(Miq=4LTs8NAjs8VcZ)?'S!
+k5SDNs8)cqpAb*knc&U.$0_Efp?`1<!;ZQmndM'D"XDHk*"4[RqY'shXY^#%PlLafMEq4nc^?0]
+1u/'/ruAa=*'MXCrs[:"2Xh6@s6fle']f;88cSDXs8DoWs*t~>
+hu>A1^]NWns8UpUgAq7!D=RZ+n,!(^!XA]1qu=Z&&kLmDs7cu%,760Ys8Mqh.K^9HrVmB&!W;ur
+s8W)uqu8sss8)`p./i`:k5bP^F=I8:JGoQKrrBGN!B&+$!!!$$s7QDa0-1[tp&>$ls6ose+nu"/
+/bh7Ss8VWhSfo'pRf<?bb<$_4_Z0Z5!j*[M9Z?]'s#p;_qu?Zqs6T4S!;$6im/Qq^potP)!<<&j
+s7H?hs61U)ru9Php&!_is76-gs6(<As6+D9(1oI>r(2A7rr4,.p&FgUs7bF]s8W#ss6)5Xs7uTm
+rr5gAlMpMVrr;]_rr3@+L]@DRs8Mrjmf*:brsIui$2sc%!!WE/kl(Miq=4LTs8NAjs8VcZ)?'S!
+k5SDNs8)cqpAb*knc&U.$0_Efp?`1<!;ZQmndM'D"XDHk*"4[RqY'shXY^#%PlLafMEq4nc^?0]
+1u/'/ruAa=*'MXCrs[:"2Xh6@s6fle']f;88cSDXs8DoWs*t~>
+hu=Gls!)ggr:-(+q$-Q.*rnZciW&rUr<<3#HEe%,rPo\lq=jqll18LAq"DES`;\%HNq`SHrrN&t
+rVuoss8MF/q#C?nh=psLqi"MGs(0mabZ+TBs764eh"6%KrVmE&q>^,f0WtH)25fU?s82Wls7ZKm
+g(jo5kPtDYXuF;bc8V'gY9D$HaYCQorr?WSr*M;YrVm'""8i,to`"k0r"U.P+0tq?s5tW#rrM9X
+s8V3\r6eJYq>V#urr3)e$M45qs%7iJs6<$gp=)Y:U&N7op@eO`s8V9^s7?8R6N@)]s8)a6Shg?n
+N;qlVV)86&S*L%Rr;Zff)WLPbs8V3\s8)Quq#C<is8W#tmJd+jqGDJ:s8Duarr3c/s8R::cMu?[
+J,''*n,ND(g&M*Ms7#sd!s/<QFT2;3KeMlps8V`f"BX+<M?$H#s)'jms8&H8^])G=M>mQ_f_'Cq
+8)j2O62:KF^+I@_as>1!!,:ots'SRus8Q(cqZ$@$pAb!hrr(pXJ,~>
+hu=Gls!)ggr:-(+q$-Q.*rnZciW&rUr<<3#HEe%,rPo\lq=jqll18LAq"DES`;\%HNq`SHrrN&t
+rVuoss8MF/q#C?nh=psLqi"MGs(0mabZ+TBs764eh"6%KrVmE&q>^,f0WtH)25fU?s82Wls7ZKm
+g(jo5kPtDYXuF;bc8V'gY9D$HaYCQorr?WSr*M;YrVm'""8i,to`"k0r"U.P+0tq?s5tW#rrM9X
+s8V3\r6eJYq>V#urr3)e$M45qs%7iJs6<$gp=)Y:U&N7op@eO`s8V9^s7?8R6N@)]s8)a6Shg?n
+N;qlVV)86&S*L%Rr;Zff)WLPbs8V3\s8)Quq#C<is8W#tmJd+jqGDJ:s8Duarr3c/s8R::cMu?[
+J,''*n,ND(g&M*Ms7#sd!s/<QFT2;3KeMlps8V`f"BX+<M?$H#s)'jms8&H8^])G=M>mQ_f_'Cq
+8)j2O62:KF^+I@_as>1!!,:ots'SRus8Q(cqZ$@$pAb!hrr(pXJ,~>
+hu=Gls!)ggr:-(+q$-Q.*rnZciW&rUr<<3#HEe%,rPo\lq=jqll18LAq"DES`;\%HNq`SHrrN&t
+rVuoss8MF/q#C?nh=psLqi"MGs(0mabZ+TBs764eh"6%KrVmE&q>^,f0WtH)25fU?s82Wls7ZKm
+g(jo5kPtDYXuF;bc8V'gY9D$HaYCQorr?WSr*M;YrVm'""8i,to`"k0r"U.P+0tq?s5tW#rrM9X
+s8V3\r6eJYq>V#urr3)e$M45qs%7iJs6<$gp=)Y:U&N7op@eO`s8V9^s7?8R6N@)]s8)a6Shg?n
+N;qlVV)86&S*L%Rr;Zff)WLPbs8V3\s8)Quq#C<is8W#tmJd+jqGDJ:s8Duarr3c/s8R::cMu?[
+J,''*n,ND(g&M*Ms7#sd!s/<QFT2;3KeMlps8V`f"BX+<M?$H#s)'jms8&H8^])G=M>mQ_f_'Cq
+8)j2O62:KF^+I@_as>1!!,:ots'SRus8Q(cqZ$@$pAb!hrr(pXJ,~>
+i;ZpV!<8Drq>9\2SG36as8TND%g5M.s8N)mrr5.-s8)bi70!8hq"t*c#l4KZ`;fi:gFN=$s8N,t
+s8Dutrr<#=.KBDCq#CBdq8EQds8Vid#64So&b,f+rr3>[%fcM.s7l3c-Ii%p"P4Ii$2+8s*:Npm
+s*k`&s7u]p6.>E)s3!1t6+Hspp8p1ErrE&u"8*3)o)AZ'r<)rsrr;lkqu?]pr7;p=s8R?rs6g^&
+s7Q0err<$rs8VNoqZ$![rt=f#s7H=ZWrK@ps8Du7!8?u:$NL#%oD\CPr9aO!$.f%Js7H0f!%,\^
+dO::Y"X1b_`$(]@q>]j^rrE)hs7cNm'CGer!<<*%!WWu9!<;9WrM:1ui;N[.m.^P[rr<!\!!!Er
+qZ$?js7Gmgs6]jUp](9^nc/@cs-aGes7RD(rrE)os8N)us#ol^gA(^=!<;Wi38aE/p?a[3!WVfl
+mg&CQs8E3"s7&%Vs8W&%2ZEi^lMpGI!8mbC!hKAas"VUpr;?TnjSs`~>
+i;ZpV!<8Drq>9\2SG36as8TND%g5M.s8N)mrr5.-s8)bi70!8hq"t*c#l4KZ`;fi:gFN=$s8N,t
+s8Dutrr<#=.KBDCq#CBdq8EQds8Vid#64So&b,f+rr3>[%fcM.s7l3c-Ii%p"P4Ii$2+8s*:Npm
+s*k`&s7u]p6.>E)s3!1t6+Hspp8p1ErrE&u"8*3)o)AZ'r<)rsrr;lkqu?]pr7;p=s8R?rs6g^&
+s7Q0err<$rs8VNoqZ$![rt=f#s7H=ZWrK@ps8Du7!8?u:$NL#%oD\CPr9aO!$.f%Js7H0f!%,\^
+dO::Y"X1b_`$(]@q>]j^rrE)hs7cNm'CGer!<<*%!WWu9!<;9WrM:1ui;N[.m.^P[rr<!\!!!Er
+qZ$?js7Gmgs6]jUp](9^nc/@cs-aGes7RD(rrE)os8N)us#ol^gA(^=!<;Wi38aE/p?a[3!WVfl
+mg&CQs8E3"s7&%Vs8W&%2ZEi^lMpGI!8mbC!hKAas"VUpr;?TnjSs`~>
+i;ZpV!<8Drq>9\2SG36as8TND%g5M.s8N)mrr5.-s8)bi70!8hq"t*c#l4KZ`;fi:gFN=$s8N,t
+s8Dutrr<#=.KBDCq#CBdq8EQds8Vid#64So&b,f+rr3>[%fcM.s7l3c-Ii%p"P4Ii$2+8s*:Npm
+s*k`&s7u]p6.>E)s3!1t6+Hspp8p1ErrE&u"8*3)o)AZ'r<)rsrr;lkqu?]pr7;p=s8R?rs6g^&
+s7Q0err<$rs8VNoqZ$![rt=f#s7H=ZWrK@ps8Du7!8?u:$NL#%oD\CPr9aO!$.f%Js7H0f!%,\^
+dO::Y"X1b_`$(]@q>]j^rrE)hs7cNm'CGer!<<*%!WWu9!<;9WrM:1ui;N[.m.^P[rr<!\!!!Er
+qZ$?js7Gmgs6]jUp](9^nc/@cs-aGes7RD(rrE)os8N)us#ol^gA(^=!<;Wi38aE/p?a[3!WVfl
+mg&CQs8E3"s7&%Vs8W&%2ZEi^lMpGI!8mbC!hKAas"VUpr;?TnjSs`~>
+i;ZRO!rha,VZ*Y'q#:?oq>1$WrNT!/K`2#Prq?EUpAb0Z'`[_(s8DQf"98B(!!!*$!#,/'s7??i
+s8Dutrr;l;1]$nHnFuq^^&YY=s7?3h')2D+s6]meqtC$iqYgNkr;Z@0r;['9"oeT&s8MlnruTZ)
+'bKO-s76?n&-r7F!:^KhqXjgf&H;A3jo>5T!;uk'r<)rsrp]U\s6Tdbs6]:rrn7A3s8N*!s6K^b
+q>]DNE:j/>mJ$YXmKijjpAaabs6q>Op%n]W!<<#k$iBl"s8VZinGgT1](Q*qs8VWc&`EKbqU6\Z
+!:]RUs4J1drtY2*(ubMpo`"mk$3:)/s8V?`rVultrr38t,anQ0r:p<jrVo=_l&%7PpVo^Equ?<^
+s8N`"qXFOb!!!N=oDK$rm38#!TH`n#$2"8lknEpgq>UHps8;j)nFHSZ!"&]3!!*$!s8VQa#lai)
+nc8[h)%HEAnbr=frW)uur;YkTDZ>J/s8;fp9=k!!rrDuXs*t~>
+i;ZRO!rha,VZ*Y'q#:?oq>1$WrNT!/K`2#Prq?EUpAb0Z'`[_(s8DQf"98B(!!!*$!#,/'s7??i
+s8Dutrr;l;1]$nHnFuq^^&YY=s7?3h')2D+s6]meqtC$iqYgNkr;Z@0r;['9"oeT&s8MlnruTZ)
+'bKO-s76?n&-r7F!:^KhqXjgf&H;A3jo>5T!;uk'r<)rsrp]U\s6Tdbs6]:rrn7A3s8N*!s6K^b
+q>]DNE:j/>mJ$YXmKijjpAaabs6q>Op%n]W!<<#k$iBl"s8VZinGgT1](Q*qs8VWc&`EKbqU6\Z
+!:]RUs4J1drtY2*(ubMpo`"mk$3:)/s8V?`rVultrr38t,anQ0r:p<jrVo=_l&%7PpVo^Equ?<^
+s8N`"qXFOb!!!N=oDK$rm38#!TH`n#$2"8lknEpgq>UHps8;j)nFHSZ!"&]3!!*$!s8VQa#lai)
+nc8[h)%HEAnbr=frW)uur;YkTDZ>J/s8;fp9=k!!rrDuXs*t~>
+i;ZRO!rha,VZ*Y'q#:?oq>1$WrNT!/K`2#Prq?EUpAb0Z'`[_(s8DQf"98B(!!!*$!#,/'s7??i
+s8Dutrr;l;1]$nHnFuq^^&YY=s7?3h')2D+s6]meqtC$iqYgNkr;Z@0r;['9"oeT&s8MlnruTZ)
+'bKO-s76?n&-r7F!:^KhqXjgf&H;A3jo>5T!;uk'r<)rsrp]U\s6Tdbs6]:rrn7A3s8N*!s6K^b
+q>]DNE:j/>mJ$YXmKijjpAaabs6q>Op%n]W!<<#k$iBl"s8VZinGgT1](Q*qs8VWc&`EKbqU6\Z
+!:]RUs4J1drtY2*(ubMpo`"mk$3:)/s8V?`rVultrr38t,anQ0r:p<jrVo=_l&%7PpVo^Equ?<^
+s8N`"qXFOb!!!N=oDK$rm38#!TH`n#$2"8lknEpgq>UHps8;j)nFHSZ!"&]3!!*$!s8VQa#lai)
+nc8[h)%HEAnbr=frW)uur;YkTDZ>J/s8;fp9=k!!rrDuXs*t~>
+hu@6fqYsn^r],f2pC$Qlr;ZZoo`)`;r;ccirt=o&s8)a"r;Qcsrr;fps8)frnG`Idp%JF^rW2rs
+rVuoss8C)%s8;QirV=&7VZ-Vis82WjqZ$<or;Qcls76$qs82lspAb-mpAY'qq>L*lq"k!i,P;$$
+<AiSg48AjU#Q"/es8Vrq"nqurr9=[irrE)os8N*!rr2pHr<)rsrr<#oqZ$Tfs8V<cs$L;rp\4si
+rVuors7Q9[#QO?Iec5@Bk8aL$)uKX8o`#-hs8W"65kb,l2ZN[Sp](!_s0)d1q#::5qt:!h+m]1*
+s8N*[email protected]"BoEY0ls7u]gs8;j*q"4NE-3*K7rVccqs7cQbs8NYkq>^KR
+(]471s8VmuR/[+$p&F[a!;lcrs8?dlr]Y<$rrDrqs8N)urtG)5oD&@c!VcWo#4MQgs8;Wi!;ZWo
+$3B\ss8!'"s8NPrrr3c)&afl"s7,ma`ZXe%I/X*FqC:.ps8:mVJ,~>
+hu@6fqYsn^r],f2pC$Qlr;ZZoo`)`;r;ccirt=o&s8)a"r;Qcsrr;fps8)frnG`Idp%JF^rW2rs
+rVuoss8C)%s8;QirV=&7VZ-Vis82WjqZ$<or;Qcls76$qs82lspAb-mpAY'qq>L*lq"k!i,P;$$
+<AiSg48AjU#Q"/es8Vrq"nqurr9=[irrE)os8N*!rr2pHr<)rsrr<#oqZ$Tfs8V<cs$L;rp\4si
+rVuors7Q9[#QO?Iec5@Bk8aL$)uKX8o`#-hs8W"65kb,l2ZN[Sp](!_s0)d1q#::5qt:!h+m]1*
+s8N*[email protected]"BoEY0ls7u]gs8;j*q"4NE-3*K7rVccqs7cQbs8NYkq>^KR
+(]471s8VmuR/[+$p&F[a!;lcrs8?dlr]Y<$rrDrqs8N)urtG)5oD&@c!VcWo#4MQgs8;Wi!;ZWo
+$3B\ss8!'"s8NPrrr3c)&afl"s7,ma`ZXe%I/X*FqC:.ps8:mVJ,~>
+hu@6fqYsn^r],f2pC$Qlr;ZZoo`)`;r;ccirt=o&s8)a"r;Qcsrr;fps8)frnG`Idp%JF^rW2rs
+rVuoss8C)%s8;QirV=&7VZ-Vis82WjqZ$<or;Qcls76$qs82lspAb-mpAY'qq>L*lq"k!i,P;$$
+<AiSg48AjU#Q"/es8Vrq"nqurr9=[irrE)os8N*!rr2pHr<)rsrr<#oqZ$Tfs8V<cs$L;rp\4si
+rVuors7Q9[#QO?Iec5@Bk8aL$)uKX8o`#-hs8W"65kb,l2ZN[Sp](!_s0)d1q#::5qt:!h+m]1*
+s8N*[email protected]"BoEY0ls7u]gs8;j*q"4NE-3*K7rVccqs7cQbs8NYkq>^KR
+(]471s8VmuR/[+$p&F[a!;lcrs8?dlr]Y<$rrDrqs8N)urtG)5oD&@c!VcWo#4MQgs8;Wi!;ZWo
+$3B\ss8!'"s8NPrrr3c)&afl"s7,ma`ZXe%I/X*FqC:.ps8:mVJ,~>
+iVuRLrrE*!c4-6IhZ*3Js8Dutp](9kiY;Csmf3;>]Dqa,Z7GtT!;lfrrW)uu/@,<Uq>^*ep&Fgf
+s7cQno_SUfjVRgop\Fif$G?05s"aTPs8VZhquH`r!rr2rrrW5s!<<)op/@des7u]frrMros8W#f
+s+gd-o%O@us8P$^rr2pPo`$SRn,NBj5PP0Xs763i!WW,mrr;uupAb$es8;fpqu?]nat*Jo!"o84
+!"')5s7cNm?J6(ms'UW]rVrNjs82irrX.T`#6"2okSn.3s"pbPs8W)unc,-\YlF_&s8N&urr6/k
+q>('@1\+qDq=Xd80DYPGpAap8%I<]as8;co!<3>us7H?kr;Qrjs7cT(rr30!s8Vfirr)it']T,l
+$gIusp]'a_oY_[/q#::<qYpQqo`tNsaoJaJhZ!NVs8;fp!rr;trW)ZlnG`Lgqu8@Pr;S>F$MON!
+rrW5ur;Qius8+jcq#BZi49#EVs8;iqs"]65cg^u/r=Ar$s8DunjSs`~>
+iVuRLrrE*!c4-6IhZ*3Js8Dutp](9kiY;Csmf3;>]Dqa,Z7GtT!;lfrrW)uu/@,<Uq>^*ep&Fgf
+s7cQno_SUfjVRgop\Fif$G?05s"aTPs8VZhquH`r!rr2rrrW5s!<<)op/@des7u]frrMros8W#f
+s+gd-o%O@us8P$^rr2pPo`$SRn,NBj5PP0Xs763i!WW,mrr;uupAb$es8;fpqu?]nat*Jo!"o84
+!"')5s7cNm?J6(ms'UW]rVrNjs82irrX.T`#6"2okSn.3s"pbPs8W)unc,-\YlF_&s8N&urr6/k
+q>('@1\+qDq=Xd80DYPGpAap8%I<]as8;co!<3>us7H?kr;Qrjs7cT(rr30!s8Vfirr)it']T,l
+$gIusp]'a_oY_[/q#::<qYpQqo`tNsaoJaJhZ!NVs8;fp!rr;trW)ZlnG`Lgqu8@Pr;S>F$MON!
+rrW5ur;Qius8+jcq#BZi49#EVs8;iqs"]65cg^u/r=Ar$s8DunjSs`~>
+iVuRLrrE*!c4-6IhZ*3Js8Dutp](9kiY;Csmf3;>]Dqa,Z7GtT!;lfrrW)uu/@,<Uq>^*ep&Fgf
+s7cQno_SUfjVRgop\Fif$G?05s"aTPs8VZhquH`r!rr2rrrW5s!<<)op/@des7u]frrMros8W#f
+s+gd-o%O@us8P$^rr2pPo`$SRn,NBj5PP0Xs763i!WW,mrr;uupAb$es8;fpqu?]nat*Jo!"o84
+!"')5s7cNm?J6(ms'UW]rVrNjs82irrX.T`#6"2okSn.3s"pbPs8W)unc,-\YlF_&s8N&urr6/k
+q>('@1\+qDq=Xd80DYPGpAap8%I<]as8;co!<3>us7H?kr;Qrjs7cT(rr30!s8Vfirr)it']T,l
+$gIusp]'a_oY_[/q#::<qYpQqo`tNsaoJaJhZ!NVs8;fp!rr;trW)ZlnG`Lgqu8@Pr;S>F$MON!
+rrW5ur;Qius8+jcq#BZi49#EVs8;iqs"]65cg^u/r=Ar$s8DunjSs`~>
+i;Yn5#Q4Q#*tUm@jSo\OD2u@1qr,"6UAl%`o)Hi4ci(g)b5_A?s7lKd!rr;B*jb_$L2$\fmJd[r
+s7>s^rrGR1rr3@j)795>s7ZKks7QBjs$-SancAUes7uceruJoTrVrlC\Gt3F;Y'ngs6BUZs3h7G
+s7cAY!87.V(qo_+N`l+s'AEK&-+j3W!:0[\quufnrrhE_)#4(/s*XYB?@_><^a#H>s8VBarrV]a
+s$`OBm`S"Lr:SMI^A#;IcN!_?oD`*\s'Jk-`^Kl^dUl2Hs7bp[qYuBfaT)59s8P"Us7--F(V'.f
+1kYhf'tO@m4,rq2q>1-kn[KQqf_G0uR0!*`s6Td`o`+pks6sYsrr;imqZ$Bis(h*'qK><Wq8,F=
+s8VZip\k-##*Rp8qUgcKlMgq[rVoLj:]L@`!W)irq>p0Zs8NH+s8MWjrVuo4(rGb2L/IsNs763\
+!W)irq>p0es1BSnrn8$orrr2ps8Dip[fA)]s7--5:[e8^rqtgVJ,~>
+i;Yn5#Q4Q#*tUm@jSo\OD2u@1qr,"6UAl%`o)Hi4ci(g)b5_A?s7lKd!rr;B*jb_$L2$\fmJd[r
+s7>s^rrGR1rr3@j)795>s7ZKks7QBjs$-SancAUes7uceruJoTrVrlC\Gt3F;Y'ngs6BUZs3h7G
+s7cAY!87.V(qo_+N`l+s'AEK&-+j3W!:0[\quufnrrhE_)#4(/s*XYB?@_><^a#H>s8VBarrV]a
+s$`OBm`S"Lr:SMI^A#;IcN!_?oD`*\s'Jk-`^Kl^dUl2Hs7bp[qYuBfaT)59s8P"Us7--F(V'.f
+1kYhf'tO@m4,rq2q>1-kn[KQqf_G0uR0!*`s6Td`o`+pks6sYsrr;imqZ$Bis(h*'qK><Wq8,F=
+s8VZip\k-##*Rp8qUgcKlMgq[rVoLj:]L@`!W)irq>p0Zs8NH+s8MWjrVuo4(rGb2L/IsNs763\
+!W)irq>p0es1BSnrn8$orrr2ps8Dip[fA)]s7--5:[e8^rqtgVJ,~>
+i;Yn5#Q4Q#*tUm@jSo\OD2u@1qr,"6UAl%`o)Hi4ci(g)b5_A?s7lKd!rr;B*jb_$L2$\fmJd[r
+s7>s^rrGR1rr3@j)795>s7ZKks7QBjs$-SancAUes7uceruJoTrVrlC\Gt3F;Y'ngs6BUZs3h7G
+s7cAY!87.V(qo_+N`l+s'AEK&-+j3W!:0[\quufnrrhE_)#4(/s*XYB?@_><^a#H>s8VBarrV]a
+s$`OBm`S"Lr:SMI^A#;IcN!_?oD`*\s'Jk-`^Kl^dUl2Hs7bp[qYuBfaT)59s8P"Us7--F(V'.f
+1kYhf'tO@m4,rq2q>1-kn[KQqf_G0uR0!*`s6Td`o`+pks6sYsrr;imqZ$Bis(h*'qK><Wq8,F=
+s8VZip\k-##*Rp8qUgcKlMgq[rVoLj:]L@`!W)irq>p0Zs8NH+s8MWjrVuo4(rGb2L/IsNs763\
+!W)irq>p0es1BSnrn8$orrr2ps8Dip[fA)]s7--5:[e8^rqtgVJ,~>
+iW!firrVHbrNuX@s8VEcs8SNf$kESHV#UI_"[rC]b=3"4d-L0##PA&rr;urpm_([r$!!kqs8VZj
+gAh3Os8;Wgs0P_rs7-Nt!!j#6!<<&up&F:OrrDTh!<<#rrrE)mQkqs[s6d<?)&#W\rt#&-CAS]8
+s6fp`s&1*3s/n^'!(aa!p!bT#3kt^jp^@,js6p$gqY:*jo`,F$!<E06n[2F:"Y$2Gs8;oslMh%f
+p]%j$%gXtTs7?9j_C>O3`;]f5q>^2]./_t&$nf,N!#pR`s7H$br;Zd,qu@E4p+?=BrVuo=/-7/T
+s7c!"0*E>KrVlosr;Q^iY&59h!&@X2rW)Wkq#(*iq#L9k!!a#7!<<)n,l.B<r;HZqqM61+15c,(
+p&G'drUo^;9cO3J/7-Etnc8^gs.0D#rVults8Dor!<3!&ncSOFs8N3#s"O2E;ZmM4Yl=t$qssae
+s8Dor!<;ogs0t>r1Xc'u!<<)pm/QeZ"JYYbs6sBqs8VuTs*t~>
+iW!firrVHbrNuX@s8VEcs8SNf$kESHV#UI_"[rC]b=3"4d-L0##PA&rr;urpm_([r$!!kqs8VZj
+gAh3Os8;Wgs0P_rs7-Nt!!j#6!<<&up&F:OrrDTh!<<#rrrE)mQkqs[s6d<?)&#W\rt#&-CAS]8
+s6fp`s&1*3s/n^'!(aa!p!bT#3kt^jp^@,js6p$gqY:*jo`,F$!<E06n[2F:"Y$2Gs8;oslMh%f
+p]%j$%gXtTs7?9j_C>O3`;]f5q>^2]./_t&$nf,N!#pR`s7H$br;Zd,qu@E4p+?=BrVuo=/-7/T
+s7c!"0*E>KrVlosr;Q^iY&59h!&@X2rW)Wkq#(*iq#L9k!!a#7!<<)n,l.B<r;HZqqM61+15c,(
+p&G'drUo^;9cO3J/7-Etnc8^gs.0D#rVults8Dor!<3!&ncSOFs8N3#s"O2E;ZmM4Yl=t$qssae
+s8Dor!<;ogs0t>r1Xc'u!<<)pm/QeZ"JYYbs6sBqs8VuTs*t~>
+iW!firrVHbrNuX@s8VEcs8SNf$kESHV#UI_"[rC]b=3"4d-L0##PA&rr;urpm_([r$!!kqs8VZj
+gAh3Os8;Wgs0P_rs7-Nt!!j#6!<<&up&F:OrrDTh!<<#rrrE)mQkqs[s6d<?)&#W\rt#&-CAS]8
+s6fp`s&1*3s/n^'!(aa!p!bT#3kt^jp^@,js6p$gqY:*jo`,F$!<E06n[2F:"Y$2Gs8;oslMh%f
+p]%j$%gXtTs7?9j_C>O3`;]f5q>^2]./_t&$nf,N!#pR`s7H$br;Zd,qu@E4p+?=BrVuo=/-7/T
+s7c!"0*E>KrVlosr;Q^iY&59h!&@X2rW)Wkq#(*iq#L9k!!a#7!<<)n,l.B<r;HZqqM61+15c,(
+p&G'drUo^;9cO3J/7-Etnc8^gs.0D#rVults8Dor!<3!&ncSOFs8N3#s"O2E;ZmM4Yl=t$qssae
+s8Dor!<;ogs0t>r1Xc'u!<<)pm/QeZ"JYYbs6sBqs8VuTs*t~>
+i;X>_s8V`gp]('^s8Vrqp&Fdcrs\o,s82-^s7cQjs7Z9frs.uks6ojbrq69j!qH9]rr3T*s8Vur
+s7lNlqu?<gqGZ/Kp&=tMrVuogs8DriqZ$Tos8VQes8N#trpTmdn,<1Rs8N&ls6fpeo`"^erqufk
+s8;oqs7H'bq>^<err3f1s8Voms7u]ks8)3\s8Duos8)chpAb$hru1D,oDARbqt^9lo_/=Qq#C9j
+s7H?kp\+UUr;Q^#q=OUbmJlhXrsnkos("jhs7,^\m.LDYrr)j"q>9d`qtg=(med%ali6\Yl1Y/W
+rVuWlqYpL$o)Jafrr;Wjqu$Hn!r;Wjqu7Ass7H?es75sOs8VN&)?9U6rVu`jrr3;rm/QPJs7cQn
+r;Q^&mf3:dnFu_Js8;iq+Su-8q!\4^rr2rsn,N:bs8)cqnc/X^pAb0Ps8VKds6Tab-h%'7rr2rs
+n,*.as8N&uq#C*ds7?9jqu;`uiW&oWiEbsQs7QEjr8dm.~>
+i;X>_s8V`gp]('^s8Vrqp&Fdcrs\o,s82-^s7cQjs7Z9frs.uks6ojbrq69j!qH9]rr3T*s8Vur
+s7lNlqu?<gqGZ/Kp&=tMrVuogs8DriqZ$Tos8VQes8N#trpTmdn,<1Rs8N&ls6fpeo`"^erqufk
+s8;oqs7H'bq>^<err3f1s8Voms7u]ks8)3\s8Duos8)chpAb$hru1D,oDARbqt^9lo_/=Qq#C9j
+s7H?kp\+UUr;Q^#q=OUbmJlhXrsnkos("jhs7,^\m.LDYrr)j"q>9d`qtg=(med%ali6\Yl1Y/W
+rVuWlqYpL$o)Jafrr;Wjqu$Hn!r;Wjqu7Ass7H?es75sOs8VN&)?9U6rVu`jrr3;rm/QPJs7cQn
+r;Q^&mf3:dnFu_Js8;iq+Su-8q!\4^rr2rsn,N:bs8)cqnc/X^pAb0Ps8VKds6Tab-h%'7rr2rs
+n,*.as8N&uq#C*ds7?9jqu;`uiW&oWiEbsQs7QEjr8dm.~>
+i;X>_s8V`gp]('^s8Vrqp&Fdcrs\o,s82-^s7cQjs7Z9frs.uks6ojbrq69j!qH9]rr3T*s8Vur
+s7lNlqu?<gqGZ/Kp&=tMrVuogs8DriqZ$Tos8VQes8N#trpTmdn,<1Rs8N&ls6fpeo`"^erqufk
+s8;oqs7H'bq>^<err3f1s8Voms7u]ks8)3\s8Duos8)chpAb$hru1D,oDARbqt^9lo_/=Qq#C9j
+s7H?kp\+UUr;Q^#q=OUbmJlhXrsnkos("jhs7,^\m.LDYrr)j"q>9d`qtg=(med%ali6\Yl1Y/W
+rVuWlqYpL$o)Jafrr;Wjqu$Hn!r;Wjqu7Ass7H?es75sOs8VN&)?9U6rVu`jrr3;rm/QPJs7cQn
+r;Q^&mf3:dnFu_Js8;iq+Su-8q!\4^rr2rsn,N:bs8)cqnc/X^pAb0Ps8VKds6Tab-h%'7rr2rs
+n,*.as8N&uq#C*ds7?9jqu;`uiW&oWiEbsQs7QEjr8dm.~>
+i;WrSs7H?^rr3]+s8Vlns8DutqssdTr:p<dmJlnWrr4#2s8V`hpAb'jr9F=^mJm.bs6BXaoDeLZ
+qu?WkoDS[shbO4Hs8VlomJm4WrVm5is7cNfs8VQfs6ose!;QNm$iL&&s69R`p](-jmJ[&$kPX`I
+o)JRds7lWon+QeMs8)9co)JF\r;R-'q#:6is8W#ms6Tab"RuHjs82fq%I=&js8Voprr<#ks8W&s
+rsSi+s6p!bs7lWfs7cKl)u9)A+Fhr3s68@=90rUUq>]XXrU0^cqXjgfnGW@eo)AY)q#CBdr;ZQl
+nGiOUs6fdas8)Hho)8Lcq$[6%rr<#mr:Bs`qtL$g&H2Y(s$X6kq#C9jo`+Uas8;lr$i9o'nc/Ld
+s6BXYoD\b(r;ZTms7lNYs7$'`s8VQfs6p!frVc`umI^GSrr3?)nc/@Qs8VQfs6]gc"7Q9in,<8+
+p\Og]s763hs7Z0dnFkWSI/j$Bnkn9Do`"mjp>c1'~>
+i;WrSs7H?^rr3]+s8Vlns8DutqssdTr:p<dmJlnWrr4#2s8V`hpAb'jr9F=^mJm.bs6BXaoDeLZ
+qu?WkoDS[shbO4Hs8VlomJm4WrVm5is7cNfs8VQfs6ose!;QNm$iL&&s69R`p](-jmJ[&$kPX`I
+o)JRds7lWon+QeMs8)9co)JF\r;R-'q#:6is8W#ms6Tab"RuHjs82fq%I=&js8Voprr<#ks8W&s
+rsSi+s6p!bs7lWfs7cKl)u9)A+Fhr3s68@=90rUUq>]XXrU0^cqXjgfnGW@eo)AY)q#CBdr;ZQl
+nGiOUs6fdas8)Hho)8Lcq$[6%rr<#mr:Bs`qtL$g&H2Y(s$X6kq#C9jo`+Uas8;lr$i9o'nc/Ld
+s6BXYoD\b(r;ZTms7lNYs7$'`s8VQfs6p!frVc`umI^GSrr3?)nc/@Qs8VQfs6]gc"7Q9in,<8+
+p\Og]s763hs7Z0dnFkWSI/j$Bnkn9Do`"mjp>c1'~>
+i;WrSs7H?^rr3]+s8Vlns8DutqssdTr:p<dmJlnWrr4#2s8V`hpAb'jr9F=^mJm.bs6BXaoDeLZ
+qu?WkoDS[shbO4Hs8VlomJm4WrVm5is7cNfs8VQfs6ose!;QNm$iL&&s69R`p](-jmJ[&$kPX`I
+o)JRds7lWon+QeMs8)9co)JF\r;R-'q#:6is8W#ms6Tab"RuHjs82fq%I=&js8Voprr<#ks8W&s
+rsSi+s6p!bs7lWfs7cKl)u9)A+Fhr3s68@=90rUUq>]XXrU0^cqXjgfnGW@eo)AY)q#CBdr;ZQl
+nGiOUs6fdas8)Hho)8Lcq$[6%rr<#mr:Bs`qtL$g&H2Y(s$X6kq#C9jo`+Uas8;lr$i9o'nc/Ld
+s6BXYoD\b(r;ZTms7lNYs7$'`s8VQfs6p!frVc`umI^GSrr3?)nc/@Qs8VQfs6]gc"7Q9in,<8+
+p\Og]s763hs7Z0dnFkWSI/j$Bnkn9Do`"mjp>c1'~>
+hu=5brVuosp%J+TrVu`ds8V?\s8Vt's8Muss7QB^s7cQiqu?]ds8VQfqtg3^s8VWas7cQjoD/Fd
+rqZT]s82ior:^0\s8N&^mJlt]mJm4[s7u]ds8N#toDeXdq>'^`s7u]nqu>mQs8)ZnqXOUUs7u]f
+rr3,hq>^EjrVmT+rr;ilqu?]ls8Vfmq>^3hrqcZkrr5afo`+:Xs6Ta_nc/XYs7$'gn,*.Ts8V]j
+irArVq"+O\s7uTipAb0[rVHKmmf1RE0,FTt+@_mPq#B[Vs7Q-dn+m"`o`+dfoDS%Us82fn#lj]"
+o(rCbm/?n_&,Gu"q>L?ir;ZEhs82fgrVlg,li6taq"OgHs8Vlgs7--grW)Kert4r#s8Vcls7lEi
+meZtRs7QElrquuas7cQer;RN-s8V]jrr2rhs8)ccs7QEfs8;o`rr2p8rVuoos7lWds8V]jrr2rh
+s8W&ps7H?bs7lQm&b5]]%TrQ*pAb0ks8Vrks8W)Ys*t~>
+hu=5brVuosp%J+TrVu`ds8V?\s8Vt's8Muss7QB^s7cQiqu?]ds8VQfqtg3^s8VWas7cQjoD/Fd
+rqZT]s82ior:^0\s8N&^mJlt]mJm4[s7u]ds8N#toDeXdq>'^`s7u]nqu>mQs8)ZnqXOUUs7u]f
+rr3,hq>^EjrVmT+rr;ilqu?]ls8Vfmq>^3hrqcZkrr5afo`+:Xs6Ta_nc/XYs7$'gn,*.Ts8V]j
+irArVq"+O\s7uTipAb0[rVHKmmf1RE0,FTt+@_mPq#B[Vs7Q-dn+m"`o`+dfoDS%Us82fn#lj]"
+o(rCbm/?n_&,Gu"q>L?ir;ZEhs82fgrVlg,li6taq"OgHs8Vlgs7--grW)Kert4r#s8Vcls7lEi
+meZtRs7QElrquuas7cQer;RN-s8V]jrr2rhs8)ccs7QEfs8;o`rr2p8rVuoos7lWds8V]jrr2rh
+s8W&ps7H?bs7lQm&b5]]%TrQ*pAb0ks8Vrks8W)Ys*t~>
+hu=5brVuosp%J+TrVu`ds8V?\s8Vt's8Muss7QB^s7cQiqu?]ds8VQfqtg3^s8VWas7cQjoD/Fd
+rqZT]s82ior:^0\s8N&^mJlt]mJm4[s7u]ds8N#toDeXdq>'^`s7u]nqu>mQs8)ZnqXOUUs7u]f
+rr3,hq>^EjrVmT+rr;ilqu?]ls8Vfmq>^3hrqcZkrr5afo`+:Xs6Ta_nc/XYs7$'gn,*.Ts8V]j
+irArVq"+O\s7uTipAb0[rVHKmmf1RE0,FTt+@_mPq#B[Vs7Q-dn+m"`o`+dfoDS%Us82fn#lj]"
+o(rCbm/?n_&,Gu"q>L?ir;ZEhs82fgrVlg,li6taq"OgHs8Vlgs7--grW)Kert4r#s8Vcls7lEi
+meZtRs7QElrquuas7cQer;RN-s8V]jrr2rhs8)ccs7QEfs8;o`rr2p8rVuoos7lWds8V]jrr2rh
+s8W&ps7H?bs7lQm&b5]]%TrQ*pAb0ks8Vrks8W)Ys*t~>
+iVs,Srr<#ms8Mus..mQ;qu?Wpp]'m]s8Dutqt^9lkl:JYq"FUbs82Efs7uWfs82inp&4mi!Vl?e
+rt+u$s8VZir;ZNks8)<dp&FFYs$cb`s7?9jhZ*KJs82]nq"t'js7u]ns8;Qfs7QElkl:VRq#Bsc
+p&F[\s6TIZq>^-fnc/OSs8Dusr;ZEhq>^Kbs7cQmrVlrnqtU*h!qPsWrr4&<o`+OSs8W)up](9_
+s7$'Zs7Q0es7cBiq>^6ip%\Od!9jF^#Pe?!q#CBnq#::&p&G'cs5j:\kPkMAs5s=\(]+1&s7u]b
+s8)cms8)cps6BXap%SLdq#::@o)J"Lo`+shs7u3bo`"Xcs60LLs8VEbs8;`nq==Rcl2UJWqu$K^
+rr3)us8W)trr`#qr:g'f+o1]qs6'FZq#C6gs7lKcs8UsUs7cQfr;Z0as7Pp^s82cort"Ppq#C6g
+s7lKkq>^0grVc`q(%M>!s7QElq>^9jrqufcs8W)rs8VuWs*t~>
+iVs,Srr<#ms8Mus..mQ;qu?Wpp]'m]s8Dutqt^9lkl:JYq"FUbs82Efs7uWfs82inp&4mi!Vl?e
+rt+u$s8VZir;ZNks8)<dp&FFYs$cb`s7?9jhZ*KJs82]nq"t'js7u]ns8;Qfs7QElkl:VRq#Bsc
+p&F[\s6TIZq>^-fnc/OSs8Dusr;ZEhq>^Kbs7cQmrVlrnqtU*h!qPsWrr4&<o`+OSs8W)up](9_
+s7$'Zs7Q0es7cBiq>^6ip%\Od!9jF^#Pe?!q#CBnq#::&p&G'cs5j:\kPkMAs5s=\(]+1&s7u]b
+s8)cms8)cps6BXap%SLdq#::@o)J"Lo`+shs7u3bo`"Xcs60LLs8VEbs8;`nq==Rcl2UJWqu$K^
+rr3)us8W)trr`#qr:g'f+o1]qs6'FZq#C6gs7lKcs8UsUs7cQfr;Z0as7Pp^s82cort"Ppq#C6g
+s7lKkq>^0grVc`q(%M>!s7QElq>^9jrqufcs8W)rs8VuWs*t~>
+iVs,Srr<#ms8Mus..mQ;qu?Wpp]'m]s8Dutqt^9lkl:JYq"FUbs82Efs7uWfs82inp&4mi!Vl?e
+rt+u$s8VZir;ZNks8)<dp&FFYs$cb`s7?9jhZ*KJs82]nq"t'js7u]ns8;Qfs7QElkl:VRq#Bsc
+p&F[\s6TIZq>^-fnc/OSs8Dusr;ZEhq>^Kbs7cQmrVlrnqtU*h!qPsWrr4&<o`+OSs8W)up](9_
+s7$'Zs7Q0es7cBiq>^6ip%\Od!9jF^#Pe?!q#CBnq#::&p&G'cs5j:\kPkMAs5s=\(]+1&s7u]b
+s8)cms8)cps6BXap%SLdq#::@o)J"Lo`+shs7u3bo`"Xcs60LLs8VEbs8;`nq==Rcl2UJWqu$K^
+rr3)us8W)trr`#qr:g'f+o1]qs6'FZq#C6gs7lKcs8UsUs7cQfr;Z0as7Pp^s82cort"Ppq#C6g
+s7lKkq>^0grVc`q(%M>!s7QElq>^9jrqufcs8W)rs8VuWs*t~>
+i;X\as8Duqs8DrsoDe1Ws7uTms7H?kq#C-hq#14/pAagcs7cQkrr;orpAb0is8Vrps8Vijrr3#q
+rVlg%q>^Hhr;ZHgrVmN%s8W)ss7?9is7H?bs8Vrqs8)`p$hsYss8)ZnrVuonp&4mmq#C!arVllp
+rr3>ss8)c`s8M`lqYU3j!q?6frVpj2s8;osoDeOar;Z`hs8N&uoDJLcq>U<lqu-Ejrr;cks82Tk
+p&Fjdrr<#os8Duas8V]gp]'d\p&Fdas7?9eq#C-es8)cqq#CBhs8Vfmp](3js8)<dq"asirr;fe
+s8N&umJm4_s8Vinqu?Whqu9"Ns7ZKmrr<#ss8Vigs82]nr;Zfrqu?]mqu?9fqu?]hs82imrVuHg
+s8)Egnc/7]p[\@`s763ir;$Bcs8Vrqs8)`p&,Q>+p](9ks763irqHHmqYgEon,<7oqZ$Tls8W)u
+p&>!fqYpm$s8)Whs7QEjr;Q^"p](9kr;PdWJ,~>
+i;X\as8Duqs8DrsoDe1Ws7uTms7H?kq#C-hq#14/pAagcs7cQkrr;orpAb0is8Vrps8Vijrr3#q
+rVlg%q>^Hhr;ZHgrVmN%s8W)ss7?9is7H?bs8Vrqs8)`p$hsYss8)ZnrVuonp&4mmq#C!arVllp
+rr3>ss8)c`s8M`lqYU3j!q?6frVpj2s8;osoDeOar;Z`hs8N&uoDJLcq>U<lqu-Ejrr;cks82Tk
+p&Fjdrr<#os8Duas8V]gp]'d\p&Fdas7?9eq#C-es8)cqq#CBhs8Vfmp](3js8)<dq"asirr;fe
+s8N&umJm4_s8Vinqu?Whqu9"Ns7ZKmrr<#ss8Vigs82]nr;Zfrqu?]mqu?9fqu?]hs82imrVuHg
+s8)Egnc/7]p[\@`s763ir;$Bcs8Vrqs8)`p&,Q>+p](9ks763irqHHmqYgEon,<7oqZ$Tls8W)u
+p&>!fqYpm$s8)Whs7QEjr;Q^"p](9kr;PdWJ,~>
+i;X\as8Duqs8DrsoDe1Ws7uTms7H?kq#C-hq#14/pAagcs7cQkrr;orpAb0is8Vrps8Vijrr3#q
+rVlg%q>^Hhr;ZHgrVmN%s8W)ss7?9is7H?bs8Vrqs8)`p$hsYss8)ZnrVuonp&4mmq#C!arVllp
+rr3>ss8)c`s8M`lqYU3j!q?6frVpj2s8;osoDeOar;Z`hs8N&uoDJLcq>U<lqu-Ejrr;cks82Tk
+p&Fjdrr<#os8Duas8V]gp]'d\p&Fdas7?9eq#C-es8)cqq#CBhs8Vfmp](3js8)<dq"asirr;fe
+s8N&umJm4_s8Vinqu?Whqu9"Ns7ZKmrr<#ss8Vigs82]nr;Zfrqu?]mqu?9fqu?]hs82imrVuHg
+s8)Egnc/7]p[\@`s763ir;$Bcs8Vrqs8)`p&,Q>+p](9ks763irqHHmqYgEon,<7oqZ$Tls8W)u
+p&>!fqYpm$s8)Whs7QEjr;Q^"p](9kr;PdWJ,~>
+JcF^/#QFZ$rVuoqp\b$qp\Y!grVuWkrs&?"s82Wlq#:9pqY:$grs\c%q#:<cs8W#ss8)]nrrMrl
+qu6lrrr;Qhs8DZk'DVUss8VZis7cQnirB&Ls8;corVca!pAb!hp@nReqYU:(q>C9mkl:\Os8VWf
+s7$'grdk+1s*t~>
+JcF^/#QFZ$rVuoqp\b$qp\Y!grVuWkrs&?"s82Wlq#:9pqY:$grs\c%q#:<cs8W#ss8)]nrrMrl
+qu6lrrr;Qhs8DZk'DVUss8VZis7cQnirB&Ls8;corVca!pAb!hp@nReqYU:(q>C9mkl:\Os8VWf
+s7$'grdk+1s*t~>
+JcF^/#QFZ$rVuoqp\b$qp\Y!grVuWkrs&?"s82Wlq#:9pqY:$grs\c%q#:<cs8W#ss8)]nrrMrl
+qu6lrrr;Qhs8DZk'DVUss8VZis7cQnirB&Ls8;corVca!pAb!hp@nReqYU:(q>C9mkl:\Os8VWf
+s7$'grdk+1s*t~>
+JcF[.$1Iomo(MnZqYU6jruM"/s8Vrqs7uEhrVH6fr;HWoqtg?mr9X%Tqu?9drr3#up&=slq"ajf
+!r)9Zrr32as8VEbs7Z3e%eB&fo`+FUrq$0in+-MQrr3B"s8N#ns8Vccs8MW`rrVrcpAY'po`+s`
+m/6kcq>:3bJcFd1J,~>
+JcF[.$1Iomo(MnZqYU6jruM"/s8Vrqs7uEhrVH6fr;HWoqtg?mr9X%Tqu?9drr3#up&=slq"ajf
+!r)9Zrr32as8VEbs7Z3e%eB&fo`+FUrq$0in+-MQrr3B"s8N#ns8Vccs8MW`rrVrcpAY'po`+s`
+m/6kcq>:3bJcFd1J,~>
+JcF[.$1Iomo(MnZqYU6jruM"/s8Vrqs7uEhrVH6fr;HWoqtg?mr9X%Tqu?9drr3#up&=slq"ajf
+!r)9Zrr32as8VEbs7Z3e%eB&fo`+FUrq$0in+-MQrr3B"s8N#ns8Vccs8MW`rrVrcpAY'po`+s`
+m/6kcq>:3bJcFd1J,~>
+JcF^/%/p4rnc/Oequ?]pq=ssh'Dhb*s8;oqq>^?ls8)Wms7u]pq>UC,rVlisqu?]fs8Vufq>^Ko
+q>:'es8Vs"s7?6irUfmb!WDckrrMchr;RE/s7QElo)JUep](9bs8Vris8;]ms82`o&,Z2&pA=mi
+p&+L_s7QEjoR[&&s*t~>
+JcF^/%/p4rnc/Oequ?]pq=ssh'Dhb*s8;oqq>^?ls8)Wms7u]pq>UC,rVlisqu?]fs8Vufq>^Ko
+q>:'es8Vs"s7?6irUfmb!WDckrrMchr;RE/s7QElo)JUep](9bs8Vris8;]ms82`o&,Z2&pA=mi
+p&+L_s7QEjoR[&&s*t~>
+JcF^/%/p4rnc/Oequ?]pq=ssh'Dhb*s8;oqq>^?ls8)Wms7u]pq>UC,rVlisqu?]fs8Vufq>^Ko
+q>:'es8Vs"s7?6irUfmb!WDckrrMchr;RE/s7QElo)JUep](9bs8Vris8;]ms82`o&,Z2&pA=mi
+p&+L_s7QEjoR[&&s*t~>
+JcF^/(%VD)qZ$Qpp\Xges8Dfmp[eFbli6e[rrV]hn,E>7o_8Ccqu-Hgs8VQfs7uKes7Q3bs8Dfc
+s8W)oqu$<gs7H9cs7cQmq#:Eps7-*g%.sT!oDe4Wrr<#ps7-*g"7H0fr;Q]trr;rlrseu'qu$<g
+s8W)us6K^^rr3/us8W#srdk+1s*t~>
+JcF^/(%VD)qZ$Qpp\Xges8Dfmp[eFbli6e[rrV]hn,E>7o_8Ccqu-Hgs8VQfs7uKes7Q3bs8Dfc
+s8W)oqu$<gs7H9cs7cQmq#:Eps7-*g%.sT!oDe4Wrr<#ps7-*g"7H0fr;Q]trr;rlrseu'qu$<g
+s8W)us6K^^rr3/us8W#srdk+1s*t~>
+JcF^/(%VD)qZ$Qpp\Xges8Dfmp[eFbli6e[rrV]hn,E>7o_8Ccqu-Hgs8VQfs7uKes7Q3bs8Dfc
+s8W)oqu$<gs7H9cs7cQmq#:Eps7-*g%.sT!oDe4Wrr<#ps7-*g"7H0fr;Q]trr;rlrseu'qu$<g
+s8W)us6K^^rr3/us8W#srdk+1s*t~>
+JcF[.#k@rpk5Y>Qs8N#t(&7\+s7--hp](9boDej^s8;`ns7c-art>>2s7$'_q>^Enqu?]kr;ZZo
+rr)itp\Fgg"nqTfmJleQrrq`gpAaa]rr2uirVlokrVlfsp&+gnmeHh^l2LMY!<2rs%eof!s82Hg
+s7lKgl2USXrr2ukJcFg2J,~>
+JcF[.#k@rpk5Y>Qs8N#t(&7\+s7--hp](9boDej^s8;`ns7c-art>>2s7$'_q>^Enqu?]kr;ZZo
+rr)itp\Fgg"nqTfmJleQrrq`gpAaa]rr2uirVlokrVlfsp&+gnmeHh^l2LMY!<2rs%eof!s82Hg
+s7lKgl2USXrr2ukJcFg2J,~>
+JcF[.#k@rpk5Y>Qs8N#t(&7\+s7--hp](9boDej^s8;`ns7c-art>>2s7$'_q>^Enqu?]kr;ZZo
+rr)itp\Fgg"nqTfmJleQrrq`gpAaa]rr2uirVlokrVlfsp&+gnmeHh^l2LMY!<2rs%eof!s82Hg
+s7lKgl2USXrr2ukJcFg2J,~>
+JcF^/48/^Js8Vuls82]er;Zfrs8V?RrrDBbs8;ojs8;ons8W)urU]j`o)&ISs8McXFo^7rs8Duq
+p\k'fqu-Ntp]1?or:U(%r;HZ\&c_Fts8Vhn*]"3&mIpMY!r)`crr2ujp](9ls82cp%eTens4'Rf
+"`;Naq#C?dJcFd1J,~>
+JcF^/48/^Js8Vuls82]er;Zfrs8V?RrrDBbs8;ojs8;ons8W)urU]j`o)&ISs8McXFo^7rs8Duq
+p\k'fqu-Ntp]1?or:U(%r;HZ\&c_Fts8Vhn*]"3&mIpMY!r)`crr2ujp](9ls82cp%eTens4'Rf
+"`;Naq#C?dJcFd1J,~>
+JcF^/48/^Js8Vuls82]er;Zfrs8V?RrrDBbs8;ojs8;ons8W)urU]j`o)&ISs8McXFo^7rs8Duq
+p\k'fqu-Ntp]1?or:U(%r;HZ\&c_Fts8Vhn*]"3&mIpMY!r)`crr2ujp](9ls82cp%eTens4'Rf
+"`;Naq#C?dJcFd1J,~>
+JcF^/-2dN;li-GSr:g6kn,E@Zs82`opCRAopAFsds8VTgmelPRs7uZnrsSi+irB#\7h5S!oCi1`
+!;ZWo"oSE!o`"pjrrW&mq=t!irVum9!;HEbqu?[9l2C\_p](9clMpn^s8)?Zs8VihrrDlorseo+
+rUg-hs8P0/lg\Larr3#moR[&&s*t~>
+JcF^/-2dN;li-GSr:g6kn,E@Zs82`opCRAopAFsds8VTgmelPRs7uZnrsSi+irB#\7h5S!oCi1`
+!;ZWo"oSE!o`"pjrrW&mq=t!irVum9!;HEbqu?[9l2C\_p](9clMpn^s8)?Zs8VihrrDlorseo+
+rUg-hs8P0/lg\Larr3#moR[&&s*t~>
+JcF^/-2dN;li-GSr:g6kn,E@Zs82`opCRAopAFsds8VTgmelPRs7uZnrsSi+irB#\7h5S!oCi1`
+!;ZWo"oSE!o`"pjrrW&mq=t!irVum9!;HEbqu?[9l2C\_p](9clMpn^s8)?Zs8VihrrDlorseo+
+rUg-hs8P0/lg\Larr3#moR[&&s*t~>
+JcF[.70Shd+M3OG(8Um.riJ-[/>)nA!WWc1nO!I@pA+RkQkUF6p](9Z5mogQpAb*e!<;fns7H0f
+s7`BG!%k)JrrAE$%^k^!rrrAh1CKlXrr<#s'EJ16!<N)tm7IOWlhUPL0]i8m.eNN9"o"lL!%k)G
+rsJr/p](.$nGiOds7_*EjSs`~>
+JcF[.70Shd+M3OG(8Um.riJ-[/>)nA!WWc1nO!I@pA+RkQkUF6p](9Z5mogQpAb*e!<;fns7H0f
+s7`BG!%k)JrrAE$%^k^!rrrAh1CKlXrr<#s'EJ16!<N)tm7IOWlhUPL0]i8m.eNN9"o"lL!%k)G
+rsJr/p](.$nGiOds7_*EjSs`~>
+JcF[.70Shd+M3OG(8Um.riJ-[/>)nA!WWc1nO!I@pA+RkQkUF6p](9Z5mogQpAb*e!<;fns7H0f
+s7`BG!%k)JrrAE$%^k^!rrrAh1CKlXrr<#s'EJ16!<N)tm7IOWlhUPL0]i8m.eNN9"o"lL!%k)G
+rsJr/p](.$nGiOds7_*EjSs`~>
+JcF[..fjAaQ4IQjSJV>+r#*$@ZY&_,!VucoBlsB/Du]M9EU];5rVu\0POZ/#rVlg4!<;rro_ngb
+oD]r@p:4Q/r;_W1Te#U2rrD]js$?PYqdcSnI/s6Gr;ZNk!<;s#qYsojrO?nJs80N!rD:6%r;Z]p
+s8N&poD]r@p:4Q/s8Vur;N:_9CgR/<s8W)kJcFg2J,~>
+JcF[..fjAaQ4IQjSJV>+r#*$@ZY&_,!VucoBlsB/Du]M9EU];5rVu\0POZ/#rVlg4!<;rro_ngb
+oD]r@p:4Q/r;_W1Te#U2rrD]js$?PYqdcSnI/s6Gr;ZNk!<;s#qYsojrO?nJs80N!rD:6%r;Z]p
+s8N&poD]r@p:4Q/s8Vur;N:_9CgR/<s8W)kJcFg2J,~>
+JcF[..fjAaQ4IQjSJV>+r#*$@ZY&_,!VucoBlsB/Du]M9EU];5rVu\0POZ/#rVlg4!<;rro_ngb
+oD]r@p:4Q/r;_W1Te#U2rrD]js$?PYqdcSnI/s6Gr;ZNk!<;s#qYsojrO?nJs80N!rD:6%r;Z]p
+s8N&poD]r@p:4Q/s8Vur;N:_9CgR/<s8W)kJcFg2J,~>
+JcF[.0`_7Pm/["_rrDuqq\P"Ks7lWf!<;cm)#4'e"98B$s7?6js7cNrp]'8"r:Kpe"T.lks&]-q
+s8*=Xl14lQrrMurncSplqYpNop%/.^q\o#)lkB<ks8)cj!qH9js6ps$o(!^or;-Fi=C^=is7cQa
+pAb-ls8*=Xl14lQoDe^fi#Mdt+m](%rqV-Fir=N~>
+JcF[.0`_7Pm/["_rrDuqq\P"Ks7lWf!<;cm)#4'e"98B$s7?6js7cNrp]'8"r:Kpe"T.lks&]-q
+s8*=Xl14lQrrMurncSplqYpNop%/.^q\o#)lkB<ks8)cj!qH9js6ps$o(!^or;-Fi=C^=is7cQa
+pAb-ls8*=Xl14lQoDe^fi#Mdt+m](%rqV-Fir=N~>
+JcF[.0`_7Pm/["_rrDuqq\P"Ks7lWf!<;cm)#4'e"98B$s7?6js7cNrp]'8"r:Kpe"T.lks&]-q
+s8*=Xl14lQrrMurncSplqYpNop%/.^q\o#)lkB<ks8)cj!qH9js6ps$o(!^or;-Fi=C^=is7cQa
+pAb-ls8*=Xl14lQoDe^fi#Mdt+m](%rqV-Fir=N~>
+JcF^/$2+o.s8Nhls82lrrt=44'K<T$rrDfnoF9p^rsJf&%0$89!<<)b"onW-!<<)nqZQou1AUY?
+s8VfTC*kdZr:L'ipAY-mr:Bsg!"9S/p\t9hmJd1ds8)WdrrE*!#QOf-!"&f.rr4;CciM>is8;ob
+rsf#/rVuTRC*kdZr;ZfdmV%I@pP)lEs8Vopqgne.s*t~>
+JcF^/$2+o.s8Nhls82lrrt=44'K<T$rrDfnoF9p^rsJf&%0$89!<<)b"onW-!<<)nqZQou1AUY?
+s8VfTC*kdZr:L'ipAY-mr:Bsg!"9S/p\t9hmJd1ds8)WdrrE*!#QOf-!"&f.rr4;CciM>is8;ob
+rsf#/rVuTRC*kdZr;ZfdmV%I@pP)lEs8Vopqgne.s*t~>
+JcF^/$2+o.s8Nhls82lrrt=44'K<T$rrDfnoF9p^rsJf&%0$89!<<)b"onW-!<<)nqZQou1AUY?
+s8VfTC*kdZr:L'ipAY-mr:Bsg!"9S/p\t9hmJd1ds8)WdrrE*!#QOf-!"&f.rr4;CciM>is8;ob
+rsf#/rVuTRC*kdZr;ZfdmV%I@pP)lEs8Vopqgne.s*t~>
+JcF[.9*#"cp':Wir!EB$me$MYYS6d2!<;lp)<h+^+Sl$;s7l?jq<e2+q#C$ds6KRX!rW)or;Zfr
+qZ$<ipUCP0rrDofrrDrqs8;Hbqu6U#pFPJ,li@(arr4eM!;uisq=G*qq"k$_m/-fe<Fc'rrq?B`
+rVuirqZ$<ipUCP0qtpEk$1e#orrE)js8VP=s5X-0~>
+JcF[.9*#"cp':Wir!EB$me$MYYS6d2!<;lp)<h+^+Sl$;s7l?jq<e2+q#C$ds6KRX!rW)or;Zfr
+qZ$<ipUCP0rrDofrrDrqs8;Hbqu6U#pFPJ,li@(arr4eM!;uisq=G*qq"k$_m/-fe<Fc'rrq?B`
+rVuirqZ$<ipUCP0qtpEk$1e#orrE)js8VP=s5X-0~>
+JcF[.9*#"cp':Wir!EB$me$MYYS6d2!<;lp)<h+^+Sl$;s7l?jq<e2+q#C$ds6KRX!rW)or;Zfr
+qZ$<ipUCP0rrDofrrDrqs8;Hbqu6U#pFPJ,li@(arr4eM!;uisq=G*qq"k$_m/-fe<Fc'rrq?B`
+rVuirqZ$<ipUCP0qtpEk$1e#orrE)js8VP=s5X-0~>
+JcF[.!!*#u0`_4QrX/5rs'j%=]aXr@1=c$n?B+`3AGu65m/QSYqZ$S"N:4]/o)8Ug"RQ0goDe7X
+rsiM>m'7u<nIts&q?m#trr)j?rr;ZT@C>fB&+9Jtqtp:#rV['&s)En[c=ZqQs0b8o8YQ.`"Si#l
+r:p9k"CeJ!Z6oSN%J'N_C&.Oa70!;Nqu?PEs5a31~>
+JcF[.!!*#u0`_4QrX/5rs'j%=]aXr@1=c$n?B+`3AGu65m/QSYqZ$S"N:4]/o)8Ug"RQ0goDe7X
+rsiM>m'7u<nIts&q?m#trr)j?rr;ZT@C>fB&+9Jtqtp:#rV['&s)En[c=ZqQs0b8o8YQ.`"Si#l
+r:p9k"CeJ!Z6oSN%J'N_C&.Oa70!;Nqu?PEs5a31~>
+JcF[.!!*#u0`_4QrX/5rs'j%=]aXr@1=c$n?B+`3AGu65m/QSYqZ$S"N:4]/o)8Ug"RQ0goDe7X
+rsiM>m'7u<nIts&q?m#trr)j?rr;ZT@C>fB&+9Jtqtp:#rV['&s)En[c=ZqQs0b8o8YQ.`"Si#l
+r:p9k"CeJ!Z6oSN%J'N_C&.Oa70!;Nqu?PEs5a31~>
+JcF^/9`,:rq>(Ttn*UP_j8Z/$%48ggrQHBWs62]U-2[]A!;ulq!<;ZgqHa.WK)blHoF:j#p\uiF
+p\jib0-DUPs8N)ls8N*!qt^-cs8Dor#Nn&HW<rV!r;Q^3!<2uus81be"W!X.naRmpjPMT[q#C$c
+rtkJ/pS]_f-Fs0LnGhn@D#a]1jn\QKpA':>j8XW~>
+JcF^/9`,:rq>(Ttn*UP_j8Z/$%48ggrQHBWs62]U-2[]A!;ulq!<;ZgqHa.WK)blHoF:j#p\uiF
+p\jib0-DUPs8N)ls8N*!qt^-cs8Dor#Nn&HW<rV!r;Q^3!<2uus81be"W!X.naRmpjPMT[q#C$c
+rtkJ/pS]_f-Fs0LnGhn@D#a]1jn\QKpA':>j8XW~>
+JcF^/9`,:rq>(Ttn*UP_j8Z/$%48ggrQHBWs62]U-2[]A!;ulq!<;ZgqHa.WK)blHoF:j#p\uiF
+p\jib0-DUPs8N)ls8N*!qt^-cs8Dor#Nn&HW<rV!r;Q^3!<2uus81be"W!X.naRmpjPMT[q#C$c
+rtkJ/pS]_f-Fs0LnGhn@D#a]1jn\QKpA':>j8XW~>
+JcF^/!:p-h!W)corrD9^rt"f&s8DuknGiO]q>^<gs8)`p%/BJpnc/XZs8VQfs7QBk)"djoq>^Kg
+s82iroCN"\p\4^fq#:0^s8Drs)>sL2s8VKds82Bes8Ducqu?]bs7c3dp](*hrtbA/nc/Rds7lTn
+s8;`ms82iroCN"\p\t1#o(N"]s8;osrVuBbJcFd1J,~>
+JcF^/!:p-h!W)corrD9^rt"f&s8DuknGiO]q>^<gs8)`p%/BJpnc/XZs8VQfs7QBk)"djoq>^Kg
+s82iroCN"\p\4^fq#:0^s8Drs)>sL2s8VKds82Bes8Ducqu?]bs7c3dp](*hrtbA/nc/Rds7lTn
+s8;`ms82iroCN"\p\t1#o(N"]s8;osrVuBbJcFd1J,~>
+JcF^/!:p-h!W)corrD9^rt"f&s8DuknGiO]q>^<gs8)`p%/BJpnc/XZs8VQfs7QBk)"djoq>^Kg
+s82iroCN"\p\4^fq#:0^s8Drs)>sL2s8VKds82Bes8Ducqu?]bs7c3dp](*hrtbA/nc/Rds7lTn
+s8;`ms82iroCN"\p\t1#o(N"]s8;osrVuBbJcFd1J,~>
+JcFX-!V?<hrtbJ2s82`os8N#ms8VHbs8V`ks8Dipo`"k/oDejbs82irq>^Kas7ZKhs7ZEkp&G'[
+s8VZgrrMWbrVlllrr<#rs8NE(s8W)ps7uZorVlg>p&>!jrVuTkq#CBjp&G'hrr)los6]jYs8Vck
+s6fpeo)AY!p]'a_s7ZKgs7uWnnGi66s5X-0~>
+JcFX-!V?<hrtbJ2s82`os8N#ms8VHbs8V`ks8Dipo`"k/oDejbs82irq>^Kas7ZKhs7ZEkp&G'[
+s8VZgrrMWbrVlllrr<#rs8NE(s8W)ps7uZorVlg>p&>!jrVuTkq#CBjp&G'hrr)los6]jYs8Vck
+s6fpeo)AY!p]'a_s7ZKgs7uWnnGi66s5X-0~>
+JcFX-!V?<hrtbJ2s82`os8N#ms8VHbs8V`ks8Dipo`"k/oDejbs82irq>^Kas7ZKhs7ZEkp&G'[
+s8VZgrrMWbrVlllrr<#rs8NE(s8W)ps7uZorVlg>p&>!jrVuTkq#CBjp&G'hrr)los6]jYs8Vck
+s6fpeo)AY!p]'a_s7ZKgs7uWnnGi66s5X-0~>
+l2LbZrr33!r;Zfks8Dor!rDrkrr33%s7lQmq>1'i%fZM$s8W)uoDeF^q"FadJcC<$JcGWIJ,~>
+l2LbZrr33!r;Zfks8Dor!rDrkrr33%s7lQmq>1'i%fZM$s8W)uoDeF^q"FadJcC<$JcGWIJ,~>
+l2LbZrr33!r;Zfks8Dor!rDrkrr33%s7lQmq>1'i%fZM$s8W)uoDeF^q"FadJcC<$JcGWIJ,~>
+kl1_]oD8@a+8l07nb`@^s8Vccr;Zfqs8Dutp\=dcs8Micp&G'jq#13noCdb8JcC<$r;V9~>
+kl1_]oD8@a+8l07nb`@^s8Vccr;Zfqs8Dutp\=dcs8Micp&G'jq#13noCdb8JcC<$r;V9~>
+kl1_]oD8@a+8l07nb`@^s8Vccr;Zfqs8Dutp\=dcs8Micp&G'jq#13noCdb8JcC<$r;V9~>
+l2Le]rVc`uq"+ObrVlosr;-EnpAY'srr<#trVuWXrr3#tqu6Ttr;-BfJcC<$JcGWIJ,~>
+l2Le]rVc`uq"+ObrVlosr;-EnpAY'srr<#trVuWXrr3#tqu6Ttr;-BfJcC<$JcGWIJ,~>
+l2Le]rVc`uq"+ObrVlosr;-EnpAY'srr<#trVuWXrr3#tqu6Ttr;-BfJcC<$JcGWIJ,~>
+l2Lnbs8Vokrr3]'rr;ohs8DlqmJ[(Sn,NF_rr;c^rr3N*s8Vuks8W#ss7Z'as7u>=s+13$s8;nI~>
+l2Lnbs8Vokrr3]'rr;ohs8DlqmJ[(Sn,NF_rr;c^rr3N*s8Vuks8W#ss7Z'as7u>=s+13$s8;nI~>
+l2Lnbs8Vokrr3]'rr;ohs8DlqmJ[(Sn,NF_rr;c^rr3N*s8Vuks8W#ss7Z'as7u>=s+13$s8;nI~>
+kPl+kq#(0kp&G'goDS^hqu??^rVm#ss7uWlrr3&lrVlcq!rW)trr<#sJcC<$JcGTHJ,~>
+kPl+kq#(0kp&G'goDS^hqu??^rVm#ss7uWlrr3&lrVlcq!rW)trr<#sJcC<$JcGTHJ,~>
+kPl+kq#(0kp&G'goDS^hqu??^rVm#ss7uWlrr3&lrVlcq!rW)trr<#sJcC<$JcGTHJ,~>
+l2Le^qu6Trp\b$j&,lP.o)8U\s8Vfms7?6hq#:9rnc/OepAY(!r:g6`qYL6er;ZVEs+13$s8;nI~>
+l2Le^qu6Trp\b$j&,lP.o)8U\s8Vfms7?6hq#:9rnc/OepAY(!r:g6`qYL6er;ZVEs+13$s8;nI~>
+l2Le^qu6Trp\b$j&,lP.o)8U\s8Vfms7?6hq#:9rnc/OepAY(!r:g6`qYL6er;ZVEs+13$s8;nI~>
+k5Q_)rr<#lp&FX`s7cQhs7Z<hs8DutqZ$0ep%&.[s8Dunr;ZNbrVlumqZ#u7s+13$s8;nI~>
+k5Q_)rr<#lp&FX`s7cQhs7Z<hs8DutqZ$0ep%&.[s8Dunr;ZNbrVlumqZ#u7s+13$s8;nI~>
+k5Q_)rr<#lp&FX`s7cQhs7Z<hs8DutqZ$0ep%&.[s8Dunr;ZNbrVlumqZ#u7s+13$s8;nI~>
+l2NC0s8VZis-XfMeGlm-(Uj@a(F-Njs1fWp`W*e''u0d[+<@ojZmug4oDc6F+LZk$JcD,;qYog\
+J,~>
+l2NC0s8VZis-XfMeGlm-(Uj@a(F-Njs1fWp`W*e''u0d[+<@ojZmug4oDc6F+LZk$JcC<$qu;0~>
+l2NC0s8VZis-XfMeGlm-(Uj@a(F-Njs1fWp`W*e''u0d[+<@ojZmug4oDc6F+LZk$JcC<$qu;0~>
+kl1\ZoD\bA%ahRUp-P1O7/o??WB1(V1pE]9s!snQ1B0J7[5.VFUS]gHpH,d[2uipUq>L6k"o82u
+rr2kIs+13LrrE&rquQEerr2?cJ,~>
+kl1\ZoD\bA%ahRUp-P1O7/o??WB1(V1pE]9s!snQ1B0J7[5.VFUS]gHpH,d[2uipUq>L6k"o82u
+rr2kIs+13FrrDfYs*t~>
+kl1\ZoD\bA%ahRUp-P1O7/o??WB1(V1pE]9s!snQ1B0J7[5.VFUS]gHpH,d[2uipUq>L6k"o82u
+rr2kIs+13FrrDo\s*t~>
+l2NL9s8;]mlP[^`$iD+2k8!J#q">Ens!$P(%e(55mhPj5n(nl\"97^,li.:Trs/Jtrr)j'q=O[Z
+qu6Nms8RZJJc)PG"T.iaq"t'g!r2comf.e~>
+l2NL9s8;]mlP[^`$iD+2k8!J#q">Ens!$P(%e(55mhPj5n(nl\"97^,li.:Trs/Jtrr)j'q=O[Z
+qu6Nms8RZJJc)MF!r2WhrVllqm/MS~>
+l2NL9s8;]mlP[^`$iD+2k8!J#q">Ens!$P(%e(55mhPj5n(nl\"97^,li.:Trs/Jtrr)j'q=O[Z
+qu6Nms8RZJJc)PG!ri)qk5Tr~>
+l2NU)s8Drps.0Bb$LA6%rrE'!p[8CfrW)ue"9/B$m0<7es8NGs%J0T$s8N-"q?luns8Vrkp\t6l
+JcC<$WW*;(r;QTerr2KfrpKf:~>
+l2NU)s8Drps.0Bb$LA6%rrE'!p[8CfrW)ue"9/B$m0<7es8NGs%J0T$s8N-"q?luns8Vrkp\t6l
+JcC<$V>gYls8V]Ws*t~>
+l2NU)s8Drps.0Bb$LA6%rrE'!p[8CfrW)ue"9/B$m0<7es8NGs%J0T$s8N-"q?luns8Vrkp\t6l
+JcC<$V>gYps8VcYs*t~>
+kl37.q>^?ln,Mndrr_WI%f[:DknNde&aoK(r"Abl)u:6+lk9<uqtL?frt"Df$i^/8lc--3ZEBq2
+\$`TIZ`\kdJ[DD`$)t/6\[:u.r;Q]`s*t~>
+kl37.q>^?ln,Mndrr_WI%f[:DknNde&aoK(r"Abl)u:6+lk9<uqtL?frt"Df$i^/8lc--3ZEBq2
+\$`TIZ`\kdJ[DD`#H=r4\[;&0rTsQ7~>
+kl37.q>^?ln,Mndrr_WI%f[:DknNde&aoK(r"Abl)u:6+lk9<uqtL?frt"Df$i^/8lc--3ZEBq2
+\$`TIZ`\kdJ[DD`"f\`2\[;"os*t~>
+l2LhPs7ZEk/aB<BqF%]f9E.#MO];AW6Ck#<s%/0S8,[email protected]]nkcH]1AgtKs8D`lrrpF:
+rr<#rJcC<$V>gVpnA4o"s8MZjJ,~>
+l2LhPs7ZEk/aB<BqF%]f9E.#MO];AW6Ck#<s%/0S8,[email protected]]nkcH]1AgtKs8D`lrrpF:
+rr<#rJcC<$V>g\qn%eu&li2J~>
+l2LhPs7ZEk/aB<BqF%]f9E.#MO];AW6Ck#<s%/0S8,[email protected]]nkcH]1AgtKs8D`lrrpF:
+rr<#rJcC<$VuQeq"8V>urTaE5~>
+kl3XAp[S:Q0Esl%s3(fr[f=G^/[k3L_^-&Grjt9(\c8o_*P_Wt"<tV[rPK-YbQ%,1s8W&ts891u
+rr2uoJcC<$V#LSq[f?(#qu?]qo`'F~>
+kl3XAp[S:Q0Esl%s3(fr[f=G^/[k3L_^-&Grjt9(\c8o_*P_Wt"<tV[rPK-YbQ%,1s8W&ts891u
+rr2uoJcC<$VuI&"rr2\urq66hmJh\~>
+kl3XAp[S:Q0Esl%s3(fr[f=G^/[k3L_^-&Grjt9(\c8o_*P_Wt"<tV[rPK-YbQ%,1s8W&ts891u
+rr2uoJcC<$W;d/%q"ss]Z2F4jm/MS~>
+kl2"Xs8V?\s7Z?is8;]m#l"B!nGi:Ws7?0g"76'dnc&Omp](0ks7#XZrs\i&r;Q`%s8W)up&Fi=
+s+13LrrDurrrTY/qYL6lrq-5@~>
+kl2"Xs8V?\s7Z?is8;]m#l"B!nGi:Ws7?0g"76'dnc&Omp](0ks7#XZrs\i&r;Q`%s8W)up&Fi=
+s+13Lrs&8rrr9;'p?Va/~>
+kl2"Xs8V?\s7Z?is8;]m#l"B!nGi:Ws7?0g"76'dnc&Omp](0ks7#XZrs\i&r;Q`%s8W)up&Fi=
+s+13MrsJ_tq"jijqt'^`rU0]9~>
+kl344s7ZKmoDedgs7lWor;ZTmrr;ims8W)urVuoprqlWnrVucps7QEhs8;omrr<#srr3<(s0;V(
+qu?TorIP!"s/#_sYQ+:ls8W)js*t~>
+kl344s7ZKmoDedgs7lWor;ZTmrr;ims8W)urVuoprqlWnrVucps7QEhs8;omrr<#srr3<(s0;V(
+qu?TorIP!"s/H#&rr)]mX8_YTs*t~>
+kl344s7ZKmoDedgs7lWor;ZTmrr;ims8W)urVuoprqlWnrVucps7QEhs8;omrr<#srr3<(s0;V(
+qu?TorIP!"s/Q)+rVQBaql'D[qu-K]s*t~>
+kl1bPs8VcjrttV4rr;TipAb0jp]('hrVuWhs6]jbp&G$irsAZ$s7lWoq=t!eq>UN&s8.BIJcDPG
+$N9u(pU1%rs8N&lrVllro`'F~>
+kl1bPs8VcjrttV4rr;TipAb0jp]('hrVuWhs6]jbp&G$irsAZ$s7lWoq=t!eq>UN&s8.BIJcDPG
+$N0l%p9akos8;ojrVllro`'F~>
+kl1bPs8VcjrttV4rr;TipAb0jp]('hrVuWhs6]jbp&G$irsAZ$s7lWoq=t!eq>UN&s8.BIJcDPG
+$MsSsoWnGgrVccirVllro`'F~>
+kPkYPs8VZhs8Va"rVuohs760hnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQeq>UN&s8.BIJcDPG
+$N9u(s0Mb$s6fpbrr2uroDa=~>
+kPkYPs8VZhs8Va"rVuohs760hnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQeq>UN&s8.BIJcDPG
+$N9u(s0Mb$s6fpbrr2uroDa=~>
+kPkYPs8VZhs8Va"rVuohs760hnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQeq>UN&s8.BIJcDPG
+$N9u(s0Mb$s6fpbrr2uroDa=~>
+l2LkRs8;?brsSPns8Vlorr;ZkoDJUf%/Khks82iro`+Uas5j7[$2FDtrr<#os8VulrrTP,qgncu
+s/#bqrWW2sr361urr*&tmf3=_oDa=~>
+l2LkRs8;?brsSPns8Vlorr;ZkoDJUf%/Khks82iro`+Uas5j7[$2FDtrr<#os8VulrrTP,qgncu
+s.KAnZ2ae%rri5es8Vlcs*t~>
+l2LkRs8;?brsSPns8Vlorr;ZkoDJUf%/Khks82iro`+Uas5j7[$2FDtrr<#os8VulrrTP,qgncu
+s.KAlZi'h,qsOLapAOX`J,~>
+kl1YUrr2ugrr3Dqs8Vfbs8VQfpAap[rr<#d'*%D"s7u]cs8Vc`s7Pj\q"jm_p\t<$s8.BIJcDSH
+$NBqsnG0$[qu#sPrr3#pp%/36~>
+kl1YUrr2ugrr3Dqs8Vfbs8VQfpAap[rr<#d'*%D"s7u]cs8Vc`s7Pj\q"jm_p\t<$s8.BIJcDMF
+"9/&pXoA>$o^Mk[!VuBZs*t~>
+kl1YUrr2ugrr3Dqs8Vfbs8VQfpAap[rr<#d'*%D"s7u]cs8Vc`s7Pj\q"jm_p\t<$s8.BIJcDJE
+!r`/(rr3#no)AXjp[\:Ts*t~>
+kl:\]/H5JFRL9Y(s1KZs_#D:j*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(s1g$'`q]B0!jhq(JcC<$
+V>h#&q"<qHWq,o\r;6HmrUKo<~>
+kl:\]/H5JFRL9Y(s1KZs_#D:j*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(s1g$'`q]B0!jhq(JcC<$
+UAk\ss0MV%s8W#qs8;orrq-5@~>
+kl:\]/H5JFRL9Y(s1KZs_#D:j*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(s1g$'`q]B0!jhq(JcC<$
+T`5#'rVm*$rVu`mrVZ<fJ,~>
+kl1Y\rr4G=+j7n>n5#UR6N9H@VFKqP:SXONpcYFE4o\<LX@E4JT;"sIqbWcO9_eVhZiBoRs+13H
+rt,,$o'Z.anFcP9r:U*bs8Vugs*t~>
+kl1Y\rr4G=+j7n>n5#UR6N9H@VFKqP:SXONpcYFE4o\<LX@E4JT;"sIqbWcO9_eVhZiBoRs+13E
+rso&.bPM5;kl:AVp](6hrq6;A~>
+kl1Y\rr4G=+j7n>n5#UR6N9H@VFKqP:SXONpcYFE4o\<LX@E4JT;"sIqbWcO9_eVhZiBoRs+13C
+rrCRJrs.ojq#C$cqtB[^J,~>
+l2NC/s8V?`ruf+h0)l"HpBpU.l1,/TrsJ;b%0$P)q#L3lrT=@a!<;@!nG`d[r;cWm!jhq(JcC<$
+V>gPmq#CU2k5PDWq=F4XJ,~>
+l2NC/s8V?`ruf+h0)l"HpBpU.l1,/TrsJ;b%0$P)q#L3lrT=@a!<;@!nG`d[r;cWm!jhq(JcC<$
+V#LN!$3^_7!so#ElMpn[q!\7^p&BO~>
+l2NC/s8V?`ruf+h0)l"HpBpU.l1,/TrsJ;b%0$P)q#L3lrT=@a!<;@!nG`d[r;cWm!jhq(JcC<$
+V#Lr8)&!bs%L`X^mJm4\p?_\Ks*t~>
+kPm..s8VSc$4`*r&+KT#rrE)s!<;iqs8E&u$Le!#rsJ,m!:pisrW)un!<;[+q>($lZiBoRs7?9d
+rpg$cro*k[rqu]nrr)lsrr)cprlP0KrquZhq"OIUq>C0irl>$Lq#D6N+;uIN-33i9p&G'^oDa=~>
+kPm..s8VSc$4`*r&+KT#rrE)s!<;iqs8E&u$Le!#rsJ,m!:pisrW)un!<;[+q>($lZiBoRs8;om
+rnm_arr;utrr;utrr;utrm(NJrr;utrr;u`s8DrbrrE&srrE&CrsfPt3^5_o5<AuIr:U*io(2m3~>
+kPm..s8VSc$4`*r&+KT#rrE)s!<;iqs8E&u$Le!#rsJ,m!:pisrW)un!<;[+q>($lZiBoRs7u]m
+rS[\arVuirrVuirrVuirrR1`FrV6EYrTX@\rQP9P,#D<E=Bnm#%fcM!qtodZo`'F~>
+l2O!Hp&G'Zs!,1n/,fqFo*t^4k4T;br"A8_$iV(,pC$m0o&gD\$M3d#s8NE#r<WB"s7+16Za[38
+b-JC`\?<;tZMh'.ZN%6:[CEcY]"G\dZh^g(Z2_-0Zhq'-Z2:^:Z*UdEZaI-IZaI-IZaI-IZa02-
+&[/4DXKAt8Zb<`DVmNG5WMd#lZN%6S[Bm9I[Bm?O]WecLYe@BY]!f/WYIq<TYJIQU^9tAU[C-"B
+!O\s,!!!&t!"G@3Yd1jK]!o/W]<eEFiNick\ZiNGTs_B+Z4X&9'a"sH!"feCo(r:apA=adp&BO~>
+l2O!Hp&G'Zs!,1n/,fqFo*t^4k4T;br"A8_$iV(,pC$m0o&gD\$M3d#s8NE#r<WB"s7+16Za[38
+b-JC`\?<;pZ2q59riuL,rN61)Z2(`rZMV!-Z4+"DZ*LX?Z*LX?Z*LY)Z4XFN_R-SWY-PaNY->UF
+_Qg2JrNZ1(rj2I+(p^KV\?E0CXh([I[B[*CWjf7@Wk>LA\Zu.?rj;^5&?Z-C"WRaQ$3UF*a0W([
+Z*jS:"1bb:\`'n#Y.CmIYbJS9qQg[?#!k4A5Wq\'#64`#s7c*aJ,~>
+l2O!Hp&G'Zs!,1n/,fqFo*t^4k4T;br"A8_$iV(,pC$m0o&gD\$M3d#s8NE#r<WB"s7+16Za[38
+b-JC`\?<;tZN%95[^<LB[/[E3Yl:d,Xfeu*[f3Z6ZN%0+ZMq6.[LomNY->(5Y->(5Y->(5Y->.9
+o!Aq:`3unXXK]CM[(!u_`3ZZF[f3Z6ZMq*-XoYi8rNcI-s0=MiX/rG%[Ap^@Xg"n(Z`UL0\>ld@
+ZG+/j]XbGVZ`OBC&1nkG+VbKhca^?iY-P77Z+@?E^#?C)Ye7<QZD>"AqR$jK-#RIKH?4=@*<6'4
+q!\+Os*t~>
+kPm[Dli6JUfY7df;3naMs$EN[3;WGJWNSJT9V&.Ps$E$a5kI[>X#U.J8?.bGs7QElq"4Obs1eC%
+r;ZfmJcGKEs82rqr;6Hjs8Mcms8N#q"T/,or;?'a*rc3=s8N&ts8N&ts8N&rpYkT=s8VuorqZ9_
+q!7bRl2Lh_rVQQn"nquqqZ$KlrsA,nrr;cnmJZq\rVd?)p])<Y#7Vab/-,8$lMgMUrrr#nrq?-[
+iq!6@p$)JK!VGjWoaC0f'ESXB!!EZ0i:6gH!r)<cp&BO~>
+kPm[Dli6JUfY7df;3naMs$EN[3;WGJWNSJT9V&.Ps$E$a5kI[>X#U.J8?.bGs7QElq"4Obs1eC%
+r;ZfmL&_)Ms8Duq"T/&mr;OP4!Uog_rr`#ms8N#t!qlTnr;Hfurr;ugrr`/rqYpKo&G?&!pAXjd
+rquc\rqcWdrp0L\s8N&u'a-H^0KiB!7g&e[nc/7\q>1!YrVucQrrW0!pAP!kr;$@"#=^mR91DK=
+#P.WfrrDuhs*t~>
+kPm[Dli6JUfY7df;3naMs$EN[3;WGJWNSJT9V&.Ps$E$a5kI[>X#U.J8?.bGs7QElq"4Obs1eC%
+r;ZfmJcG]KrqulprU^'hrUBjXrUBgkn+ZeXqXjU]rrDcds8W&sqZ6Qjq>CEkqY:!fr=JMrp[e:T
+qtp3dkPP#Nnb_\Ns8W)urt5`0=\r[[AmuMTqt^9drV?3ao$.1F/9uQ(O,/C),Q@B2pA"O\o`'F~>
+l2NI:qu?]fs0MnKWW0RV(!?*f&Mq#us0`ONf)NBG!6"oF3!IM*`sX*Co`)`G+3"$Pqu6s"Y5/+t
+rr;ioM>R;MqYU9is8E6#qtg0aqY9sap\Xmb!r2Werqc-]')_Y)qu$?hqu$?hqu$<fq#:6_rr3f.
+s8MrppAa^]r;QWnr;QWnr;QWnr;QWiqu6U/qZ$'brq$-gmJcVMrq$-[rqZQmqYUs$pZVZ0)?L9H
+![%L4o(VtXnc&OlrqZBbo'52r#2J>b%LFF&qB$:h!#PeC!<<-2!:p'eo)JU]rq6;A~>
+l2NI:qu?]fs0MnKWW0RV(!?*f&Mq#us0`ONf)NBG!6"oF3!IM*`sX*Co`)`G+3"$Pqu6s"Y5/+t
+rr;ioM>R;KrqlQgs7lZkrqccpqu#gX!rVrnmJ@[qqtg3dqtg3dqtg3dr;Zcrr9aL_qt9pf!r2fc
+qYCBmqYU-dqYpBhr;ZZort>>,rpTjdo`+sZs7,pbo`+O_qY'pqqZT_a2F]qm63R5d"n;Qlrr;uR
+rs&E$67s]U55@DR#=LXE845^.'`\41n,NFdo`'F~>
+l2NI:qu?]fs0MnKWW0RV(!?*f&Mq#us0`ONf)NBG!6"oF3!IM*`sX*Co`)`G+3"$Pqu6s"Y5/+t
+rr;ioLAUuKp](3j!rr6!r;HBequ$ZtrVuipnbX-uqt^-bqt^-bqt^-bqtpEiqtK:Iq"XI[rrrDp
+qsF:Zr;6NirV-<brq-6a!r)Ndr;R<%s8Vlos7$'[qu?Bip&Fs_rs0KZD.nHOF(H6errD`CrrcOr
+6=*ai=:e[fEGgA_J9>QXs8V`Rq#10`s*t~>
+l2Lq`s8W&trVlg*k5,,Ks7u]prTjI_rVlg=p\k*[s8W)up&G$krVuK`s7Q9ds8N&uqtg9krVcc*
+rr3&qs8ITLs8N#qrVQWo#64]&rr;utrr2ZlrVl`pnc&%X!VQBdrrVoooBuVYrqcO0o^)MQr:^'^
+q=O@ToD&.Op\=IFq=O+Mq>U7Vq=sXQlMq8)$31&2'`d[kh=pR=q"s(Hq!mu#,Tn9R+s8'P+s8'P
++s8'P+s8'P+s8'P+s8'P+s8'P*%i/fl2KiYkiV*kkiV*k!$2IS#71YT!:p-grrW,krq6;A~>
+l2Lq`s8W&trVlg*k5,,Ks7u]prTjI_rVlg=p\k*[s8W)up&G$krVuK`s7Q9ds8N&uqtg9krVcc*
+rr3&qs8IlTqu-WrrlG-1rXJo$rVuosrr)`nrq6<\rr;Qgq#;-)nGiLfq>^9jrVZ]ls8Vrps8DHe
+rUopb3<qB17mo^73s>T`lMpb]qu>jZs8N$S4[2+p5!M4q5!M4q5!M4q5!M4q5!M4q5!M4q5!M4q
+3))='rs/it4$lD-5Xu%Xs8W'!s82HgJ,~>
+l2Lq`s8W&trVlg*k5,,Ks7u]prTjI_rVlg=p\k*[s8W)up&G$krVuK`s7Q9ds8N&uqtg9krVcc*
+rr3&qs8IiSrr'e8!;l?`&FfGhq"FFVq"t$]qs4%NpA=^bq>:0ir;QfpoD\airq-3mp&G'jp\tUF
+>'5@LMM5FXs8VrnrrDHbs!'m0<)ut!<)ut!<)ut!<)ut!<)ut!<)ut!<)ut!<)usp@SZRq%jl"&
+F*rCSC)m9Rq"OUaqt0o=~>
+kl21ms8)cqoD7tVs7-'fli6\Xrt4\hs8;oso)Jacs7c9ap&F[[qu6lms82irrqlWn#Hn%(p%&.\
+r/1LNs8W'1rVH<ap\+7NpA=jhrr;utrr;usqu-?ir;QfsrU]mdrpTjln,NF_qu?]irVllmnc&Xh
+qtg/6qt9j\qtp*So^hbEp$;;Cp##H7n+?;Eq"aa\p\"+E,60.m"Tn`.+93]A-n7J,1FPd6/1i@D
+p\Ogar;-?fr;-?fr;-?fr;-?fr;-?fr;-?fr;-?frquchq#($crqucnrqucj!#lO^$P<dc!;Gp]
+s7H6erq6;A~>
+kl21ms8)cqoD7tVs7-'fli6\Xrt4\hs8;oso)Jacs7c9ap&F[[qu6lms82irrqlWn#Hn%(p%&.\
+r/1ISrVZWm!ri/tq#:TurVlcprVlcbrW)oorq$-jrr)Ecs8NMorr2N\rr2Hdrqucbnc&Ibrr2rt
+#5eH!s8W&krr3&us7uZo"7?-gqu-QprqudT64I-P92\AW9*RRK3B0\a4>BYZ3'B>&rr2lqrVlcp
+rVlcprVlcprVlcprVlcprVlcprVlcprr3,tq>^Blq>Up-4#oPk7QE[>s6fmcoD\@]J,~>
+kl21ms8)cqoD7tVs7-'fli6\Xrt4\hs8;oso)Jacs7c9ap&F[[qu6lms82irrqlWn#Hn%(p%&.\
+r/(CUr;-9frq69qr;QWnr;QWmrql`lrW2rrr;?-c!WMiao+:WjjnSW>nGE+Nq=sUSjn/BHqY:!_
+rs&B#q>:'^oD&=cp@J;"="8Z'IZ'#7DB;bZ8OZ`?764X,6qU)-rrN#qpAYU;<*EmMEaW,is6fa[
+n,;kXJ,~>
+kPkYOs8VQdrs8B!s7cBis7l-`rrr2tp&G'brr2umrr3<!s8W#jp&Fddq>C6srr<#qp\)"Gs82g&
+rquTfp\"1Lp\smdqu63e%fZD*r;QWnr;QWnr;QWnnG`mls8W&tqu6Whnc/UVruqC=q"a^\q"a^Q
+p%e1Nq!RnKm.'Z3n+,]5l13p+nes;<r\4X3/Li++!!O#6!"TG;lf[g/hY$X7nFQ;Clh0'5!;lNj%
+g4(&,SM7;*WZ$9r;ZNkrq-5@~>
+kPkYOs8VQdrs8B!s7cBis7l-`rrr2tp&G'brr2umrr3<!s8W#jp&Fddq>C6srr<#qp\)"Is8W)u
+rVlfdrrE&trrE&fs8N#es8W';rVlcprVlcprVlcprVlTls8Duqs8Vf]rqZTjnc&Ugq#;3(s8W#q
+s7cQnr;Zfns8Vloq>^*es!g;pr\tZR4$,V*&iWKN1/U+k%KHA+s6BXarVHNn!rW)uir'&VpAOaa
+o(`.nrt.7Y8Noa13X#K^p\sdTs*t~>
+kPkYOs8VQdrs8B!s7cBis7l-`rrr2tp&G'brr2umrr3<!s8W#jp&Fddq>C6srr<#qp\)"Hs8;ig
+s8Dlrqu-Kcs8DopqZ-Tbruh46qY9p^qY9p^qY9p^qY9[YqtpEms8Vl`qt9[PoCVnWrU9ajqu?]n
+r;ZE[rrY2T8kT%Q$VO:q0jK$KCm&jA,lR`CpA"XfrSmMSo'c;Ap?VMI%fI8:>@_,X>>Pn2r:BdU
+o)F4~>
+kl2:\s8)?ep](3lmJm4Js8D9`s7QBk!r;lgrr3,pnGhqIrr3#uqu6U#o_\Udrr;]hqu6o,rVuon
+rUfl9rs/Q$r;$-^p%\4[s8N&rs8MTh0E2"Ns8N&ts8N&ts8N&rq=j[Yq"ORXq"ORXq"ORYqr7GG
+m.Bo;q"a=WrV6Ebrq$%2qtTp\p\=LXp[Iq@p\=CPp[mq>ng$+K.4[1k1+"I@n+ZhV)u'$rnE9iY%
+hf-P&etE6mdfi;p\=LWp%7G<pYc&On,<7dn+cqY!!`Sfs8Vurs7c0cJ,~>
+kl2:\s8)?ep](3lmJm4Js8D9`s7QBk!r;lgrr3,pnGhqIrr3#uqu6U#o_\Udrr;]hqu6o,rVuon
+rUflAs8;iss8McmrVcfsrr2Kgq>T=P%d*fkq#CBjs8VNer:p<al2Lt_s6p!fr;$?l%Jp)]7RB*s
+6RY8Z3WK*Rrs0/k5"\.59K<IZrrN)tqu6Zjrr:sV!9jC\!9j7X&H;e7%1<CH#m:e(rqlEgrq?!a
+J,~>
+kl2:\s8)?ep](3lmJm4Js8D9`s7QBk!r;lgrr3,pnGhqIrr3#uqu6U#o_\Udrr;]hqu6o,rVuon
+rUfl>s8Mujs8DfpqYg9krV$9jrVcWnq>gENrrD6Xrs&&oq!e"DrUKmfrU9am5uUQK85M0>6Uq(T
+s8)fpr;R$W??D'^Q],2lo)I\D!93tP!93hL&GlV>)BKk?*YfOZrV?'bs82HgJ,~>
+l2NC7s8W#sqZ$<hs8Vrds8Vfms8Dorq#C<mrqcZns8W#ss6BX]qZ$?jl2Ue[s7ZEk$iB_ss8B>'
+s8Vrqrdk+JrrN,srql?f"TJ>srr2!Y!WMlco`FmR"Sr*6!s%ifqtg3cq"a^\q"a^\q"a^\q"a^[
+pDEEU0/G+;.O[5/./!6!o^_YIo^VSEp%S4[p`&u$oBQB%&el>n&M4"Jo'lDKoCr(Uq!n%Mo).MI
+#Pe>ir:g6kp%n\!rqlK_jLa@>o]lGUs82ieoDa=~>
+l2NC7s8W#sqZ$<hs8Vrds8Vfms8Dorq#C<mrqcZns8W#ss6BX]qZ$?jl2Ue[s7ZEk$iB_ss8B>'
+s8VrqreUULrqHHhrq$0frW<-!ro*kbp(7B6"Vq:Q";:k2jSobf4#f;X5;G&a4#[-=q#C?mrrW0!
+rqQL)r!#GE4A%Xq8-Jkjr;Zfprr2p"qu?]piVs/Xs76*^s8Vccrs\VKpAb0_s82cfrp]pZs*t~>
+l2NC7s8W#sqZ$<hs8Vrds8Vfms8Dorq#C<mrqcZns8W#ss6BX]qZ$?jl2Ue[s7ZEk$iB_ss8B>'
+s8Vrqre1=OrVQKlr;clrrVucoqZ$HmrV-?krVcTpqYU0\rUBgsr#$%d*&&K`)']Rgs8VuYrs;:h
+:.A2O6;U0<p&>0oq>'mdrVm-H@pa/,G]%"(e,K[Js76*^s8VcbrrCpTrs&5tqYTscp%/36~>
+kPkVVs82cp#Oh]mq>^*eq>UBpr;HKl"8)Wgr;Q^&rVuors8)clrqQKm$iU#%rr2lqZ2FOqq>UDO
+rr;ouqu-NkrrDrqrrW3"r;Q]rrql`qrWE,rqu-Bj$NL,*r;Zfjs8W)tr;QcqrVllorVlues8VK]
+ruh42!%8]k*$#V',QRB+o^)5Co(DSHo_%hKo_%kLo_%nQ0a96gp%S+QnG`.iq"ORXq"ORXq"ORX
+rV-BhrqcfrqsOgd!!Vuhq=XXYrql`ls7cWhp=&X?p\XXTm]cBYpAF=XJ,~>
+kPkVVs82cp#Oh]mq>^*eq>UBpr;HKl"8)Wgr;Q^&rVuors8)clrqQKm$iU#%rr2lqZ2FOqq>UDJ
+rr)fqrW`#prr;utr;Q]rqYpKorVc`qs7uX*s8Dups8VZhrqcKjrqlZnq>L9upAP!js6]jdmIpPd
+"@[email protected]'$57.>h!;Z-arAjm=s#U6@62gf`r:'acrY5>1rr)if&H`@D('Y<Q#lal(qZ$E5rr`,q
+q7Z_+!ri/srr2QiJ,~>
+kPkVVs82cp#Oh]mq>^*eq>UBpr;HKl"8)Wgr;Q^&rVuors8)clrqQKm$iU#%rr2lqZ2FOqq>UDO
+rqud4rqcHbp@RYBo(;SLqZ$Top\Xg`q>1$er;ZZn&cDV)rV?Ehnb`4Xp\Xj_qYU!bqZufiqu?]`
+s8VK[rs9EF>$5lf@oQVOm/R)\s%Ebm8Ol388,rVgs7kgX$2b\M()%u3*tAk]rrW3"rQ,!@pA=a)
+r;ZfqnGe"~>
+l2Me&r;Q`rli6bEs76!`rr;Tirr<#ns8VQfp&"X]rVc`ujT#8Trr3<#s8Dutnb)bUrqucr[f$.+
+q=ojI"9/2pr;?Qpqu$KnrWE)qs7lEirqlcqq>UZsrV$'es8;iq#6+Z&q#CB[r;Quus8Vros7Z6f
+(@hGG+pJ&S%2ffZmG7-jnEoB/kOS*`q(*+1p@e7Sp\+@Tpt#63oCr%Nqss[bqZ6Wor;R2es8DNa
[email protected]'^^qu?]q1&UqDp\=LXp\=LXp\=LXp\=LXp\=LXp\=LXp\=LXp\=LXp\=LXp\=LXp\=LX
+p\=R`rWN/$nF?GCs*t~>
+l2Me&r;Q`rli6bEs76!`rr;Tirr<#ns8VQfp&"X]rVc`ujT#8Trr3<#s8Dutnb)bUrqucr[f$.+
+q=o^ErVdK/nb2t]s8Vrps8W#sp\t-irr;uhruM%9pA+agqu6Wos7u]mp&=sQs8Dusrq??joCi1P
+q>UEo('['#4$?#$7QLbRoDeXdrqHHfs8O`8qE+a>rr)rurr)j$iW&rVs8W&ds8N#trVuj*jT#8R
+s8VrqhuEHKr58O=Zh=%ls8N#rr;cihs*t~>
+l2Me&r;Q`rli6bEs76!`rr;Tirr<#ns8VQfp&"X]rVc`ujT#8Trr3<#s8Dutnb)bUrqucr[f$.+
+q=oXC"T.ufkj89>%Ia#js8N&kqtg-bqYgBbrs/K#pA+agq>:0f#57ohnGE%ArqZotqXXFVmI9o8
+q=t!i#p*N"D/joGE*FC\rrE&srrb>P8P)SR9E7i_rs%TbrVZ]oq<7hiirB#Ns8VurirAfQrr<#s
+rQG3FrVHKmZhX@^s*t~>
+l2NC8s7c-brs8Z1!<:7_'Z'gh%kG'Xs2$#sci:I>%D;_D.NcD)aors)s8BhG'$U=S$2aPoqYRSs
+rqlNjs,-dYrVH<drV$6prqZ?br;?Hls8N#p!WN,trr;rqrXAMqr9s[WqYC0\s8VimrrW&pr;Q^!
+r:p<lrV6C/h>eDn":>,2"!7Nt+[Ik+.lSD0-n"TSqXP6jp\=RZq=sd\q=sUWq=XROrU^!krVQKj
+rr)isrqQKnrVlisrQ5'Br:p6d\EX$D~>
+l2NC8s7c-brs8Z1!<:7_'Z'gh%kG'Xs2$#sci:I>%D;_D.NcD)aors)s8BhG'$U=S$2aPoqYRSs
+rqlNjs,$aTs8W)tr<W?"r:g!cs8W)srsSf*qu6QnrVlfrrr;fnrVmi5r;Z9do(MkWn,E@Ys8N&l
+qtU*crU]LVrUfs_r>,G$*()8G:d.9-9,.(Z=%YA681[Iq3:6_LqZ$Tns75a[r;R9+rVcWbqu$3c
+pAFmhs8Drss8;]ls8=_NrVZWlrVZWlrVZWlrVZWlrVZWlrVZWlrVZWlrVZWlrVZWlrVZWlrVZWl
+rVQEiqRHP)rr2lp!<2WjJ,~>
+l2NC8s7c-brs8Z1!<:7_'Z'gh%kG'Xs2$#sci:I>%D;_D.NcD)aors)s8BhG'$U=S$2aPoqYRSs
+rqlNjs,-gRrsSi&p\"1MmdKlCq#($h"o.ujq>C0hrrN,srVl]o)u]g:o)8"Lo_e%RqssX_qt9^X
+q=OCIkk=`;oD8.rs8Ful>^qc]IV<[Ss$gHs5t=a0=$o=<rrN-!oDSdgq>9mjq=4@\qu?Zprs&H!
+rVcWgq"snHr;-6`q=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq=j^Zq>'aU
+q=V2plMlA~>
+l2NR5s8Vons6fp#8Gt65WD*%EV2nRTqa6pO4T@p2YtG$cVR8kS:TU0Xs6rdaSh^-<r;QZnrs-"4
+s8;Qdp&'^I"9/2pr;?Qpqu6U&o(;ePo'GW2qu6Tls8MrnrsJc'pA"7Vq=4:Xr;HU#rVl3`pAXaa
+p\t.FnG`@VpAY!gqu-Ejqu-<W!"]qQ!!!60-3,pkg#__eo]P`:n`oc=oCVYHoCVbNqY:B^qsjRU
+oDAIUs8W)orsST$s8DrskPtAXs8Kt:"T5t5rqc!]J,~>
+l2NR5s8Vons6fp#8Gt65WD*%EV2nRTqa6pO4T@p2YtG$cVR8kS:TU0Xs6rdaSh^-<r;QZnrs-"4
+s8;Qdp&'ODs8ET.rq-0gs75j]rVu`cq#CBmrr2`n!<2or"oA2ms8Vljrs8W(mf3%]pAapes!@=;
+s7?*es8N&ts8N&ts8E3`:JF5J90cD\:]Kh[s7u]err<#mnc&monGi1]p\+Ucli.Opr;6BUqYKaQ
+r8[hMrr;lpqZ$TpdJa(E"T,e0qYC'g!<)orp&BO~>
+l2NR5s8Vons6fp#8Gt65WD*%EV2nRTqa6pO4T@p2YtG$cVR8kS:TU0Xs6rdaSh^-<r;QZnrs-"4
+s8;Qdp&'LC#lFJnmeZeWo(W+_"8r/us8DiprVZZqrVQTurVufqs8Mfn#4VZgs7lWjrr3,os8Vij
+pAYOF@Y0JmMhlG#,%1HErVllro`#3qq"aa_rVuokq>^'b!rM]`rV$9d%f6(erVc?]rS[SDqtg$^
+qYC9jqY&D1#kn,lqY%>op\4%SJ,~>
+kl3=(rVuo[s8P-ts!R+($N1\=kna!j'CY](q%NJk*;gN0kR.=krpBs^rse2a$NKu#rr`&dYPeA!
+!W2kRrVl]qrVlcq%fH@lq"=4JmdKZ9kkX];rr3'!rVc`lrVliq%/fu!q=!SBp%%kPpZ;>J2tHb6
+q!e(Qo]t\pkMk[h'dY(N,:+Q\-:Rt\!!WE'!tu:ImI^)>lhBcAq!7_Nq"a^\q"a^\q=jdkp&+CY
+nc&OZrrE&tr;ciqrrE&mrs&>qqu?]qrVZZArs&5os8TM(rp0T7~>
+kl3=(rVuo[s8P-ts!R+($N1\=kna!j'CY](q%NJk*;gN0kR.=krpBs^rse2a$NKu#rr`&dYPeA!
+!W2kNrVl]tqu$<imJ6bdp&FXRs8;for;uusrqcQrrr<#no)&Femem(fqu?Nmq>C70p](6ms"m#.
+5sdk(5s\TU8hrq,3CQM##6+W,rVHQes8VZVrs&<!pAajdrU]perVcZoqu?Kqo_\Ucrql^"p\=Ub
+s8Drpr;lipdej@Er;Z`"pA+^errN-!rVlKiJ,~>
+kl3=(rVuo[s8P-ts!R+($N1\=kna!j'CY](q%NJk*;gN0kR.=krpBs^rse2a$NKu#rr`&dYPeA!
+!W2kRrVc`rrVZNns7H-e#laktnbr:Zqtp?l"oJ,mqu-KkrrDllrrD`Zrt@t,='8U-='8R?*,f;?
+MLC)$?6&kB"8r3!q!A"aq#C$co)8.T!;lZn&cMUuq=s[UoC;GIqYKdTpA=a_q9o$Eq=XR\poO&Z
+qu-Hms8DTiJ,~>
+l2NsBr;Zcrs7*<[s7QHjquZluq!e^krrE)e"TJK%nHARhs8N>o&G5i&s8N-"q@!,rs8Vicr;Zf*
+q"=@SrV;$E"98;R"o/-##i>CVqu6`sr;?Km&H;V)lM1,@oCD#0nE9B/o&0N<%ajk9m5$+8-6FQB
+,ShQcqW&LWiW'Z($j7%B)\E)EkPP)Nr9XFUrql]^q>:!f!VcKirrDTPrs8Q&qWn1\q>]dYrrDuq
+rltKCr;Zcs]D_d.rpg#=~>
+l2NsBr;Zcrs7*<[s7QHjquZluq!e^krrE)e"TJK%nHARhs8N>o&G5i&s8N-"q@!,rs8Vicr;Zf*
+q"=@SrV;3JrVd<*rr:pg!sAf9"pkG9)!Lqu!<2ip!<2lq%IsJuqZ$Tgr;ZNkr;Z9crsdres8>;D
+2aT_u.mu9]q#:ck#VnV:92e,L1^j?PrVm)hs7ZKjs6fmarVZ`oqu6Wq!VcKirrDWhrseu-rr;ut
+rr;utrr;usq#(KnrqYs]s82i]r;Qcpp\ufDs8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&t
+s8N&ts8N&ts8N&trVm#t[f61'r;Zcqo`'F~>
+l2NsBr;Zcrs7*<[s7QHjquZluq!e^krrE)e"TJK%nHARhs8N>o&G5i&s8N-"q@!,rs8Vicr;Zf*
+q"=@SrV;0Irr)ir$gf,U+=8]e+r:n=nc&OjrVQQlrVluuqu-KlrrDfdrrE#srrDKdrs;Li7T`c"
+6sWSlp\tU?<,I>KQ@*sW*<5R-rrVckqYpKpnG`FcquH`lrtbA)qtg0alM18RrVQQjrVQQjrVQQj
+rV-=%q>9gDo^hMGjnelOrVcTer@@pHs8Durs8Durs8Durs8Durs8Durs8Durs8Durs8Durs8Dur
+s8Durs8Dor#6">&q"O[ar;Qisqu-3fJ,~>
+kl3jEs7lW`s"_XprtYCr(\&79p_EE#+lWG6lPolq&cW7.jW4@$s7@?!rsIui#lal(m)ulG\@8'X
+^U:8PYe#[ss0_j76FF/'U:(%C*Yf>&(F^R/Z_FJ(ZaI-FZE^U<ZaI-GZE^U9_iLt&TWt8tWMu=:
+,oJcc'gEZd.&*]9Wgp9(Xfeh#qQ1U=V?SRa$ig86$R>_U_6:/LXi[QQYeR<]q7$F5qQq!H[^`]C
+Z`h'KZEpjCZEpjCZEpjCZMLp-Z4O:MU8tc7[\p72WkPa@Xg5G7YPYR[ZE^^?ZE^^?ZE^^?ZE^^?
+ZE^^?ZE^^?ZE^^?ZE^^?ZE^^?ZE^^?ZE^^?ZE^[5Zc8m@rr`8ur;Q6dJ,~>
+kl3jEs7lW`s"_XprtYCr(\&79p_EE#+lWG6lPolq&cW7.jW4@$s7@?!rsIui#lal(m)ulG\@8'X
+^U:8PYe#[srNR*AZ*CU7_ZMtd5X@Uo6okRhX0/\4Z2Ls1Za-mArNcI0+3^.c]s>Pa`P0'i5WUMo
+1Fc?Y4[$9g[^`<La1AmpY55^I\Y]d'4@M:r68^t4Z,!HJZDkg>[B.!>`3fBK!4)I-'t1NZZ_t+3
+]X"iJZE^^?ZE^^?ZE^_4YlM$-Yn+FBYJ.oj[C<EA]s4fF[_):?1:"6lZa-pCZa-pCZa-pCZa-pC
+Za-pCZa-pCZa-pCZa-pCZa-pCZa-pCZa-mFXgQ-Arr2fps8MZjJ,~>
+kl3jEs7lW`s"_XprtYCr(\&79p_EE#+lWG6lPolq&cW7.jW4@$s7@?!rsIui#lal(m)ulG\@8'X
+^U:8PYe#[s!3lI*6a3l)]=6?4?"n.sC0+P3(<j(hYct:7YdCdG['6^;Yd1XE\'q(lb.uEDeBcIV
+;+j,^6p"sH:/8mV`P]"#d)3f?\,*u[_QFebApefOH!OSeYe-[0XJj.9[]R->_6O!Ds/lF)Y-7],
+'st<TZ)+\+]!/EEYd1L=Yd1L=Yd1M4ZN%9G[^WfX]>Le]`5oj)\?;^>YH=t8](`Kf['I'E['I'E
+['I'E['I'E['I'E['I'E['I'E['I'E['I'E['I'E['I'E['[EK[)8I0qYU0is8)fpp&BO~>
+l2O!HqYU<mrO#K%s7nsOX>p5BT;jsPpb8bD5lWU1\h3qMUouWT6_UD6s7JCXUc/8Gs8W#lrVZN'
+p\"I`s7lNErtGD3rr;utrr;utrr;utrqlWns8Moq"oeQ%r;6KPs7?6crtYG#n,OIE#R1_N*u=qH
+nG)nYrquZhrqQKirqZTh+7_9=2^1"".4?K%i:6<enF?#3nE]N-o_&4Up\t!frqcNnrVuTlrVllr
+rr3)ss8W#cs8W&rrrDo]rt58.p\XXSp[.MFqu?QmrquNfqu"e>"T8,qqn2n-"9/5rrpg#=~>
+l2O!HqYU<mrO#K%s7nsOX>p5BT;jsPpb8bD5lWU1\h3qMUouWT6_UD4rq/:XVE"VLs8W&ns8W)4
+qtL*is7lNUrXJo,s8N&ts8N&ts8N&tlMph^nc/Lco)A^hnc/Ufs8Dus%fcA)"[GC;5t4(.3=#T`
+n,Emq69%Lk68CV`3(``As5s=\%Jg&%s82ims7Q0eqZ$Tjr=o;6"Uk\K#R:\;s82irqYpBjo_na_
+qu6Hl#6+Z%s8Mrlrr)rsq!\7\rWiK#s8;coqYpKo"T/2us80k:"oePu\GlI's8W)js*t~>
+l2O!HqYU<mrO#K%s7nsOX>p5BT;jsPpb8bD5lWU1\h3qMUouWT6_UD5s7\U_V)SACqtp0\r;Z`/
+qY'mfs7lHSrser,rVuirrVuirrVuirnbrFd$2so(qtU$bs8W&rrs8T'rVuirrVuins76-Ws8Doo
+rs9o^EH->RBkLEfm/IAb6W--E5Y4L9=oSF$pA"Xkrr;`hs8;Tj(^Cd"2)dWM,9-scp%7tLqtp?a
+rVH0`qYL3drq6?erqcWks8DuorVllpnc/XfoD]$orV?Bks89k9"SfD$qYU0i!r`#pp&BO~>
+l2Le`p&=tNqDQUus7=eL+3OT)%OAj`s25osa8`h!'Z0je+;D`n^Dn<>oDciH&&J8Cs8VHbqXF6W
+q"+CSrr2otr9F:arVuoqpAYj+r;QWnr;QWnr;QWnr;QN`o^i+Tqu6lms7>mSqu6-c!rW)oqu6Zo
+rVm)sr:p*br8dYNs8)fqrr3l8qtKR[&J,6N!!*B@!9`J7o(D84nE00+.K(Y7.P!&$0^SJrp[7hN
+q>'p`qt^-bqt^-bqt^-drpg!prqlK_o()GIqu4S7rVl`m!<2rsq#8V>#6+T$qmc\*rr<#tnGe"~>
+l2Le`p&=tMqDQUus7=eL+3OT)%OAj`s25osa8`h!'Z0je+;D`n^Dn66mJb0F'?:(Ms8VKds82i%
+s8;olrr3*"pA=deqZ-E^r!*-!r;Q`ks8N!$s8N&ts8MHd$haPps7uTiq>^6ip%JFbrr)cuqu6?h
+o_najr;QHirWiDts82`ns6'1Ws8Mrp%fZM.#!#(@845a37gT.lrr3/qq>^<ks8>(f5!;%k4?iT@
+p&FgErrE&gs8Drbrs&K&rr;utrh'2orr;l)s8Dfo!<2TiJ,~>
+l2Le`p&=tTqDQUus7=eL+3OT)%OAj`s25osa8`h!'Z0je+;D`n^Dn9;nc-fR'Z0_;o^gu6q=Xcj
+s7u]erVcWlpAFmgrrDuerso#&rVQ?drVHKirVQQjrUKdarsSJrq>KdKmI1#Lqt0mf#lFStrVQQj
+rVQKj"ShibqXFI[!r2W`rqZZnrVZZqme$PZrr)j',$f8;K7\Q"GVJjk#$"Jp:/">Sr^m.i!<(@G
+s8Dups8Dorq>L<iqYc]Z"T,V*qu-Bk!<)QiJ,~>
+kPkh^q"=[[s8)ckrr2uirr3?&s8W#gs82irrpTjd#6"Q$s7QE[rr3r1q=j[^pAapfs6B@Ll`K^G
+p$hkPs8N&urr;l`rs&H!p&G'kqWe(br:Tgas7Q'`s8VclrrVrfr;-HhrVZZspAa^[s8W'2k5P8W
+nG`%Yr;QWnr;QTgp\F^cr$_C.m/S(2#64`+#m11Z0IJ7t/MI5M+<g(9lKdd'md]l.p\=L[o_e<3
+s3UcLrr;l)s8D9`J,~>
+kPkh^q"=[[s8)ckrr2uirr3?&s8W#gs82irrpTjd)#aI6s7QE[rr)feqYL-iq>^0gs7--hrk\U6%
+/U#!s8)]loDA%Kqtfm\#QO_uo`+siq<%\`r;-6gp\4[_qY^'es8;ckr;I,qrpKdbrVl]nr;HZ\r
+r3&ls7c'`(Ae%<84#p984lN9#k^VF2)RK^(HOK7q#:Tgs8W)uq>^2?s3UcLrr;l)s8D9`J,~>
+kPkh^q"=[[s8)ckrr2uirr3?&s8W#gs82irrpTjd#6"Q$s7QE[rr3?#rr;rqo(M>>p?MYW!5ea8
+$iBtus82irq>^6fs76'nqYg9co)8Oap\FdYqu6U'qXsg`oB>E0qYg*`rr;oms82ims8;or!rr8u
+rVI#lqs4.VqYU'bq>:3Zrr3&os8)3a'I[m?JV&f=Li>6O@STHe;d2"X<`f(r!;ZTn!r`/oJcF*s
+"oeQ!\,ZEms*t~>
+l2Lk_rVucnrr`5ks8Dor$3'\ts7lWop]'j`rt+_us8M`fr;Zfrr;Zfqr;??grrDT`!"/Mcrr)Qj
+o`+sdqt'Rfq>C9mpAb$gkl21hp](9hn,E@erpT[_s7c?arr`8uqtpBg(%hM)nc&OSrq69ip&=ab
+rqHHes8MNertGA2rVuirq=<tDo(;VJo'PQ>!"Su.*<cQh!%[=.p%.qMo'u50n*]W4n*oo>p%\.F
+r;?5=s3CWJrr;l)s8D9`J,~>
+l2Lk_rVucnrr`5ks8Dor$3'\ts7lWop]'j`rt+_us8M`fr;ZfppAP!is8Vrorrhur#6bP8#Rh4P
+"97fhqXaXQr;?9Yrs&K&s7ZKirV?Horr)Hd#6"AkrVccmrVm0"s8DoiqZ$Qoo`$$-s8VZis6]j[
+s8Vfmq>UEfs7H?gnGiOdrVZWlrVZWgrsf;j9fbj?7m0]Y6hp]YqY^?noCr7fqXOUaon!.grrrE%
+qmZV(li2J~>
+l2Lk_rVucnrr`5ks8Dor$3'\ts7lWop]'j`rsJ;os8M`fr;Zfqq#(.-p\Xg`qt:C5)Bfn1',_Gk
+s763iqZ$Ejs7-'frr_upqu,aY"8VKWo`"mjqYpL&o^VJEp@S"NpA"O`q>V9/s8V`ks6p!_s8Vlo
+qu?]dp?VGCk4\NFo)S^_rsC8_Jp!!4KQM]!?gRdpp&G'bJcF$q"oeQ!\,ZEms*t~>
+kl1h]s7H?dpAP"+nGiO_s7lWorr;rms8;okqu?Wps82cp3;NURs7u]oqYpHnp[e@Z!$!+*(D%K$
+(]a-qnGN:Xr:KRUo^_YFo^_YFo^_YFo^_YIpA4^_r;-3d!<2He$i^2"o(2bUoCDVTrqZTorr2`m
+q#C$sq=s[Uq=j[Oq=s^Vq=ss]!:Kd_!;63d0_d">,pt)i.46AG!$MCH!!*HA(BEmrr;Q*\jnJK)
+p\":Rp\4IXq>9aOs8Vurs8ITLd/O:Ks80;*rTjK6~>
+kl1h]s7H?dpAP"+nGiO_s7lWorr;rms8;okqu?Wps82cp+o209rq6<kqu?WpoC;h[!\ll-5rq1i
+1)']^o`+sas7c6Vrrr?"s8Dusp\t6loDB-ts8VZhs8W&ts8Dutrpp'`rsSf'r;HQkrVccrrVc`q
+$MON"rr)lsqu$<]r;Qcmq>UOX4$#G%3>OY=-5'9A8PDZF6pCnUrVulds6K^bl1b2_p@/+^qYU9j
+JcF*s"oeQ!\,ZEms*t~>
+kl1h]s7H?dpAP"+nGiO_s7lWorr;rms8;okqu?Wps82cp,PhB<rUg-irVucnnFHVZ(JnXZBjb=K
+9.']=rVuoos8N&urpfpGrr`5nk4\WN!qt^MrVHQk!<)Ee!;lTl!W)?arrDiirtA%&:J48M8P;uK
+21KRsMM?P"@j:mO"o&&ks8Vifrs/Ajs8VlhqtksEd/O:Ks80;*rTjK6~>
+kPlUqs8DWjlKnQGs8W&mq=t!irr;rms8;okqu?Wps82cp$2OW"s7ZKlqYpKns!.11!$`6`#nA'm
+'EHeXq"aLVo_%kKq"ag_qt^-bqt^-bqt^3f"o.ueqtoaEq\eSrs7bpNp%J+Pna6)NroWkDo(;VL
+q"agdqu7K(b4YDkkOnK:me-5;nFcAAmd93!lQdtU-3*?5nF?MM)Y3=Z!"L%M"9K>_*WZ!7rqcZp
+p@nL_n,3"WrVQWmJcEgk"oeQ!\,ZEms*t~>
+kPlUqs8DWjlKnQGs8W&mq=t!irr;rms8;okqu?Wps82cp$2OW"s7ZKmr;Z`prXAN#"[>((4$QD%
+1_]6TrrDr]rrrB$q>^Kbl2M:_s8MZfs8Mlkrr;lfrr;H\s8N!.rVufJs8Vcbs8W#ps8Vflr;Qos
+q>WE<q)S3L(D/Z)3CQ2'83@1Xs8)Bes7cBis7$'erVQNmrrrE"rr2clJcF*s"oeQ!\,ZEms*t~>
+kPlUqs8DWjlKnQGs8W&mq=t!irr;rms8;okqu?Wps82cp$Mj`#rUg-iqu?QlrVm0QDK9fOMj&I"
+48o0_q#0s`qu#j]"9&9"p$)JYo)JFPrr<#srr3)hpAadXs8MusrrD$WrrE&grrH&$qG[Gmp\tdX
+>^U74F)l)!)uos8o`+shrr2ukrVulrs8;oq#5e5mqY'a`JcF-t"oeQ!\,ZEms*t~>
+l2Le_rr2rtrVZ[)oD/FcrqHBkq#CBgs7?3h.e3H:rq?0cs8W&mrr2lqs8;ons82?e)&<tl!"',N
+!:B@Eq"=+KnEKK7oCWUena6,HoD&.Vq=sd\q=ssbo(rOes6g*d!%A'>s82K[o(;SIp\=LYqY^9i
+rVH3XiUZI.kOS3/l1,`K1+!e_)CR'Yq!0'imdK`=pA"FVoBcMu'-.Z'(CDntr;Z*_s7?9jlMpn^
+q#:Nrq"OggrIP!prrrE%qmZV(li2J~>
+l2Le_rr2rtrVZ[)oD/FcrqHBkq#CBgs7?3h$M"&orq?0cs8W&mr;RN,rq?<ir<GAM8jG6u3BIBD
+s7cQnqtpC+rr;utrr;utrr;utrr2cfs8VrVrsS)r"U>YK$k`dK#3ts_s8Moos8N)hrr3N's8Vrk
+s!gB&2_@-I5XIL(s8W)qr=oGs2b65)4t9,+s8M'WqX=F`lMgh\rVuiq#Q+>go)AX]rdk*rrrrE%
+qmZV(li2J~>
+l2Le_rr2rtrVZ[)oD/FcrqHBkq#CBgs7?3h'(Po"rq?0cs8W&krVulsrV-9brr39ZDh4+:MiE.-
+0`:qQp](3gn,ECbir9Jdj968>-6+'R*Yek>rU0[crqQL"2c*:?6rm&d?;p7k'cC"QCM@Zn6X('#
+rS[JFm/R+Ps8Dcmr;lforqcurp@%GGq"":[JcF-t"oeQ!\,ZEms*t~>
+kl2"gs763ilMpeOs7Q9h$N'l'r:Bscs8W)err4>Drr<#ks6fpdr:0UYqu?Qns7l!^)A)rP$j@7b
+!$NjE3'/S]l0@g+&FfAepuD/=o(2YNq"ORXq"aI[&+oo%!Ytq@!!!'(('=O9o`"mjrY#/)q"=:M
+naZ,:nF?&d.P2i",Q9:r+nGX##5%?Vp$256q=Og`qu6EkpAbEqo`+mis7ZHl!<)Nh!W2hHs3L]K
+rr;l)s8D9`J,~>
+kl2"gs763ilMpeOs7Q9h$N'l'r:Bscs8W)err33$rr<#ks6fmd!;6?g(]X4-rqlTu6:3b':dIN@
+$9("(5!q.+qX"4bmf31]rosFolhgVe5<_:l3Bo\l$2sbdrp]pk-osLH68SU)$Sh\\rr<#rs8Vlo
+p@S@brr2j4rr3!(&-N:D"rIRLr9sUUrr2Kgs8;Zirqc]nrVHTmrVlil!<.QLd/O:Ks80;*rTjK6~>
+kl2"gs763ilMpeOs7Q9h$N'l'r:Bscs8W)err33$rr<#ks6fmd#57oiq>0[\rr3K]Fb"muOaVOr
+.o/l.8kqV9rrD]arrDc`mh4FEoFG5ACh@?sBjD8An)4'@rUTsl2+L8':I+nP!'^>\"oSE#q>^3^
+rrN)qrq[W5rs',X'd"D8//&Kjlh9W;q!\1Yq=OIVq"XUYrq?EgrVH]gp&"]=s3^iMrr;l)s8D9`
+J,~>
+kPnc_s8Vo\4:*)*bo7P9s2b`r_"RfH*?3'!]d4B0rkfim_uIIk*Q[UF`>B6.s8W&nnGjCA!<<-)
+&/P?6p%e+Ppa@UI+=JWf-n6Vp-n6Vp-n6Vp.jlf&2"C/3pC?urrr;utrr;utrr;utrr)j)q#Cj6
+!"'&5%LiF6rVuos/,];>pFe-M.k3"s.Om"Bme-5@o^MJFo^hYHp[n@Rq#($[qYU-dqYU-drUp0s
+p@J%GmG7F)s8Moq!;6'c#QFc&s8)]oo7?qgrrrE%qmZV(li2J~>
+kPmX?s8Vo\4:*)*bo7P9s2b`r_"RfH*?3'!]d4B0rkfim_uIIk*QdgNaVki2rr)`orrtb\4[;J'
+6Tt\QruC\1s"cZ'1d!l^4?GYe4?GYe4?GYe4>SfW55Y9@s8W'-p]Nl_4'#BD<C$c_rr2`nr]L*A
+s#LAar;Zfos8;`n!r`/nrr2ump](9ms8Doo)#+".qYL6hs7$'as7cKhr;Q`ro_e^drr;lp#Q=]$
+s7uTmnq$hfrrrE%qmZV(li2J~>
+kPmX?s8Vo\4:*)*bo7P9s2b`r_"RfH*?3'!]d4B0rkfim_uIIk+3jEWar(]&q"ajfs!;N4H$t6g
+Eb-Kmrte+!>YS3t<E)st<E)st<E)st<DYnC7S!.O%fQ2!q"jd^q"jd^q"jd^rqHus&8@&EOH=RB
+BG1%6q#1'h#t7?U92&)U9LhPCrs&>snbE"YnbDq`qtg*]o`"Fbo^M\VrVQU)r;6$Vo(;bTqsa@T
+pA4X^qZd#rrV-0en:CVdrrrE%qmZV(li2J~>
+l2NC4s8)9cs&Qi5s8G<VXu?;ASuFdNq_YOO49$h,[5.bEVmS;W6)1;3rq&1WVE4_V/bnf8&f(uh
+!"T_e!:om^rquZgp%7qSrr;utrr;utrr;utrr;okp[R`01+FaL00q0=-7C2h-7C2e1Fja?mca00
+j7**P!WrK4!!!K/mk5b0-7C8k.P*1Gq"t!grr;upq"a^\q"a^\q"a^\q"agdjSoD_q==(KqtpEn
+rq$0irr2fqrdk*srs&H$s8B;#qWn03~>
+l2NC4s8)9cs&Qi5s8G<VXu?;ASuFdNq_YOO49$h,[5.bEVmS;W6)1;4rqAO_V`4PR#n&ge8PCm*
+4@954rrr;r5!1YXq)SI9*B?/@3]T5Z7m&d2s7u]ppAYml8Ou9G6TRdDs$AL=48q;*s8W',rVlcp
+rVlcprVlcprVc`qrVZQprVlfls8N#ps8Muus8ITL`;^&?rr;r'qYKOXJ,~>
+l2NpCs8)9cs&Qi5s8G<VXu?;ASuFdNq_YOO49$h,[5.bEVmS;W6)1A;s8G6lU+l62q#::6=)iSF
+GCFRM,PV3KrV66aqY9p^qY9p^qY9pcrVlsi76Nd064?:X;H$Il;H$Ii?WL#"rtI&$It)ctGB.gK
+s%u-Y9MA&M7n#eurrr;pq"F@Orp^-_pA"O`qu6ZprqHfrrVuorqtTs`qu-JEs2Y-DrVliqZhjOa
+s*t~>
+kl40Ms7c3b'(,_lrs%rW*W?cJp([,u,38b6n.kul(&ng5hA?1os6L]irW_Qb#ljr$o(2o'*<Hf_
++rha+n+QYVr;69_o_/4Srt52&o()P;p\=LXp\=LXp\=FNq<]Qmj6[j>.N]]f,6.iH"onW9$3gJK
+lg*s+nF?&>o_%nNq>:'erVZQaq#L<^r;Z`hrsSf'q!mhFq#(0lrVZZj"T/,ss8DoorVQWjrV-Eh
+qgn[nqum#qs80@ks*t~>
+kl3jDs7c3b'(,_lrs%rW*W?cJp([,u,38b6n.kul(&ng5hA?1os6LZhrX%fg#lXc#q>Ugi9fGI(
+90G<=q"jses8;rtn,<Ffqu?-PrtPD*s"Ql)2E"5h#=:sU6oA+I6jGF?rri?"rVZW^quHWcqZ$Eo
+r;6Ekqu?Nkqu?QorVlfsrVZTlrUp*brIOmoqum#qs80@ks*t~>
+kl3dBs7c3b'(,_lrs%rW*W?cJp([,u,38b6n.kul(&ng5hA?1os6_*'rsn>m!:fOGnc'2"A6Etl
+H"L2!rr<#r!<2rs!;#gK!;$0h!;PjZ&Q3(F<D[.",BJHjHu>(-FX'?Irri?!qYL-Krrr>qq"OIS
+rUU0bp\=U_r;R3%p\4IZr;ZcoqY0a\rVZWnqYpQpJc*so"TJ8tqmktkJ,~>
+kl3F6nc/Ld###Msrs\r)!<3&nmg/sm!<;KirrE)d#5/3"rsJ<+oD\pmrW)ll$MaZ$r878L!X.N^
+rVlotr:'U`q%*8pn+lVAme6>Ip%J(Pp%A1R%/9>ep[RqNn+ZAE!"o21(]aU:#QXMSo_JF_qtp3a
+pA"CTo^q_Fp&+F]!WN#gqZQ`iq"aabqu$BlqZZfjo_&"WrVllqrqQTmrr2rrrr)cnqu?Hmqu20H
+dJjFLqt@Q"qY0@VJ,~>
+kl3sEnc/Ld###Msrs\r)!<3&nmg/sm!<;KirrE)d#5/3"rsJ<+oD\ghrW3&r$i'`$s6L+"%hB$V
+$3peKlMpk^rVcWorU9b<rqQNlo(W+^rVlcprVlcprVlcprVlips8Vrqs7u]nrt/'u7R^3I6UqI_
+li$_Ys8@NKJcGNF#6"Gm\GuF"m/MS~>
+kl3gAnc/Ld###Msrs\r)!<3&nmg/sm!<;KirrE)d#5/3"rsJ<+oD]'qrs&N""mk^Jo\p,b(`O2)
+'+PHdm,e6MrVuoor9""i.t`V5LQmaLH6`Ias8W)t^]4?2!<)fps8.BI_#FW;qt@Q"qY0@VJ,~>
+l2O!Ds82`opBT3n!<3&\r"B#Es616iq[r8m%/^b4mMl!9i9V*V!;lQtq#:iend>Eis80jCR@9nB
+Xe)/qV8\u&[0*eBZ*El(#G86-Vmre2_"b5hZ*U^AZ*U^<Y.UdEVR3_0Yakb'!!E?'!<E0#Y,oON
+]=PS`\$iWGXfSP%Vl-W&o!S%p!jJc*rMojuqlTk!!O/p0[0a1DY-"h1ZaI3Ir367.r3?7*!O8t^
+[*c5`Z+\>RrTaE5~>
+l2O<Ms82`opBT3n!<3&\r"B#Es616iq[r8m%/^b4mMl!9i9V*V!;lKmoDT9cp'guos8C9ZXgZ'U
+`3Z\fY0*9@Za-j?Yd(L?o!J^u[CNBPYdDCE\0/>l\[]2[\[/`\ZG!EO]WelB"@GOK83oa:2$UOr
+aL8MU[f<f>\@&cS\,Nl;\+-g*[IUd'[fX"I\,3T9\$i`QrNuR3s0hs8rj;U2!4;O/J[Ee2"L5Y`
+T`+0UJ,~>
+l2P,ds82`opBT3n!<3&\r"B#Es616iq[r8m%/^b4mMl!9i9V*V!;lU!q>V/tpBgWZoC'Q,X1?-U
+^9"?LWQ(C8\@o\ra2uB:\\#Da\\#Da\\#Da\\#DN\\55`[(+6R]_T/V[^a8_^p(Jd[_K!`EI3Cl
+I"HlW*Pf;4\,NcD\%0,`]=knm^VIXu[e$g)Yk,%"[(F-Q^B;0a]tOEWrOr6G!P,Z<Z3dnJ]=khe
+['6dCrO;j9qmcX9!P#Rh[*c5`Z+\>RrTaE5~>
+l2NF7s8Mfnn5ZX7*</=(Y!DeCViasYqEgaN56"35Yt+ahU9$iO<3)Wcs79$cS1aU9rs[TYp%7pW
+o_\O`o)AXQrs/Q$q>C$cq=a[\,5Cj%o^_YFo^_bDn+H)@pZhDDo*HKT*#^+/*$t[]mc4!6rqQKg
+s8LdQ!VuEeo`"O_p\ssfq#UBlr;Qosq=sd`rVufp!<;inJcF*s#5S2k[f?:)m/MS~>
+l2NF7s8Mfnn5ZX7*</=(Y!DeCViasYqEgaN56"35Yt+ahU9$iO<3)QXr:*UdTeu`Irs%3Wrr<#*
+r;Q]rpAFpnrr<#trposmrVuors8;oqqYL-jrqQL7r;6Nis8Vlos8!Kt6UO%/01\Y@s8)9arVZTl
+r;?Nhs7-'grU]perpKgcrqZQordk*ars&;spU:,"rp9Z8~>
+l2NdAs8Mfnn5ZX7*</=(Y!DeCViasYqEgaN56"35Yt+ahU9$iO<3)TZrUa'pUbqi@p@Zl2rVuo+
+rr2otp\Y!jrTO7]rVHNorqZHss7c9fp&G'err3BR@VB:YBi&Y\)?9a9p\t<nqtpBhnb_nP!;l0`
+s8)fpqYpTnqLS[^rs&;spU:,"rp9Z8~>
+kPm1,s8)cD*u:1Bb8))/s2bm*[djC8,o+l-]0$Y8s03sm^]2I[--#ub_@$dkqu-Nos82iq$G$36
+r;Zcjlhp\[li.1cq#C!ds8)Tl!WMokp^6Teq!@eEp\=LJs7cR%!U':Mq"aa_qu$Hmg&D-Qq>'p_
+s7llrr;?Qnr;QTn"T8)kqu20H])MiAs8;3_J,~>
+kPm^;s8)cD*u:1Bb8))/s2bm*[djC8,o+l-]0$Y8s03sm^]2I[+hdgO_[mO,s8W)us7c?hs0qq#
+qZ$Tjn+m"Sr!<9#qY:*_s8VrcrrrB$s7cQirr3JurW!'*!s\o7$NpUos8DTirr2rt*WH*<s8N&t
+s8N&ts8N#qr;6Ehr;6Ehr;6Ehr;6H]s8W'"rVlfms8W&rrrE%Ls2+d;\GuKms*t~>
+kPn$Ds8)cD*u:1Bb8))/s2bm*[djC8,o+l-]0$Y8s03sm^]2I[+Lq1C`=j'7s8;]hqY'jes181(
+rVuoonGiIaqY9^TpAOO]#5\,po`+sfq#C3h(&.\*nbr+Xs8Vur#8nNq'G)-+)%5[&rtkY2qY'XT
+o_/.YrVQQjrVQQjrVQQjrVQ0^!;l3a"8hrkrVQTsrVHBhrVuTiJcF!p!kA:.li2J~>
+l2Ltarr<#ns8)`p"nqQfqZ$*ars8B!s7$'`pAaa^rr_WfrUKgcs8)upl0\KBq#13no=Ou$#6"Js
+q>'pcl2Lb[mJdFfpAasgs8DcmrsJPnq>0j]nG*%`q;;2\rr;utrr;utrr;utroa:`rqlTjJcEF`
+#5e5qppC"sli2J~>
+l2Ltarr<#ns8)`p"nqQfqZ$*ars8B!s7$'`pAaa^ru:>)rUKperUp3hs8VZ^s75aYo_SFKYl4P"
+rr)$[!<2ut!;Z?gq#1Woo)A=]rqZ6bnGN:c$2s`#rr;fkn,E:`rq6:"rr;utrr;utrr;utroO1Z
+rW)oqrWN2trVlforr`8ur;Q]qp&9OBdJjFJq>U/rrVPp\J,~>
+l2Ltarr<#ns8)`p"nqQfqZ$*ars8B!s7$'`pAaa^ru:>)rUKpbo]u;Ks8Voks7Q$aqZ$TcXRu5]
+qu-Hm"oJ/ko_/.PqZ-Qnr;cTcrV6C"p[eFYs8VrfqWR_MrrVlbmJ?k_rVl]lqZ$L%s8Durs8Dur
+s8DurnGa='qY9p`[email protected]"Xa`rrr;pq"t$gr;6Njr:g<hrIP!srs&ArrqNl!
+qs494~>
+l2M1fs6fpequ?Ths8N&srr3f1s8N&pr;Zfrs8Dutqu6Kjs8Dups8Vflrrr>toD/:\qYpQ,rVm,r
+r;6<equ$HmrtbV3rqucnrqucnrqucnrr2lrs7lWorTaC_rVZ[#q!n1[s7c-an,NFeo)Aair:Bdc
+rosFbrqucpJcE=]"8o_0rp0T7~>
+l2M1fs6fpequ?Ths8N&srr4SGs8N&pr;Zfrs8Dutqu6Kjs8Dups8Vcjq>^Bmqu?]orr)Whp%nQh
+rV?Hlp?2Ger;Z]hrr;forr;utrr;usrVHElq>L4)qt0g^r9jLYq"k!hq"k$gn,2qXrr)iqf`1mK
+rVulrrVc`prquirr;Zfrs8;uts7?5@s3CWHr42k,li2J~>
+l2M1fs6fpequ?Ths8N&srr4#7s8N&pr;Zfrs8Dutqu6Kjs8Dups8VW]nG)k[rqucrrVca"X7PiU
+qt0gd"o\>pq"X^Vq[`K!qt'd`q"t$erVQQjrVcQl!;ufq')qY(p\*\?rVlfrs8)cqo]>f>r;@!"
+rVQQjrVQQjrVb^T!r2K_rqQNirqHoqo^qbIqu-Egq"jmdr;Qrtq"Xa`rVZQmqY^*hqYc!Fci4+F
+\c;Zps*t~>
+q>Uj"r;ZEhq#1-jqu?$^rsAT$s8Drqs7lBbrr3&os8Drs&,c2%q>^Enp\Y!Xs8DWjrr)j'rVQWl
+s8VlgrqcHj!k/..rr;lpr;R3)s8N&ts8N&ts8N&tgA_0PrVllsh#HsEkPkP]JcE=]"oeQ!\,ZEm
+s*t~>
+q>Uj"r;ZEhq#1-jqu?$^rsAT$s8Drqs7lBbrr3&os8Drs&,c2%q>^Enp\Y!Xs8DWjrr)j+rVQTg
+s8Vois82irrr2oq"9,V*qVqM_rr;utrr;utrr;utli-_[q#1<orlkE@rWN9#s8W)ns8W)urrE%L
+s24j?rr;l)s8D9`J,~>
+q>Uj"r;ZEhq#1-jqu?$^rsAT$s8Drqs7lBbrr3&os8Drs&,c2%q>^Enp\Y!Xs8DWjrr)j'rV??_
+rVucks8Dcn"L7jurVcTmlhq4krVuirrVuirrVuibrr`5sqYU*g"8hrlrVZ[$rVuirrVuirrSRVV
+rVQKfrVZNnrVufoqu?Tm!<;]iJcF*s"oeQ!\,ZEms*t~>
+p\tj!s7H-es6p!Xs7#a^r:^-iqY^?or:g-h#4hcnnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQe
+q>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+p\tj!s7H-es6p!Xs7#a^r:^-iqY^?or:g-h#4hcnnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQe
+q>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+p\tj!s7H-es6p!Xs7#a^r:^-iqY^?or:g-h#4hcnnbiFYrr3,mq#C3frVm;ss8V<_q#9jas7cQe
+q>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+q>Ud!oDeRbs8MEcp&+h'o)JO]s8DQhp%eC\s82<cq>^'arr3E&r:0gas8V`kp&G'Rrr3<"qu?Zq
+s7u]pqt^6nZiBoRs+13FrrrE%qmZV(li2J~>
+q>Ud!oDeRbs8MEcp&+h'o)JO]s8DQhp%eC\s82<cq>^'arr3E&r:0gas8V`kp&G'Rrr3<"qu?Zq
+s7u]pqt^6nZiBoRs+13FrrrE%qmZV(li2J~>
+q>Ud!oDeRbs8MEcp&+h'o)JO]s8DQhp%eC\s82<cq>^'arr3E&r:0gas8V`kp&G'Rrr3<"qu?Zq
+s7u]pqt^6nZiBoRs+13FrrrE%qmZV(li2J~>
+pAZ!*s80]#%KAEas8MBbqZ$Hmo`+seq#CBgrr32pn,N+]q"4Rcs6^O"mf3=_s763ip%/4Vn,N1Z
+qtTpc!jhq(JcC<$U]1Mss80;*rTjK6~>
+pAZ!*s80]#%KAEas8MBbqZ$Hmo`+seq#CBgrr32pn,N+]q"4Rcs6^O"mf3=_s763ip%/4Vn,N1Z
+qtTpc!jhq(JcC<$U]1Mss80;*rTjK6~>
+pAZ!*s80]#%KAEas8MBbqZ$Hmo`+seq#CBgrr32pn,N+]q"4Rcs6^O"mf3=_s763ip%/4Vn,N1Z
+qtTpc!jhq(JcC<$U]1Mss80;*rTjK6~>
+q#;'+s8Vrq-)ptB!<;lks8Dutnb2eTrW"8Jm^`ZEbl>X"*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(
+s1g$'`q]B0!jhq(JcC<$U]1Mss80;*rTjK6~>
+q#;'+s8Vrq-)ptB!<;lks8Dutnb2eTrW"8Jm^`ZEbl>X"*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(
+s1g$'`q]B0!jhq(JcC<$U]1Mss80;*rTjK6~>
+q#;'+s8Vrq-)ptB!<;lks8Dutnb2eTrW"8Jm^`ZEbl>X"*5V[TV]62ks/d[j_Yq7g'Y"+^*$`N(
+s1g$'`q]B0!jhq(JcC<$U]1Mss80;*rTjK6~>
+q>UftoDe4XrtEc[h\Q4k#lO8cr;ZZorrE&u,[email protected](0R&3@>s%fD^7JK$ASj!*LSubE]2P6^9
+nG?%ORnWVW!jhq(JcC<$U]1Mss80;*rTjK6~>
+q>UftoDe4XrtEc[h\Q4k#lO8cr;ZZorrE&u,[email protected](0R&3@>s%fD^7JK$ASj!*LSubE]2P6^9
+nG?%ORnWVW!jhq(JcC<$U]1Mss80;*rTjK6~>
+q>UftoDe4XrtEc[h\Q4k#lO8cr;ZZorrE&u,[email protected](0R&3@>s%fD^7JK$ASj!*LSubE]2P6^9
+nG?%ORnWVW!jhq(JcC<$U]1Mss80;*rTjK6~>
+p\tX"s8)E0*WRLunGN+]s"4!Fs8Morqu?0_*o?E;n.b-X$2=H,na?nd#5.clq#^NX"oeT&lP/jg
+#j_Ehq#:E%s8.BIJcDMF"oeQ!\,ZEms*t~>
+p\tX"s8)E0*WRLunGN+]s"4!Fs8Morqu?0_*o?E;n.b-X$2=H,na?nd#5.clq#^NX"oeT&lP/jg
+#j_Ehq#:E%s8.BIJcDMF"oeQ!\,ZEms*t~>
+p\tX"s8)E0*WRLunGN+]s"4!Fs8Morqu?0_*o?E;n.b-X$2=H,na?nd#5.clq#^NX"oeT&lP/jg
+#j_Ehq#:E%s8.BIJcDMF"oeQ!\,ZEms*t~>
+q>W\Yr:U*es8VinoDejgrr;cns7--_rtYnZWrE(nrrE'!s82lsq#UNp!WEGprs8W3m/I(W'));)
+s7cTooG.2trrTP,qgncus.fStrr;l)s8D9`J,~>
+q>W\Yr:U*es8VinoDejgrr;cns7--_rtYnZWrE(nrrE'!s82lsq#UNp!WEGprs8W3m/I(W'));)
+s7cTooG.2trrTP,qgncus.fStrr;l)s8D9`J,~>
+q>W\Yr:U*es8VinoDejgrr;cns7--_rtYnZWrE(nrrE'!s82lsq#UNp!WEGprs8W3m/I(W'));)
+s7cTooG.2trrTP,qgncus.fStrr;l)s8D9`J,~>
+q#:Kqs7--Zrr5I^s82irq#C<hs7lWor;X5>rZ1Cl&-!:)p(%-#''\imrYjqn$iCP+k6q:soC3In
+rsAK!#lX]$n]7o?\$;aOZF%*NY.&tfJ[4gO#Ip\<X1#I?[DB-QUrTd=]Dqiqs*t~>
+q#:Kqs7--Zrr5I^s82irq#C<hs7lWor;X5>rZ1Cl&-!:)p(%-#''\imrYjqn$iCP+k6q:soC3In
+rsAK!#lX]$n]7o?\$;aOZF%*NY.&tfJ[4gO#Ip\<X1#I?[DB-QUrTd=]Dqiqs*t~>
+q#:Kqs7--Zrr5I^s82irq#C<hs7lWor;X5>rZ1Cl&-!:)p(%-#''\imrYjqn$iCP+k6q:soC3In
+rsAK!#lX]$n]7o?\$;aOZF%*NY.&tfJ[4gO#Ip\<X1#I?[DB-QUrTd=]Dqiqs*t~>
+q#:Baq#::aloYFO!<<&ns7u]hs7lEili47%q+Qs]3r_OBW&XYL;5p`^nP#LQ7fPf@]Kl*]SZ=aM
+mmsI?:&jnds7l6bs8Tk0o_eahq18Qss7$'grVum!p&FQrrrqE^]CYpnm/MS~>
+q#:Baq#::aloYFO!<<&ns7u]hs7lEili47%q+Qs]3r_OBW&XYL;5p`^nP#LQ7fPf@]Kl*]SZ=aM
+mmsI?:&jnds7l6bs8Tk0o_eahq18Qss7$'grVum!p&FQrrrqE^]CYpnm/MS~>
+q#:Baq#::aloYFO!<<&ns7u]hs7lEili47%q+Qs]3r_OBW&XYL;5p`^nP#LQ7fPf@]Kl*]SZ=aM
+mmsI?:&jnds7l6bs8Tk0o_eahq18Qss7$'grVum!p&FQrrrqE^]CYpnm/MS~>
+q#:d#rqufr!6bE:s8W#rrr4Y<qZ$T[3WKf0s0+!fbOige1V3Vd[Ls,%s1CJp`;d5)"j?qd$R43p
+s1oTq`VB?-rs8P*q>^Kos8)_GqgnY7qZlQhs6TdWs6%5q#6+Z&qR?J$li2J~>
+q#:d#rqufr!6bE:s8W#rrr4Y<qZ$T[3WKf0s0+!fbOige1V3Vd[Ls,%s1CJp`;d5)"j?qd$R43p
+s1oTq`VB?-rs8P*q>^Kos8)_GqgnY7qZlQhs6TdWs6%5q#6+Z&qR?J$li2J~>
+q#:d#rqufr!6bE:s8W#rrr4Y<qZ$T[3WKf0s0+!fbOige1V3Vd[Ls,%s1CJp`;d5)"j?qd$R43p
+s1oTq`VB?-rs8P*q>^Kos8)_GqgnY7qZlQhs6TdWs6%5q#6+Z&qR?J$li2J~>
+q>Vc1s8VZirJ.0Hs6]jdrV$3_q#CBms6K^bo'QJWq=jphrTjI_rVlg=p\k*[s8W)up&G$krVuK`
+s7Q9ds8N&uqtg9krVcc*rr3&qs8ITLJcG3=!;lcq!Ufp$rs&5tqOd`dq<\-3~>
+q>Vc1s8VZirJ.0Hs6]jdrV$3_q#CBms6K^bo'QJWq=jphrTjI_rVlg=p\k*[s8W)up&G$krVuK`
+s7Q9ds8N&uqtg9krVcc*rr3&qs8ITLJcG3=!;lcq!Ufp$rs&5tqOd`dq<\-3~>
+q>Vc1s8VZirJ.0Hs6]jdrV$3_q#CBms6K^bo'QJWq=jphrTjI_rVlg=p\k*[s8W)up&G$krVuK`
+s7Q9ds8N&uqtg9krVcc*rr3&qs8ITLJcG3=!;lcq!Ufp$rs&5tqOd`dq<\-3~>
+q#;H6o)JLT#QOi-#Pn5ks82irq!\7Ys8Vins8N&uo`+Xart4\hs8;oso)Jacs7c9ap&F[[qu6lm
+s82irrqlWn#Hn%(p%&.\r.4iurpfsms7$'Ys8Vlf_#=Q<mf10"p%dtSJ,~>
+q#;H6o)JLT#QOi-#Pn5ks82irq!\7Ys8Vins8N&uo`+Xart4\hs8;oso)Jacs7c9ap&F[[qu6lm
+s82irrqlWn#Hn%(p%&.\r.4iurpfsms7$'Ys8Vlf_#=Q<mf10"p%dtSJ,~>
+q#;H6o)JLT#QOi-#Pn5ks82irq!\7Ys8Vins8N&uo`+Xart4\hs8;oso)Jacs7c9ap&F[[qu6lm
+s82irrqlWn#Hn%(p%&.\r.4iurpfsms7$'Ys8Vlf_#=Q<mf10"p%dtSJ,~>
+q#:Ees7cHk!:'L^s7?9j&,lOus8)coq>^Hks8N&nnc&Olq#C$es7QBk!;HKm$2=K"r:]g`p]('e
+rs&K&s82Qa[=S@/s6'C`r;ZW.rs&>is6m#gq<S'2~>
+q#:Ees7cHk!:'L^s7?9j&,lOus8)coq>^Hks8N&nnc&Olq#C$es7QBk!;HKm$2=K"r:]g`p]('e
+rs&K&s82Qa[=S@/s6'C`r;ZW.rs&>is6m#gq<S'2~>
+q#:Ees7cHk!:'L^s7?9j&,lOus8)coq>^Hks8N&nnc&Olq#C$es7QBk!;HKm$2=K"r:]g`p]('e
+rs&K&s82Qa[=S@/s6'C`r;ZW.rs&>is6m#gq<S'2~>
+q>V3(s7--bo`+FYs8VTgs8)cos8;coqYpL%r:p<bo)JaUs8VckrrW#ro`"jnp@/+Mo)AXirql]p
+#P@olrr2rkqtpBuZMjh'q>Ks\JcC<$nc&g^s7ZKm!;+#*"SD]os7bjZJ,~>
+q>V3(s7--bo`+FYs8VTgs8)cos8;coqYpL%r:p<bo)JaUs8VckrrW#ro`"jnp@/+Mo)AXirql]p
+#P@olrr2rkqtpBuZMjh'q>Ks\JcC<$nc&g^s7ZKm!;+#*"SD]os7bjZJ,~>
+q>V3(s7--bo`+FYs8VTgs8)cos8;coqYpL%r:p<bo)JaUs8VckrrW#ro`"jnp@/+Mo)AXirql]p
+#P@olrr2rkqtpBuZMjh'q>Ks\JcC<$nc&g^s7ZKm!;+#*"SD]os7bjZJ,~>
+q>Up&s8Vlis2-8h-b]Q[qYgF&qYg9jo`+sbs7ZEkj8T)Yr>P_2s8DusqZ$Nos8;oslMpbXs7lW\
+s8Vrqp&=q#s82Wjs8TS-s8MciqY^?2rr`8urr14C!<2lq"8r&nr9XFcrqu]ndJj:Iqu$Bls8;lr
+!WN#crW3&uj8T2[qu6Tp#6+8pru%7F_#FT9s8O10+TDBCqt^-gnc++~>
+q>Up&s8Vlis2-8h-b]Q[qYgF&qYg9jo`+sbs7ZEkj8T)Yr>P_2s8DusqZ$Nos8;oslMpbXs7lTW
+rr2cop\k*uqtU*hr3Q>$s82cprVl0`!<2rsrVlZn%K?D,s8N&ts8N&ts8N#rr;ciorrE&srSdbG
+rrW,qrVQTprr)ffrmh&Crr2p"rquZkrr3'!rVb+C!r`#orVm6'rr;Zimf7>-oDHN+#laVspAeq.
+p@S7^s8MZjJ,~>
+q>Up&s8Vlis2-8h-b]Q[qYgF&qYg9jo`+sbs7ZEkj8T)Yr>P_2s8DusqZ$Nos8;oslMpbXs7lWY
+s8VrqpAOprq=a[`rNuP's8)Qk!<)ln$iTu$qu-Ejqu-EjqtU-Lrr`/pqYT%I!<)Nd!<)0^r;HTo
+ir/9ErVaS4#lX8fl2YZ$m/+["%JBA[!*fNoo)8UcqYL0]s*t~>
+q>UNos5EtW0,_.lW#bp<nGi:`rV-?lr;ZQhs8Vopq>C6lqt^6krp]sfpAa^\s8VfmrVuKho_ndq
+rr<#smelkXrqud%_>jQ4o^qPFr;?Tprlb<DqtU!WdJs4F!W;rqrrrDro(;\UrVlrss8Dor!;?9h
+"oe>jp&"aarrrAss8Vurp\k?drr)imr;HWert4\knc/V4s8V?Yrr<#onb2eTrVQZkp\P!iqu-Hr
+s8)cqqs==sq<.JOr;ZT_s"hs<eNEm$rqZQbpA"X5rsV6Hf%!:js75XAq>TsVs*t~>
+q>UNos5EtW3#T*uW#bp<nGi:`rV-?lr;ZQhs8Vopq>C6lqt^6krp]sfpAa^\s8VfmrVuKho`+mc
+qt9pfs7?0g"oSAuqmHA#rs&H%s8DimrU0^cr;ccpr<3,urr2lqrYPV6rVcZmr;HQlr;HQlr;HQj
+qY9g[qu6Tp#PnArp@n@Qr8[bUrq$-lrq?![qu7<+oBlACr:p3dqtoj[q>:'erVlEg"TJ8ts8;Tj
+!;-9j!WE&srr2irr;HR0r;6EirUU!cq"=^Yrq-6ho(i=brr)iprrE#js8Dp"s7uZnqX=D"qt0IZ
+qYpH`r;ZB`!+JB,!;H$`qZ$3^q#Ab@&H2>'>t7Wim.gV\rVuoerVlKiJ,~>
+q>UNos5EtW3Z5="W#bp<nGi:`rV-?lr;ZQhs8Vopq>C6lqt^6krp]sfpAa^\s8VfmrVuKho`+pi
+s7lTlr9sOXrqcioqtp<#rquors8;co')VCpp@e:Tq"FLVq"FLVq"FLXrVHNj!<(sX"8)'NlMUY^
+r8R_WrV6!X!;l]os8Dor"T/5qs8;iq!;HKm#lFJnq"jshs8Droqt^Kko_SFXqY0ahlhL5Lo_AFU
+rs8W(qY'[ap]($brrE&rrrE&os8DrprrE&`rtYG2q#CBis8(jB!*D6S!;,sarr;cjao;nMo\fd,
++#!]Yp&4LEnbW.Ss*t~>
+q>V$$oDeCUr>)[4aTVY>rr2`lrr5+Sp[/"-!rp(X*Q.ok+Y:A)s3(lm])Tl"$GHJN)AU^#_B0rJ
+r;X>?)U@sOq>'scqu?]&s8Vf\o_&"Wqu6ZqbPqeDq"=Oar;5"Ds8N#qrVm'!o^MDCkl1SgpAajd
+rVulss82]n"TJ2eo_eRc(]474qu?]qs8MurrVlcprVHQor;Z6`s8Drqrri2ts8W)trt+o'o`"kC
+R5"[8q"t*kqt0dbrW2omq#19krqQTlr8[eWqtpBt.C\('hVKWsrt"]Og>N#2aYj+gnauhWs7Z*b
+J,~>
+q>V$$oDeCUr>)[4aTVY>rr2`lrr4tOp[/"-!rp(X*Q.ok+Y:A)s3(lm])Tl"$GHJN)AU^#_B0f;
+n,0O()UnQ_s8MunpA"N\pAOmcrVm#uqYL-hmf3(]rVccqnbiXgqY9m`rr)j#rq,XJqYT:NrVcit
+rqHEprqH*^r;RGtr;$-Oqt0m^q=jgcp&"O]r;HWfrtbJ2s8)`prVuiqrVlcprVlWms8Dueqtg?m
+rY>5(qtg*`rVZ0as8Vcm9*"nis7u?^qu6]pqsj[nrr)clqXO@TlhC2Gq$$HPmJm4crq6<k"oqOc
+5s&TWrqZWcrqcHcde=(ChZ.4M8Q8=_qYgErp\XCWp&BO~>
+q>V$$oDeCUr>)[4aTVY>rr2`lrr5"Pp[/"-!rp(X*Q.ok+Y:A)s3(lm])Tl"$GHJN)AU^#_B0iB
+pA_Q2(sV[Lq"XUWoCi$Yq"j[SrVHNrqXjFTmeZq[!<(sX"7tmCo@s9Tqtg3dqtg3dqtg3dqtg3f
+rri;tqu?0brrr)qp](-iqu6ftqY9j_rVulqrVHinqu-6drVQQhq$6TiqtU'Sp\jpf&c;P,rqu`p
+s8N&soB60E!;-3`rrN,tpAb'hs82fl"S2?_mIp,C&bG5RoCVbIo^D&%!&c5Q&jHBqoDn7WoZH_7
+n^IP"#o5*T!;cQ`m-X<5s*t~>
+p\tNsq>^9"0)up+rr4kSs8Vfjs8;osoKrWQ9T-)NoKT4>7K<3NWiA>Z4.<9KqFmTh4mPS;RlCBI
+6F!.Dqu$6frr)is^&J$6p&+^^q>Us&q>0p`q>0p`q>0p`q>1*ds8)`ms8;rsqu7<.rVlcprVlcp
+rVlcprVlcnr;HWo$N0bjrq6<kr;?Qmir8rWs8Muqr;7c8r;[email protected]:Rq#:9jpuD2;
+rr2rtrqc?[p&=Xa!WMohrrDWerrDroq#C-kr;QQkrtG,+s6K\MfuV5Rs7H9is7Q0es8;Qi"oe/a
+o_8=FrtU]@S!:=ORO>\\s8VlX_Cq.>WKX3Nq4uH9%%f5Ian,2gd]F5^rnHrBJ,~>
+p\tNsq>^9"0)up+rr4eQs8Vfjs8;osoKrWQ9T-)NoKT4>7K<3NWiA>Z4.<9KqFmTh4mPS;R4eF7
+4KtG?s8W&rrt58/Z2=M!q#C<fqtg*_qYL-go)ARerr2rr!;ufm,5V38rr)iprr)iprr)iprr)ir
+s8Dilr;Zfjs7?3fr;Zfrir&iQ!r;]hrVH]pqu$?jquZ`mrql^!p&4@Zs82`o"7-!Wrr2frrVlfr
+!;lWg#Pe5or;??]p\=UflLk&Irqc]nr;Q`ps8N)rrVmT%o_n@Y!+nW+!<;ujoBH&Ms7c-Zrqlcj
+qYL9lr;R0(qtTmKmdB,tl/h=(mhkERh.g/4>]F%h!+\8o8jZQl!*<<><bZ"<B@:B(BF8?L<'EEF
+@0$9+h>R3Eq#0mcJ,~>
+p\tNsq>^9"0)up+rr4kSs8Vfjs8;osoKrWQ9T-)NoKT4>7K<3NWiA>Z4.<9KqFmTh4mPS;RPFjA
+5-CG:r;HBfqu-HuZi0dsnb`1ZrVm#tq"4:Yo)A^erqZQjs8Dip!WDoeq#^9\o`"jurUT@8o^r1`
+rq,jYj8JEG%K6+rpA"Obr;ZWns7Q?hrs/8tr;Zfqqtoj^!<)Zl!;63gqYpNp!<)lr'_V7pdEqqa
+/P6$.mI9c+gZ\G/pA4dg!;cQks83E(q=jXTnEfMsiT&SFh::*Je/6Z^`()^`6X2oG!&4p5)$:gF
+!'<>?3_`&c9+Fl#=>23=*_^&DrU\+tp@A66~>
+p\tBks8V]brr3;sl2U2<s8V`ks8MpNJT;(p#5Rfortaep$1.[!lg>#X!<;3^rrr&S&,uq#q]GY2
+$hO9'rqcKhrquK]pTX5g!<2Tf"T/#iq>'scs8;orn,ERjq=sjbrqufrq?6]fp%eU@s8Dp"s8N#q
+qu-?gq[W/lm.gAHrUf%Cp%A(Pr;HWsrqlWfrrDucrs&>so`+pjrr)j#o)&Ieq"O^d"ZX]]s4]Tm
+rs#*`Y`QMjV=UJaWk,k=rru-=p%mV!6G`[.-EH#!iP.#Fs7Yp]J,~>
+p\tBks8V]brr3;sl2U2<s8V`ks8MpOJT;(p#5Rfortaep$1.[!lg>#X!<;3^rrr&S&,uq#q&Aqu
+#OhNss8;fos8MfdpT45jrr<!%rVlcorr)iqc2[hCrVluqqZ$QQrs/Q%rVZWlrVZTl!rW#qpAYEl
+s7QElr;ZHOrVlrss8W&s"98B!r;6?nqY^'arVQZjqY1!c"nqTWnEg/Nrtk8's8Vferr2cjnGuKK
+<_*5gr:0=Ms8W&l!V#RQpC[6!rr)clq=jUSnn)'B8TRsBo4.f.*,P<Dn*f*"p%8;Z9L1X7!:]IH
+lgXB1n*of8n*n]m&b52f6W@8a;ulXio`+mXq=jj\s*t~>
+p\tBks8V]brr3;sl2U2<s8V`ks8MpGJT;(p#5Rfortaep$1.[!lg>#X!<;3^rrr&S&,uq#qAf2&
+#k%KorVQEir<i5ior\)fq>'mar;HWtrVQHgiVsPfq"jd^q"jd^q"jd^q"jXLn,*+a$MsDeqYpNp
+p?V,BdJj7BpAX[mq#16mr;ZEfq!n4Tl2(D[rSRW"rVuWlrVuirrVuieq>^Efp&FpalGrrH%5K:2
+h!!e\hp^$3rp9aKjnJ0Amg\[NlKIBjiDiHS2e#0Go1'B]85[gbdFcOhc,BZ)+VFbj!<1FLcdU@i
+b0pjUjo?e_2DIl*s8V<MmHX9BJ,~>
+q#:?\r;QfmqYpLgrr<#bq#CB^q#@ZVp&t'rs6'mX!<<'+s8N*!rW)s'qu6]s!rr9#o*,*m!WW06
+s69X_qu?ZhpA=a_\ao1`rVuWjq"OFQp%\C\r:Bmhr;-3fpC$ZdoC;>>mdBK0nbVkV%K#nlo_%tT
+qu$HhrqksYpu)#CqZm&rqtTdSp\Xph&c;M#q>C9ks8N&uiq2s3q>1*grrN,qqY:*i"nM<_o`"jc
+rs&E$s5a4[r9jRi38<]ts7OMnq>UW=VQ-r"QMREbVlQkuVkg#WR>Qk"rrDo_rrDlkrrta&i8$d#
+oYLP5;7<p\2#mLNrr2p!q>1*`s*t~>
+q#:?\r;QfmqYpLSrr<#bq#CB^q#@ZVp&t'rs6'mX!<<'+s8N*!rW)s'qu6]s!rr9#o*,*m!<<'1
+r8n"Uq>^KkqYpL+_u96(r;ZKirVlisrr)clq=F@^q>:-gs8Mfn!;uHb!;uir$2sbtqtp?frr;Nf
+rrE&Vr:g'jqYU0grr3#uqu6BmqZ$Qos8W!0pAY*Urr;cnr;-6ap\4CVqu$?hr;Zd$oC`%Ss8N#o
+r=&H!rSRSPp\jp`q"a^aq>C./rVZQckQ#6V7lNS.!:]aMmHF65b_9S@E+N#F@hE0W?=%#J@Us(X
+AG5fdqrmqQoCsI$h=:"'q"!eAm.p,N6!.[uo\TE?p$);?p\=LXp\=LWde4"Aqt17n6>-AjoD\di
+rW2imo`'F~>
+q#:?\r;QfmqYpLSrr<#bq#CB^q#@ZVp&t'rs6'mX!<<'+s8N*!rW)s'qu6]s!rr9#o*,*m!<)j,
+rT=1Xr;Zfmqu6U%_YN]op\OFTp@nL\!;l-_!<)lrqu%0)q>:!bq>:!bq>:!bq>9gJkk>#U$N9et
+qu?]gqX!P?i;4#_qu-Ejqu-Ejqu-Ejp[J1J"7>UMq>L=)qt01?lhLA>s8Vrqq=jUWqt0pgpAt9f
+p\uoGs8V3\s8N&np%S.Rp%S.Uq"ja]q"j[OfDmf5'+5U3!9*.qcagp8Wae@b:.$f55n?=R9MS>Z
+;,^Ij<9NQ)m+Usr(Y\6:j7Dg0n_W?]!&$T(!9)>mmHNEniQCHrnb_eU/fdOaoD&@Zn*]l>s*t~>
+q#<MSs6fpY!<<)_6hgQZq>^Kbp](9`7*kK;rrD3O+9)fCgB7?Q$1I-rjUgtB)Y4F-jWX=@g[bdP
+o+LHg-3!o[m)6-6Yb7/nZ+%?VYe%-CX/W2(ZF.15\c9/=[f<`CZa-g>YHG%0XK/M3o=$B][Bd$@
+ZF.6S^8J3?Wj&S'[C*HN[^EQO[^EQO[^EQO[^EQO[^EQO[^EQO[^ERB[K!]5\,<cj[B-I9]Yh_+
+^7r0>SAW1]*R)$qb,r.HZ*h-T^;.S$]sY)MZF.-M\uWibbKRQ=`VI@V^Vmq?Xi8,tbl#ccbT=mM
+dF5dtI#0Pac27P@qp;o)D47&oX-U*?j5]+[lh][ekje97mc`]de]cL[ZbX#E[^ETS\%&oW\%&oW
+\%&oW][OR+\?*<b\\5_n0#+Hh.DEC"Z+mZR^p^YZ[C3KO[^`iX\@K,[\@K,[\@K,[\@K,[\@K,[
+\@K,[\@K,[\@K,[\@K,[\@K,[\@K,[[^r`S5-R0Lrs8Pcqu?<fp\"IWs*t~>
+q#=Fms6fpY!<<)_6hgQZq>^Kbp](9`7*kK;rrD3O+9)fCgB7?Q$1I-rjUgtB)Y4F-jWX=@g[bjR
+o+C6^+T;6;lc?NI]!%sX]=YP[Xh20W]tM%h\$i^7[/[Q6[f<i:\,s4P])K<+]!o,U[^EQO[^EQO
+[^EQO\%92^\$i]O[()j7[B[9LXgkjK\$icS\$icS\$icS\$icS\$icS\$icS\$icSqmZL3r3[]X
+]tM"bZ*1@9TY7\)^9aa<[\oqCZb`cT\$`TKZ*:F:[JmZ7[L'@9]WeuYVm<M+qPaatX/E^sXJi8$
+r2K[q*iZ6IZ_)VQFUMhW68qJ%:i$,+F`M\L>&ob"U7e<^qP/J3S!f_8StVpVVRNh0]XXrOYHG"1
+Xfee/Xfee/Xfee,[ALUPV5C;b['ZP-B1uV3WOAq2\Zi9MYd(F;Yd(F:YHP+4Y-5"3Y-5"3Y-5"3
+Y-5"3Y-5"3Y-5"3Y-5"3Y-5"3Y-5"3Y-5"3Y-5"4\u(MgA,u8ms7?9jp$r'4~>
+q#<MSs6fpY!<<)_6hgQZq>^Kbp](9`7*kK;rrD3O+9)fCgB7?Q$1I-rjUgtB)Y4F-jWX=@g[baM
+nIOp\,l[fWnB&,N\ZDRN]"5>UW3`\2Z*LaFrONBK]">Pc]">Pc]">QM]D]>>\0JGl[^NQO['m?M
+['m?M['m?MYGA&&]u%Us[^rEM_7-eDQa,PY!4;@'*jMcGWiN8-\@\lb];)s9RK0=ZS].kLX1>UC
+Z*LgLrkJKH%D0-Y['?1.Vm*7iUnOIXU'RBeTX]uXTqnCXTH9\uW2Pr#<Ghe.,ngG&)`(Lp6=X.o
+8iBXiKS4r3N;A6WLPh+ROcu&tS=?UXT<kYlZE^[@Z*U^AZ*U^AZ*U^AZ+[<S_QC5ZXgbU.!+n\p
+!2d61Y._*H]sP)PZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pEZF$pE
+ZF$pE[)/Va!($\LnGi+Tn`BK8s*t~>
+q>Uirr;Zff%1iL>$E3aus"F3Js7lWj!W`H1!(a0)0DJ#0XBG,o8"m"Gs$``h2ZH:AY<;hDX0"\[
+r_Su\9)/Dc#kRHXp%5NWn+ck]#lFAenauVSrquBb!<2Ng!<2Tc!;uirs8;lr"o\K#r;?*2s8Vch
+rrW2cq>UC$2PM;ns8Duhm.gMSrrE&]rrf7%WMc]oWW/psV?NluV3I:[rVm3I]]e\]gpnO,s8:jU
+!<)Bd&GH._nb`+]s82Bes!FE^s8Drss89q;&GGo!s![pIrq5UPrqH'Tkkk&QJ,~>
+q>Uirr;Zff%1iL>$E3aus"sQOs7lWj!W`H1!(a0)0DJ#0XBG,o8"m"Gs$``h2ZH:AY<;hDX05"g
+s%o#V6h1*QrqH*brs$IBp\4CXp\Fghrpg!jrVQKiqtgBirqc`mr:'abrWrH!qsXFYrr2KfrZ2%<
+s8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&trVufps8Duqrqc]prr3Z-p%.kOqsj[apZ;Hc!;H'S
+s7l<ertYM0q=s^Zqu-KkqYBmZoCLu/nEB<-p[/7QmUU'E@:B.Cs'bq:(hIDl<`O[ooCMJPAlL]Y
+6"0imroNqJp\Fg`"7u'Xq"j^cp$r%N!qGmSrq6Kir:]g_rq^L-qYC!`qYC!`qYC!`q;qPCs8MN^
+q>L!_l2Y>pp[7qOqsj=Tq>1!bqtg3dqYC!`qYC!`qYC!`qYC!`qYC!`qYC!`qYC!`qYC!`qYC!`
+qYC!`qYC!`qYC!`r;Q]nl2gGLs8Vurs82fqr:L#>~>
+q>Uirr;Zff%1iL>$E3aus"F3Js7lWj!W`H1!(a0)0DJ#0XBG,o8"m"Gs$``h2ZH:AY<;hDX0+e\
+rD&]W9)/Dc!W)QirsQdFqY^6ipA4RZqYU3j%f6)!qtg3dqtg3dqtg3go`#X(s8DfhqY9p^qY9p^
+qY9p^qY9^Xr;Qfpn,<7gp\OU^`r?DEk5\`enaH#JqtL*i!<)Zl$iBYdjPS,+c,7Q@chPrndaLc`
+91MYO9c-Z):-UsW[GgK9!(/FQ-RD4^n+PZ+h;Ii&p]L-Xq"X^[!;6<^rUgEhp%\CUo(r4QrrVln
+q"t'rr;Z9eB`Rbt_>b#Em*5U]l2CYZp[mhDs8DTiJ,~>
+pAY?ks7u`qs6ose4n8RGs8;ojs8VZirrE)B((eIb_BBZ4s8'eS+M%Nl&KJsn_]Kc5p<=Nk]DMN;
+,TOl)qYpNoqtTmVU@nN_rtbG'p%\Fas8Monqu$?hqu$?hqu$?hrp]sZqZ-WprrE&srs'kMs82fb
+s8C(>!<)os"Y)ae^p5QVrs$$1XerV*WVNIoUopcbrt>>2.88OIc7Aq]q>^Kos8W&nr;Q]rrn.5d
+nabu6s8;omq=t!i)?9U6p\Opiq>^H9rt+htq>\50s7tpRoDS^\o()\Ns*t~>
+pAY?ks7u`qs6ose2=^_?s8;ojs8VZirrE)B((eIb_BBZ4s8'eS+M%Nl&KJsn_]Kc5p<=Nm_#OGI
++rA&loD/C`rs,k0rqlHbo(W%]s8;Ee!;uck!;ZWj!;ZTi!;l<d!WDrqr@7^>pB9dYq#0XYoDS[e
+rr)iprr)iprr)iprr)iprr)iprr)iprr)iprr)lsrWW9"r;HQkrqdi9s8D]_mdBQ8n,)hN!!$G%
+?NBW]q"spdrVZNep@\(Mrq?Bb$M<o[n^r1uBO>[`pgOJ7BP$GkmHj0;m/?;OmelMsnbrLd!!#tg
+?3'oqs82Wbrr)]dq>C3hqu$EjrVZWlqtg<es7uZj#Q+5lr;6Egr:0Y"o`+p`r:'R_s7Q3[!;Z-^
+o_8=_pAOmbr;ccDq[WT(s76)irr<#ms7H0fq==Q9~>
+pAY?ks7u`qs6ose1\(M=s8;ojs8VZirrE)B((eIb_BBZ4s8'eS+M%Nl&KJsn_]Kc5p<=Nj])2H:
+,oao)qtg<mZMa_'q"F^^!;l`p&,l4spA"@VpA"@VpA"@VqtC'irU0O_qY^?qoBcP>rr3&qs75+J%
+f?5%rVQQjrVQQjrVQQjrqHNjrVZ[/qsj^e;EIYSjP]Lunal;>n+$&DrVI*$p@Ib>k2F6h8P;9C4
+\#6<#=M<[ccsqih"0>5jno#C!!#2=8c\#8rVuicqrdt\r;Q`qrp]pfrV?Hsr;ZWoo^'?ms6'cSk
+k>&Qs6oLMn+-L/~>
+q>UH_rr3#rr;?R,p\Y!_s8VurrVuKhs82Tfs7-'f)Z'C3p%n^_s7c6do_SU`s7cQnqZ$EkoDA@\
+rr2ulrr33#o(`%N]D;:&s8;*\!;l]o!<2uq!<2ut!rN#op&>'hr;Q]t/"IsbrrV`jqY:'orVuTj
+s7baW!;ufq!<2Wj#<Blgs7b3p9)S\kSY)UNrh^%$X0&G&Vkg#WOfmI=$hsGks8P'h0)th@p&=sk
+r:'acrr<#nrr;ofqZ[!!s7l?frVllsqu6Zoo(gZ0"TJH$`;fi9r;Qitqu69gJ,~>
+q>UH_rr3#rr;?R,p\Y!_s8VurrVuKhs82Tfs7-'f0DbVHp%n^_s7c6do_SU`s7cQnqZ$ElqZ$Qn
+rr)c`qY^?ipAY*g^\7Nto^VSLrVlg:rqlKcqu?WprVlfrrr;utrr;usq>'maqssX^rqcX"r;$6]
+qssXYqYMuErVlcmr:oj`@K?6%rq-3_rVcZmr;HQlr;-?_qYg$ar;HQlr;HQlr;HQlr;HQmq>Vf:
+s8)copAOm]na,K#jlu4)mdC-W:eX/M@K>ETjn&%YCM@HoAnCpOs(24B#\[Y!i:Z^8m.^&D"SMEZ
+p%A:Ws7cQgs7luur;Z`mjT&fkr;Q]tr;-?jrX8](rVlcprVlcprVlfprr2rrr;Q'_!<2rs$2jYs
+s8W)qq"am's8W!(ppC"us8MunqYU3]s*t~>
+q>UH_rr3#rr;?R,p\Y!_s8VurrVuKhs82Tfs7-'f)Z'C3p%n^_s7c6do_SU`s7cQnqZ$EjoDAC\
+rr2umrVm&qr;ZN.rVQTsqtTs`rVmE-q"a^\p\O[]q"jd^q"jmcrsJN#rVuipqtp6drU'UmqWlo:
+6icTMs7u]jpAY-lmJeU2oCVYHoCVYAoC2ADlh'T&g"G-8i8WeWf$FCK,97CC493.@`m`=+r^ISo
+92SDQ6UXI<:K1FrHJA&`qXOFUoCN(WqsaUkp@6u>>la*WptYlLrUTjcrV?HtrVH6ZnalOnqu6Tu
+qsUHSq>UBrrV6*_o)F4~>
+pAYumlZDFF(]_bZs8;ols8)]gs82ijp](!Urr3&ls7Q?j"oJ>orVucort>>*s7uZns7c']qu$?i
+r:p<lpAY*lrWDu,s7H0fs8M`l!;?0e''0)js8N&rqYBs]p\+I`s7H?gp&>$frr3-U=No1#0`M(P
+psT0[VLb87Xg5@>Vk93F/&Td%r;Ys!b=8,/M5K\?"8r2lroO1[rr;ltq<S%ZrrjDBs8;]imf*Ii
+qtTs^q>L3jr;HTqr;6*]"oSE"q"XjerrDuprrN&no(^Z/!W2forr^"8rVl0`J,~>
+pAYumlZDFF(]_bZs8;ols8)]gs82ijp](!Urr3&ls7Q?j"oJ>orVucors8Vus7uZns7c-as8W$%
+qXa[anbrIdrsAP0qrdbKn+lk[rr3B*qt^'br:g-eqYKRTr!E8uqVM2Gs8N&tqYq]9qW@YAqY'dZ
+p\+@Tp\+@Xl1t/>!!$A:<rgkJqrmnPqY1*Zo)ACco(_nJp]:6hrVQWk2Yle9q=s94>\[k[?X7#L
+BkqbiE)]:Z9MeGj!)@?*Dt<JhnF,i6md9H1n*ol<o_.VHqt0jZnGW:^s8;fns8N#t#4VZfp[eI[
+rVmN.q>'mcs8N&ts8N&ts8N&ts8M]krVl-_!ri)prr3'!r;FD1%fZA'ppL,"s8Dikq>'pdoDa=~>
+pAYumlZDFF(]_bZs8;ols8)]gs82ijp](!Urr3&ls7Q?j"oJ>orVucort>>*s7uZns7c$[qYg9j
+rVHQop\t0rrVQ8ps7-$e"9&#gqY^?trV6?iqtodWrVum)rSmkQrVZQgq=saap'(9ls7cQmpAY[%
+lML;4!!"o=2#tnprTX1Sp]9gRrqHQcq"=4Q47qq(lKINslKINhlKINfHV.429i"P^;c-7c!'VG7
+!#R"[email protected]\air2dhW=4kqqM,WoDeX_p&ORMnbCo>%K6(uq"jd^q"jd^q"jdb
+qZ$HmrVlisrC$PZq"41Mq"X^\qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^
+qY9p^qY9p^qY9p^qY9p^qY9pcrr_u!qYgEn"9&)kqXXZ:~>
+q>V3+s5j8W_#IB#]cR4Mrr<#nrVuosp&4mpmf3:\s8Voort"`!s5X.Equ?9[pAb0Ns8;iq)tj-s
+rr2corqH-ds8N&ds/c8#pA"1Qn+c\Rq>U6prr;uts8DWjs8E0!rpg$`q#:?nn,EVZf]i/&o?p>(
+rro6_Xe)tpn>-,\rMBOk"d-*aX/NQ&rsJZ's!k\Hs5_D)3pZeMq#C!YqtU!Xp]13bs8Dp$s8Dut
+rr;rjrtbV6rr;utrr;utrr;utrqlNeqtp<jrosFor:osXq>C6kq=sa\r;69ar5/I>r;6Nk[f#su
+r9aN7~>
+q>V3+s5j8W_#IB#]cR4Mrr<#nrVuosp&4mpmf3:\s8Voort"`!s5X.Equ?9[pAb0Ns8;iq(\dt!
+s8VrprUo^[rqZHVrhKJlp%nF_q>1*srV?$\qXOFRqYL!gqYpHn!qcNgq>VT8p%S4XqYL!ar;6Eh
+r;6<]naGiF>!b>39N2#Ylga!'qX+UWj^_8*?$0QGA--7MA,Tm:@3J<]=^tiYcL1;to'u8Aq#'jc
+quBu1;E@`S!:94Ho(MkSrV-Hgq"jsd#Q4Q!rqHHfp[/"Zrq??sq=sdNq==L_r;-TkoCVqErtYP2
+qtg-aqu-Qos8N&ts8N&ts8N&ti;Y_7s8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&ts8N&t
+s8N&ts8N&ts8N&urr2f)s8N#t"o\AsrVlfgs*t~>
+q>V3+s5j8W_#IB#]cR4Mrr<#nrVuosp&4mpmf3:\s8Voort"`!s5X.Equ?9[pAb0Ns8;lr'`IV!
+mJ[(_s8Vris8DZaiUiT6s8Drs"oJ8loCVnXrr`9#s8DZk#lOPrq"j=OnbE"T#l+AnrVHQms82Zm
+&c;4jn)sa=*YT)54TO[2n_)Ojcj.t=7Pmk)=$lII&P5bq;Gg=h;GfS_92net^u=SUm3V,Wj4XJg
+2('/'6icB:naH&=n*TT6oChhDm-O-0oCVhSp&Fjcmf*:co(rggp]'jbq"j^Sn+6>Brs8Mnn+$#A
+pA4a_rs\l+rVuirrVuirrVuifs8W#tqu6OUs8Durs8Durs8Durs8Durs8Durs8Durs8Durs8Dur
+s8Durs8Durs8Durs8Durs8Durs8Durs8Durr;Qfp[J^%,rVQHgo)F4~>
+q#;Q2s8N)hl3R1K$N'l$s7u]os7lWop\4^Us8VBas8)cqnbN%]!VuBarrqWdq>0sfrr*,pr:9mf
+rq66i&(LXZq=O1<mI^2OrquZgq>UBorUp0lqt]gCrstKh/\C!,s8V`G[k3`/T;DC`!N33PrsJ\s
+p\+VB_T(HF/+`f:rWr8dr;?Hiq"X[Vp]^Kkrr;utqu.$%rqucqqZ$0erqQ*_q#Bm`ir98]q=sa\
+qu$Biq>^3iq8*(=q=j^XYkRhbp\=X`nGe"~>
+q#;Q2s8N)hl3R1K$N'l$s7u]os7lWop\4^Us8VBas8)cqnbN%]!VuBarrhQcq>1!ert5),oD\aa
+mJZt\qn`4+rVuorq#;!*qY9d[r;-<fr;6Ehr;6HjrV$6js83/rp%.bEnF,l;rqHTcq"OR[pC[)[
+BlF&W><#5J6WI4g@VBOjqI^%EDsZrVn)*O'mfDkCqWn.G$g-a>kjS9Cq=j^^rr2p-o_&8f4'5ql
+n+,T.qYU3fr;cimrrN#frVloqrSdbYnb_DErVm0%qtg0dqY'[^lMpn`s8Don!<)Kfn,Ejrs8N&t
+s8N&ts8N&ts3goFrrN)0q#:?noDa=~>
+q#;Q2s8N)hl3R1K$N'l$s7u]os7lWop\4^Us8VBas8)cqnbN%]!VuBartjo!q=s[[rVccms7cQn
+q!.YHna3RJnbi@c"o@iXmIU,NrrE&krr_u`kk+iFqX4IPlMg/Qk3_O&q<S[L@ql!94q\nY)EL=f
+>[h#5qF(WV:!1`#c+V<kblQ;KpYcD6iSi\XpA=a`rV-iqnCuXs3>t+b!;$'WqX=Fbrq5XX!WDfa
+p&aOSkPkM]qZQWaoCi.OrsJYpn+#r>o_/(WrVHO&rVuirrVuirrVuirrU0\JrVuirrVuirrVuir
+rVuirrVuirrVuirrVuirrVuirrVuirrVuirrVuirrVuirrVuirrVuirrVuirrVQTp]DV[2rVQQl
+o)F4~>
+q>V6-s8DF;\oV`gdnTlBqu?]prr;lqs82fq-Mld&p\44Qp&Fmfs6BFRs7Q!`mJleFs7ZKmq=ssh
+jo>>>qt^-drVm9)s8O2@s82BKlL+EErsAW#m/HGPrp0RKqYom^"KA;i^6JJm%%s6\s8OCMaQVg!
+^*Lc!$iB\ghYdER1runm+TDE@rWr2rrr;uqqt^-^rrE#crr`2pqt^'b%K-,$s8VienaYo:p\4L^
+rrW)mr.G"[r:fgTn>u9Qo'u5=nb)_UoDa=~>
+q>V6-s8DF;\oV`gdnTlBqu?]prr;lqs82fq,5U@"p\44Qp&Fmfs6BFRs7Q!`mJleFs7ZKmq=ssg
+jT#8Br;R*%r;,^Pm/ZSPrUp0qnc/+Ys6]jQp\u!-rU9OSna5W(j5AhNiT'@cBP(Lt;u1,=C4kCB
+qZ'nm;GfMj!;QQanb;nR"7#XNmeunMo)[email protected]&Dp?q_Ss8Dlorr2p.n,N@Y!,,AB!:]d[
+qYg0err2lr!<)cl#Q+Apqt9g]r:9gUrrN)hq#:Epr;Q3c!WMuqq?-WmrVi)^!5%LqJ,~>
+q>V6-s8DF;\oV`gdnTlBqu?]prr;lqs82fq,5U@"p\44Qp&Fmfs6BFRs7Q!`mJleFs7ZKmq=smb
+hu3N:r;R*"q"!>+gAogko)8S/p?h#'kjA$;lhg)HrTO4CrVQQjrVQQioC),9jR)j5rp^9Xe'c60
+8jHfDqF_ArDU.Y3!'(u@*tCa?j6bjcq<S4AmH<R/mIKKBlgXcC#P%9Xq"FLPqYpL*rVQKjrVkpN
+m,7q@6<aH_eGfOGnb<OZq#16frr)`jq"X^_lMh_"qtg$YoC;;:mI0cDqY9p^qY9p^qY9p^qtg<e
+rq??drVAnVqY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^qY9p^
+qY9p^qY9p^qYL*gs8Th3s8Muds*t~>
+q#:]ls7s;3-g1M6g@kOG$1RupqXOL`li-e\rrW&rrr2p)o`+p\s7lW[s8V!TrrqWdqsXR]rr35j
+rql0ZjSAZMrs1-T9E5%iht6@#rrDlorsbNXVkKrdXg5:AZEL+3o)B*fs8O<I]tDH9s7#s[rs&H%
+s7lQmpuhYunc/Xas8DfjrVuosqY0XTiqi]T4dI&es763fpA=jgrr`8uqtp0gs8;ormf*=cq>L3h
+r;?Qnrsnedg[ah-p\Fggs8MT[qr[qYrW2rri;X5bs8N&ts8N&ts8N&td/OUTq=aRTZ2++fo'l):
+o_J(XJ,~>
+q#:]ls7s;3-g1M6g@kOG$1RupqXOL`li-e\rrW&rrr2p)o`+p\s7lW[s8V!Ts%_eXqsXR]s8N#a
+s8Vopmf34]oD87V!+Q0#qu6'ap\t'apA"L^rVQ?cnau_Tqtg3dqtg3dqtf4Fp[*!*D.-dW>$+j,
+=_D;flKdoin+uG_o(`7Zs7--k;GhE6rU^'gp\Y6fr;?$Ur9s.QrVQTl%JfthrVcHhr;ZfrrVlfp
+rs\5dp[J;i!;cQVrVlWjrr)j*rVZTlqu$?hqss=Mo_n[YquH]crs&2rs8VWhrr)lsrr)lgrWrK!
+q"aa^qu$EWs8W)urV-?lrkAC5rj_b'!ri/tp&BO~>
+q#:]ls7s;3-g1M6g@kOG$1RupqXOL`li-e\rrW&rrr2p)o`+p\s7lW[s8V!Ts"!=5qsXR]rVQKW
+rVuZmmJZkQlgO3(!(R%EmJ62Mo'tl"gu%/Um-X--jluO.#jq!*lK[AC<,)>?raH1E?!'^%cd:1R
+eG@W+gZS+kn_!mB-mqXfjPoh%oDA@`#5A/to(W1TkPkYTs8VuorrW2trr)j'kje0(!)N[cqX!SK
+s8)iqr9aOTr<E#nqsrkIq>C6qqtTgWqs47grVH6ZnaGl3n+cAKs8)cjrq?Bes8'P."oA#is8Th4
+s8Mucs*t~>
+q>UNhs7H9i48o3Zr;ZT_o)JX^qu?]R49,Ynp;8<i]CWlL(XN-Taql/>rP9I!`9tAU'ZC$g(E1<n
+s1&sW^%_@%q>UBt,F$?a74n!.%_8(0WiN/#WiN.g^S$gejSoVeq=t!i3OL=9rV6?js8)Ttm/HAN
+rq69inbi@arqm-"r:Bg[nbMJFq>:'h!qcEirVm-=s8VWhrp9X`lMgk[nG`Lfnc&dgs8MK_rr)j!
+q=XCSl2USYm/I@hq>($is8Mrq]DhlFrr3-#q"47Wnc++~>
+q>UNhs7H9i2uWdVr;ZT_o)JX^qu?]R49,Ynp;8<i]CWlL(XN-Taql/>rP9I!`9tAU'ZC$g(E'sb
+rjs3hbPqM^p&+[K!)Zic!!)]goCqb?kN;!on*fYjlfm]oE)ZRA'39Kg<GU^emIp>Oqu$ElrUK^Y
+nc&=anG;qmp[RnTs7uBV!,V`3rr;rkm.pMU#OVQYs8Vfms6BOfrr;fos8)cfrVllsrqmT2o`"jg
+qY'R^r;#UWs7$'crVZQjr;Q]crrDiarr<#rrr;osr;6@!pA=@Ys7u]pq=jX\r;Z<cqYp<jnbiRh
+rVZWgs8Ms*rr)iprr)iprr)iprm1NJs8MukZMF=qr;Qlsq"Xg\s*t~>
+q>UNhs7H9i=T/:"r;ZT_o)JX^qu?]R49,Ynp;8<i]CWlL(XN-Taql/>rP9I!`9tAU'ZC$g(Dja\
+rO<mcbQ%V>m.'Go!'WY!!!)`kq>0I9f@/4#gtpl'gtLN3@79rj#ZON?=%m)Wki)O+rp0gUn*9Q:
+m/HVWlh^5cp@S+Zs7>I.!*90dq#CBkn,3%]"n2K[s8VlVrrr5us7u]drVuorq>U`ro)S"7h"Ld>
+rr3-"qtg0dr;?`prVQQkqu6Nop@A1Mrr_liqXF@]"8;-LqTAj<rO`(4q"=Uc_#FB6qZ-T`s*t~>
+q#:]ps8W)hs7cNks7Q?j4T5<[p\b'Os1o-C7%0oCs$3QY55P:,Y*i&]33B#?s";*_2?,h:UJ1Rb
+6'S`3nb2t^rVn4@_;F#"XtBYQ%A0T(['-F$TUNQdX/`_srs&Apo^VSNq#:9onFuVU!U0F[rrjGC
+s82Whrr;fl"nMTco)/+IquH`qr;ZX#p%e1Rq!n+Oq>Bja"oJ?"r;Q]arrDrqrrW&krnIGRrVHHl
+"8MQaqsj[drqcNnrqu]nm/ICkqt^'crr2imr4Dt/_YsK9rqZH\s*t~>
+q#:]ps8W)hs7cNks7Q?j:]:=np\b'Os1o-C7%0oCs$3QY55P:,Y*i&]33B#?s";*_2?,h:U.G"V
+6'\uCqu?]ql1P*iA5P^";?61Nnmu6:?!h&QAl`tQ@:4$'lM9ZMlK@O!nFH;Hr;$?mp\t-mn+QSV
+&cD:qrU9dcmIUDQqu?]kp\+R]rrr,rqtC'akl1hcs82irqu$I*rqu]kr;?HjrVH0_r:L$hr;Q]r
+rqu]orV6Bmr;Q]sqtTX[!<2los8;lnrq['#q>9[Ys8W)sp\":Xr;ZBe!<2`mqu6Wo&cDV*rVZWl
+rVZWlrVZWmrr)firrE&drAOTPr;HQlr;HQlr;HQlr;HQlr;HQlr;HQlr;HQlr;HQlr;HQlr;HQl
+r;HQlrVZQcYk\"krr)j!qtKmap&BO~>
+q#:]ps8W)hs7cNks7Q?j:]:=np\b'Os1o-C7%0oCs$3QY55P:,Y*i&]33B#?s";*_2?,h:TLJGL
+6'o5Jr;QTehWOrA;E67#70)cAo4)!(;cHe%>=iEt<)[8Hh>5n8i8s(ck3VF#lL"!-n,DhYo`+jg
+rrMchq#:^"s8Vclqrd;GnbD_U"o&&pq>^<Trs/N&qZ$Tls8N#ts8Dcn#Q"Dmip?4+qu6U!rVH<_
+q"XU[!;?Eg!VZ-SqZ-T`rri)nqYL0frr`&bn,%_:$MsMqs1\O5rVQKjn,In~>
+q>V--rVud&!!*-$!s&8srr;rso`+jgs#BGS(&nd3oaUj8jn0>^rtOtp#lPb*miDB;l1Y5Y&Fnro
+rq[N%lPTNrlMpl8Y,g1Gj4)>O315TZrrN,srqc]pn,NFequ?]qrVtgT!<;lor;?ToXoAD#r;Zco
+!<2KfqYgNqroX7Zrr<#trk&11]);U.rp]r<~>
+q>V--rVud&!!*-$!s&8srr;rso`+jgs#BGS(&nd3oaUj8jn0>^rtOtp#lPb*miDB;l1Y5Y&Fo$"
+s7mDojV\!slMU2Q?qFO%6V1T^!,cEJp&t'^p\FXSq#:'lqYU3hrp0Rcrqu]mrr`2rqu$Ems82lr
+ci<Y:qZ$EkgAh$Krr)corVluur;HTls7?6\rtPJ4rr;utrr;utrr;utrr;utrr;ugs#^5[rr;ut
+rr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;utrr;us#5nJs
+[/Kt&r;Qlur;HWfs*t~>
+q>V--rVud&!!*-$!s&8srr;rso`+jgs$?(\(&nd3oaUj8jn0>^rtOtp#lPb*miDB;l1Y5Y&Fnoj
+q"5Emmiqf3kk=0>;`mT3,:l2F!+&jrn+$#Aq"jdZo(2qUqtU!`!;l-_"o\;mq"js&rrr;rq"jmd
+rVuor!;kXOmJm1aqYpZrqYL/BrsAW#s8KP.rr;rqmf.e~>
+q#="Xs7Xl<A]=TIrr2rtq>^?lrTsRVrs8\-nc8^i!<3'!rs&2s!;QQoqZ-Zr!;d!#q@*B(s8E)e
+rri<#!WMckoDehRf[A[;gr)U3s+13Hrs&E#q7-J'rp9Z8~>
+q#=.\s7Xl<A]=TIrr2rtq>^?lrTsRVrs8\-nc8^i!<3'!rs&2s!;QQoqZ-Zr!;d!#q@*B(s8NH!
+rrDTc!<2ipm.o`CE)TD)=]YUmnG2t\r;uuurdk*#s0)G,r;QN%s8Dr`s*t~>
+q#=4^s7Xl<A]=TIrr2rtq>^?lrTsRVrs8\-nc8^i!<3'!rs&2s!;QQoqZ-Zr!;d!#q@*B(s8;r_
+qZ?Zp$ig5)jQtIu@mVn(4$!Amh!4G'qgncus/Z/(r;QN%s8Dr`s*t~>
+q>XOqs82iqs0jm1LuA='oDeC]s7lWjp&FEX+9*5Riu72%lf&rbrtb.e*rcN:o+:p0n)"oM&,PT%
+r:qN2q%rbnoDYo?k;g)qa@SVE`RD-*\[f2Y[^EMo[Xkll[KX%B]?$WBlMlA~>
+q>XOqs82iqs0jm1LuA='oDeC]s7lWjp&FEX+9*5Riu72%lf&rbrtb.e*rcN:o+:p0n)"oM&,PZ.
+s7dGtmhGTnrr8^pXoMI%;ZHfbS@PH'[^EQO[^W_s[Xkll[KX%B]?$WBlMlA~>
+q>XOqs82iqs0jm1LuA='oDeC]s7lWjp&FEX+9*5Riu72%lf&rbrtb.e*rcN:o+:p0n)"oM&,PQ#
+qXts'qAoV4q"BlASH),H56(\:MQ3)HZ*LaF[^<Dm[Xkll[KX%B]?$WBlMlA~>
+q>Uius8VZip](%s"r->$s"jZSr;6Nor;Zf5*q2@^\OZZP\Z%aarD9K&0CrG3XZHJSOhXKc8"ueF
+qtig\Ud+bLnFHPX!]-rAqu6ZorVH]nq"X]:qgnXMqZm/rp[u)srVGm\J,~>
+q>Uius8VZip](%s"r->$s"FBOr;6Nor;Zf5*q2@^\OZZP\Z%aarD9K&0CrG3XZHJSOhXKc8"ukM
+rV&FDRQUNJ%K,qi!+#Z\nb2hRs82`nqZHcprVV6DJbubM#QOSnost,$qX"64~>
+q>Uius8VZip](%s"r->$s$H_br;6Nor;Zf5*q2@^\OZZP\Z%aarD9K&0CrG3XZHJSOhXKc8"uhH
+qY3@PUI5(]q=4"Ak2QG=!7'Win*]uFp\ssjp\+@WJbt#qZMOn,q"OHls8Df\s*t~>
+p&@;Is0XU6MYHl9s7lWks8Vi^rriQ?ZM;im#K$Mc&Ke[cs.gD=ci:F%)8kjO/c`H^cl3nFr;X\`
+(s_O;naZAErr39Fs8W)ts7l-]r;HWpquH_Is+13Trr`6"r4;.mJ,~>
+p&@,Ds0XU6MYHl9s7lWks8Vi^rriQ?ZM;im#K$Mc&Ke[cs.gD=ci:F%)8kjO/c`H^cl3tLrVa>I%
+F"GBrsSMuq!8"QpZqSRr;)!EJcD\K"9&8t]'96F~>
+p&@\Ts0XU6MYHl9s7lWks8Vi^rriQ?ZM;im#K$Mc&Ke[cs.gD=ci:F%)8kjO/c`H^cl3qLs8Tk[
+'@64DqtTgEmHrp6n+#N0qtp3grrrAuq"FL]JcC<$Z2Xq)s89Ims*t~>
+q#;Vss8Tl*ABFlOoDe^fp%A@Grr<#ls7QEis6fperVlinp]'pTrVm!!p](-fs8Vd:s7ZBPs8W#s
+s82KZl.bt3qZ"Y:rU9ORp%S4Vr;HQkq>1#?rIOpQrVlg"rNuFrrp9Z8~>
+q#;Vss8Tl*ABFlOoDe^fp%A@Grr<#ls7QEis6fperVlinp]'pTrVm!!p](-fs8Vcus7cQUrVQ'\
+rr)j&o)Ja]r4;RsoDJUirr)forrE%LrIOpQrVlg"rNuFrrp9Z8~>
+q#;Vss8Tl*ABFlOoDe^fp%A@Grr<#ls7QEis6fperVlinp]'pTrVm!!p](-fs8Vd-s7u]\s8Vfm
+s8DikoA]K;lh7m]q"":]"oJ)go_/05rIOpQrVlg"rNuFrrp9Z8~>
+pAY0b"TAB,!WW<#qtg?mpAY(:mJZtZo`+g_s8VfmpAb-ls7u]ds7ZK_s8VNerp]a`s7ZKkrql`q
+s8!B+p@RnDnG*"KYke%co%E[$qu6Tp"9/2prdk*#s0D\)qZ?fr\*<pC~>
+pAY0b"TAB,!WW<#qtg?mpAY(BmJZtZo`+g_s8VfmpAb-ls7u]ds7ZK_s8VNerp]a`s7ZKls8Vrl
+qsjCZqYpT`[/L".mJln[s8ITLJcDhOs8)ltrO;%kJ,~>
+pAY0b"TAB,!WW<#qtg?mpAY(8mJZtZo`+g_s8VfmpAb-ls7u]ds7ZK_s8VNerp]a`s7Z<h$hEob
+q"jj_q>L9Y[Jg+,mf3._rrrAuq"FL]JcC<$ZN't%!rr5.l2Q8~>
+q#:s*s82ios8V`kp&G!es7cQnnG`G)qZ$Tns8Vrqs8D`ms8;osrVuons8W&sq#16mpBLZlrpKUV
+rr)j.r:0FOp$hkUVtJs7nac5Grr)j!rqlTlJcC<$YQ"b&[J]gtm/MS~>
+q#:s*s82ios8V`kp&G!es7cQnnG`G)qZ$Tns8Vrqs8D`ms8;osrVuons8W&sq#16mpC.)rs7QEd
+r;HTks8W&srrr9!s0;Upqu?ZoJcC<$WrE5![J]gtm/MS~>
+q#:s*s82ios8V`kp&G!es7cQnnG`G)qZ$Tns8Vrqs8D`ms8;osrVuons8W&sq#16mpB1His82cp%
+K#qsqXaR^s82irZN'FhrrDrqq>gJFs+13Rrri5,r:p3Vs*t~>
+kl3.%s7--hp]'gaq#Bpbp&Fdds82fqr;Zfls8W)up](6ms7Q*cpAFIUpAY!i%K?8!o_JLaYkRqe
+o(`+Ys8Vusrdk*#s0D\)rWN9!ZhjOas*t~>
+kl3:)s7--hp]'gaq#Bpbp&Fdds82fqr;Zfls8W)up](6ms7Q*cpAb!hqu?ZprVQTo"o\8prqs5(
+rrE&trri;tqYU5Bs+13Qs8W'$s895"qWn03~>
+kl2sus7--hp]'gaq#Bpbp&Fdds82fqr;Zfls8W)up](6ms7Q*cpA=miqZZ`jqu-Eirr3,.q>L9g
+q>^HmJcC<$Z2ak'"TSD+qYKOXJ,~>
+l2LbQrVllnrr2uYrr482s8DWjrVlfks763`s763imf3:Uq>^Kgs82TcpAFsarr;ioqu6o-rVl`g
+r:U!brrW2trdk*#s/uA'\c;Wos*t~>
+l2LbQrVllnrr2uYrr3i&s8DWjrVlfks763`s763imf3:Uq>^KgrVmB,s8MTbqt9gbrr)fnrNcG&
+$2a_opA=[]qY^>Ds+13NrrTb2rTjK6~>
+l2LbQrVllnrr2uYrr3i&s8DWjrVlfks763`s763imf3:Uq>^KgqYp]gpA"4Qqu6o(o_A4Sq==<3
+s+13HrrTb2rTjK6~>
+kl1hcs6B.SlMgekq>9jbs7$'apAadQrVluupAb$ers8Aos7c?Jq>9m\s8W#t^%D=+rqubHs+13U
+rri2lqtIP`s*t~>
+kl1hcs6B.SlMgekq>9jbs7$'apAadQrVluupAb$ertbA(s7lW[s8Vlorr)cmqu$?co('*crr2p&
+rquWgq"jmdJcC<$YQ"b%pA=Tml2Q8~>
+kl1hcs6B.SlMgekq>9jbs7$'apAadQrVluupAb$ers8Aos8)c_s8Vilr;lrtrVm3#Y4M;Xq"X^_
+rIP!"s/Q)%qY'g\[d!gB~>
+kl1YErr4JG1]S,[qpuYr\Gsba*kVIPUD46bs0O*i`9t/h!4i-W*#lopqm@X\aS5N1"M+R4qt9aa
+!WN%Krdk'Rrr2p#rjVn(rp9Z8~>
+kl1YErr4YL1]S,[qpuYr\Gsba*kVIPUD46bs0O*i`9t/h!4i-W*$*3%s19Wl`q00+p\Xjeq@9P$
+qt0IZqtg-aq"adarIOs!rilD$rri>1rql]]s*t~>
+kl1YErr4SJ1]S,[qpuYr\Gsba*kVIPUD46bs0O*i`9t/h!4i-W*$!6's19Tja7TE3rVZ[&Vt0EF
+l1k#Jr;?Qks+10#rj)P&rri>1rql]]s*t~>
+kPm.-s8;`Zs0F$O2P@W<s"1aZ4S/JHW4=VQ>EGpIs%/<e8c(uNV*Y.T2kc]urqZQo_>aH9q>^GF
+s+13Ks8Vs!s805'rp0T7~>
+kPmU:s8;`Zs0F$O2P@W<s"1aZ4S/JHW4=VQ>EGpIs%/<e8c(uNV*Y.V4/\c4s8MfeqY^3er3Q:u
+s8)`ps8;oo"8r,srdk*#s0;V(qZQrr[Jp0ks*t~>
+kPm+,s8;`Zs0F$O2P@W<s"1aZ4S/JHW4=VQ>EGpIs%/<e8c(uNV*Y.U3iAZ6rr2utrVlosZi9e&
+o_\LarIP!"s/Z2"qZQrr[Jp0ks*t~>
+kl1\\qY^@AlllBAm-keX)X?9$s8Ni'k9'^0o(!@l$LZabmg]'Y'`[tGn*UYZqYL3l[Jp10qYBj^
+qu6Tp!WN"JqgnXKqZd*!s80;*rTjK6~>
+kl1\\qY^@KlllBAm-keX)X?9$s8Ni'k9'^0o(!@l$LZabmg]'W%fQ/@p%B-uqYpHlrr<#qWqHAj
+rs8Q&qtg*_q>'l<qgnXKqZd*!s80;*rTjK6~>
+kl1\\qY^@?lllBAm-keX)X?9$s8Ni'k9'^0o(!@l$LZabmg]'X%fQ)=p%TC$rsJ`%poaGms8N&p
+rquZmrIOisqm$#&s8Dup\,ZEms*t~>
+kl3p<s8VZis7^YtrrDTh!<3'!rrr)q!;HKnqZ-Zr!;cs"q@!<'s8NT&rrMWa!;Q$[rqH$\qu">/
+oChkJme?PVJcC<$WrE;&r:d]#q"="RJ,~>
+kl3I/s8VZis7^YtrrDTh!<3'!rrr)q!;HKnqZ-Zr!;cs"q@!<'s8E/er;lTk"98)ps7l9drs$11
+oDS^hrr2rprdk*#s02M-rquN"s7l9Rs*t~>
+kl3[5s8VZis7^YtrrDTh!<3'!rrr)q!;HKnqZ-Zr!;cs"q@!<'s8<&ar;l]n#QOf's8)<]q"r#0
+qu6TqrIP!"s/5l$rquN"s7l9Rs*t~>
+kPmO8s8VclQWsIb&,G`'r>"Dc'DDG>n+-e`*pE&4r"&)f!ril'm2Z0+)rolpo_/1M`N68LY,'4D
+riH<uYH4q5r3Ls[J[2Pd"LP8;`hVeuJ,~>
+kPmjAs8VclQWsIb&,G`'r>"Dc'DDG>n+-e`*pE&4r"&)f!ril'kn<^c)s?H1rVcceag&:dZ_PUI
+[_'5Z]="uNZ%933ZE:D8[&gXSUZqf/~>
+kPm+,s8VclQWsIb&,G`'r>"Dc'DDG>n+-e`*pE&4r"&)f!ril'kRmL`)sZc9rr3T'b,qhNXf9j_
+]=bh_\[8`LZMh"YZ@T<dZ37P9[)Sm*s*t~>
+l2NF7s7ZKfs+Y.cqYrsWSk&`HX/%oTs!b4D:\clIUHec9[APt`5b"cIqYrjG[l3pTrX#q2qY^9g
+qu$HmJcC<$WrE8%s80;*rTjK6~>
+l2NF7s7ZKfs+Y.cqYrsWSk&`HX/%oTs!b4D:\clIUHec9[APt`5b"]CpAI:B\2sH]rrTP+qgncu
+s.fStrr;l)s8D9`J,~>
+l2NF7s7ZKfs+Y.cqYrsWSk&`HX/%oTs!b4D:\clIUHec9[APt`5b"`Cp&77D\i]cds8Mrs[=S@/
+s.TGrrr;l)s8D9`J,~>
+kl37(s8W)n+92cLpWF-s_XtbW(s`-TbS_;9s2Q<1_<8KG*khTt'c4[bs100ca8#Z9ZiBoRs+13F
+rrrE%qmZV(li2J~>
+kl37(s8W)n+92cLpWF-s_XtbW(s`-TbS_;9s2Q<1_<8KG*khTt'c4[bs100ca8#Z9ZiBoRs+13F
+rrrE%qmZV(li2J~>
+kl37(s8W)n+92cLpWF-s_XtbW(s`-TbS_;9s2Q<1_<8KG*khTt'c4[bs100ca8#Z9ZiBoRs+13F
+rrrE%qmZV(li2J~>
+l2M4js8Dffs7cQfp](6fmJ[%lo`+p\s8)c^s8UpRrrqZep$)MQrr3/gs8VfmlhUP^ZiBoRs+13F
+rrrE%qmZV(li2J~>
+l2M4js8Dffs7cQfp](6fmJ[%lo`+p\s8)c^s8UpRrrqZep$)MQrr3/gs8VfmlhUP^ZiBoRs+13F
+rrrE%qmZV(li2J~>
+l2M4js8Dffs7cQfp](6fmJ[%lo`+p\s8)c^s8UpRrrqZep$)MQrr3/gs8VfmlhUP^ZiBoRs+13F
+rrrE%qmZV(li2J~>
+l2N=)s7lWomf3%Xs7?'dqZ$TkpAasfs6BIYs7>XXli6bNs7?9jp@J=ajT#8ApAY3#s8.BIJcDMF
+"oeQ!\,ZEms*t~>
+l2N=)s7lWomf3%Xs7?'dqZ$TkpAasfs6BIYs7>XXli6bNs7?9jp@J=ajT#8ApAY3#s8.BIJcDMF
+"oeQ!\,ZEms*t~>
+l2N=)s7lWomf3%Xs7?'dqZ$TkpAasfs6BIYs7>XXli6bNs7?9jp@J=ajT#8ApAY3#s8.BIJcDMF
+"oeQ!\,ZEms*t~>
+kl2:hrqHHmoD/.\p&G'jq=jphnbN+_&,lP-q>^Kls8DipmJlnZqYgEqq#Bs]rrTP,qgncus.fSt
+rr;l)s8D9`J,~>
+kl2:hrqHHmoD/.\p&G'jq=jphnbN+_&,lP-q>^Kls8DipmJlnZqYgEqq#Bs]rrTP,qgncus.fSt
+rr;l)s8D9`J,~>
+kl2:hrqHHmoD/.\p&G'jq=jphnbN+_&,lP-q>^Kls8DipmJlnZqYgEqq#Bs]rrTP,qgncus.fSt
+rr;l)s8D9`J,~>
+l2Lq_rr<#sq#:9qp&G']rr2umrr3N#qu>XTlMU\Sp%JFckl:JWrs/8tn,NFas8Mio!jhq(JcC<$
+U]1Mss80;*rTjK6~>
+l2Lq_rr<#sq#:9qp&G']rr2umrr3N#qu>XTlMU\Sp%JFckl:JWrs/8tn,NFas8Mio!jhq(JcC<$
+U]1Mss80;*rTjK6~>
+l2Lq_rr<#sq#:9qp&G']rr2umrr3N#qu>XTlMU\Sp%JFckl:JWrs/8tn,NFas8Mio!jhq(JcC<$
+U]1Mss80;*rTjK6~>
+kPl(^s8Vfmme?SXrVuiaq#C!brrr5urr<#jrVm,ms7lNis8VEarr`2tqt9aa!jhq(JcC<$U]1Ms
+s80;*rTjK6~>
+kPl(^s8Vfmme?SXrVuiaq#C!brrr5urr<#jrVm,ms7lNis8VEarr`2tqt9aa!jhq(JcC<$U]1Ms
+s80;*rTjK6~>
+kPl(^s8Vfmme?SXrVuiaq#C!brrr5urr<#jrVm,ms7lNis8VEarr`2tqt9aa!jhq(JcC<$U]1Ms
+s80;*rTjK6~>
+kl1hYs8MQgq>L=9nc/Xfs8Vlls7Q3fo`+UYs7lNlp&Fm^s8Vros7cQkr;Q]ro(i:eZiBoRs+13F
+rrrE%qmZV(li2J~>
+kl1hYs8MQgq>L=9nc/Xfs8Vlls7Q3fo`+UYs7lNlp&Fm^s8Vros7cQkr;Q]ro(i:eZiBoRs+13F
+rrrE%qmZV(li2J~>
+kl1hYs8MQgq>L=9nc/Xfs8Vlls7Q3fo`+UYs7lNlp&Fm^s8Vros7cQkr;Q]ro(i:eZiBoRs+13F
+rrrE%qmZV(li2J~>
+kPm78qu?WfI/s<Daqbl3rPB]m`;f\T)'H<d^)%O/s25fr])9Ph'>OSI]HeE6s8W&rrr3<(s0D\)
+qtg?mrIP!"s/,eur42k,li2J~>
+kPm78qu?WfI/s<Daqbl3rPB]m`;f\T)'H<d^)%O/s25fr])9Ph'>OSI]HeE6s8W&rrr3<(s0D\)
+qtg?mrIP!"s/,eur42k,li2J~>
+kPm78qu?WfI/s<Daqbl3rPB]m`;f\T)'H<d^)%O/s25fr])9Ph'>OSI]HeE6s8W&rrr3<(s0D\)
+qtg?mrIP!"s/,eur42k,li2J~>
+l2NF.s7lWkrr@TSs6rU[Z9&"TTWD;es$rca2uc+BXZ6;NT!L?T0s7TGpARmTV+(%UrsSc%r;Q`-
+s8W&ns8@NKJcD\K#5e5qppC"sli2J~>
+l2NF.s7lWkrr@TSs6rU[Z9&"TTWD;es$rca2uc+BXZ6;NT!L?T0s7TGpARmTV+(%UrsSc%r;Q`-
+s8W&ns8@NKJcD\K#5e5qppC"sli2J~>
+l2NF.s7lWkrr@TSs6rU[Z9&"TTWD;es$rca2uc+BXZ6;NT!L?T0s7TGpARmTV+(%UrsSc%r;Q`-
+s8W&ns8@NKJcD\K#5e5qppC"sli2J~>
+kl3j6oDedds8N)mrsmcK(B4j:gB7?Q$1I0qkmd=D*V0d/koT^Ch=D!Rndk![+oh*1s8W&ts88qi
+qZ$Kmp&0IAJcDSH!kA:.li2J~>
+kl3j6oDedds8N)mrsmcK(B4j:gB7?Q$1I0qkmd=D*V0d/koT^Ch=D!Rndk![+oh*1s8W&ts88qi
+qZ$Kmp&0IAJcDSH!kA:.li2J~>
+kl3j6oDedds8N)mrsmcK(B4j:gB7?Q$1I0qkmd=D*V0d/koT^Ch=D!Rndk![+oh*1s8W&ts88qi
+qZ$Kmp&0IAJcDSH!kA:.li2J~>
+l2LbQrVnPCs6TgdrrE*!"8i0!rsJf+!<<'!rs/N&"9/N(rrD]qs8N*!rt,.l!;cTms8D`lrrBt7
+rrDtJs+13Jrs&;spU:,"rp9Z8~>
+l2LbQrVnPCs6TgdrrE*!"8i0!rsJf+!<<'!rs/N&"9/N(rrD]qs8N*!rt,.l!;cTms8D`lrrBt7
+rrDtJs+13Jrs&;spU:,"rp9Z8~>
+l2LbQrVnPCs6TgdrrE*!"8i0!rsJf+!<<'!rs/N&"9/N(rrD]qs8N*!rt,.l!;cTms8D`lrrBt7
+rrDtJs+13Jrs&;spU:,"rp9Z8~>
+kl37/rVu*]p&>B_s!$Xp$2bS%q[)Wh$L@-drrW5b!<38siY)8!lMDUppBgBf$i^/8lc--3ZEBJ4
+ZEC=9Ye>UpJ[DA_"L5Y`T`+0UJ,~>
+kl37/rVu*]p&>B_s!$Xp$2bS%q[)Wh$L@-drrW5b!<38siY)8!lMDUppBgBf$i^/8lc--3ZEBJ4
+ZEC=9Ye>UpJ[DA_"L5Y`T`+0UJ,~>
+kl37/rVu*]p&>B_s!$Xp$2bS%q[)Wh$L@-drrW5b!<38siY)8!lMDUppBgBf$i^/8lc--3ZEBJ4
+ZEC=9Ye>UpJ[DA_"L5Y`T`+0UJ,~>
+l2NU9s82cprUp0js78RJSk8rHVO'aOqEh3^6hN^1Yu(<kUTd)J8uS79s8P<hTfiAOs8Vrkrr35C
+s8)Wks7lMCs+13Krs&H!p:1/!p[%p1~>
+l2NU9s82cprUp0js78RJSk8rHVO'aOqEh3^6hN^1Yu(<kUTd)J8uS79s8P<hTfiAOs8Vrkrr35C
+s8)Wks7lMCs+13Krs&H!p:1/!p[%p1~>
+l2NU9s82cprUp0js78RJSk8rHVO'aOqEh3^6hN^1Yu(<kUTd)J8uS79s8P<hTfiAOs8Vrkrr35C
+s8)Wks7lMCs+13Krs&H!p:1/!p[%p1~>
+l2NL;s8Vuds7lQno`)<K-aWie+Y:A)s3(lk]`$+u%_D\N*=pg"`u?,Co`)?2)U\<Trr)j!q=LZ^
+rVlosqLSQqr2KSsrqcZl\`s-E~>
+l2NL;s8Vuds7lQno`)<K-aWie+Y:A)s3(lk]`$+u%_D\N*=pg"`u?,Co`)?2)U\<Trr)j!q=LZ^
+rVlosqLSQqr2KSsrqcZl\`s-E~>
+l2NL;s8Vuds7lQno`)<K-aWie+Y:A)s3(lk]`$+u%_D\N*=pg"`u?,Co`)?2)U\<Trr)j!q=LZ^
+rVlosqLSQqr2KSsrqcZl\`s-E~>
+kl2_#qu?]as7H?hqu?$_s7H?gq>UEnnGiI_s7c-bs7ZHl&GcA%rr2fpp\k-jnGiOdq>L9l#.+@0
+qss^_JcC<$W;d)#rr;r'qYKOXJ,~>
+kl2_#qu?]as7H?hqu?$_s7H?gq>UEnnGiI_s7c-bs7ZHl&GcA%rr2fpp\k-jnGiOdq>L9l#.+@0
+qss^_JcC<$W;d)#rr;r'qYKOXJ,~>
+kl2_#qu?]as7H?hqu?$_s7H?gq>UEnnGiI_s7c-bs7ZHl&GcA%rr2fpp\k-jnGiOdq>L9l#.+@0
+qss^_JcC<$W;d)#rr;r'qYKOXJ,~>
+^Ae<5s8VukrrTP,qgncus.fStrr;l)s8D9`J,~>
+^Ae<5s8VukrrTP,qgncus.fStrr;l)s8D9`J,~>
+^Ae<5s8VukrrTP,qgncus.fStrr;l)s8D9`J,~>
+_>ac5s8MrrnGiL`rrTP,qgncus.fStrr;l)s8D9`J,~>
+_>ac5s8MrrnGiL`rrTP,qgncus.fStrr;l)s8D9`J,~>
+_>ac5s8MrrnGiL`rrTP,qgncus.fStrr;l)s8D9`J,~>
+_#FW2s8N&os7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FW2s8N&os7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FW2s8N&os7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FW7s8Vurs7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FW7s8Vurs7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FW7s8Vurs7Z9g!jhq(JcC<$U]1Mss80;*rTjK6~>
+_>a`(s7?9jr;HEj!jhq(JcC<$U]1Mss80;*rTjK6~>
+_>a`(s7?9jr;HEj!jhq(JcC<$U]1Mss80;*rTjK6~>
+_>a`(s7?9jr;HEj!jhq(JcC<$U]1Mss80;*rTjK6~>
+^Ae>R*$)ilq>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+^Ae>R*$)ilq>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+^Ae>R*$)ilq>UN&s8.BIJcDMF"oeQ!\,ZEms*t~>
+_>a`1s5uVCRRd/Q!jhq(JcC<$U]1Mss80;*rTjK6~>
+_>a`1s5uVCRRd/Q!jhq(JcC<$U]1Mss80;*rTjK6~>
+_>a`1s5uVCRRd/Q!jhq(JcC<$U]1Mss80;*rTjK6~>
+_#FT-rsA2p!;QQqZiBoRs+13FrrrE%qmZV(li2J~>
+_#FT-rsA2p!;QQqZiBoRs+13FrrrE%qmZV(li2J~>
+_#FT-rsA2p!;QQqZiBoRs+13FrrrE%qmZV(li2J~>
+_>b>Hs7uitp]^]js8W#lrr;r+rVuiis8Vr1rr`&rs7jS5"8MorpqHb4rr;rns8W&6rs/N%s8W)q
+s80Y4#58)rrPAC*li2J~>
+_>b>Hs7uitp]^]js8W#lrr;r+rVuiis8Vr1rr`&rs7jS5"8MorpqHb4rr;rns8W&6rs/N%s8W)q
+s80Y4#58)rrPAC*li2J~>
+_>b>Hs7uitp]^]js8W#lrr;r+rVuiis8Vr1rr`&rs7jS5"8MorpqHb4rr;rns8W&6rs/N%s8W)q
+s80Y4#58)rrPAC*li2J~>
+_#FT8rsJ#j!<3!-m)ulG\@8KOW4BOJXgl3Q#H5;AZF-jC\&ko\\$`BHZEq3B_6O<QYd_'G\>QgP
+Z3S"FYcb[<^oY>Ws02X=Vu#]YJ,~>
+_#FT8rsJ#j!<3!-m)ulG\@8KOW4BOJXgl3Q#H5;AZF-jC\&ko\\$`BHZEq3B_6O<QYd_'G\>QgP
+Z3S"FYcb[<^oY>Ws02X=Vu#]YJ,~>
+_#FT8rsJ#j!<3!-m)ulG\@8KOW4BOJXgl3Q#H5;AZF-jC\&ko\\$`BHZEq3B_6O<QYd_'G\>QgP
+Z3S"FYcb[<^oY>Ws02X=Vu#]YJ,~>
+_>b>LnbYhCY<i3cs8Vicr;Zf;r;$BfrV?H/rs-11rqZTlqYA85#Pn5os7uZg]>4FNq>C9cp;H^A
+rs/Q"rVHH,q=hW'"SK>'s7bm[J,~>
+_>b>LnbYhCY<i3cs8Vicr;Zf;r;$BfrV?H/rs-11rqZTlqYA85#Pn5os7uZg]>4FNq>C9cp;H^A
+rs/Q"rVHH,q=hW'"SK>'s7bm[J,~>
+_>b>LnbYhCY<i3cs8Vicr;Zf;r;$BfrV?H/rs-11rqZTlqYA85#Pn5os7uZg]>4FNq>C9cp;H^A
+rs/Q"rVHH,q=hW'"SK>'s7bm[J,~>
+^]+N1`[qeMoD8Cb#5I_aqu?]jrr9h5"0DP&rr)l=rVc`urr<#"_>X<3!rfS,_>X<3!j)D$_>OW2
+r;Zeur;ZTZs*t~>
+^]+N1`[qeMoD8Cb#5I_aqu?]jrr9h5"0DP&rr)l=rVc`urr<#"_>X<3!rfS,_>X<3!j)D$_>OW2
+r;Zeur;ZTZs*t~>
+^]+N1`[qeMoD8Cb#5I_aqu?]jrr9h5"0DP&rr)l=rVc`urr<#"_>X<3!rfS,_>X<3!j)D$_>OW2
+r;Zeur;ZTZs*t~>
+_>ao5rVu]fs763cr;QZnrs-74q>U-dp@c?&#.+@0n+Z\Wa8ZABqY0IYs0KQA#5\,js8Vu"^]4?+
+!rDr'^&J91s/Q,!o'HC,~>
+_>ao5rVu]fs763cr;QZnrs-74q>U-dp@c?&#.+@0n+Z\Wa8ZABqY0IYs0KQA#5\,js8Vu"^]4?+
+!rDr'^&J91s/Q,!o'HC,~>
+_>ao5rVu]fs763cr;QZnrs-74q>U-dp@c?&#.+@0n+Z\Wa8ZABqY0IYs0KQA#5\,js8Vu"^]4?+
+!rDr'^&J91s/Q,!o'HC,~>
+^]+K0s8Vrqp\t0rqt^'aqmHG'"8r3!rPAI8\,?:*rVt"=rVm!!s89@Brquctqn<$GrW3&urr3&7
+r;XV4"S_l_s/G8_J,~>
+^]+K0s8Vrqp\t0rqt^'aqmHG'"8r3!rPAI8\,?:*rVt"=rVm!!s89@Brquctqn<$GrW3&urr3&7
+r;XV4"S_l_s/G8_J,~>
+^]+K0s8Vrqp\t0rqt^'aqmHG'"8r3!rPAI8\,?:*rVt"=rVm!!s89@Brquctqn<$GrW3&urr3&7
+r;XV4"S_l_s/G8_J,~>
+_>al@s76-gs8;cjqu6Nn#H@S"rU^'hqSE15_!V!srrD`6rrD`jrrW&a^qp$Ur;ZZfs7+>(_>ac:
+qu?]b`pio>rrU%/q!7s1~>
+_>al@s76-gs8;cjqu6Nn#H@S"rU^'hqSE15_!V!srrD`6rrD`jrrW&a^qp$Ur;ZZfs7+>(_>ac:
+qu?]b`pio>rrU%/q!7s1~>
+_>al@s76-gs8;cjqu6Nn#H@S"rU^'hqSE15_!V!srrD`6rrD`jrrW&a^qp$Ur;ZZfs7+>(_>ac:
+qu?]b`pio>rrU%/q!7s1~>
+_#FQ8s8Vchrr3<'r;HWorVlfrn,E=fp]&)/!;ZWo"8qups2k9?rrMrnrr2uo_>X]8s8Mios763+
+rW3&prr3&ms8Tq7#QOPurp]sfqX"64~>
+_#FQ8s8Vchrr3<'r;HWorVlfrn,E=fp]&)/!;ZWo"8qups2k9?rrMrnrr2uo_>X]8s8Mios763+
+rW3&prr3&ms8Tq7#QOPurp]sfqX"64~>
+_#FQ8s8Vchrr3<'r;HWorVlfrn,E=fp]&)/!;ZWo"8qups2k9?rrMrnrr2uo_>X]8s8Mios763+
+rW3&prr3&ms8Tq7#QOPurp]sfqX"64~>
+\,QO+q>:-j#5/#joDejfaSuM;s82`fs8Voorr`/us8L%<"8ViooY1>/r;Zfgs7X;/"TJ2rq"t$i
+"oA9!q#Bj.rsSi#rqucgs8W#sq>0FWJ,~>
+\,QO+q>:-j#5/#joDejfaSuM;s82`fs8Voorr`/us8L%<"8ViooY1>/r;Zfgs7X;/"TJ2rq"t$i
+"oA9!q#Bj.rsSi#rqucgs8W#sq>0FWJ,~>
+\,QO+q>:-j#5/#joDejfaSuM;s82`fs8Voorr`/us8L%<"8ViooY1>/r;Zfgs7X;/"TJ2rq"t$i
+"oA9!q#Bj.rsSi#rqucgs8W#sq>0FWJ,~>
+\c2^!r;HWtp&FXRrVlolrQ5'@nGiCbrs%rls8;fpqo8X@q>^Hos8)cl_>a]7qu?*am_8]-qZ$Tk
+m/Q_Rr:0dd!V?-7rs&E$qYgHjq#:9sirB&Us7bm[J,~>
+\c2^!r;HWtp&FXRrVlolrQ5'@nGiCbrs%rls8;fpqo8X@q>^Hos8)cl_>a]7qu?*am_8]-qZ$Tk
+m/Q_Rr:0dd!V?-7rs&E$qYgHjq#:9sirB&Us7bm[J,~>
+\c2^!r;HWtp&FXRrVlolrQ5'@nGiCbrs%rls8;fpqo8X@q>^Hos8)cl_>a]7qu?*am_8]-qZ$Tk
+m/Q_Rr:0dd!V?-7rs&E$qYgHjq#:9sirB&Us7bm[J,~>
+\,QU(qt'jWrr3)so`+j0rrr<"p[/"Qr;Qous8W&qaSuJ9s8VlmrqjJ1!;QQn!W23!rt"i!s6p!f
+nG`Ifo`+RYs8:4C%.X5prr;rfs8Vrgs7kp[J,~>
+\,QU(qt'jWrr3)so`+j0rrr<"p[/"Qr;Qous8W&qaSuJ9s8VlmrqjJ1!;QQn!W23!rt"i!s6p!f
+nG`Ifo`+RYs8:4C%.X5prr;rfs8Vrgs7kp[J,~>
+\,QU(qt'jWrr3)so`+j0rrr<"p[/"Qr;Qous8W&qaSuJ9s8VlmrqjJ1!;QQn!W23!rt"i!s6p!f
+nG`Ifo`+RYs8:4C%.X5prr;rfs8Vrgs7kp[J,~>
+\c2[%rVm#fs)SCsrr3&ls8L.?!<2ut"Ss&;&XrXt!W2f9rs&2so_ngJ#JpEErUg,o!#)NNrsngQ
+$NKkS4UE5-s69R`o[*U<q>UC%mJles"p2(#.Kgcpm/MS~>
+\c2[%rVm#fs)SCsrr3&ls8L.?!<2ut"Ss&;&XrXt!W2f9rs&2so_ngJ#JpEErUg,o!#)NNrsngQ
+$NKkS4UE5-s69R`o[*U<q>UC%mJles"p2(#.Kgcpm/MS~>
+\c2[%rVm#fs)SCsrr3&ls8L.?!<2ut"Ss&;&XrXt!W2f9rs&2so_ngJ#JpEErUg,o!#)NNrsngQ
+$NKkS4UE5-s69R`o[*U<q>UC%mJles"p2(#.Kgcpm/MS~>
+\,Qd&s7u[#K+%_ZpAY'lm`>D;p$r(Zs8TDDs7H?gs8L+>#O29Ws8Upu#J^9BrX@)l%J@R;$3Yt]
+s8-'Ho)8FRrr2uid/OXPs6fmdm.UJX_\<(Gq614ms*t~>
+\,Qd&s7u[#K+%_ZpAY'lm`>D;p$r(Zs8TDDs7H?gs8L+>#O29Ws8Upu#J^9BrX@)l%J@R;$3Yt]
+s8-'Ho)8FRrr2uid/OXPs6fmdm.UJX_\<(Gq614ms*t~>
+\,Qd&s7u[#K+%_ZpAY'lm`>D;p$r(Zs8TDDs7H?gs8L+>#O29Ws8Upu#J^9BrX@)l%J@R;$3Yt]
+s8-'Ho)8FRrr2uid/OXPs6fmdm.UJX_\<(Gq614ms*t~>
+\c2s5s8Mlos5a(Xrr3#uo>gk2rr)j&p&F(fs7ZKkrPnjAr;$'XRt1^Yrs&?"q@VQ0*l%^aq#gQp%
+K#qqs8W#es8:4C%f5htoD\dcr3@F?s7uR9m/MS~>
+\c2s5s8Mlos5a(Xrr3#uo>gk2rr)j&p&F(fs7ZKkrPnjAr;$'XRt1^Yrs&?"q@VQ0*l%^aq#gQp%
+K#qqs8W#es8:4C%f5htoD\dcr3@F?s7uR9m/MS~>
+\c2s5s8Mlos5a(Xrr3#uo>gk2rr)j&p&F(fs7ZKkrPnjAr;$'XRt1^Yrs&?"q@VQ0*l%^aq#gQp%
+K#qqs8W#es8:4C%f5htoD\dcr3@F?s7uR9m/MS~>
+\,Qp:s8MlprsSYpq>^KnrlG*En,N+]q=0?)rVlrqs80q<#Pn5rp#m+d!5\[?r:Bra!W]+i_>b&/
+rrE)k&j6i#l2:SUs8VT9rt#)#s8W)dp%8:uU\XrhFFifYJ,~>
+\,Qp:s8MlprsSYpq>^KnrlG*En,N+]q=0?)rVlrqs80q<#Pn5rp#m+d!5\[?r:Bra!W]+i_>b&/
+rrE)k&j6i#l2:SUs8VT9rt#)#s8W)dp%8:uU\XrhFFifYJ,~>
+\,Qp:s8MlprsSYpq>^KnrlG*En,N+]q=0?)rVlrqs80q<#Pn5rp#m+d!5\[?r:Bra!W]+i_>b&/
+rrE)k&j6i#l2:SUs8VT9rt#)#s8W)dp%8:uU\XrhFFifYJ,~>
+\GuU+s8NE!s7-0ds8W#rqT/[Ir;ZHis8JBds7?9cs8)cmao;VCs8MmObl7d[rri0<^r[M/rsT#(
+rrU?i'*&"*s7l?8rso#-rq-6jp](8b*<5i(>jME?~>
+\GuU+s8NE!s7-0ds8W#rqT/[Ir;ZHis8JBds7?9cs8)cmao;VCs8MmObl7d[rri0<^r[M/rsT#(
+rrU?i'*&"*s7l?8rso#-rq-6jp](8b*<5i(>jME?~>
+\GuU+s8NE!s7-0ds8W#rqT/[Ir;ZHis8JBds7?9cs8)cmao;VCs8MmObl7d[rri0<^r[M/rsT#(
+rrU?i'*&"*s7l?8rso#-rq-6jp](8b*<5i(>jME?~>
+Z2Y".s82Khs7+21&,cD's88Eds82ils8Vrqp<!=Fp](3l!!!]5%IsJps7$'^a8Z>A&^\K3r5&C@
+q>UHps#dX8*;9F/c2S=Os7?9jp](!b_%cg6@/g)js*t~>
+Z2Y".s82Khs7+21&,cD's88Eds82ils8Vrqp<!=Fp](3l!!!]5%IsJps7$'^a8Z>A&^\K3r5&C@
+q>UHps#dX8*;9F/c2S=Os7?9jp](!b_%cg6@/g)js*t~>
+Z2Y".s82Khs7+21&,cD's88Eds82ils8Vrqp<!=Fp](3l!!!]5%IsJps7$'^a8Z>A&^\K3r5&C@
+q>UHps#dX8*;9F/c2S=Os7?9jp](!b_%cg6@/g)js*t~>
+Z2Y"Cl2UeZq!cB)%fQG-k5PGb!!MTel2UVRa8ZSErTjL`lNQhYqu?]ba8ZA=r;Vm#$(\j2%fHJ/
+jP)9eUAt)is82ipdJjaSs8W&hs5"Xp$H2`?!!E;gs*t~>
+Z2Y"Cl2UeZq!cB)%fQG-k5PGb!!MTel2UVRa8ZSErTjL`lNQhYqu?]ba8ZA=r;Vm#$(\j2%fHJ/
+jP)9eUAt)is82ipdJjaSs8W&hs5"Xp$H2`?!!E;gs*t~>
+Z2Y"Cl2UeZq!cB)%fQG-k5PGb!!MTel2UVRa8ZSErTjL`lNQhYqu?]ba8ZA=r;Vm#$(\j2%fHJ/
+jP)9eUAt)is82ipdJjaSs8W&hs5"Xp$H2`?!!E;gs*t~>
+Z2Y'ls7ZKes8Vr;s8W!!p&G']rVm&ts8Dipn]Ce;rVuops6Td`s7?3h!WMl9rs/N&q#:<noCB`t
+&,cJ-qu?]cs8N&js8;`nrmC`Qqu?Tos7cQnrr;inrrD]Xs*t~>
+Z2Y'ls7ZKes8Vr;s8W!!p&G']rVm&ts8Dipn]Ce;rVuops6Td`s7?3h!WMl9rs/N&q#:<noCB`t
+&,cJ-qu?]cs8N&js8;`nrmC`Qqu?Tos7cQnrr;inrrD]Xs*t~>
+Z2Y'ls7ZKes8Vr;s8W!!p&G']rVm&ts8Dipn]Ce;rVuops6Td`s7?3h!WMl9rs/N&q#:<noCB`t
+&,cJ-qu?]cs8N&js8;`nrmC`Qqu?Tos7cQnrr;inrrD]Xs*t~>
+Yl=q*rVufqs8L+>%.F5pnc.qRp%n@]s7FA3&,?1is8VuerqZ6eqs4:^qoJd>jo>AF^Ae`?rVQNk
+s7uQlqu?]gs8W)Ers\/is7c*Us8Vrjs7?!Ns*t~>
+Yl=q*rVufqs8L+>%.F5pnc.qRp%n@]s7FA3&,?1is8VuerqZ6eqs4:^qoJd>jo>AF^Ae`?rVQNk
+s7uQlqu?]gs8W)Ers\/is7c*Us8Vrjs7?!Ns*t~>
+Yl=q*rVufqs8L+>%.F5pnc.qRp%n@]s7FA3&,?1is8VuerqZ6eqs4:^qoJd>jo>AF^Ae`?rVQNk
+s7uQlqu?]gs8W)Ers\/is7c*Us8Vrjs7?!Ns*t~>
+Z2XjrnG`Fgq=MZ+$gRcds8Vlor9"%Zou6q=nc&Ofr;ZforVufnaSuMCs8DornGN*rrsSW%li7"\
+s8Vrqs7Xh>s8;os#jM!]s8D'Zs6o4PJ,~>
+Z2XjrnG`Fgq=MZ+$gRcds8Vlor9"%Zou6q=nc&Ofr;ZforVufnaSuMCs8DornGN*rrsSW%li7"\
+s8Vrqs7Xh>s8;os#jM!]s8D'Zs6o4PJ,~>
+Z2XjrnG`Fgq=MZ+$gRcds8Vlor9"%Zou6q=nc&Ofr;ZforVufnaSuMCs8DornGN*rrsSW%li7"\
+s8Vrqs7Xh>s8;os#jM!]s8D'Zs6o4PJ,~>
+YQ"b&mf3=^aSue?s7cQnnbi4^m/R+^pAas0rrDHcrsA>tp[J4Rs8VrmaSuMAs8;iqqu?Z3rs/)n
+s8W&pq=O[d"8;cpnB_+Ep\k-lqt^*\s8Mcms5s:Hs*t~>
+YQ"b&mf3=^aSue?s7cQnnbi4^m/R+^pAas0rrDHcrsA>tp[J4Rs8VrmaSuMAs8;iqqu?Z3rs/)n
+s8W&pq=O[d"8;cpnB_+Ep\k-lqt^*\s8Mcms5s:Hs*t~>
+YQ"b&mf3=^aSue?s7cQnnbi4^m/R+^pAas0rrDHcrsA>tp[J4Rs8VrmaSuMAs8;iqqu?Z3rs/)n
+s8W&pq=O[d"8;cpnB_+Ep\k-lqt^*\s8Mcms5s:Hs*t~>
+Z2Xmns8;lr!;sn;"T&/ks82cp"o[ras8Vo7rsJ\is8Vlms8Vrhq8WF<pAa^^s7O,+!W)HdrrrAr
+p&Fjcd/OUMs8V?`s763im/6\Zs7kp[J,~>
+Z2Xmns8;lr!;sn;"T&/ks82cp"o[ras8Vo7rsJ\is8Vlms8Vrhq8WF<pAa^^s7O,+!W)HdrrrAr
+p&Fjcd/OUMs8V?`s763im/6\Zs7kp[J,~>
+Z2Xmns8;lr!;sn;"T&/ks82cp"o[ras8Vo7rsJ\is8Vlms8Vrhq8WF<pAa^^s7O,+!W)HdrrrAr
+p&Fjcd/OUMs8V?`s763im/6\Zs7kp[J,~>
+Z2Xn(s7ZEk!<("=%JTc"o`+s`s8;osrV$!+rsnZ#rr;lps8V]js82iroZ7%9r;Zfls8Kh6&,?2!
+s8VZ_s8N&urVuHgq9]-Bo)8Rf!<)lr"T&/hs7>UWJ,~>
+Z2Xn(s7ZEk!<("=%JTc"o`+s`s8;osrV$!+rsnZ#rr;lps8V]js82iroZ7%9r;Zfls8Kh6&,?2!
+s8VZ_s8N&urVuHgq9]-Bo)8Rf!<)lr"T&/hs7>UWJ,~>
+Z2Xn(s7ZEk!<("=%JTc"o`+s`s8;osrV$!+rsnZ#rr;lps8V]js82iroZ7%9r;Zfls8Kh6&,?2!
+s8VZ_s8N&urVuHgq9]-Bo)8Rf!<)lr"T&/hs7>UWJ,~>
+JcD\K$i^,(rqQ?is7cQfqYpL&rqufbs8Vclq>^9frVm*#s8;Qis6kO=Zi>O~>
+JcD\K$i^,(rqQ?is7cQfqYpL&rqufbs8Vclq>^9frVm*#s8;Qis6kO=Zi>O~>
+JcD\K$i^,(rqQ?is7cQfqYpL&rqufbs8Vclq>^9frVm*#s8;Qis6kO=Zi>O~>
+JcD_L"8)Nkqu6U'nG*"ZqZ$<io)JadrVmB'qX=IMs7bs]s763irUtgBZN#F~>
+JcD_L"8)Nkqu6U'nG*"ZqZ$<io)JadrVmB'qX=IMs7bs]s763irUtgBZN#F~>
+JcD_L"8)Nkqu6U'nG*"ZqZ$<io)JadrVmB'qX=IMs7bs]s763irUtgBZN#F~>
+JcD\K#PJ,skP5&Vq#::#o_.tXp[nL^q>]j]rr`,to'u_Z#6"T$s7$'eJcE+WJ,~>
+JcD\K#PJ,skP5&Vq#::#o_.tXp[nL^q>]j]rr`,to'u_Z#6"T$s7$'eJcE+WJ,~>
+JcD\K#PJ,skP5&Vq#::#o_.tXp[nL^q>]j]rr`,to'u_Z#6"T$s7$'eJcE+WJ,~>
+JcD_L%IF,nrq731!!W#pnc/:\rt4`"s7lWbq=FXPs8VfhpAb$UJcDtSJ,~>
+JcD_L%IF,nrq731!!W#pnc/:\rt4`"s7lWbq=FXPs8VfhpAb$UJcDtSJ,~>
+JcD_L%IF,nrq731!!W#pnc/:\rt4`"s7lWbq=FXPs8VfhpAb$UJcDtSJ,~>
+JcDYJ(B"(0!<)ros7`Y[qZ$!UqYL6Xs8VZnrr3B#s6BX_o`+pbs8DYBs0VfV~>
+JcDYJ(B"(0!<)ros7`Y[qZ$!UqYL6Xs8VZnrr3B#s6BX_o`+pbs8DYBs0VfV~>
+JcDYJ(B"(0!<)ros7`Y[qZ$!UqYL6Xs8VZnrr3B#s6BX_o`+pbs8DYBs0VfV~>
+JcD\K%IX/op'^Tks8W#X+WmHXrtN=!%3G$N!W_f!)%smerr?X.s8VM<s0M`U~>
+JcD\K%IX/op'^Tks8W#X+WmHXrtN=!%3G$N!W_f!)%smerr?X.s8VM<s0M`U~>
+JcD\K%IX/op'^Tks8W#X+WmHXrtN=!%3G$N!W_f!)%smerr?X.s8VM<s0M`U~>
+JcDYJ,Q.-4$NL2-q>^3hj8f&KruR9cs7cNns8OOQW&XD@!TX4FpOW@Ms*t~>
+JcDYJ,Q.-4$NL2-q>^3hj8f&KruR9cs7cNns8OOQW&XD@!TX4FpOW@Ms*t~>
+JcDYJ,Q.-4$NL2-q>^3hj8f&KruR9cs7cNns8OOQW&XD@!TX4FpOW@Ms*t~>
+JcD_Ls8)ouqYL9kruD$,-OBeQs7H]rs7lWg"8_usqu-TqrrE)qs8VkFs0M`U~>
+JcD_Ls8)ouqYL9kruD$,-OBeQs7H]rs7lWg"8_usqu-TqrrE)qs8VkFs0M`U~>
+JcD_Ls8)ouqYL9kruD$,-OBeQs7H]rs7lWg"8_usqu-TqrrE)qs8VkFs0M`U~>
+JcDYJ"8)We!<3!=p&>01rrDikrud@%s7-*ro`$&DYVGtR!<;cmqtksEZi>O~>
+JcDYJ"8)We!<3!=p&>01rrDikrud@%s7-*ro`$&DYVGtR!<;cmqtksEZi>O~>
+JcDYJ"8)We!<3!=p&>01rrDikrud@%s7-*ro`$&DYVGtR!<;cmqtksEZi>O~>
+JcD_L!:^!f,P)ZLnGi7\Sdtl&q!J+-,6\YYs.2mR[1!_Rs8EQ/s4mYSq18RQs*t~>
+JcD_L!:^!f,P)ZLnGi7\Sdtl&q!J+-,6\YYs.2mR[1!_Rs8EQ/s4mYSq18RQs*t~>
+JcD_L!:^!f,P)ZLnGi7\Sdtl&q!J+-,6\YYs.2mR[1!_Rs8EQ/s4mYSq18RQs*t~>
+JcD\K-1g[,p\"LbrVulsp%n^]s8Dorq#16Wq>^Kis8VinqXaR_s7Z&8s0M`U~>
+JcD\K-1g[,p\"LbrVulsp%n^]s8Dorq#16Wq>^Kis8VinqXaR_s7Z&8s0M`U~>
+JcD\K-1g[,p\"LbrVulsp%n^]s8Dorq#16Wq>^Kis8VinqXaR_s7Z&8s0M`U~>
+JcDYJ!W)WkrsSc"s8V-Zp&FjVs7H<j&F9Arq>('cq#C-gs8Vops6tU>Zi>O~>
+JcDYJ!W)WkrsSc"s8V-Zp&FjVs7H<j&F9Arq>('cq#C-gs8Vops6tU>Zi>O~>
+JcDYJ!W)WkrsSc"s8V-Zp&FjVs7H<j&F9Arq>('cq#C-gs8Vops6tU>Zi>O~>
+JcD_L$M+5sqYfmXqZ$6crr2ulrVlrmqYC-j!V?9hrsAT#s6]gbmf3=^JcE+WJ,~>
+JcD_L$M+5sqYfmXqZ$6crr2ulrVlrmqYC-j!V?9hrsAT#s6]gbmf3=^JcE+WJ,~>
+JcD_L$M+5sqYfmXqZ$6crr2ulrVlrmqYC-j!V?9hrsAT#s6]gbmf3=^JcE+WJ,~>
+JcD\K"o/#qq>^!aruLn7m/R(bq=s1Rs8Dorp&G'Ym/R%arr;`fs763eJcE+WJ,~>
+JcD\K"o/#qq>^!aruLn7m/R(bq=s1Rs8Dorp&G'Ym/R%arr;`fs763eJcE+WJ,~>
+JcD\K"o/#qq>^!aruLn7m/R(bq=s1Rs8Dorp&G'Ym/R%arr;`fs763eJcE+WJ,~>
+JcD_L%fZM.qu>XTqY1$gs8V`irVm,js8;oos6fmbrs/,plMpVYs87HJZi>O~>
+JcD_L%fZM.qu>XTqY1$gs8V`irVm,js8;oos6fmbrs/,plMpVYs87HJZi>O~>
+JcD_L%fZM.qu>XTqY1$gs8V`irVm,js8;oos6fmbrs/,plMpVYs87HJZi>O~>
+JcF^/s8Miorr1RMrr*T%rr;Kfp&G'is8MThs8)ces8;iprt"o)s7H?`s8VrqqZ$T_s8%<H[/YX~>
+JcE"Ts8Mlp'D2>)nGi1\rV-<hmJ["Yrq$-cqu6U+q#CBds7H?kqZ$Els6]j_JcE+WJ,~>
+JcFR+r;HTorr(LL'D)8(o)JIas82irnc/Xds7?9fr;Q^,q#CBds7H?kqZ$Els6]j_JcE+WJ,~>
+JcFa0"9.ujrql^8qY]s_oD\des8Vros82ioq>^?bs8Dipp%\Odp\t0mpAP!kpAY'pqXjgemJZt^
+rqQKtqt:!es8V]irt4l&qtL-crVuops8Vloqu?Wnrr3N*rVQWiq>^Kfs7ZK_s8VflrsJc*q#:<n
+rVufqq>UBonq$hrs*t~>
+JcF^/-2RZArquTks8W#sq>^-frql`qqYgHks8;]mqt:!fqu??arr;`lrrDckrrDclrWN#gs8VWc
+s!7UBpA+I[p%eISnG`.[rpg$fs7?9fp]($es8Vurs7lWks8Doqrt"u)qu?Hes8VclpAa[_s7ZHl
+$NC)#rr<#ss8;omrr2uhJcFO*J,~>
+JcFR++o([(qYU*gp\jUUq>('jqYgHks8;]mqt:!fqu??arr;`lrrDckrs8>urVcQas8VZ[ru:e-
+s8)cqo)8LdoDe^^s7lQms82irq#C6krVc`q&,Q8%s7lEis7QEcs7--hpAY(!rr;cms8W&tr;ZTl
+rrDV@s4mX)~>
+JcFa0"TJ;qq"t'j#5J&mo(2YUrr4)-s8Vops8;osp&G'equ?]ns7ZHlpAap[q>L!ds7,j_rs8Q%
+l21AUr;Q]prs\Z%s5X.Zqu?]fqu?TlrrN&mr;S>2s7lHis8Vcks75d]rVuZ`s8VNdqYL6dqt]g_
+mf3%Us8W#sr;Z]pr;ZQcJcFI(J,~>
+JcFX-$MjGqrVlKes82`nrVn22s8Vops8;osp&G'equ?]ns7ZHlpAap[q>L!ds6oRYrr;ormJ6br
+rp]jai;EECrVl?\rV6?krr<#rq#(.CkPt>Rrr<#krr;Q\s8Dumo)JaXrqcKkp\XdWs6fp]p](9k
+s8;ops8;olp4<7ts*t~>
+JcFX-2#I"ApA".Ns8)QfqY'^_mJm4^s8W#ss7QElq"t*kqu?Bhs7ZKfo_JIYs8VTZrVuoqs6f[^
+'DVV-kPtSZs8V`fs7uZmr;Zfpq#(.CkPt>Rrr<#krr;Q\s8Dumo)JaXrqcKkp\XdWs6fp]p](9k
+s8;ops8;olp4<7ts*t~>
+JcF^/!VlWms!%:=s8;]^q"t'br;ZZos8;ihs8D-\s7?9gmf2eVs7?-frr2p.n,MqVs8W)hq=ikG
+o_eXdrVm<*o]Yc=kj\96r:U!brr3u7s60L_p](-Ys8Vopp&Fpfs8VWgs8Drns8W&krVluqs8Vfl
+rsSDtnc/4Us6p!fmJd+b!W)M@s4mX)~>
+JcF^/#5S8urqQ'\rr2uprr3l1q>^?ls8;ihs8D-\s7?9gmf2eVs7?-frr2p+n,MqVrr2c`q=iqL
+q#(0lrr<!(rVQWjs8Vrqp\t3mrZ(_5kl:\Ws826as7u]fs82cps7-*grVlZns8DZirr`)ss7ZHl
+$hF>fs7?$cn,NFTrr2ouqY#L?h#Dm~>
+JcF^/-i<rBqXX"Hqu?]os8Vubo)8Ics8;ihs8D-\s7?9gmf2eVs7?-frr2p+n,MqVs8Vudq=inK
+p\=aqp@nUYrVuTkpAb-kruCk7kl:\Ws826as7u]fs82cps7-*grVlZns8DZirr`)ss7ZHl$hF>f
+s7?$cn,NFTrr2ouqY#L?h#Dm~>
+JcF[.!VZNlrs/Dkq""+Oq=FRb$iL&)qu?]ks7Gj]rr2p(qt'ddq>^KaqtpBm"7cEgr;Q`rrW<#s
+rqud,r9`56qsNb7p$i"Np\+Xdrr4#,p]($fs8DEdmJm4Js7#^]p%n^Qs7c9\s7H3foDS\#nFZ,J
+li6eQs7u]bs7QEjrIP"%s*t~>
+JcF[.#kIfhrqcHas8;lr!;6<j$iL&)qu?]ks7Gj]rr2p(qt'ddq>^KaqtpBm"S)NfqYp9is8E-!
+s8Vols!RC;qu?Nmr;Q`rme?bVrr;rcs6]jdjo=iCs7Q6gl2UMPp&F[]rq$*g&Ff>Zs6K^\o`+ae
+nc/:^rV_<Ig&HR~>
+JcF^/#Q=,apA"@Up\b%&o_SF_s8;osqu?]ks7Gj]rr2p(qt'ddq>^KaqtpBm"7cEfqtg?mrVZNn
+qW\"U$2aJon,<"\q>^EmruLP%s7lTnrU9dRs8V3\nFchSqZ#g[p\4@\o_\XZrVmGuo^2\Es7u<e
+q>^!bp&G!hJcFF'J,~>
+JcFR+/,]GFo^;/;mHsiOnc/OTrqcZpnbi1[s8V`[s7--hrVuoppAa^`q#16moD\amlMpkMq"aq%
+jRW?Jn*095s8V]kMYmAQpAP!j!Vu?drrW3"nGE4do_SIb"7-!equ6U1r:p<lqu6Wgs8W)dq#BOW
+nc/O^s71a@h#Dm~>
+JcF^/0E1hIqtL-jrVZ]qqtC'hm/R"OrqcZpnbi1[s8V`[s7--hrVuoppAa^`q#16moD\^llMpnP
+qYpKsrr)fnrr3#smf!.lr;HX+Q2gjapAP!j!Vu?drrW3"nGE4do_SIb"7-!equ6U1r:p<lqu6Wg
+s8W)dq#BOWnc/O^s71a@h#Dm~>
+JcFa0#6"Dhq"=7Wq>VW:l2CPJrqcZpnbi1[s8V`[s7--hrVuoppAa^`q#16moD\aolMpnMp\k!f
+q@iYtl1+B,o(MkOqYU*qOoPF_pAP!j!Vu?drrW3"nGE4do_SIb"7-!equ6U1r:p<lqu6Wgs8W)d
+q#BOWnc/O^s71a@h#Dm~>
+JcF^/!<)lr!WLRF!!)3]rrDurrrM]`rr4#<s8Dutmf34ZlNHGOs6]j\q#BUYs7lWis7u`pp\Fh:
+q#C@Fro2i8s8;Ef,i\_%s8W&rqu?]`q>^Ejr;Zfhp&":Zs8)chrVmf)s7QElr<Duqo(2nZs7Yj[
+s8;osq!nFbq>,[Bg])d~>
+JcF^/%JKYtr;ZfP!t,\D!se/krW)lqrrM]`rr48Cs8Dutmf34ZlNHGOs6]j\q#BUYs7ZHfs7u`q
+q#CBnrr)cmrr4;0!<;uds7b[S$o%#I!WW2urVQWpmJ6e\qu$Koo_&+Os8VrqpAP"0n,N(\s8</q
+s75d]r;ZKXs8W#ss7l-bs7uMBs4dR(~>
+JcFa0%f>bcp@eIbjUr[b*#TRdrr2urrr3#ip&=t6rr;rss6fpbpZhtGs8VKdp\=dQs8Vopq>^9k
+rU]p_q#0n7oBbi)!:St(pA!kE!\EX:"98E"rVQWpmJ6e\qu$Koo_&+Os8VrqpAP"0n,N(\s8</q
+s75d]r;ZKXs8W#ss7l-bs7uMBs4dR(~>
+JcFU,0_b/5nc0@A)Bf+Tr9a@cDZ@!m+M@Hb&2:6coEBRJi"l@nquD0F4octcq#GsYf`1pNpAY1]
+W>PR54o>:eK_YWI\-+Rmp[8T=!9F1Zr:g8On\HRa[/[?N$cW/?!/D$K!!!K.#^?;2!@ln'!.G1*
+rr<Q0s8VqHs4mX)~>
+JcF^/rr+VFoDeh(1,q3S$ig.jqZ^s<Z7@'1pV@CpXo@qrHO8UH!!)osIK)J2-f"LtIh:94rW)rt
+:&b+hr;6Bho)MJbs8Mi`li.3-NW0%Z\-+Rmp[8T=!9F1Zr:g8On\HRa[/[?N$cW/?!/D$K!!!K.
+#^?;2!@ln'!.G1*rr<Q0s8VqHs4mX)~>
+JcFa02#I(Aq""+Xs!^]E=&pLEs7#skDZ@!m+M@Hb&2:6coEBRJi"l@nquD0F4octcq#H![gAh-P
+;#C+ap@S"KoC(o*!)`gamdp/BqZ(>hrrW51">[:Wmga[EjT#5Wp]-<D_']f$s0*LO`W,Z4LCNMK
+!"Jr6GQ0c+.bst&IL"O*!"T)0s8%<Hh#Dm~>
+JcF[.2ZECKq<[JK.L[aH!:0I[r<;BU0s\bNs!GUg3rf-ZT>a@o"98$!iq39N_(,HbT#O%lrrrH"
+q#:FNb/tt+rt#2#*9R>",e^!,s8N(qcoh4)s!S!#ruo+n3:8Z;djG+p!2mk'rs\kr!oEtUs4Jao
+$(K:1p%o!ns8;bFs4mX)~>
+JcF^/>Q4Hjs8Vrq##$dG3s>E[rqlr_o.dPi0)m98Z9&$a!M@>%o`P6e#NGCUs1p2b!1^tmqYpa!
+r;ZfrrVZTjq=Xe^;?6Xln`TB@#Q,n7!WF@XUbDcJ!2\%)qu6UD"4mJq^;;kt28.Hcs8N(sa$K_6
+rUBsGs8DuN-MRn:cpdX)#QFc$qgne&s*t~>
+JcFa0"9&)fnGW@j,&^P'>p0+G8d4DL0s\bNs!GUg3rf-ZT>a@o"98$!iq39N_(,HbT>s:prr`/l
+qY'XToCMM>joALi!:9+@nG)h[pa#;0r?T(P0E;%PV9h@%rr4AKf)Ho-_Dps@^!e>.rrAt;62qAl
+nH.SIrVtOtp^*G:7J6N_rr;onJcFO*J,~>
+JcF[.s8FeI2Bi\4*tSl'!$3pLqZHll"98E-q[NT+#l+6"s7-Bf!rW''s8S?*'F=C6s7cTorrE&u
+:@eGbqi?2_*N[!.S.UX>YQ+V'mu;r"oaLK^)#rk,s7??l!!*$!s8N'!$j-G6"oo5(rsA_u!<3W!
+rr_upRj&+Ao+(g#!<;rsrVuZiJcFO*J,~>
+JcF[.2#dOP6T$>*7QNIq$SO\"qucum"98E-q[NT+#l+6"s7-Bf!rW''s8S?*'F=C6rq6?lrrE&u
+:@A,[mX]1l!+@fjAH6XYC#eq!ooF_*oaLK^)#rk,s7??l!!*$!s8N'!$j-G6"oo5(rsA_u!<3W!
+rr_upRj&+Ao+(g#!<;rsrVuZiJcFO*J,~>
+JcF^/J,T<Fs%GgJ0l:B,B.6DM5Q:icp&k?q#l>)3!!rAr"on,tp&b0l#QOgh*Y\nR!rr&ts8N)r
+qYK=Io]:=,@fT_&BjLdM@WUo.$1j12!qcuon/22j#ljMtrr<'!!<<'!!"8r/#6k/>nG`gpo`5"'
+n,EL`s-k2<"nN6(rs&Q(quH]qq"oXBh#Dm~>
+JcFa0s8G"LqtTIEjo>c2%3PZ6o_ACcs8Oghs6ot:](5n$quHQl!<3E%rrE)h(<PnCrr`<$&G#K)
+p@S:Zrr2urrr3'UdD@%'s#L/ZlQ-60*P8Bip\t6nrrE#os6g9on1)iYp\u8Ns8W#s!:g'jo`4@Y
+!<<!&eF3bD!<;cooCidipjrJ!s*t~>
+JcF[.%/9f%q#C@"1.sPq"o\H#F9)@@0u3hXs!bPMs8Vusq>LBo$Mj]%s7$lHli@%frr*K"oagch
+qtL*br9jFWp]+T!!;cB\jR2aKs61C$rZ/VP)#+%1s8N)tqZ$!js6qMcp%SJ,_Z0Z6rrDTh!qcQ[
+rrE)t#Lr5KrrE)n!V?$rp\9=>gAc[~>
+JcF[.!;QKl"XmMo?Y^nbs)\8@s"V=hn,FiJo)Jaf!;ZTorsJT%!<;R)am9$-"98B6o(<IanFlAF
+n+>`4mcXXa>la0Tna6&B!WD:("TKLSX;L^3!<<'!rVHQ_$30KEdIm86*Q%jVr;QcerrVinm/I(c
+r<LjA#lao)pAsm[&,5jMs4[L'~>
+JcFa0%K?5!q=jC<lMr4O$n;8VmO%o5s5q6=);P#=*Z!,hrrE)s%KE(ZnIYa#9)o8-e-,gO!;-;\
+7fE>erql]s15d%Is#^;]s.Bkp_uq1.s7u`frrDoqmf*:en%fhOjnlt9'A`We!<<'!s/\TW%dO'i
+!"/ej&HDb1s8ScZs7,o9s4mX)~>
+JcFR+2uW@J#"_6=9a1RopAY-mk/82Vh"]JB(=;FJ!<;s+s.D:?&HDc'!!s+a"TJB#o`(COs8N&t
+p\k"[q"Xn[#QOhpmHXZRs8A8fo>CbRci<hAo`"pfs6fmes6mc@&*<],*#%0,rrE*!!<9,fn.+a`
+:B1b&kRddo!<<(m6N?TOJcFO*J,~>
+JcFI("X7_q<c'&Zs)nDBk/82Vh"]JB(=;FJ!<;s+s.D:?&HDc'!!s+a"TSK%o`(=Jqtg0an+HDJ
+oB#6;7KDoIlgX<<!<)kb#kZ%<+4'u`!;-9kqZ$!`!<;N((_>a*`#KHHrVlltrrE)#6gtTNs%`V&
+!9b!orrE*!TgJeLq18S$s*t~>
+JcFa0#QFAjo^q\GmeZtdnb)_Drr4#6s5CEdk5Y1pr;Zfrs8W&ns8Vfiqu?]qp]'a_pAY'qrqu<d
+s8Drs#lXSrq>WSFp[.t[!qZ<arVlurs5WhOrt5),s763ir;Q`rqt-f`s8Vtprr35ls8ViZs8W)s
+rsJ>sqY'ses7H'cnq$hos*t~>
+JcF^/%/g/&rVHQo%0d"L$jHY1!:9^b*r,co[f>LipVm(1s8N&urV?KnpA=aes8McmnG`(Zrr4&=
+oDejerr)fdp&Fg[)=RUsrqH3Ys7c?cpAXpgj7`HO&c)J,o)Jafrr<#qoV_Tds8/bors/#ms7bjZ
+s8Mus$M+5npAb'jo_8CVJcFF'J,~>
+JcFI("X+p2/g_P:rrDKdruLn7iO8dKs7aM1s8W)us8Dcns7Z?es8W)ms7$'_rVm#tnGW7Wrq[Du
+m.'6,'ArECo_/(IqXaO[q>^<kj7`HO&c)J,o)Jafrr<#qoV_Tds8/bors/#ms7bjZs8Mus$M+5n
+pAb'jo_8CVJcFF'J,~>
+JcFa0*<,j2kPY2Iq![b4mdBW<k4elEo`+m`s8Vins6K[a"8DiqpAY(!fDkgArVu]cr;ZKhrs/E"
+r;QZcs8N#t$hO2lp%e7Tqu?]qo)/Lpp%\Ods7Q<ep\*bKrr`8ss8)`p)#F%)o`+XRs8VQ^s8W&r
+s8V?Vs8V?`qtKse!;;!Dg])d~>
+JcFX-#OMKip](0kq#14%med%Ro`+m`s8Vins6K[a"8DiqpAY(&fDkgArVu]cr;ZEgrr<#rrVm#k
+s8)`mrr3#jm/I"hrr)Wlq>^KorX/>nrr<#kr;66^k5PA_rqcZkrr3i3q"s^`p@&%]n+Zk^rVccr
+l1P)Vl2UYTqYpQhJcFL)J,~>
+JcFX-"7Z?jqYC.#nbiFVo`+m`s8Vins6K[a"8DiqpAY(!fDkgArVu]cr;ZHgrrDrqrt>8!qtL!a
+qXX:DjnAKEp%\7Wnc&CorVuQcrr<#kr;66^k5PA_rqcZkrr3i3q"s^`p@&%]n+Zk^rVccrl1P)V
+l2UYTqYpQhJcFL)J,~>
+JcFa0"TIKZrqHEl+S5*sp##99rr;lqnc/X]s7ZHls8Mues8W&os7--ds82cp!rN#mrr4>9lMpkT
+q>C0is7--dr;69hs82H]r;-Ejnbhn?s8W&rs7cQls8;lr#lF>qp@81_pZ_YV!;$3i!VH9grs88s
+r:p<lrr;Tgrs8MqrV?<is7uJAs4mX)~>
+JcF^/%-dflp\t3mp\=dgm/$_](]47&s8V`kpAY*lrr)Bes8Dfonc/Ldqu-O&qu?Hirqu9Ns8Vil
+rVluirqH?frt>80qu?]ks75ITs8Dorp](3lr;Q^%qtC'`nc/X`l2CV^oD\ajo_\Xf#k\/pq#CBn
+s7?3h#lF>oq>1-kq>#UAh#Dm~>
+JcF^/-ggs6p&"XbpA=mio)/Obqt^9^s8V`kpAY*lrr)Bes8Dfonc/Ldqu-O&qu?Hjs8DKQs8Vfj
+rVmQ$s7lHfp\Oa`p\"FVq>0UXmH+6Er<<5qs8Duqrr39$pAajVs8ViXrVllhrr3#kqu6U$o`+ja
+s8W)uoDS[pqtC!aqZ$Tkq18S$s*t~>
+JcFa0!ri,srr3r9s8W#qp\b$cq#CBXs8VEbs7uB_s8VZis7H6grsA5ls7c6emJm4Zrr2ugrr4PK
+n,)_Sr;Q]qs8)Qjs8V?`rr;umo_\IZq"FRas8)0`q#C0iq"jgdqu?]jrr3Don,NCenF6>Tnc/UW
+rVmK!s7cQgmJm(^s8W&ts6p!frIP"(s*t~>
+JcFU,*W5m-pAXmer;Zflo`"mSs8VEbs7uB_s8VZis7H6grsnSqs7c6emJm4Zs8N#brr2p!oDeX`
+rsSMfoDJRFr;-HnrV?Bk&cD\/qX4CYs7u]iqYC0gs8Vimrs\;`s8N&fnGE7Us8MKcrt4c#p]($U
+s82cps8Dutn,NFdJcFO*J,~>
+JcFX-*rYm+l0\38q=spbmca9>kl:\Ks8Vogp](9as8V`hrr3GtqZ$<`s6]jdp&G'jm/?qco`+aa
+rsSYpp](9Rs7uWjp[\:Z')25%s8)0`q#C0iq"jgdqu?]jrr3Don,NCenF6>Tnc/UWrVmK!s7cQg
+mJm(^s8W&ts6p!frIP"(s*t~>
+JcF^/"Sr&ns8Dor"8`&mr;Q^;qZ$Tjs8Vurs8;lgs8V`ks82cks8VNes7u]pqu?<frsAW%q#:3_
+r;-6frr2os!;HKm%/U#'oDJLMq!n+XrVZWo'Dqgus8W#ps7ZKis7cNmrqlQlqu6U4qu?WprqZEj
+s8;ogs8VTgpAb0ks7?9]pOWA!s*t~>
+JcF^/;YpFhrq-0fp](!fq>C9mrV?Knq#CBks8W#ro`+s`s8VupqZ$T`s8Vops82igrql]krV6Em
+p](6krr<#srV?<XrVHB\rr;ips7?9is8W&qrVmQ.s6p!fr;?Tgs82ijrr;upqZ$HlrttY5rVulm
+qZ$Tns7?9jnGi4^s8Duhs75o8s4dR(~>
+JcF^/3r]0RqWmbEme6/HoCVbJo(E%_q#CBks8W#ro`+s`s8VupqZ$T`s8Vops82igs8)]krV6Em
+q#CBnqYpQerr3E!s8DQdqWn%NqYgBjrVmQ.s6p!fr;?Tgs82ijrr;upqZ$HlrttY5rVulmqZ$Tn
+s7?9jnGi4^s8Duhs75o8s4dR(~>
+JcDeNr;Q<frVlfoJcDPGJ,~>
+JcFR+rVkLMs8MZj!WN&prdk*=s*t~>
+JcFU,!<)imrVc`m!<(%>qYc!FV#Pr~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+JcC<$JcE+WJ,~>
+%%EndData
+showpage
+%%Trailer
+end
+%%EOF
diff --git a/lib/megaco/doc/src/note.gif b/lib/megaco/doc/src/note.gif
new file mode 100644
index 0000000000..6fffe30419
--- /dev/null
+++ b/lib/megaco/doc/src/note.gif
Binary files differ
diff --git a/lib/megaco/doc/src/notes.gif b/lib/megaco/doc/src/notes.gif
new file mode 100644
index 0000000000..e000cca26a
--- /dev/null
+++ b/lib/megaco/doc/src/notes.gif
Binary files differ
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
new file mode 100644
index 0000000000..26c64f7c52
--- /dev/null
+++ b/lib/megaco/doc/src/notes.xml
@@ -0,0 +1,1167 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco Release Notes</title>
+ <prepared>Lars Thors&eacute;n, H&aring;kan Mattsson, Micael Karlberg</prepared>
+ <docno></docno>
+ <date></date>
+ <rev>%VSN%</rev>
+ <file>notes.xml</file>
+ </header>
+ <p>This document describes the changes made to the Megaco system
+ from version to version. The intention of this document is to
+ list all incompatibilities as well as all enhancements and
+ bugfixes for every release of Megaco. Each release of Megaco
+ thus constitutes one section in this document. The title of each
+ section is the version number of Megaco.</p>
+
+ <section>
+ <title>Megaco 3.13</title>
+
+ <p>Version 3.13 supports code replacement in runtime from/to
+ version 3.12 and 3.11.3.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>A minor optimization by using ets:update_element
+ instead of ets:insert for some table updates.</p>
+ <p>Own Id: OTP-8239</p>
+ <!-- <p>Aux Id: Seq 11332</p> -->
+ </item>
+
+ <item>
+ <p>The documentation is now built with open source tools
+ (<em>xsltproc</em> and <em>fop</em>) that exists on most
+ platforms. One visible change is that the frames are removed.</p>
+ <p>Own Id: OTP-8249</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Replacing obsolete guard tests.</p>
+ <p>Own Id: OTP-8164</p>
+ <p>Aux Id: Seq 11332</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.13 -->
+
+
+ <section>
+ <title>Megaco 3.12</title>
+
+<!--
+ <p>Version 3.12 supports code replacement in runtime from/to
+ version 3.11.3.</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Improve handling of async transaction reply. </p>
+ <p>For asynchronous requests, issued using
+ <seealso marker="megaco#cast">megaco:cast/3</seealso>,
+ the reply will be delivered using the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function. </p>
+ <p>If a receiver of a request, issued using
+ <seealso marker="megaco#cast">megaco:cast/3</seealso>,
+ does not reply in time, megaco re-sends the request.
+ If the receiver of the request sends the reply at the same
+ time as megaco re-sends, it may also send a reply to the
+ resent request (thinking the first reply got lost). These
+ two replies may arrive more or less at the same time,
+ causing confusion. </p>
+ <p>In order to improve this situation, a number of
+ improvements have been done: </p>
+ <list type="bulleted">
+ <item>
+ <p>When the first reply arrives, a timer, request-keep-alive,
+ is started. This timer is used to decide when to stop
+ accepting replies as legitimate. </p>
+ <p>The timeout time for the timer is specified by the
+ config option <em>request_keep_alive_timout</em>,
+ which can be set per
+ <seealso marker="megaco#ui_request_keep_alive_timeout">user</seealso>
+ or per
+ <seealso marker="megaco#ci_request_keep_alive_timeout">connection</seealso>. </p>
+ </item>
+ <item>
+ <p>We also keep track of how many replies has been received
+ (we do this as long as the request-keep-alive timer is
+ running). </p>
+ </item>
+ <item>
+ <p>Each reply that arrives while the request-keep-alive timer
+ is running (including the first) will be delivered using the
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
+ callback function, but with the UserReply augmented to
+ include a serial number indicating which reply number this
+ is.
+ The <em>first</em> reply to arrive,
+ will be numbered <em>one (1)</em>. </p>
+ </item>
+ <item>
+ <p>Replies arriving after the timer has expired will be delivered
+ in the same way as before, using the
+ <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans/3,4</seealso>
+ callback function. </p>
+ </item>
+ <item>
+ <p>Note that if the timer was <em>not</em> configured,
+ megaco will act exactly as before! </p>
+ </item>
+ </list>
+ <p>Own Id: OTP-8183</p>
+ <p>Aux Id: Seq 11393</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>If the megaco app received a transaction reply, for a request
+ issued using the
+ <seealso marker="megaco#call">call/3</seealso> function, from
+ the wrong remote entity (wrong MId)), megaco would still deliver
+ the reply (<seealso marker="megaco#call">call/3</seealso>
+ returnes) as if from the correct remote entity (right MId). </p>
+ <p>This has been changed so that the function now returns with
+ an error reason. </p>
+ <p>See <seealso marker="megaco#call">call/3</seealso> for more
+ info. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-8212</p>
+ <p>Aux Id: Seq 11305</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ </section> <!-- 3.12 -->
+
+
+ <section>
+ <title>Megaco 3.11.3</title>
+
+<!--
+ <p>Version 3.11.3 supports code replacement in runtime from/to
+ version 3.11.2, 3.11.1 and 3.11.</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Replacing obsolete guard tests.</p>
+ <p>Own Id: OTP-8164</p>
+ <!-- <p>Aux Id: Seq 11332</p> -->
+ </item>
+
+ <item>
+ <p>Added the config option
+ <seealso marker="megaco#ui_call_proxy_gc_timeout">call_proxy_gc_timeout</seealso>
+ to be able to control the way unexpected replies (when requests issued
+ via calls to <seealso marker="megaco#call">call/3</seealso>)
+ are handled. </p>
+ <p>See
+ <seealso marker="megaco#user_info">user_info/2</seealso>,
+ <seealso marker="megaco#conn_info">conn_info/2</seealso> and
+ <seealso marker="megaco#call">call/3</seealso> for more info. </p>
+ <p>Own Id: OTP-8167</p>
+ <p>Aux Id: Seq 11393</p>
+ </item>
+
+ <item>
+ <p>Make flex scanner c89 compiler compliant.</p>
+ <p>Akira Kitada</p>
+ <p>Own Id: OTP-8191</p>
+ <!-- <p>Aux Id: Seq 11332</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Replacing obsolete guard tests.</p>
+ <p>Own Id: OTP-8164</p>
+ <p>Aux Id: Seq 11332</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.11.3 -->
+
+
+ <section>
+ <title>Megaco 3.11.2</title>
+
+ <p>Version 3.11.2 supports code replacement in runtime from/to
+ version 3.11.1 and 3.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Megaco was unnecessarily strict when parsing the SDP
+ attribute <c>maxptime</c> (leading or trailing spaces
+ cased the value parse to fail). </p>
+ <p>This has been improved so that leading and trailing
+ spaces are stripped before parsing the value.
+ The same has been done for the attribute <c>ptime</c>.</p>
+ <p>Own Id: OTP-8123</p>
+ <p>Aux Id: Seq 11364</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
+ <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
+ prev3c and v3) only. </p>
+ <p>Own Id: OTP-8114</p>
+ <p>Aux Id: Seq 11353</p>
+ </item>
+
+ <item>
+ <p>The reply proxy could crash if the timeout time calculation
+ results in a negative number. This will result in a function
+ clause with resulting error report.</p>
+ <p>Own Id: OTP-8081</p>
+ <p>Aux Id: Seq 11332</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.11.2 -->
+
+
+ <section>
+ <title>Megaco 3.11.1</title>
+
+ <p>Version 3.11.1 supports code replacement in runtime from/to
+ version 3.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>In order to better utilize multi-core procs, the
+ <c>flex</c> (text) scanner has been improved. </p>
+ <p>The <c>flex</c> (text) scanner has been made reentrant,
+ <em>if</em> the flex utility supports this. Note that the version
+ of <c>flex</c> supplied with some OS/distros (Solaris 10,
+ FreeBSD and OpenBSD to mention a few) may not support this, in which
+ case the flex scanner will be non-reentrant, just as before. </p>
+ <p>Own Id: OTP-7302</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
+ <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
+ prev3c and v3) only. </p>
+ <p>Own Id: OTP-8114</p>
+ <p>Aux Id: Seq 11353</p>
+ </item>
+
+ <item>
+ <p>The reply proxy could crash if the timeout time calculation
+ results in a negative number. This will result in a function
+ clause with resulting error report.</p>
+ <p>Own Id: OTP-8081</p>
+ <p>Aux Id: Seq 11332</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.11.1 -->
+
+
+ <section>
+ <title>Megaco 3.11</title>
+
+<!--
+ <p>Version 3.11 supports code replacement in runtime from/to
+ version 3.10.1 and 3.10.0.1.</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>In order to better utilize multi-core procs, the
+ <c>flex</c> (text) scanner has been improved. </p>
+ <p>The <c>flex</c> (text) scanner has been made reentrant,
+ <em>if</em> the flex utility supports this. Note that the version
+ of <c>flex</c> supplied with some OS/distros (Solaris 10,
+ FreeBSD and OpenBSD to mention a few) may not support this, in which
+ case the flex scanner will be non-reentrant, just as before. </p>
+ <p>Own Id: OTP-7302</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>The (plain) text scanner could incorrectly identify
+ character strings (any 17 char long string with the
+ char t in the middle) as a TimeStampToken.</p>
+ <p>Own Id: OTP-7249</p>
+ <p>Aux Id: Seq 10917</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.11 -->
+
+
+ <section>
+ <title>Megaco 3.10.1</title>
+
+ <p>Version 3.10.1 supports code replacement in runtime from/to
+ version 3.10.0.1, 3.10 and 3.9.4.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Updated file headers.</p>
+ <p>Own Id: OTP-7851</p>
+ <p>Aux Id: Seq 11140</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Unexpected <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso> callbacks. </p>
+ <p>The <seealso marker="megaco_user">megaco_user</seealso> callback function
+ <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso>
+ could during high load be called with unexpected values for the Trans
+ argument, such as an <c>TransactionReply</c> where <c>transactionResult</c>
+ had the value <c>{error, timeout}</c>. This was a result of a raise condition
+ and has now been fixed. </p>
+ <p>Own Id: OTP-7926</p>
+ <p>Aux Id: Seq 11255</p>
+ </item>
+
+ <item>
+ <p>[text] PropertyParm values cannot be quoted. </p>
+ <p>It was not possible to encode a PropertyParm value as a quoted string
+ (unless it *had* to (has at least one RestChar)). The megaco text codec's
+ now also accepts quoted strings as PropertyParm values. </p>
+ <p>Own Id: OTP-7936</p>
+ <p>Aux Id: Seq 11258</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>If the transport module calls the
+ <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
+ or
+ <seealso marker="megaco#receive_message">receive_message/5</seealso>
+ function(s) for the initial message, then the
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>
+ function will now be called and not the
+ <seealso marker="megaco_user#connect">handle_connect/2</seealso>
+ function. </p>
+ <p>Own Id: OTP-7713</p>
+ <p>Aux Id: Seq 11140</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.10.1 -->
+
+
+ <section>
+ <title>Megaco 3.10.0.1</title>
+
+ <p>Version 3.10.0.1 supports code replacement in runtime from/to
+ version 3.10 and 3.9.4 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Updated file headers.</p>
+ <p>Own Id: OTP-7851</p>
+ <!-- <p>Aux Id: Seq 11140</p> -->
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Memory leak in the flex scanner. There was a memory
+ leak in the flex scanner function handling
+ Property Parameters. </p>
+ <p>Own Id: OTP-7700</p>
+ <p>Aux Id: Seq 11126</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>If the transport module calls the
+ <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
+ or
+ <seealso marker="megaco#receive_message">receive_message/5</seealso>
+ function(s) for the initial message, then the
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>
+ function will now be called and not the
+ <seealso marker="megaco_user#connect">handle_connect/2</seealso>
+ function. </p>
+ <p>Own Id: OTP-7713</p>
+ <p>Aux Id: Seq 11140</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.10.0.1 -->
+
+
+ <section>
+ <title>Megaco 3.10</title>
+
+ <p>Version 3.10 supports code replacement in runtime from/to
+ version 3.9.4, 3.9.3, 3.9.2, 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Added new API function
+ <seealso marker="megaco#connect">megaco:connect/5</seealso> and
+ the corresponding new <c>megaco_user</c> callback function
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>.
+ The purpose of this is to be able to pass information to the
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>
+ function by calling the
+ <seealso marker="megaco#connect">megaco:connect/5</seealso>
+ function. </p>
+ <p>Own Id: OTP-7713</p>
+ <p>Aux Id: Seq 11140</p>
+ </item>
+
+ <item>
+ <p>Update file headers with new copyright notice. </p>
+ <p>Own Id: OTP-7743</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Memory leak in the flex scanner. There was a memory
+ leak in the flex scanner function handling
+ Property Parameters. </p>
+ <p>Own Id: OTP-7700</p>
+ <p>Aux Id: Seq 11126</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>If the transport module calls the
+ <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
+ or
+ <seealso marker="megaco#receive_message">receive_message/5</seealso>
+ function(s) for the initial message, then the
+ <seealso marker="megaco_user#connect">handle_connect/3</seealso>
+ function will now be called and not the
+ <seealso marker="megaco_user#connect">handle_connect/2</seealso>
+ function. </p>
+ <p>Own Id: OTP-7713</p>
+ <p>Aux Id: Seq 11140</p>
+ </item>
+
+ </list>
+
+ </section>
+ </section> <!-- 3.10 -->
+
+
+ <section>
+ <title>Megaco 3.9.4</title>
+
+ <p>Version 3.9.4 supports code replacement in runtime from/to
+ version 3.9.3, 3.9.2, 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Miscellaneous dialyzer related and test case cleanup. </p>
+ <p>Own Id: OTP-7614</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Segmenting a reply failed (with a badmatch) if the message
+ did not actually need to be segmented (e.g. was within the
+ size limit,
+ <seealso marker="megaco#ui_max_pdu_size">max_pdu_size</seealso>). </p>
+ <p>Own Id: OTP-7733</p>
+ <p>Aux Id: Seq 11168</p>
+ </item>
+
+ <item>
+ <p>Improve the error handling of megaco_tcp for received
+ messages. </p>
+ <p>Own Id: OTP-7728</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9.3.1 -->
+
+
+ <section>
+ <title>Megaco 3.9.3</title>
+
+ <p>Version 3.9.3 supports code replacement in runtime from/to
+ version 3.9.2, 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Miscellaneous dialyzer related and test case cleanup. </p>
+ <p>Own Id: OTP-7614</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Memory leak in the flex scanner. There was a memory
+ leak in the flex scanner function handling
+ Property Parameters. </p>
+ <p>Own Id: OTP-7700</p>
+ <p>Aux Id: Seq 11126</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9.3 -->
+
+
+ <section>
+ <title>Megaco 3.9.2</title>
+
+ <p>Version 3.9.2 supports code replacement in runtime from/to
+ version 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Miscellaneous dialyzer related and test case cleanup. </p>
+ <p>Own Id: OTP-7614</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>The text encoders (v1, v2, v3, ...) all failed to
+ properly encode the DigitMapDescriptor. </p>
+ <p>Own Id: OTP-7671</p>
+ <p>Aux Id: Seq 11113</p>
+ </item>
+
+ <item>
+ <p>The mini decoder some time incorrectly identifies
+ plain text as tokens. </p>
+ <p>Own Id: OTP-7672</p>
+ <p>Aux Id: Seq 11103</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9.2 -->
+
+
+ <section>
+ <title>Megaco 3.9.1.1</title>
+
+ <p>Version 3.9.1.1 supports code replacement in runtime from/to
+ version 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Miscellaneous dialyzer related and test case cleanup. </p>
+ <p>Own Id: OTP-7614</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>[text] The flex scanner did not allow an empty quotedString
+ in propertyParm. </p>
+ <p>Own Id: OTP-7573</p>
+ <p>Aux Id: Seq 11062</p>
+ </item>
+
+ <item>
+ <p>[text] Unable to decode a version 2 message with a
+ topologyTriple containing an (optional) eventStream. </p>
+ <p>Own Id: OTP-7576</p>
+ <p>Aux Id: Seq 11066</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9.1.1 -->
+
+
+ <section>
+ <title>Megaco 3.9.1</title>
+
+ <p>Version 3.9.1 supports code replacement in runtime from/to
+ version 3.9, 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>[text] The text codec(s) has been optimized. The parsing of
+ "property parameters" has been moved to the scanner(s). Which means
+ that when decoding messages containing property parameters, using
+ the flex scanner, decode time(s) will be reduced. The reduction
+ depends on the message, but can be as large as 25%. </p>
+ <p>Own Id: OTP-7431</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[text] The flex scanner did not allow an empty quotedString
+ in propertyParm. </p>
+ <p>Own Id: OTP-7573</p>
+ <p>Aux Id: Seq 11062</p>
+ </item>
+
+ <item>
+ <p>[text] Unable to decode a version 2 message with a
+ topologyTriple containing an (optional) eventStream. </p>
+ <p>Own Id: OTP-7576</p>
+ <p>Aux Id: Seq 11066</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9.1 -->
+
+
+ <section>
+ <title>Megaco 3.9</title>
+
+ <p>Version 3.9 supports code replacement in runtime from/to
+ version 3.8.2, 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[text] The text codec(s) has been optimized. The parsing of
+ "property parameters" has been moved to the scanner(s). Which means
+ that when decoding messages containing property parameters, using
+ the flex scanner, decode time(s) will be reduced. The reduction
+ depends on the message, but can be as large as 25%. </p>
+ <p>Own Id: OTP-7431</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>If a TransactionRequest arrives while a user is
+ connecting (is in the callback function
+ handle_connect as a result of a megaco:connect call),
+ megaco responds with a pending message and then drops
+ the request.</p>
+ <p>These messages will now be silently dropped, forcing the
+ other side to resend. </p>
+ <p>Own Id: OTP-7192</p>
+ <p>Aux Id: Seq 10884</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.9 -->
+
+
+ <!-- section>
+ <title>Release notes history</title>
+ <p>For information about older versions see
+ <url href="part_notes_history_frame.html">release notes history</url>.</p
+ </section> -->
+</chapter>
+
diff --git a/lib/megaco/doc/src/notes_history.xml b/lib/megaco/doc/src/notes_history.xml
new file mode 100644
index 0000000000..97aa4c66a5
--- /dev/null
+++ b/lib/megaco/doc/src/notes_history.xml
@@ -0,0 +1,3365 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco Release Notes history</title>
+ <prepared>Micael Karlberg</prepared>
+ <responsible>OTP</responsible>
+ <docno></docno>
+ <approved>OTP</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>A</rev>
+ <file>notes_history.xml</file>
+ </header>
+
+ <section>
+ <title>Megaco 3.8.2</title>
+
+ <p>Version 3.8.2 supports code replacement in runtime from/to
+ version 3.8.1 and 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Some minor documentation cleanup of the
+ <seealso marker="megaco_run#transaction_sender">transaction sender</seealso>
+ chapter of the User's Guide. </p>
+ <p>Own Id: OTP-7417</p>
+ <p>Aux Id: Seq 10989</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[text] Messages with property parm values "containing" keywords
+ confused the parser when using the flex scanner. </p>
+ <p>Own Id: OTP-7534</p>
+ <p>Aux Id: Seq 11039</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.8.2 -->
+
+
+ <section>
+ <title>Megaco 3.8.1</title>
+
+ <p>Version 3.8.1 supports code replacement in runtime from/to
+ version 3.8 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Some minor documentation cleanup of the
+ <seealso marker="megaco_run#transaction_sender">transaction sender</seealso>
+ chapter of the User's Guide. </p>
+ <p>Own Id: OTP-7417</p>
+ <p>Aux Id: Seq 10989</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>The event parameter value for completion event ce
+ of the dd package was incorrectly encoded as type
+ Value instead of as a quoted string. </p>
+ <p>Own Id: OTP-7444</p>
+ </item>
+
+ <item>
+ <p>DigitMap ([0-9ef]) incorrectly interpreted as ([0-9]ef).</p>
+ <p>Own Id: OTP-7449</p>
+ </item>
+
+ <item>
+ <p>Receiving an unexpected segment reply could case
+ an case clause crash. Now a warning message will
+ be issued instead.</p>
+ <p>Own Id: OTP-7455</p>
+ </item>
+
+ <item>
+ <p>The flex scanner had problems parsing wildcarded
+ service-change request, ammRequest (with add) and
+ notifyRequest.</p>
+ <p>Own Id: OTP-7457</p>
+ <p>Aux Id: Seq 11014</p>
+ </item>
+
+ <item>
+ <p>Processing requests when "autoconnecting"
+ caused function cause after reboot.</p>
+ <p>Own Id: OTP-7459</p>
+ <p>Aux Id: Seq 11017</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.8.1 -->
+
+
+ <section>
+ <title>Megaco 3.8</title>
+
+ <p>Version 3.8 supports code replacement in runtime from/to
+ version 3.7.5, 3.7.4 and 3.7.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Miscellaneous <em>text</em> codec(s) improvements. Both
+ regarding code size and <em>decode</em> performance. </p>
+ <p>See the
+ <seealso marker="megaco_performance">performance</seealso>
+ chapter of the Users Guide for details.</p>
+ <p>Own Id: OTP-7228</p>
+ </item>
+
+ <item>
+ <p>Added the value <c>flag</c> to the resend_indication config
+ option. See
+ <seealso marker="megaco#ui_resend_indication">resend_indication</seealso> for more info. </p>
+ <p>Own Id: OTP-7259</p>
+ <p>Aux Id: Seq 10901</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>If a TransactionRequest arrives while a user is
+ connecting (is in the callback function
+ handle_connect as a result of a megaco:connect call),
+ megaco responds with a pending message and then drops
+ the request.</p>
+ <p>These messages will now be silently dropped, forcing the
+ other side to resend. </p>
+ <p>Own Id: OTP-7192</p>
+ <p>Aux Id: Seq 10884</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.8 -->
+
+
+ <section>
+ <title>Megaco 3.7.5</title>
+
+ <p>Version 3.7.5 supports code replacement in runtime from/to
+ version 3.7.4, 3.7.3, 3.7.2, 3.7.1 and 3.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Documentation of function
+ <seealso marker="megaco#conn_info">megaco:conn_info/2</seealso>
+ has been updated to include known exit reasons. </p>
+ <p>Own Id: OTP-7286</p>
+ <p>Aux Id: Seq 10933</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>The transaction id counter could be incorrectly
+ updated at wrap-around. The risk was expecially high
+ at high load. </p>
+ <p>Own Id: OTP-7303</p>
+ <p>Aux Id: Seq 10939</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.7.5 -->
+
+
+ <section>
+ <title>Megaco 3.7.4</title>
+
+ <p>Version 3.7.4 supports code replacement in runtime from/to
+ version 3.7.3, 3.7.2, 3.7.1 and 3.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>In order to better deal with codec's not implementing
+ the entire
+ <seealso marker="megaco_encoder">megaco_encoder</seealso>
+ behaviour, translations of undefined (not implemented) functions
+ to the <c>{error, not_implemented}</c> return value has been
+ added for the functions
+ <seealso marker="megaco_encoder#encode_transaction">encode_transaction/3</seealso>,
+ <seealso marker="megaco_encoder#encode_action_requests">encode_action_requests/3</seealso> and
+ <seealso marker="megaco_encoder#encode_action_reply">encode_action_reply/3</seealso>. </p>
+ <p>Own Id: OTP-7251</p>
+ <p>Aux Id: Seq 10879</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>The (plain) text scanner could incorrectly identify
+ character strings (any 17 char long string with the
+ char t in the middle) as a TimeStampToken.</p>
+ <p>Own Id: OTP-7249</p>
+ <p>Aux Id: Seq 10917</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.7.4 -->
+
+
+ <section>
+ <title>Megaco 3.7.3</title>
+
+ <p>Version 3.7.3 supports code replacement in runtime from/to
+ version 3.7.2, 3.7.1 and 3.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Updated the graphs of the performace chapter with
+ to reflect this version of megaco. Also included
+ results with HiPE-compiled codec's..</p>
+ <p>Own Id: OTP-7180</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>The behaviour <c>megaco_encoder</c> was lacking three functions
+ which was made mandatory as of version 3.7. </p>
+ <p>See
+ <seealso marker="megaco_encoder#encode_transaction">encode_transaction/3</seealso>,
+ <seealso marker="megaco_encoder#encode_action_requests">encode_action_requests/3</seealso> and
+ <seealso marker="megaco_encoder#encode_action_reply">encode_action_reply/3</seealso>
+ for more info</p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ <item>
+ <p>It was possible to create permenant pending counter
+ data for a somewhat misbehaving (request) receiver.
+ If a megaco entity ("sender") sends a request and the
+ "receiver" (of the request) responds with a pending
+ message but never actually sends the reply (or if
+ it is lost), the created pending counter data would
+ never be deleted if the
+ <seealso marker="megaco#ui_long_request_timer">long_request_timer</seealso>
+ was set to <c>infinity</c> (old default) and the
+ <seealso marker="megaco#ui_recv_pending_limit">recv_pending_limit</seealso>
+ was set to an integer value (default is <c>infinity</c>). </p>
+ <p>Own Id: OTP-7189</p>
+ <p>Aux Id: Seq 10879</p>
+ </item>
+
+ <item>
+ <p>If a counter whas reset (wrap-around) as a result of
+ increment larger than 1, then it was actually always
+ set to the min_trans_id-value.</p>
+ <p>Own Id: OTP-7216</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>For those implementing their own codec's, the new megaco_encoder
+ behaviour will require three more functions. See above for more
+ info. </p>
+ <p>Own Id: OTP-7168</p>
+ <p>Aux Id: Seq 10867</p>
+ </item>
+
+ <item>
+ <p>The default value of the
+ <seealso marker="megaco#ui_long_request_timer">long_request_timer</seealso>
+ has been changed from <c>infinity</c> to <em>60 seconds</em>. </p>
+ <p>Own Id: OTP-7189</p>
+ <p>Aux Id: Seq 10879</p>
+ </item>
+ </list>
+
+ </section>
+ </section> <!-- 3.7.3 -->
+
+
+ <section>
+ <title>Megaco 3.7.2</title>
+
+ <p>Version 3.7.2 supports code replacement in runtime from/to
+ version 3.7.1 and 3.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Reporting of error(s) detected during loading of the
+ flex driver has been improved, by calling the
+ erlang:format_error function.</p>
+ <p>Own Id: OTP-7005</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>There is a race condition when cancelling requests
+ during a high load situations which could lead to
+ spurious (megaco internal) messages beeing sent to
+ user processes. When a request is issued using
+ <seealso marker="megaco#call">megaco:call</seealso>,
+ which returns only after a "reply" can
+ be delivered, the request timer might expire
+ during the cancelling of the request, which will cause
+ megaco to attempt to deliver the timeout info, which
+ will result in the spurious message.
+ This problem has now been eliminated by introducing
+ a proxy process, which simply dies when the "real"
+ response has been delivered. The spurious reply will
+ then be sent to a non-existing process. </p>
+ <p>Own Id: OTP-6972</p>
+ <p>Aux Id: Seq 10450</p>
+ </item>
+
+ <item>
+ <p>[text] Decoding a version 2 message with an observedEventParameter
+ where the value of the parmValue was CT, failes.
+ CT is defined as the context attribute token in version 3,
+ and this incorrectly caused the scanner (which is version
+ agnostic) to create an ContextAttrToken, which caused the
+ version 2 parser to crash. </p>
+ <p>Own Id: OTP-7138</p>
+ <p>Aux Id: Seq 10854</p>
+ </item>
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Implementing (SDP-) support for RFC 4566 also means that some of
+ the existing sdp-record definitions have been changed. </p>
+ <p>Own Id: OTP-6804</p>
+ <p>Aux Id: Seq 10710</p>
+ </item>
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.7.2 -->
+
+
+ <section>
+ <title>Megaco 3.7.1</title>
+
+ <p>Version 3.7.1 supports code replacement in runtime from/to
+ version 3.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Reporting of error(s) detected during loading of the
+ flex driver has been improved, by calling the
+ erlang:format_error function.</p>
+ <p>Own Id: OTP-7005</p>
+ </item>
+
+ <item>
+ <p>Updated documentation for function megaco:connect/4.</p>
+ <p>Own Id: OTP-7000</p>
+ <p>Aux Id: Seq 10815</p>
+ </item>
+
+ <item>
+ <p>Use of depricated function erlang:fault replaced with
+ erlang:error.</p>
+ <p>Own Id: OTP-6919</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Corrected usage of function file:open/2 (the Modes
+ argument is a list). </p>
+ <p>Dialyzer</p>
+ <p>Own Id: OTP-7124</p>
+ <!-- <p>Aux Id: Seq 10815</p> -->
+ </item>
+
+ <item>
+ <p>Fixed a reply timer race condition problem resulting
+ in (case clause) error message. </p>
+ <p>Own Id: OTP-6999</p>
+ <p>Aux Id: Seq 10815</p>
+ </item>
+
+ <item>
+ <p>Failure to parse SDP attribute FMTP rows. </p>
+ <p>Own Id: OTP-6992</p>
+ <p>Aux Id: Seq 10813</p>
+ </item>
+
+ <item>
+ <p>When the megaco application receives two instances of
+ the same transaction requests (re-send) within too
+ small a time, there is a small possibility that both
+ are passed on to the user via a call to the callback
+ function (handle_trans_request). </p>
+ <p>Own Id: OTP-6971</p>
+ <p>Aux Id: Seq 10802</p>
+ </item>
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Implementing (SDP-) support for RFC 4566 also means that some of
+ the existing sdp-record definitions have been changed. </p>
+ <p>Own Id: OTP-6804</p>
+ <p>Aux Id: Seq 10710</p>
+ </item>
+ </list>
+-->
+
+ </section>
+ </section> <!-- 3.7.1 -->
+
+
+ <section>
+ <title>Megaco 3.7</title>
+<!--
+ <p>Version 3.7 supports code replacement in runtime from/to
+ version 3.6.0.1 &amp; 3.6 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added support for the full v3-standard
+ (including segmentation).</p>
+ <p>See
+ <seealso marker="megaco_run#segment_reply">segmentation of transaction replies</seealso>
+ and
+ <seealso marker="megaco_encode#handling_versions">handling megaco versions</seealso>
+ for more info.</p>
+ <p>Note that segmentation is currently not supported by the
+ binary codec(s). </p>
+ <p>Own Id: OTP-5979</p>
+ </item>
+
+ <item>
+ <p>The megaco documentation source has been converted
+ from SGML to XML.</p>
+ <p>Own Id: OTP-6753</p>
+ </item>
+
+ <item>
+ <p>SDP support updated according to RFC 4566. </p>
+ <p>Own Id: OTP-6804</p>
+ <p>Aux Id: Seq 10710</p>
+ </item>
+
+ <item>
+ <p>Added a way for the transport module to transfer
+ extra information to the user callback functions
+ <seealso marker="megaco_user">callback functions</seealso>
+ upon receipt of a message. This is done by adding an extra
+ argument when calling the (new) message delivery function(s)
+ <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
+ or
+ <seealso marker="megaco#receive_message">receive_message/5</seealso>. </p>
+ <p>Similarly, the <c>UserReply</c> part of the return value for the
+ <seealso marker="megaco#call">call</seealso> function can
+ now also include such extra information. </p>
+ <p>Own Id: OTP-6865</p>
+ <p>Aux Id: Seq 10559</p>
+ </item>
+
+<!--
+ <item>
+ <p>Use of depricated function erlang:fault replaced by
+ erlang:error. </p>
+ <p>Own Id: OTP-6919</p>
+ </item>
+-->
+
+ <item>
+ <p>Improve the utility functions for information retrieval:
+ <seealso marker="megaco#info">megaco:info</seealso>,
+ <seealso marker="megaco#system_info">megaco:system_info</seealso>,
+ <seealso marker="megaco#conn_info">megaco:conn_info</seealso> and
+ <seealso marker="megaco#user_info">megaco:user_info</seealso>.</p>
+ <p>Own Id: OTP-6976</p>
+ <p>Aux Id: Seq 10804</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+ <list type="bulleted">
+ <item>
+ <p>Implementing (SDP-) support for RFC 4566 also means that some of
+ the existing sdp-record definitions have been changed. </p>
+ <p>Own Id: OTP-6804</p>
+ <p>Aux Id: Seq 10710</p>
+ </item>
+ </list>
+ </section>
+ </section> <!-- 3.7 -->
+
+
+ <section><title>Megaco 3.6.3</title>
+
+ <p>Version 3.6.3 supports code replacement in runtime from/to
+ version 3.6.2, 3.6.1, 3.6.0.1, 3.6, 3.5.3, 3.5.2, 3.5.1.1, 3.5.1 and
+ 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section><title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>Minor Makefile changes.</p>
+ <p>Own Id: OTP-6704</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section><title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+<!--
+ <item>
+ <p>Fixed a reply timer race condition problem resulting
+ in (case clause) error message. </p>
+ <p>Own Id: OTP-6999</p>
+ <p>Aux Id: Seq 10815</p>
+ </item>
+-->
+ <item>
+ <p>Failure to parse SDP attribute FMTP rows. </p>
+ <p>Own Id: OTP-6992</p>
+ <p>Aux Id: Seq 10813</p>
+ </item>
+
+<!--
+ <item>
+ <p>There is a race condition when cancelling requests
+ during a high load situations which could lead to
+ spurious (megaco internal) messages being sent to
+ user processes. When a request is issued using
+ <seealso marker="megaco#call">megaco:call</seealso>,
+ which returns only after a "reply" can
+ be delivered, the request timer might expire
+ during the cancelling of the request, which will cause
+ megaco to attempt to deliver the timeout info, which
+ will result in the spurious message.
+ This problem has now been eliminated by introducing
+ a proxy process, which simply dies when the "real"
+ response has been delivered. The spurious reply will
+ then be sent to a non-existing process. </p>
+ <p>Own Id: OTP-6972</p>
+ <p>Aux Id: Seq 10450</p>
+ </item>
+
+ <item>
+ <p>When the megaco application receives two instances of
+ the same transaction requests (re-send) within too
+ small a time, there is a small possibility that both
+ are passed on to the user via a call to the callback
+ function (handle_trans_request). </p>
+ <p>Own Id: OTP-6971</p>
+ <p>Aux Id: Seq 10802</p>
+ </item>
+-->
+
+ </list>
+
+ </section>
+
+ <section><title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>The interface of the megaco_compressed callback module
+ has been changed, see the
+ <seealso marker="megaco_edist_compress">megaco_edist_compress</seealso>
+ behaviour module for more details.
+ <p>Own Id: OTP-6609</p>
+ </item>
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 3.6.3 -->
+
+
+ <section><title>Megaco 3.6.2</title>
+
+ <p>Version 3.6.2 supports code replacement in runtime from/to
+ version 3.6.1, 3.6.0.1, 3.6, 3.5.3, 3.5.2, 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section><title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>Minor Makefile changes.</p>
+ <p>Own Id: OTP-6704</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section><title>Fixed bugs and malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>When timers expire while a connection cancel
+ (megaco:cancel) is in progress, there is a raise
+ condition possibility. This has been eliminated. </p>
+ <p>Own Id: OTP-6921</p>
+ <p>Aux Id: Seq 10450</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section><title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>The interface of the megaco_compressed callback module
+ has been changed, see the
+ <seealso marker="megaco_edist_compress">megaco_edist_compress</seealso>
+ behaviour module for more details.
+ <p>Own Id: OTP-6609</p>
+ </item>
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 3.6.2 -->
+
+
+ <section>
+ <title>Megaco 3.6.1</title>
+
+ <p>Version 3.6.1 supports code replacement in runtime from/to
+ version 3.6.0.1, 3.6, 3.5.3, 3.5.2, 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>An empty time-zone adjustment was incorrectly allowed
+ when decoding SDP using
+ <seealso marker="megaco#decode_sdp">decode_sdp</seealso>. </p>
+ <p>Also the parsing of attributes was to restrictive. </p>
+ <p>Own Id: OTP-6803</p>
+ <p>Aux Id: Seq 10710</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.6.0.1</title>
+ <p>Version 3.6.0.1 supports code replacement in runtime from/to
+ version 3.6, 3.5.3, 3.5.2, 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Minor Makefile changes.</p>
+ <p>Own Id: OTP-6704</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.6</title>
+ <p>Version 3.6 supports code replacement in runtime from/to
+ version 3.5.3, 3.5.2, 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Improved erl_dist codec handling of
+ <seealso marker="megaco_encode#erl_dist_config">megaco_compressed</seealso>
+ codec config. Introduced behaviour,
+ <seealso marker="megaco_edist_compress">megaco_edist_compress</seealso>,
+ for the megaco_compressed callback of module. </p>
+ <p>Own Id: OTP-6609</p>
+ </item>
+ <item>
+ <p>The behaviour
+ <seealso marker="megaco_transport">megaco_transport</seealso>
+ have been updated to include the <em>optional</em>
+ function
+ <seealso marker="megaco_transport#resend_message">resend_message</seealso>.
+ This function is called instead of the standard
+ <seealso marker="megaco_transport#send_message">send_message</seealso>
+ if the new config option
+ <seealso marker="megaco#ui_resend_indication">resend_indication</seealso>
+ was set to <c><![CDATA[true]]></c><em>and</em> it is a message resend. </p>
+ <p>Own Id: OTP-6442</p>
+ <p>Aux Id: Seq 10393</p>
+ </item>
+ <item>
+ <p>Add ability to decrement the timeout time for
+ incremental timers, see
+ <seealso marker="megaco#">reference manual</seealso>
+ for more info.</p>
+ <p>Own Id: OTP-6441</p>
+ <p>Aux Id: Seq 10349</p>
+ </item>
+ <item>
+ <p>Miscellaneous minor performance improvements of the
+ text codec's.</p>
+ <p>Own Id: OTP-6185</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Missing documentation link in module
+ <seealso marker="megaco_user">megaco_user</seealso>. </p>
+ <p>Own Id: OTP-6578</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The interface of the megaco_compressed callback module
+ has been changed, see the
+ <seealso marker="megaco_edist_compress">megaco_edist_compress</seealso>
+ behaviour module for more details.</p>
+ <p>Own Id: OTP-6609</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.5.3</title>
+ <p>Version 3.5.3 supports code replacement in runtime from/to
+ version 3.5.2, 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Using the <seealso marker="megaco#call">call</seealso>
+ function at high load could cause replies from other
+ transactions to be returned also. </p>
+ <p>At high load, when a process calls the function
+ <seealso marker="megaco#call">call</seealso>,
+ which times out, then makes another
+ call, it is possible that the reply to the first
+ request arrives while the process is waiting for
+ reply to the second request. As no checks were made if
+ the reply was actually the expected (transaction-id),
+ this reply was also included in the result. </p>
+ <p>This problem has been fixed by calling the megaco_user
+ callback function
+ <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans</seealso>
+ if unexpected transactions are received. </p>
+ <p>Own Id: OTP-6549</p>
+ <p>Aux Id: Seq 10598</p>
+ </item>
+ <item>
+ <p>Miscellaneous minor corrections, such as
+ removing "dead code". Detected by dialyzer. </p>
+ <p>Own Id: OTP-6520</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.5.2</title>
+ <p>Version 3.5.2 supports code replacement in runtime from/to
+ version 3.5.1.1, 3.5.1 and 3.5 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Minor improvement to the text codec error reporting.</p>
+ <p>Own Id: OTP-6404</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Misc cleanup to eliminate some dialyzer warnings [dialyzer]. </p>
+ <p>Own Id: OTP-6503</p>
+ </item>
+ <item>
+ <p>Improper text encoding of EventSpecs.
+ All codec versions [dialyzer]. </p>
+ <p>Own Id: OTP-6490</p>
+ </item>
+ <item>
+ <p>Missing (link) anchors. </p>
+ <p>Own Id: OTP-6422</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.5.1</title>
+ <p>Version 3.5.1 supports code replacement in runtime from/to
+ version 3.5, 3.4.4 and 3.4.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>When replies arrive during a call to megaco:cancel
+ there is a raise condition possibility. This has been
+ eliminated. </p>
+ <p>Own Id: OTP-6276</p>
+ <p>Aux Id: Seq 10450</p>
+ </item>
+ <item>
+ <p>MG receiving a request, when the reply to the
+ service-change has not yet been received (505)
+ (either because it's been lost or because the MGC is
+ erroneous). This will now result in a call to
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>
+ with the UserReply: <c><![CDATA[{error, timeout}]]></c>. </p>
+ <p>Own Id: OTP-6275</p>
+ <p>Aux Id: Seq 10458</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.5</title>
+ <p>Version 3.5 supports code replacement in runtime from/to
+ version 3.4.4 and 3.4.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>All error/warning messages from the megaco application
+ will be tagged in such a way that they will be easy to
+ identify (and search for in logs).</p>
+ <p>Own Id: OTP-6223</p>
+ <p>Aux Id: Seq 10423</p>
+ </item>
+ <item>
+ <p>The allowed return values of the send_message function
+ of the megaco_transport callback module has been
+ extended (to allow the transport module to cancel the message
+ sending), see the functions
+ <seealso marker="megaco#call">call</seealso>,
+ <seealso marker="megaco_user#trans_reply">handle_trans_reply</seealso>,
+ <seealso marker="megaco_user#trans_ack">handle_trans_ack</seealso>
+ and <seealso marker="megaco_transport#send_message">send_message</seealso>
+ for more info.</p>
+ <p>Own Id: OTP-6253</p>
+ <p>Aux Id: Seq 10423</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A minor problem related to the passage of the pending
+ limit could potentially prevent the reply
+ info to be retained when it should have been removed.
+ Also, the user will not be informed about the passing
+ of the pending limit in this special case. </p>
+ <p>Own Id: OTP-6256</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.4.4</title>
+ <p>Version 3.4.4 supports code replacement in runtime from/to
+ version 3.4.3, 3.4.2, 3.4.1 and 3.4 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Improved documentation of
+ <seealso marker="megaco#call">call</seealso> return values.</p>
+ <p>Own Id: OTP-6219</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>There was still one case when "pending limit exceeded"
+ was reported as a message error instead of transaction
+ error. This has been fixed. </p>
+ <p>Own Id: OTP-6217</p>
+ <p>Aux Id: Seq 10415</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.4.3</title>
+ <p>Version 3.4.3 supports code replacement in runtime from/to
+ version 3.4.2, 3.4.1 and 3.4 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added a number of v3 related error codes (defined in H248.08).</p>
+ <p>Own Id: OTP-6170</p>
+ <p>Aux Id: Seq 10372</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Added check for the illegal option reply_data in the Options
+ (third) argument to the
+ <seealso marker="megaco#call">call</seealso>
+ function.
+ The valid options was documented but never checked.</p>
+ <p>Own Id: OTP-6171</p>
+ <p>Aux Id: Seq 10345</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>A call to the function
+ <seealso marker="megaco#call">call</seealso>
+ with the illegal option, reply_data,
+ will now result in an <c><![CDATA[{error, term()}]]></c> result.</p>
+ <p>Own Id: OTP-6171</p>
+ <p>Aux Id: Seq 10345</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.4.2</title>
+ <p>Version 3.4.2 supports code replacement in runtime from/to
+ version 3.4.1, 3.4, 3.3.5, 3.3.4, 3.3.3, 3.3.2, 3.3.1 and 3.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Pending limit exceeded error message was incorrectly
+ composed as a message error instead of a TransactionReply
+ (transactionError) error.</p>
+ <p>Own Id: OTP-6148</p>
+ <p>Aux Id: Seq 10337</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The ErrorDescriptor of the pending limit exceeded error
+ is now encapsulated within an TransactionReply instead of
+ the messageBody.</p>
+ <p>Own Id: OTP-6148</p>
+ <p>Aux Id: Seq 10337</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.4.1</title>
+ <p>Version 3.4.1 supports code replacement in runtime from/to
+ version 3.4, 3.3.5, 3.3.4, 3.3.3, 3.3.2, 3.3.1 and 3.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Incorrect version string(s) in appup file. Most of
+ the version strings in the appup file was malformed,
+ which most likely made up-/downgrade impossible.</p>
+ <p>Own Id: OTP-6113</p>
+ </item>
+ <item>
+ <p>Fixed release notes history.</p>
+ <p>Own Id: OTP-6108</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.4</title>
+ <p>Version 3.4 supports code replacement in runtime from/to
+ version 3.3.3, 3.3.2, 3.3.1 and 3.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Handling failure to send reply. Previously, when megaco
+ was unable to send a reply (built from the action list
+ returned by
+ <seealso marker="megaco_user#trans_request">handle_trans_request</seealso>),
+ nothing was done, except for sending an error message.
+ This has now been changed so that the error will be returned
+ to the user via a call to the callback function,
+ <seealso marker="megaco_user#trans_ack">handle_trans_ack</seealso>
+ (unless <c><![CDATA[ack_action() = discard_ack]]></c>). </p>
+ <p>Own Id: OTP-6055</p>
+ </item>
+ <item>
+ <p>Add possibility to override send options when sending
+ reply messages. This is done by adding another return
+ alternative to the
+ <seealso marker="megaco_user#trans_request">handle_trans_request</seealso>
+ and
+ <seealso marker="megaco_user#trans_long_request">handle_trans_long_request</seealso>
+ callback function(s). </p>
+ <p>Own Id: OTP-6052</p>
+ <p>Aux Id: Seq 10284</p>
+ </item>
+ <item>
+ <p>Added another config option <c><![CDATA[long_request_resend]]></c>.
+ The purpose of this option is to make the megaco
+ application to continue re-sending requests, even after
+ having received a pending message, until it receives
+ the reply or it gives up (timeout). </p>
+ <p>See
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso>
+ for more info. </p>
+ <p>Own Id: OTP-6051</p>
+ <p>Aux Id: Seq 10284</p>
+ </item>
+ <item>
+ <p>Modify the way the stack handles the reply-timer.
+ Now, if an incremental timer is used, every time there
+ is an intermediate timeout, the timer is restarted
+ (just as before) but the reply is also <em>resent</em>. </p>
+ <p>See
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso>
+ for more info. </p>
+ <p>Own Id: OTP-6048</p>
+ <p>Aux Id: Seq 10284</p>
+ </item>
+ <item>
+ <p>Added the possibility to conditionally request
+ immediate acknowledgement of a reply (when at least one
+ pending message has been sent). </p>
+ <p>This is done by adding another return value for the
+ <seealso marker="megaco_user#trans_request">handle_trans_request</seealso>
+ callback function. </p>
+ <p>Own Id: OTP-6030</p>
+ <p>Aux Id: Seq 10270</p>
+ </item>
+ <item>
+ <p>The SDP support has received a major updated. Added two new
+ function's to
+ <seealso marker="megaco#decode_sdp">decode</seealso> and
+ <seealso marker="megaco#encode_sdp">encode</seealso> SDP. </p>
+ <p>Own Id: OTP-5980</p>
+ </item>
+ <item>
+ <p>Added support for another pre version of v3 (<c><![CDATA[prev3c]]></c>).
+ This is based on the final version of the standard, but does
+ not include support for segments.</p>
+ <p>Own Id: OTP-5769</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Removed unnecessary error report. In a special case
+ two (error_logger) error reports could be sent:
+ When receiving a transaction request for which an
+ reply, with immediate-ack-requested, has already been
+ send, the reply is resent. But if the sending fails,
+ two (error_logger) error reports is sent. This
+ has been corrected (so that only one is sent).</p>
+ <p>Own Id: OTP-6090</p>
+ <p>Aux Id: Seq 10308</p>
+ </item>
+ <item>
+ <p>Bad formated debug printout in transaction sender.</p>
+ <p>Own Id: OTP-6089</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>All of the old SDP api function(s) has been removed.</p>
+ <p>Own Id: OTP-5980</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.3.4</title>
+ <p>Version 3.3.4 supports code replacement in runtime from/to
+ version 3.3.3, 3.3.2, 3.3.1 and 3.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Misc Dialyzer warnings.</p>
+ <p>Own Id: OTP-6076</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.3.3</title>
+ <p>Version 3.3.3 supports code replacement in runtime from/to
+ version 3.3.2, 3.3.1 and 3.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Flex driver split into two separate. One for use in
+ threaded runtime system (OTP built with e.g.
+ <c><![CDATA[--enable-threads]]></c>), one for non-threaded runtime systems.</p>
+ <p>Own Id: OTP-6046</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.3.2</title>
+ <p>Version 3.3.2 supports code replacement in runtime from/to
+ version 3.3.1, 3.3 and 3.2.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Improve timer documentation.</p>
+ <p>Own Id: OTP-6022</p>
+ <p>Aux Id: Seq 10266</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[text] The parser has been made more strict with
+ regard to what ContextID values will be accepted.
+ <c><![CDATA[0x0]]></c>, <c><![CDATA[0xFFFFFFFE]]></c> and <c><![CDATA[0xFFFFFFFF]]></c>
+ will no longer be accepted.</p>
+ <p>Own Id: OTP-6017</p>
+ <p>Aux Id: Seq 10265</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.3.1</title>
+ <p>Version 3.3.1 supports code replacement in runtime from/to
+ version 3.3 and 3.2.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[text] The text encoder (both pretty and compact)
+ encodes terminationIDList incorrectly. This effects
+ MuxDescriptor This applies to all versions.</p>
+ <p>Own Id: OTP-5993</p>
+ <p>Aux Id: Seq 10248</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.3</title>
+ <p>Version 3.3 supports code replacement in runtime from/to
+ version 3.2.7 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added a utility function to facilitate pretty-printing of
+ messages, see
+ <seealso marker="megaco#token_tag2string">token_tag2string</seealso>.</p>
+ <p>Own Id: OTP-5973</p>
+ <p>Aux Id: Seq 10224</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Fixed documentation after OTP-5953. The new info print
+ functions where not documented, but the old, and
+ deprecated, where still.</p>
+ <p>Own Id: OTP-5965</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.7</title>
+ <p>Version 3.2.7 supports code replacement in runtime from/to
+ version 3.2.6, 3.2.5 and 3.2.4 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Updated configure script to handle smp-support.</p>
+ <p>Own Id: OTP-5952</p>
+ </item>
+ <item>
+ <p>Added new version info print function(s).</p>
+ <p>Own Id: OTP-5953</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Code cleanup: Compiler warnings: variable X is unused.</p>
+ <p>Own Id: OTP-5948</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The old version info print function, format_versions/1,
+ have been deprecated.</p>
+ <p>Own Id: OTP-5953</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.6</title>
+ <p>Version 3.2.6 supports code replacement in runtime from/to
+ version 3.2.5, 3.2.4 and 3.2.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Improve error message format on (reply) decode error.</p>
+ <p>Own Id: OTP-5918</p>
+ <p>Aux Id: Seq 10199</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Wrong binary name resolver used for prev3b (prev3a).</p>
+ <p>Own Id: OTP-5919</p>
+ </item>
+ <item>
+ <p>When using ber_bin-codec and option {version3,prev3b}
+ the wrong asn1 and transform modules (prev3a) where
+ used.</p>
+ <p>Own Id: OTP-5920</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.5</title>
+ <p>Version 3.2.5 supports code replacement in runtime from/to
+ version 3.2.4 and 3.2.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Aligned the
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso> functions
+ regarding trans_id retrieval.</p>
+ <p>Own Id: OTP-5887</p>
+ <p>Aux Id: Seq 10184</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The
+ <seealso marker="megaco#conn_info">conn_info</seealso> function
+ once again returns the <em>next</em> transaction id.</p>
+ <p>Own Id: OTP-5887</p>
+ <p>Aux Id: Seq 10184</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.4</title>
+ <p>Version 3.2.4 supports code replacement in runtime from/to
+ version 3.2.3 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Documentation of
+ <seealso marker="megaco_udp#upgrade_receive_handle">upgrade_receive_handle</seealso> missing one argument (<c><![CDATA[NewHandle]]></c>).</p>
+ <p>Own Id: OTP-5867</p>
+ </item>
+ <item>
+ <p>Documentation of
+ <seealso marker="megaco#conn_info">conn_info</seealso>
+ did not document legal <c><![CDATA[Item]]></c> value <c><![CDATA[local_mid]]></c>.</p>
+ <p>Own Id: OTP-5879</p>
+ <p>Aux Id: Seq 10176</p>
+ </item>
+ <item>
+ <p>Documentation of
+ <seealso marker="megaco#conn_info">conn_info</seealso>
+ did not document legal <c><![CDATA[Item]]></c> value <c><![CDATA[remote_mid]]></c>.</p>
+ <p>Own Id: OTP-5880</p>
+ <p>Aux Id: Seq 10177</p>
+ </item>
+ <item>
+ <p>Improper [text] encode of localControlDescriptor.
+ Incorrectly allowed zero length list of LocalParm.
+ All versions (v1, v2, v3 [prev3a, prev3b]). </p>
+ <p>Own Id: OTP-5882</p>
+ </item>
+ <item>
+ <p>Function format_versions documentation with wrong arity.</p>
+ <p>Own Id: OTP-5885</p>
+ </item>
+ <item>
+ <p>Timer recalculation fails when receiving pending
+ message if the timer is of the type <c><![CDATA[megaco_incr_timer]]></c>
+ and the <c><![CDATA[max_retries]]></c> field has the
+ value <c><![CDATA[infinity_restartable]]></c>. </p>
+ <p>Own Id: OTP-5886</p>
+ <p>Aux Id: Seq 10181</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[localControlDescriptor]]></c> list of <c><![CDATA[localParm]]></c> now at least
+ has to be of length 1.</p>
+ <p>Own Id: OTP-5882</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.3</title>
+ <p>Version 3.2.3 supports code replacement in runtime from/to
+ version 3.2.2, 3.2.1 and 3.2 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Assumed a more strict approach to the return values of
+ the callback functions of the
+ <seealso marker="megaco_user">megaco_user</seealso> behaviour.
+ Now, a return value other then what is described in
+ the behaviour documentation, will result in a warning
+ message. </p>
+ <p>Except for the
+ <seealso marker="megaco_user#trans_request">handle_trans_request/3</seealso> and
+ <seealso marker="megaco_user#trans_long_request">handle_trans_long_request/3</seealso>,
+ which still results in error messages.</p>
+ <p>Own Id: OTP-5830</p>
+ <p>Aux Id: Seq 10148</p>
+ </item>
+ <item>
+ <p>Introduced a <em>strict version control</em> (strict_version)
+ connection info and user info option. See the
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso> functions
+ for more info.</p>
+ <p>Own Id: OTP-5839</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Digit Map: Improper handling of duration.
+ <seealso marker="megaco#eval_digit_map">eval_digit_map</seealso>
+ and
+ <seealso marker="megaco#test_digit_event">test_digit_event</seealso>.</p>
+ <p>Own Id: OTP-5826</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ <item>
+ <p>The documentation of the
+ <seealso marker="megaco#call">call</seealso> and
+ <seealso marker="megaco#cast">cast</seealso> functions
+ was unclear regarding pre-encoded actions.</p>
+ <p>Own Id: OTP-5833</p>
+ <p>Aux Id: Seq 10146</p>
+ </item>
+ <item>
+ <p>The prev3b text codec's failed to properly decode an
+ auditReply with ErrorDescriptor.</p>
+ <p>Own Id: OTP-5836</p>
+ <p>Aux Id: Seq 10155</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The ok return value from
+ <seealso marker="megaco#test_digit_event">test_digit_event</seealso> and
+ <seealso marker="megaco#eval_digit_map">eval_digit_map</seealso>
+ has been changed.</p>
+ <p>Own Id: OTP-5826</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.2</title>
+ <p>Version 3.2.2 supports code replacement in runtime from/to
+ version 3.2.1 and 3.2 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Digit Map: Megaco does not handle "unexpected event"
+ according to chapter 7.1.14.5 point 5. See
+ <seealso marker="megaco#eval_digit_map">eval_digit_map</seealso>
+ and
+ <seealso marker="megaco#test_digit_event">test_digit_event</seealso>.</p>
+ <p>Own Id: OTP-5799</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ <item>
+ <p>The text codec of prev3b should handle
+ encoding/decoding of indAudMediaDescriptor as specified
+ in the final version of the v3 spec. This is backward
+ compatible and more aligned with the ASN.1.</p>
+ <p>Own Id: OTP-5803</p>
+ <p>Aux Id: Seq 10119</p>
+ </item>
+ <item>
+ <p>Flex scanner cannot handle empty local/remote
+ descriptors.</p>
+ <p>Own Id: OTP-5804</p>
+ <p>Aux Id: Seq 10119</p>
+ </item>
+ <item>
+ <p>Text codecs does not handle messages of unsupported versions
+ (or with incorrect version) in a good way.</p>
+ <p>Own Id: OTP-5805</p>
+ <p>Aux Id: Seq 10131</p>
+ </item>
+ <item>
+ <p>The documentation of the reply-timer was unclear.</p>
+ <p>Own Id: OTP-5816</p>
+ <p>Aux Id: Seq 10142</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The ok return value from
+ <seealso marker="megaco#test_digit_event">test_digit_event</seealso> and
+ <seealso marker="megaco#eval_digit_map">eval_digit_map</seealso>
+ has been changed to accommodate for this problem.</p>
+ <p>Own Id: OTP-5799</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2.1</title>
+ <p>Version 3.2.1 supports code replacement in runtime from/to
+ version 3.2 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>In order to allow the user to drop (ignore) a transaction
+ request a new return value, <c><![CDATA[ignore_trans_request]]></c>, has
+ been added to the
+ <seealso marker="megaco_user#trans_request">handle_trans_request/3</seealso>
+ callback function.</p>
+ <p>Own Id: OTP-5725</p>
+ <p>Aux Id: Seq 10084</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Text encoding of the termination id list in
+ contextTerminationAudit incorrect. Missing { }.
+ All versions.</p>
+ <p>Own Id: OTP-5793</p>
+ <p>Aux Id: Seq 10116</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.2</title>
+ <p>Version 3.2 supports code replacement in runtime from/to
+ version 3.1 and 3.0.1 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added support for another pre version of v3 (<c><![CDATA[prev3b]]></c>).
+ This is basically the same as <c><![CDATA[prev3a]]></c> except that
+ context priority (in contextProperties) has been
+ "fixed" so that it is backward compatible with v2.</p>
+ <p>Own Id: OTP-5717</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The (digit map)
+ <seealso marker="megaco#test_digit_event">test</seealso> and
+ <seealso marker="megaco#eval_digit_map">eval</seealso> function(s)
+ was lacking result info on what kind of completion
+ was done; <c><![CDATA[full]]></c> or <c><![CDATA[unambiguous]]></c>.</p>
+ <p>Own Id: OTP-5750</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The (successfull) return value from the
+ <seealso marker="megaco#test_digit_event">test_digit_event</seealso> and
+ <seealso marker="megaco#eval_digit_map">eval_digit_map</seealso>
+ has been changed.</p>
+ <p>Own Id: OTP-5750</p>
+ <p>Aux Id: Seq 10085</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.1</title>
+ <p>Version 3.1 supports code replacement in runtime from/to
+ version 3.0.1 and 3.0 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>The <c><![CDATA[megaco_incr_timer]]></c> has been tweaked so that the
+ max_retries field can now also take the value
+ <c><![CDATA[infinity_restartable]]></c>. This means that the only way
+ to actually restart the timer is if some external event
+ occurs, e.g. a pending message when the long request timer
+ is running. That is, if the timeout time actually expires,
+ then so does the timer.</p>
+ <p>Own Id: OTP-5619</p>
+ <p>Aux Id: Seq 9845</p>
+ </item>
+ <item>
+ <p>Added function format_versions/1 to print the extended version
+ info produced by the
+ <seealso marker="megaco#versions1">versions1</seealso> and
+ <seealso marker="megaco#versions2">versions2</seealso>
+ functions.</p>
+ <p>Own Id: OTP-5664</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Incorrect text encoding of embedded Events.</p>
+ <p>Own Id: OTP-5601</p>
+ </item>
+ <item>
+ <p>Incorrect text encoding of embedded Signal.</p>
+ <p>Own Id: OTP-5600</p>
+ </item>
+ <item>
+ <p>Misc bugs detected by Dyalizer.</p>
+ <p>Own Id: OTP-5597</p>
+ </item>
+ <item>
+ <p>Encoding of SDP was in text not done strictly
+ according RFC2327. Each line should be terminated
+ with carriage return and newline (0x0d0a), but was only
+ terminated with single newline (0x0a).</p>
+ <p>Own Id: OTP-5542</p>
+ <p>Aux Id: Seq 9669</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.0.1</title>
+ <p>Version 3.0.1 supports code replacement in runtime from/to
+ version 3.0 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Pending limit cleanup error's.
+ In some situations (high load), reply-records where never removed,
+ blocking new requests with the same transaction id.</p>
+ <p>Own Id: OTP-5401</p>
+ </item>
+ <item>
+ <p>Added utility functions to retrieve some system and application
+ info, see
+ <seealso marker="megaco#versions1">versions1</seealso> and
+ <seealso marker="megaco#versions2">versions2</seealso>.</p>
+ <p>Own Id: OTP-5446</p>
+ </item>
+ <item>
+ <p>When the
+ <seealso marker="megaco#enable_trace">enable_trace</seealso>
+ function is called with the <c><![CDATA[File]]></c> argument, it sets
+ up <c><![CDATA[dbg]]></c> so that trace events are written as plain text
+ to the given file (using <c><![CDATA[io:format]]></c>).</p>
+ <p>Own Id: OTP-5447</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The <c><![CDATA[File]]></c> argument to the function
+ <seealso marker="megaco#enable_trace">enable_trace</seealso> no
+ longer sets up <c><![CDATA[dbg]]></c> to write the trace events directly to
+ file but instead to be written to a plain text file using
+ <c><![CDATA[io:format]]></c>. </p>
+ <p>Also <seealso marker="megaco#enable_trace">enable_trace</seealso>
+ no longer accepts the argument
+ <c><![CDATA[{io, Verbosity}]]></c>.</p>
+ <p>Own Id: OTP-5447</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 3.0</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Implementation of the Megaco v2 corrigendum 1 (03/2004).</p>
+ <p><br></br>This means in short:</p>
+ <list type="bulleted">
+ <item>
+ <p>The <em>ModemDescriptor</em> has been deprecated.
+ If this descriptor is found in a received message
+ it will be ignored (removed from the message).
+ <br></br>If an attempt is made to encode a message containing
+ a ModemDescriptor, an error will be returned.
+ <br></br>If in the binary codec case, encoding-config
+ contains <em>native</em>, then the <em>ModemDescriptor</em>
+ will however be included in the message when encoding and
+ also decoded. This means that it in this case it is up the
+ user to never include the <em>ModemDescriptor</em> in a
+ transmitted message and to ignore it, if received.</p>
+ </item>
+ <item>
+ <p>Addition of the <em>EmergencyOffToken</em>, which is used
+ in the <em>contextProperty</em>.</p>
+ </item>
+ </list>
+ <p>Own Id: OTP-5204</p>
+ </item>
+ <item>
+ <p>Added receiving pending limit config property. This is
+ the limit for the number of pending messages that is
+ accepted before a request is considered "a lost cause".</p>
+ <p>Own Id: OTP-5220</p>
+ </item>
+ <item>
+ <p>Added support for preliminary version 3. Based on TD-33.</p>
+ <p>See chapter <seealso marker="megaco_encode#handling_versions">Handling megaco versions</seealso> on how to configure and
+ use the preliminary version 3 (prev3a).</p>
+ <p>Own Id: OTP-5236</p>
+ </item>
+ <item>
+ <p>Added configure thread support.</p>
+ <p>Own Id: OTP-5351</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>When text encoding the ServiceChangeParm in v2, the
+ serviceChangeInfo field was ignored.</p>
+ <p>Own Id: OTP-5352</p>
+ </item>
+ <item>
+ <p>When text parsing serviceChangeParm in v2, all of auditItem
+ was put into the auditToken field of the AuditDescriptor
+ (the serviceChangeInfo field of the ServiceChangeParm record).
+ The indAudterminationAudit should go into the auditPropertyToken
+ field.</p>
+ <p>Own Id: OTP-5353</p>
+ </item>
+ <item>
+ <p>Binary name resolver was based on RFC 2885 (version 0.8
+ of the megaco standard). Among other things the
+ package id numbering was incorrect.
+ This is the case both for version 1 and 2.</p>
+ <p>Own Id: OTP-5272</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>Package number scheme (among other things) was changed
+ in version 1 of the standard..</p>
+ <p>Own Id: OTP-5272</p>
+ </item>
+ <item>
+ <p>The config property <em>orig_pending_limit</em> has been
+ renamed to <em>sent_pending_limit</em>.</p>
+ <p>Own Id: OTP-5220</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.8</title>
+ <p>Version 2.1.8 supports code replacement in runtime from/to
+ version 2.1.7 and 2.1.6 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The error counter <em>medGwyGatewayNumErrors</em> did not work.
+ This counter is incremented by the megaco application
+ when decode of a message fails. Due to the
+ construction of the decoders, nothing beyond the
+ error reason (in the text case, basically an
+ unintelligible list of tokens) is returned. E.g. not
+ the Mid needed to be able to deduce which MG
+ (conn-handle), this message came from. This resulted
+ in an increment of the "global" <em>medGwyGatewayNumErrors</em>
+ counter instead of the connection specific.
+ This has been fixed. In the text case by adding a mini
+ decoder, that basically only decodes the message as
+ far as the Mid (if the error is in or before the Mid,
+ then this decoder also fails).</p>
+ <p>Own Id: OTP-5296</p>
+ <p>Aux Id: Seq 9669</p>
+ </item>
+ <item>
+ <p>When the
+ <seealso marker="megaco#cancel">megaco:cancel/2</seealso>
+ function is called, the
+ megaco application is supposed to perform a cleanup.
+ E.g. remove aut-dated request and reply records. For
+ the reply-records this did not work, since it only
+ removed those record which had the state field
+ set to <em>wait_for_ack</em>, and not <em>aborted</em>!
+ If the state had been set to <em>aborted</em> and not
+ yet been removed (which normally happens when
+ the reply_timer times out) when the disconnect
+ and cancel functions where called, those records
+ would never be removed. This means that if eventually
+ a transaction was received which had the same
+ transaction-id as the <em>aborted</em> reply, this would
+ just be ignored!</p>
+ <p>Own Id: OTP-5310</p>
+ <p>Aux Id: Seq 9668</p>
+ </item>
+ <item>
+ <p>Incorrect definition of hexdig in the flex-scanner.
+ <br></br>Angelo Contardi</p>
+ <p>Own Id: OTP-5312</p>
+ </item>
+ <item>
+ <p>Various cleanup of the v2 text parser:
+ <br></br>1) Removed unused nonterminal and rule digitMapName.
+ <br></br>2) Token 'TimeStampToken' also a safeToken.
+ <br></br>Angelo Contardi</p>
+ <p>Own Id: OTP-5313</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.7</title>
+ <p>Version 2.1.7 supports code replacement in runtime from/to
+ version 2.1.6, 2.1.5, 2.1.4, 2.1.3, 2.1.2, 2.1.1 and 2.1 except
+ when using any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The text decoders failed to decode the contextRequest
+ with a contextAudit (ContextAttrAuditRequest).</p>
+ <p>Own Id: OTP-5290</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.6</title>
+ <p>Version 2.1.6 supports code replacement in runtime from/to
+ version 2.1.5, 2.1.4, 2.1.3, 2.1.2, 2.1.1 and 2.1 except when using
+ any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Minor error handling improvement to the text encoder.</p>
+ <p>Own Id: OTP-5193</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The megaco text codec failed to properly encode a message
+ containing no or an empty terminationAudit list or possibly
+ a terminationAudit list with only an "empty" emptyDescriptor
+ (e.g. an AuditDescriptor without any values; auditToken is
+ either asn1_NOVALUE or []). This effected AmmsReply and
+ auditOther (AuditResult) and both v1 and v2.</p>
+ <p>Own Id: OTP-5186</p>
+ <p>Aux Id: Seq 9226</p>
+ </item>
+ <item>
+ <p>Version 2 codec corrections: Incorrectly transformed (encoded
+ and decoded) IndAudStreamDescriptor (binary), encoded
+ IndAudMediaDescriptor and IndAudStreamDescriptor (text).
+ Incorrectly decoded IndAudMediaDescriptor (text).</p>
+ <p>Own Id: OTP-5201</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.5</title>
+ <p>Version 2.1.5 supports code replacement in runtime from/to
+ version 2.1.4, 2.1.3, 2.1.2, 2.1.1 and 2.1 except when using
+ any of the drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Bad error message when encoding invalid termination id.</p>
+ <p>Own Id: OTP-5133</p>
+ <p>Aux Id: Seq 9153</p>
+ </item>
+ <item>
+ <p>The included tcp transport module had a possible
+ message queue accumulation loophole. If the
+ connection is terminated between the calls
+ gen_tcp:accept/1 and gen_tcp:controlling_process/2
+ we did not clean up the message queue.
+ Also, if controlling_process fails, a cleanup must
+ be done.</p>
+ <p>Own Id: OTP-5130</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.4</title>
+ <p>Version 2.1.4 supports code replacement in runtime from/to
+ version 2.1.3, 2.1.2, 2.1.1 and 2.1 except when using any of the
+ drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Failure to decode indAudLocalControlDescriptor with
+ more then one indAudlocalParm.
+ <br></br>This applies only to version 2.</p>
+ <p>Own Id: OTP-5106</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.3</title>
+ <p>Version 2.1.3 supports code replacement in runtime from/to
+ version 2.1.2, 2.1.1 and 2.1 except when using any of the
+ drivers (flex for text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Failure to encode a ActionReply with empty contextReply
+ (asn1_NOVALUE) and commandReply ([]).
+ Failure to decode ActionReply with error descriptor with
+ non-empty contextReply and/or commandReply.
+ <br></br>This applies to both version 1 and 2.</p>
+ <p>Own Id: OTP-5085</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.2</title>
+ <p>Version 2.1.2 supports code replacement in runtime from/to
+ version 2.1.1 and 2.1 except when using any of the drivers (flex for
+ text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Encoding of a MediaDescriptor fails if the
+ streams part is empty (asn1_NOVALUE).</p>
+ <p>Own Id: OTP-5068</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1.1</title>
+ <p>Version 2.1.1 supports code replacement in runtime from/to
+ version 2.1 except when using any of the drivers (flex for
+ text or asn1 for binary).</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A pretty text message containing an ObservedEvents
+ without timestamp, will fail to decode. This effects
+ both v1 and v2.</p>
+ <p>Own Id: OTP-5042</p>
+ </item>
+ <item>
+ <p>During node restart in a high load scenario,
+ the megaco_messenger:receive_reply_remote function
+ could be called on a node before the megaco app
+ has actually been started. This will result in a
+ crash (EXIT with badarg). This is now handled in the
+ same way as if the request was not found (with a
+ call to the callback function handle_unexpected_trans).</p>
+ <p>Own Id: OTP-5025</p>
+ <p>Aux Id: Seq 8658</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.1</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Allow separately encode action requests. Handle sending
+ of those previously encoded action requests as binaries
+ (as well as lists of action requests).
+ <br></br>See
+ <seealso marker="megaco#encode_actions">encode_actions</seealso>,
+ <seealso marker="megaco#call">call</seealso> and
+ <seealso marker="megaco#cast">cast</seealso>.</p>
+ </item>
+ <item>
+ <p>Introduce a transaction sender process (one for each
+ connection) which will accumulate transactions and send
+ several in one message.
+ <br></br>See <seealso marker="megaco_run#transaction_sender">transaction sender</seealso>,
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso>.</p>
+ </item>
+ <item>
+ <p>New encoding-config options for the erl_dist encoder which
+ makes it possible to compress the megaco messages. This makes
+ the erl_dist encoded message much more compact (about 1/3 of
+ the size).
+ <br></br>See <seealso marker="megaco_encode#erl_dist_config">megaco_compressed</seealso>.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Text parser(s) did not handle parsing of the StreamId field of
+ RequestedEvent and SecondRequestedEvent.</p>
+ <p>Own Id: OTP-4974</p>
+ </item>
+ <item>
+ <p>Repeated transaction request receiving when exceeding
+ pending limit will cause the message handling process
+ to crash.</p>
+ <p>Own Id: OTP-4956</p>
+ <p>Aux Id: Seq 8445</p>
+ </item>
+ <item>
+ <p>Text parser did not handle auditReturnItem properly,
+ as defined in IGv11.</p>
+ <p>Own Id: OTP-4950</p>
+ </item>
+ <item>
+ <p>Missing [text] servChgReplyParm consistency check.</p>
+ <p>Own Id: OTP-4949</p>
+ </item>
+ <item>
+ <p>Incorrect handling of comments in text messages.</p>
+ <p>Own Id: OTP-4946</p>
+ </item>
+ <item>
+ <p>Missing [text] serviceChangeParm consistency check.</p>
+ <p>Own Id: OTP-4945</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>Text parser did not handle auditReturnItem properly,
+ as defined in IGv11. The result which was supposed to
+ have been presented as the tuple:
+ <c><![CDATA[{emptyDescriptor, #'AuditDescriptor{}}]]></c>
+ in the termination audit list, was instead entered as
+ <c><![CDATA[{auditReturnItem, atom()}]]></c>
+ in the termination audit list. This has been fixed.</p>
+ <p>Own Id: OTP-4950</p>
+ </item>
+ <item>
+ <p>In previous releases there where a couple of user and
+ connection config items dealing with accumulating
+ transaction ack sending. These has all been renamed
+ due to the introduction of the transaction sender.
+ <br></br>See <seealso marker="megaco_run#transaction_sender">transaction sender</seealso>,
+ <seealso marker="megaco#user_info">user_info</seealso> and
+ <seealso marker="megaco#conn_info">conn_info</seealso>.</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.0.1</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Megaco did not handle IPv6-addresses.</p>
+ <p>Own Id: OTP-4920</p>
+ </item>
+ <item>
+ <p>Text encoding of hex-digits sometimes incorrect.</p>
+ <p>Own Id: OTP-4921</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 2.0</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Support for both version 1 and 2 of the Megaco standard,
+ updated according with IGv10-13.</p>
+ <p>Version selection is described in chapter
+ <seealso marker="megaco_encode#handling_versions">Handling megaco versions 1 &amp; 2</seealso>.</p>
+ </item>
+ <item>
+ <p>It is now possible to use the ASN.1 linked in driver
+ for decode/encode of messages (encoding config <em>driver</em>).
+ <br></br>See chapter
+ <seealso marker="megaco_encode#binary_config">Configuration of binary encoding module(s)</seealso>.</p>
+ </item>
+ <item>
+ <p>Added a new configuration parameter, orig_pending_limit, to
+ support the xOriginatingPendingLimit (x = MG or MGC)
+ property in the root package.
+ <br></br>See the
+ <seealso marker="megaco#user_info">orig_pending_limit</seealso>
+ parameter of the user_info function (also conn_info).</p>
+ </item>
+ <item>
+ <p>Added a new configuration parameter, threaded.
+ This tells the megaco app, that all
+ transaction requests in a message should be executed
+ in parallel (e.g. each in it's own process).
+ <br></br>See the
+ <seealso marker="megaco#user_info">threaded</seealso> parameter
+ of the user_info function (also conn_info).</p>
+ </item>
+ <item>
+ <p>Added behaviour modules
+ <seealso marker="megaco_transport">megaco_transport</seealso> and
+ <seealso marker="megaco_encoder">megaco_encoder</seealso>.</p>
+ </item>
+ <item>
+ <p>Added new (message) test functions to the megaco module, see
+ <seealso marker="megaco#test_request">test_request</seealso> and
+ <seealso marker="megaco#test_reply">test_reply</seealso>.</p>
+ </item>
+ <item>
+ <p>Minor improvements to the tracing.</p>
+ </item>
+ <item>
+ <p>Minor improvements to the simple example.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Update of the request timer incorrect when receiving
+ a pending message. Could cause an exit of the process
+ handling the message and a subsequent call to the
+ <c><![CDATA[handle_disconnect]]></c> callback function.</p>
+ <p>Own Id: OTP-4836</p>
+ </item>
+ <item>
+ <p>Failed stopping the request timer when receiving a reply. </p>
+ <p>The only effect this had was that the request timer
+ possibly ran one extra time (without doing anything).</p>
+ <p>Own Id: OTP-4843</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>signalsDescriptor has changed i v2</p>
+ </item>
+ <item>
+ <p>ServiceChangeProfile has changed in v2</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.2.3</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>- </p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Megaco re-transmission loop, when setting the long request timer
+ to an incremental timer. Megaco changes to the long request timer
+ when receiving an pending message (after having sent a request).
+ Each time the (long) timer expire, it will incorrectly result in
+ an re-send of the request. This is meaningless since we know from
+ the received pending that the "other side" has received the request
+ and is working on it. Furthermore, when in this case the "other
+ side" receives the request again, it will send another pending
+ message. Receiving a pending message in this case will
+ <em>restart</em> the timer (reset it to the initial values). This
+ means that the timer will actually never fully expire and the two
+ stacks will continue to exchange request/pending messages for as
+ long as the "other side" is working on the request.</p>
+ <p>Own Id: OTP-4760</p>
+ <p>Aux Id: Seq 8003 </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>- </p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.2.2</title>
+ <p>Version 1.2.2 supports code replacement in runtime from/to
+ version 1.2.1 and 1.2.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Only spawn a process for the reply-timer if the user
+ uses three-way-handshake.</p>
+ <p>Own Id: OTP-4729</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Encoding and decoding of the hexdig
+ in AuthenticationHeader incorrect.</p>
+ <p>Own Id: OTP-4710</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>When downgrading form 1.2.2, reply-timers started when running
+ 1.2.2 will not be properly handled since the format has changed.
+ An error message will be printed when they expire.</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.2.1</title>
+ <p>Version 1.2.1 only supports code replacement in runtime from/to
+ version 1.2.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>This is just a code up-/downgrade cleanup release. I.e. It's the
+ same as version 1.2 minus the ugly stuff needed to handle up-/downgrade
+ from/to version 1.1.2, 1.1.1 and 1.1.0.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.2</title>
+ <p>Version 1.2 supports code replacement in runtime from/to
+ version 1.1.2, 1.1.1 and 1.1.0.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>It is now possible to send more then one transaction (request)
+ in a message. See <seealso marker="megaco#call">call</seealso>
+ and <seealso marker="megaco#cast">cast</seealso>.</p>
+ <p>Req Id: M[4]-1</p>
+ <p>Own Id: OTP-4589</p>
+ </item>
+ <item>
+ <p>Two new parameters for user and connection info has been added:
+ <c><![CDATA[accu_ack_timer]]></c> and <c><![CDATA[accu_ack_maxcount]]></c>.
+ These are used together with the <c><![CDATA[auto_ack]]></c> flag and control
+ whether the acks should be sent immediately or accumulated (and sent
+ later). Note that this has nothing to do with the
+ <c><![CDATA[immAckRequired]]></c>-flag in reply transactions.
+ See <seealso marker="megaco#user_info">user_info</seealso>
+ and <seealso marker="megaco#conn_info">conn_info</seealso>.</p>
+ <p>Own Id: OTP-4669</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>TCP transport supervision error (cut-and-paste error).
+ <br></br>The megaco_tcp worker child was started as if it where a
+ supervisor (and not a worker) and with a dependency to
+ megaco_tcp_connection_sup (which it has none)</p>
+ <p>Own Id: OTP-4649</p>
+ </item>
+ <item>
+ <p>Encoding of transaction ack fails with id ranges.
+ <br></br>This was not really a problem in previous releases
+ since such a message was never created (Ack was, possibly,
+ sent for each received transaction reply).</p>
+ <p>Own Id: OTP-4652</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <list type="bulleted">
+ <item>
+ <p>Neither the TCP nor the UDP transport mechanisms are
+ part of the megaco supervision tree. This makes code up-/downgrade
+ difficult when either of them are used as transport.</p>
+ <p>This will be fixed in a future release of megaco.</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.1.2</title>
+ <p>Version 1.1.2 supports code replacement in runtime from/to
+ version 1.1.1 and 1.1.0.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Service change reason text encoding now always quoted string.</p>
+ <p>Peter-Henry Mander</p>
+ <p>Own Id: OTP-4632</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.1.1</title>
+ <p>Version 1.1.1 supports code replacement in runtime from/to
+ version 1.1.0.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added support for the Megaco mib.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Result of catch gen_udp:open not properly handled.</p>
+ <p>Own Id: OTP-4566</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.1.0</title>
+ <p>Version 1.1.0 does not support code replacement in runtime from
+ previous versions.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Reply ack timeout now results in a call to callback
+ function handle_trans_ack/4 with AckStatus = {error, timeout}.</p>
+ <p>Own Id: OTP-4378</p>
+ </item>
+ <item>
+ <p>The binary codecs ber_bin and per_bin is now both compiled
+ with the <em>+optimize</em> compiler flag for better runtime
+ performance.</p>
+ <p>Own Id: OTP-4383</p>
+ </item>
+ <item>
+ <p>The previously included tool, et, has been moved out of the
+ Megaco application. It is now provided as a separate application
+ in OTP (as of R9).</p>
+ <p>Own Id: OTP-4487</p>
+ </item>
+ <item>
+ <p>Added attribute app_vsn to all modules.</p>
+ <p>Own Id: OTP-4486</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Decode of oneStream incorrect.</p>
+ <p>.</p>
+ <p>Own Id: OTP-4490</p>
+ </item>
+ <item>
+ <p>Transaction id counter wrapping incorrect when Max is
+ <c><![CDATA[infinity]]></c>.</p>
+ <p>Incorrectly the documentation defined a connection info item
+ <c><![CDATA[min_trans_id]]></c>. It should have been <c><![CDATA[trans_id]]></c>.</p>
+ <p>Own Id: OTP-4484</p>
+ </item>
+ <item>
+ <p>Package name check in the text parser incorrect.</p>
+ <p>Own Id: OTP-4364</p>
+ </item>
+ <item>
+ <p>Fixed a minor build problem causing the file
+ 'megaco_text_parser.yrl' to not be included in the release.</p>
+ <p>Own Id: OTP-4363</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.0.4</title>
+ <p>Version 1.0.4 supports code replacement in runtime from/to
+ version 1.0.2 and 1.0.3.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Adding utility functions for megaco tracing.</p>
+ <p>Own Id: OTP-4339</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Optional line-number configure for the megaco flex scanner incorrect.</p>
+ <p>The intention was that line-numbering could be replaced with
+ token number in order to improve performance. This did not work
+ (line-numbers was always chosen). This has no runtime effect. </p>
+ <p>Own Id: OTP-4336</p>
+ </item>
+ <item>
+ <p>Improved error reporting from the megaco messenger module.</p>
+ <p>Own Id: OTP-4337</p>
+ </item>
+ <item>
+ <p>Text parsing of type octet string erroneous.</p>
+ <p>Own Id: OTP-4357</p>
+ </item>
+ <item>
+ <p>A message containing a transaction request without the transaction id value
+ is incorrectly reported back to the sender with a just an ErrorDescriptor.
+ The correct behaviour is described in chapter 8.1.1 of RFC 3015.
+ Now the result will be a transactioReply with transaction id = 0 and an
+ ErrorDescriptor.</p>
+ <p>Own Id: OTP-4359</p>
+ <p>Aux Id: Seq 7330</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.0.3</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Handling of comments in text messages incorrect.</p>
+ <p>For the ordinary text codec comments did not work. For the
+ flex text codecs, double quoted strings in comments did not
+ work.</p>
+ <p>Own Id: OTP-4299</p>
+ <p>Aux Id: Seq 7330</p>
+ </item>
+ <item>
+ <p>The <c><![CDATA[streams]]></c> field in MediaDescriptor, has been
+ made optional in order to comply with IGv6 6.50. It does
+ also mean that the new default value is <c><![CDATA[asn1_NOVALUE]]></c>.</p>
+ <p>Own Id: OTP-4288</p>
+ </item>
+ <item>
+ <p>The user arguments was not supplied to the callback function
+ <c><![CDATA[handle_unexpected_trans]]></c> as described by
+ <seealso marker="megaco_user">megaco_user</seealso>.</p>
+ <p>Own Id: OTP-4290</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>The <em>scanner</em> item of system info has been removed and instead
+ been replaced by <em>text_config</em>. Also no longer contains any MFA info.
+ From now on, just the text config.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.0.2</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added another binary decoder; per_bin.
+ <br></br>To be able to <em>use</em> the per_bin encoder the ASN.1
+ application of version 1.3.2 or later is needed for R8B systems.
+ For R7B01, ASN.1 of version 1.3.1.3 or later must be used.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Memory leak in the flex scanner. Message larger then approx.
+ 1000 bytes cannot be decoded. Will cause a core dump!
+ Note that this will only be a problem <em>if</em> the flex scanner
+ has been configured as encoding/decoding module!</p>
+ <p>Own Id: OTP-4236
+ </p>
+ </item>
+ <item>
+ <p>Fixed Makefile.in for the flex scanner. Removed unnecessary
+ '-lfl' link option.</p>
+ <p>Own Id: OTP-4224
+ </p>
+ </item>
+ <item>
+ <p>Installed source was not placed in their proper (sub-)
+ directory. </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.0.1</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The megaco application now forward's unexpected replies.
+ This is done with a call to
+ <seealso marker="megaco_user#handle_unexpected_trans">handle_unexpected_trans/3</seealso>.</p>
+ <p>Own Id: OTP-4212
+ <br></br>Aux Id: Seq 7181
+ </p>
+ </item>
+ <item>
+ <p>Megaco leaves entries in the megaco_replies table.</p>
+ <p>Own Id: OTP-4213
+ <br></br>Aux Id: Seq 7208
+ </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Megaco 1.0</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Flex scanner: Added <em>scanner</em> to system info.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Known bugs and problems</title>
+ <p>-</p>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/megaco/doc/src/part.xml b/lib/megaco/doc/src/part.xml
new file mode 100644
index 0000000000..a43720178d
--- /dev/null
+++ b/lib/megaco/doc/src/part.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco/H.248 Users Guide</title>
+ <prepared>Lars Thors&eacute;n, H&aring;kan Mattsson, Micael Karlberg</prepared>
+ <docno></docno>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>part.xml</file>
+ </header>
+ <description>
+ <p>The Megaco application is a framework for building
+ applications on top of the Megaco/H.248 protocol. </p>
+ </description>
+ <xi:include href="megaco_intro.xml"/>
+ <xi:include href="megaco_architecture.xml"/>
+ <xi:include href="megaco_run.xml"/>
+ <xi:include href="megaco_encode.xml"/>
+ <xi:include href="megaco_transport_mechanisms.xml"/>
+ <xi:include href="megaco_examples.xml"/>
+ <xi:include href="megaco_mib.xml"/>
+ <xi:include href="megaco_performance.xml"/>
+ <xi:include href="megaco_debug.xml"/>
+</part>
+
diff --git a/lib/megaco/doc/src/part_notes.xml b/lib/megaco/doc/src/part_notes.xml
new file mode 100644
index 0000000000..dfc01b54f6
--- /dev/null
+++ b/lib/megaco/doc/src/part_notes.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco/H.248 Release Notes</title>
+ <prepared>Lars Thors&eacute;n, H&aring;kan Mattsson, Micael Karlberg</prepared>
+ <docno></docno>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>part_notes.xml</file>
+ </header>
+ <description>
+ <p>The Megaco application is a framework for building
+ applications on top of the Megaco/H.248 protocol.</p>
+ <p>For information about older versions see
+ <url href="part_notes_history_frame.html">release notes history</url>.</p>
+ </description>
+ <xi:include href="notes.xml"/>
+</part>
+
diff --git a/lib/megaco/doc/src/part_notes_history.xml b/lib/megaco/doc/src/part_notes_history.xml
new file mode 100644
index 0000000000..5186ea0fc1
--- /dev/null
+++ b/lib/megaco/doc/src/part_notes_history.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco Release Notes History</title>
+ <prepared>Micael Karklberg</prepared>
+ <responsible>OTP</responsible>
+ <docno></docno>
+ <approved>OTP</approved>
+ <checked></checked>
+ <date>2007-06-15</date>
+ <rev>A</rev>
+ <file>part_notes_history.xml</file>
+ </header>
+ <description>
+ <p>The Megaco application is a framework for building
+ applications on top of the Megaco/H.248 protocol.</p>
+ </description>
+ <include file="notes_history"></include>
+</part>
+
diff --git a/lib/megaco/doc/src/ref_man.gif b/lib/megaco/doc/src/ref_man.gif
new file mode 100644
index 0000000000..b13c4efd53
--- /dev/null
+++ b/lib/megaco/doc/src/ref_man.gif
Binary files differ
diff --git a/lib/megaco/doc/src/ref_man.xml b/lib/megaco/doc/src/ref_man.xml
new file mode 100644
index 0000000000..b2bb1c046e
--- /dev/null
+++ b/lib/megaco/doc/src/ref_man.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Megaco/H.248 Reference Manual</title>
+ <prepared>Lars Thors&eacute;n, H&aring;kan Mattsson, Micael Karlberg</prepared>
+ <docno></docno>
+ <date>2007-06-15</date>
+ <rev>%VSN%</rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ <p>The Megaco application is a framework for building
+ applications on top of the Megaco/H.248 protocol. </p>
+ </description>
+ <xi:include href="megaco.xml"/>
+ <xi:include href="megaco_edist_compress.xml"/>
+ <xi:include href="megaco_encoder.xml"/>
+ <xi:include href="megaco_transport.xml"/>
+ <xi:include href="megaco_tcp.xml"/>
+ <xi:include href="megaco_udp.xml"/>
+ <xi:include href="megaco_user.xml"/>
+ <xi:include href="megaco_flex_scanner.xml"/>
+ <xi:include href="megaco_codec_meas.xml"/>
+ <xi:include href="megaco_codec_mstone1.xml"/>
+ <xi:include href="megaco_codec_mstone2.xml"/>
+ <xi:include href="megaco_codec_transform.xml"/>
+</application>
+
diff --git a/lib/megaco/doc/src/single_node_config.gif b/lib/megaco/doc/src/single_node_config.gif
new file mode 100644
index 0000000000..8b6720bf38
--- /dev/null
+++ b/lib/megaco/doc/src/single_node_config.gif
Binary files differ
diff --git a/lib/megaco/doc/src/single_node_config.ps b/lib/megaco/doc/src/single_node_config.ps
new file mode 100644
index 0000000000..eec96eaa2b
--- /dev/null
+++ b/lib/megaco/doc/src/single_node_config.ps
@@ -0,0 +1,10881 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: /clearcase/cslab/megaco/doc/src/single_node_config.ps
+%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley
+%%BoundingBox: 11 403 526 605
+%%Pages: 1
+%%DocumentFonts:
+%%EndComments
+%%EndProlog
+
+%%Page: 1 1
+
+% remember original state
+/origstate save def
+
+% build a temporary dictionary
+20 dict begin
+
+% define string to hold a scanline's worth of data
+/pix 1737 string def
+
+% define space for color conversions
+/grays 579 string def % space for gray scale line
+/npixls 0 def
+/rgbindx 0 def
+
+% lower left corner
+11 403 translate
+
+% size of image (on paper, in 1/72inch coords)
+515.30400 202.39200 scale
+
+% define 'colorimage' if it isn't defined
+% ('colortogray' and 'mergeprocs' come from xwd2ps
+% via xgrab)
+/colorimage where % do we know about 'colorimage'?
+ { pop } % yes: pop off the 'dict' returned
+ { % no: define one
+ /colortogray { % define an RGB->I function
+ /rgbdata exch store % call input 'rgbdata'
+ rgbdata length 3 idiv
+ /npixls exch store
+ /rgbindx 0 store
+ 0 1 npixls 1 sub {
+ grays exch
+ rgbdata rgbindx get 20 mul % Red
+ rgbdata rgbindx 1 add get 32 mul % Green
+ rgbdata rgbindx 2 add get 12 mul % Blue
+ add add 64 idiv % I = .5G + .31R + .18B
+ put
+ /rgbindx rgbindx 3 add store
+ } for
+ grays 0 npixls getinterval
+ } bind def
+
+ % Utility procedure for colorimage operator.
+ % This procedure takes two procedures off the
+ % stack and merges them into a single procedure.
+
+ /mergeprocs { % def
+ dup length
+ 3 -1 roll
+ dup
+ length
+ dup
+ 5 1 roll
+ 3 -1 roll
+ add
+ array cvx
+ dup
+ 3 -1 roll
+ 0 exch
+ putinterval
+ dup
+ 4 2 roll
+ putinterval
+ } bind def
+
+ /colorimage { % def
+ pop pop % remove 'false 3' operands
+ {colortogray} mergeprocs
+ image
+ } bind def
+ } ifelse % end of 'false' case
+
+
+
+579 220 8 % dimensions of data
+[579 0 0 -220 0 220] % mapping matrix
+{currentfile pix readhexstring pop}
+false 3 colorimage
+
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffff000000000000000000ffffff
+000000ffffffffffffffffffffffffffffff000000000000000000ffffff000000ffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffff000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000000000
+ffffff000000ffffffffffffffffffffffffffffffffffff000000000000000000ffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffff000000000000ffffffffffff000000ffffffffffffffffff000000
+000000ffffffffffffffffffffffff000000ffffffffffffffffff000000000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000000000000000ffffffffffff000000000000ffffff
+ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffff000000000000000000ffffffffffff
+000000000000ffffffffffffffffff000000ffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffffffffff000000
+000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff000000ffffff
+ffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffffffffff
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffff000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffff000000000000ffffffffffffffffff000000000000000000000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000000000ffffffffffffffffff000000
+000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffff000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffff000000000000000000000000000000ffffff
+ffffff000000000000000000000000000000ffffffffffff000000000000000000000000
+000000ffffffffffff000000000000000000000000000000ffffffffffff000000000000
+000000000000000000ffffffffffff000000000000000000000000000000ffffffffffff
+000000000000000000000000000000ffffffffffff000000000000000000000000000000
+ffffffffffff000000000000000000000000000000ffffffffffff000000000000000000
+000000000000ffffffffffff000000000000000000000000000000ffffffffffff000000
+000000000000000000000000ffffffffffff000000000000000000000000000000ffffff
+ffffff000000000000000000000000000000ffffffffffff000000000000000000000000
+000000ffffffffffff000000000000000000000000000000ffffffffffff000000000000
+000000000000000000ffffffffffff000000000000000000000000000000ffffffffffff
+000000000000000000000000000000ffffffffffff000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffff000000000000ffffff000000ffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffff000000000000ffffff000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+000000ffffffffffff000000000000000000ffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000ffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff
+000000ffffffffffff000000000000000000ffffffffffffffffff000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+000000000000ffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffff000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffff000000ffffff
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffffffffff000000ffffff000000000000
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffff000000000000000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffff000000000000000000ffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000ffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffff000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffff000000000000000000
+000000000000000000000000000000000000000000ffffff000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffff000000000000000000
+ffffff000000000000000000ffffffffffff000000000000ffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffff000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+000000000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffffffffff000000000000000000ffffff000000
+000000000000ffffffffffff000000000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000000000000000ffffff
+ffffff000000000000000000ffffffffffffffffff000000000000000000ffffffffffff
+ffffff000000000000000000ffffffffffffffffff000000000000000000ffffffffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffff000000ffffff000000000000ffffffffffffffffffffffff
+000000000000000000000000000000ffffff000000ffffffffffff000000ffffff000000
+000000ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
+ffffff000000ffffffffffff000000000000000000ffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+000000ffffff000000000000ffffffffffffffffffffffff000000000000000000000000
+000000ffffff000000ffffffffffff000000ffffff000000000000ffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000ffffff
+ffffffffffff000000000000000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffff000000000000000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000000000ffffff000000000000000000ffffff
+ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000ffffffffffffffffff000000000000
+000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000000000000000000000ffffffffffffffffff000000
+000000000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffff000000000000ffffff000000000000000000ffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+000000000000000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffff000000000000000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
+ffffffffffff000000ffffff000000ffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffff
+000000ffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffff000000ffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffff000000000000000000ffffff
+ffffffffffff000000000000ffffffffffffffffff000000000000000000ffffffffffff
+ffffff000000000000ffffffffffffffffffffffff000000000000000000ffffffffffff
+000000000000000000ffffffffffffffffffffffff000000000000000000000000000000
+000000ffffffffffff000000000000000000ffffff000000000000000000ffffff000000
+000000000000000000000000ffffff000000000000000000000000000000000000ffffff
+000000000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000ffffffffffffffffffffffffffffff000000000000
+000000ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000000000ffffff
+ffffffffffffffffff000000000000000000ffffffffffff000000000000000000ffffff
+ffffffffffffffffff000000000000000000000000000000000000ffffffffffff000000
+000000000000ffffff000000000000000000ffffff000000000000000000000000000000
+ffffff000000000000000000000000000000000000ffffff000000000000000000ffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffff000000000000000000000000000000000000000000000000000000000000
+ffffff000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000000000000000ffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffff000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffff000000ffffffffffffffffff000000000000
+ffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000000000ffffffffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000000000ffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000000000000000
+000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffff000000000000000000ffffff000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffff000000000000000000ffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000ffffff000000ffffffffffffffffff
+000000000000ffffffffffffffffffffffff000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000ffffff000000ffffffffffffffffff000000000000
+ffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000ffffff
+ffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000ffffff000000ffffffffffffffffff000000000000
+ffffffffffffffffff000000ffffff000000000000ffffffffffffffffff000000000000
+000000ffffff000000ffffff000000000000ffffffffffffffffffffffff000000000000
+000000ffffffffffffffffff000000ffffff000000000000000000000000ffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffff000000000000000000ffffff000000000000000000
+ffffff000000000000ffffffffffffffffff000000ffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffff000000000000000000ffffffffffffffffff000000ffffffffffff
+000000ffffff000000000000000000ffffffffffff000000ffffff000000ffffffffffff
+000000000000000000000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffff000000000000000000ffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff
+000000ffffffffffff000000ffffff000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000ffffff000000ffffffffffffffffff000000000000ffffffffffffffffff000000
+ffffff000000000000ffffffffffffffffff000000000000000000ffffff000000ffffff
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffffffffff
+000000ffffff000000000000000000000000ffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff
+ffffff000000000000000000ffffff000000000000000000ffffff000000000000ffffff
+ffffffffffff000000ffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000ffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000
+000000ffffffffffff000000ffffffffffffffffff000000ffffff000000000000ffffff
+ffffffffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffff000000ffffffffffff000000ffffffffffff
+000000000000000000000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff000000
+000000000000ffffffffffffffffff000000ffffffffffff000000ffffff000000000000
+000000ffffffffffff000000ffffff000000ffffffffffff000000000000000000000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000
+000000000000ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff000000
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000ffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff000000
+000000ffffff000000ffffffffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff
+000000ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffff000000000000000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000000000ffffffffffffffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffff000000ffffffffffff000000ffffffffffff000000000000000000000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000ffffffffffff000000000000000000
+000000000000ffffffffffff000000000000000000000000000000ffffffffffff000000
+000000000000000000000000ffffffffffff000000000000000000000000000000ffffff
+ffffff000000000000000000000000000000ffffffffffff000000000000000000000000
+000000ffffffffffff000000000000000000000000000000ffffffffffff000000000000
+000000000000000000ffffffffffff000000000000000000000000000000ffffffffffff
+000000000000000000000000000000ffffffffffff000000000000000000000000000000
+ffffffffffff000000000000000000000000000000ffffffffffff000000000000000000
+000000000000ffffffffffff000000000000000000000000000000ffffffffffff000000
+000000000000000000000000ffffffffffff000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff
+000000ffffff000000000000ffffffffffff000000ffffffffffff000000ffffffffffff
+ffffff000000ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffffffffff000000ffffff000000ffffffffffff
+000000ffffffffffff000000ffffffffffff000000ffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffffffffffffffff000000000000ffffff000000ffffff
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffff000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffff000000000000000000ffffffffffffffffffffffff000000000000
+000000000000000000000000000000ffffff000000000000000000000000000000000000
+ffffffffffff000000ffffff000000000000ffffffffffffffffffffffff000000000000
+000000ffffffffffff000000000000000000ffffffffffff000000000000ffffffffffff
+ffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffff
+ffffff000000000000000000000000ffffffffffffffffff000000ffffffffffffffffff
+ffffff000000000000ffffffffffff000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffff000000000000
+ffffffffffff000000ffffffffffff000000ffffffffffffffffff000000ffffffffffff
+000000ffffffffffffffffff000000ffffff000000ffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffffffffff000000ffffff000000ffffffffffff000000ffffffffffff000000
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffff000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000ffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffff000000
+000000000000ffffffffffffffffffffffff000000000000000000000000000000000000
+000000ffffff000000000000000000000000000000000000ffffffffffff000000ffffff
+000000000000ffffffffffffffffffffffff000000000000000000ffffffffffff000000
+000000000000ffffffffffff000000000000ffffffffffffffffffffffffffffff000000
+000000000000000000000000000000ffffffffffffffffffffffff000000000000000000
+000000ffffffffffffffffff000000ffffffffffffffffffffffff000000000000ffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000
+000000000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000ffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffff000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffff000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000
+000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000ffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffff000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffff
+
+showpage
+
+% stop using temporary dictionary
+end
+
+% restore original state
+origstate restore
+
+%%Trailer
diff --git a/lib/megaco/doc/src/user_guide.gif b/lib/megaco/doc/src/user_guide.gif
new file mode 100644
index 0000000000..e6275a803d
--- /dev/null
+++ b/lib/megaco/doc/src/user_guide.gif
Binary files differ
diff --git a/lib/megaco/doc/src/warning.gif b/lib/megaco/doc/src/warning.gif
new file mode 100644
index 0000000000..96af52360e
--- /dev/null
+++ b/lib/megaco/doc/src/warning.gif
Binary files differ
diff --git a/lib/megaco/doc/standard/H.248.1-Corr1-200403.doc b/lib/megaco/doc/standard/H.248.1-Corr1-200403.doc
new file mode 100644
index 0000000000..39ef6e4efa
--- /dev/null
+++ b/lib/megaco/doc/standard/H.248.1-Corr1-200403.doc
Binary files differ
diff --git a/lib/megaco/doc/standard/draft-ietf-megaco-h248v2-04.txt b/lib/megaco/doc/standard/draft-ietf-megaco-h248v2-04.txt
new file mode 100644
index 0000000000..abb1df8988
--- /dev/null
+++ b/lib/megaco/doc/standard/draft-ietf-megaco-h248v2-04.txt
@@ -0,0 +1,12079 @@
+
+
+ Media Gateway Control (megaco) C. Groves, M. Pantaleo
+ Internet Draft LM Ericsson
+ Document: draft-ietf-megaco-h248v2-04.txt T. Anderson
+ Expires: October 2003 Lucent Technologies
+ T. Taylor
+ Nortel Networks
+ (Editors)
+ April 2003
+
+
+ The Megaco/H.248 Gateway Control Protocol, version 2
+
+ Status of this Memo
+
+ This document is an Internet-Draft and is in full conformance with
+ all provisions of Section 10 of RFC2026.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ Abstract
+
+ This document describes the second version of the general-purpose
+ gateway control protocol standardized as Megaco in the IETF and as
+ Recommendation H.248 (now H.248.1) in the ITU-T. It is common text
+ with Recommendation H.248.1 (05/02), published by the ITU-T. Megaco
+ v2 includes the corrections to RFC 3015 which resulted in RFC xxxx
+ [draft-ietf-megaco-3015corr-02.txt], plus the following new
+ capabilities:
+
+ - ability to audit specific properties, events, signals and
+ statistics
+ - use of serviceChange to indicate that capabilities have changed in
+ the Media Gateway
+ - playing a signal on the Root Termination
+ - limiting the number of repetitions of transaction pending
+ - allowing topology to be set per stream
+ - ability to audit context properties
+
+
+ Groves et al Expires - October 2003 [Page 1]
+ Megaco Protocol version 2 April 2003
+
+
+ - new Nx64K multiplex type
+ - provision for digit buffering when a digit map completes.
+
+ In addition, the use of the Modem Descriptor was deprecated.
+
+ A detailed list of changes from draft-ietf-megaco-3015corr-
+ 02.txt/H.248.1 (03/02) to this document is given in Appendix II at
+ the end of this document.
+
+ Conventions used in this document
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC-2119.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 2]
+ Megaco Protocol version 2 April 2003
+
+
+ Table of Contents
+
+ 1 SCOPE.................................................6
+
+ 2 REFERENCES............................................6
+ 2.1 Normative references..................................7
+ 2.2 Informative references................................9
+
+ 3 DEFINITIONS..........................................10
+
+ 4 ABBREVIATIONS........................................11
+
+ 5 A NOTE ON CONVENTIONS................................12
+
+ 6 CONNECTION MODEL.....................................12
+ 6.1 Contexts.............................................15
+ 6.1.1 Context attributes and descriptors...................16
+ 6.1.2 Creating, deleting and modifying Contexts............16
+ 6.2 Terminations.........................................16
+ 6.2.1 Termination dynamics.................................20
+ 6.2.2 TerminationIDs.......................................20
+ 6.2.3 Packages.............................................21
+ 6.2.4 Termination properties and descriptors...............22
+ 6.2.5 Root Termination.....................................24
+
+ 7 COMMANDS.............................................25
+ 7.1 Descriptors..........................................26
+ 7.1.1 Specifying parameters................................26
+ 7.1.2 Modem descriptor.....................................27
+ 7.1.3 Multiplex descriptor.................................27
+ 7.1.4 Media descriptor.....................................28
+ 7.1.5 TerminationState descriptor..........................28
+ 7.1.6 Stream descriptor....................................29
+ 7.1.7 LocalControl descriptor..............................30
+ 7.1.8 Local and Remote descriptors.........................31
+ 7.1.9 Events descriptor....................................34
+ 7.1.10 EventBuffer descriptor...............................37
+ 7.1.11 Signals descriptor...................................37
+ 7.1.12 Audit descriptor.....................................39
+ 7.1.13 ServiceChange descriptor.............................40
+ 7.1.14 DigitMap descriptor..................................40
+ 7.1.14.1 DigitMap definition, creation, modification and
+ deletion.........................................40
+ 7.1.14.2 DigitMap Timers......................................41
+ 7.1.14.3 DigitMap Syntax......................................41
+ 7.1.14.4 DigitMap Completion Event............................42
+ 7.1.14.5 DigitMap Procedures..................................43
+ 7.1.14.6 DigitMap Activation..................................45
+ 7.1.14.7 Interaction Of DigitMap and Event Processing.........45
+
+
+ Groves et al Expires - October 2003 [Page 3]
+ Megaco Protocol version 2 April 2003
+
+
+ 7.1.14.8 Wildcards............................................46
+ 7.1.14.9 Example..............................................46
+ 7.1.15 Statistics descriptor................................47
+ 7.1.16 Packages descriptor..................................47
+ 7.1.17 ObservedEvents descriptor............................47
+ 7.1.18 Topology descriptor..................................47
+ 7.1.19 Error Descriptor.....................................51
+
+ 7.2 Command Application Programming Interface............51
+ 7.2.1 Add..................................................52
+ 7.2.2 Modify...............................................53
+ 7.2.3 Subtract.............................................54
+ 7.2.4 Move.................................................56
+ 7.2.5 AuditValue...........................................57
+ 7.2.6 AuditCapabilities....................................60
+ 7.2.7 Notify...............................................62
+ 7.2.8 ServiceChange........................................63
+ 7.2.9 Manipulating and Auditing Context Attributes.........68
+ 7.2.10 Generic Command Syntax...............................69
+
+ 8 TRANSACTIONS.........................................69
+ 8.1 Common parameters....................................71
+ 8.1.1 Transaction Identifiers..............................71
+ 8.1.2 Context Identifiers..................................71
+ 8.2 Transaction Application Programming Interface........71
+ 8.2.1 TransactionRequest...................................72
+ 8.2.2 TransactionReply.....................................72
+ 8.2.3 TransactionPending...................................74
+ 8.3 Messages.............................................75
+
+ 9 TRANSPORT............................................75
+ 9.1 Ordering of Commands.................................76
+ 9.2 Protection against Restart Avalanche.................77
+
+ 10 SECURITY CONSIDERATIONS..............................78
+ 10.1 Protection of Protocol Connections...................79
+ 10.2 Interim AH scheme....................................79
+ 10.3 Protection of Media Connections......................80
+
+ 11 MG-MGC CONTROL INTERFACE.............................81
+ 11.1 Multiple Virtual MGs.................................81
+ 11.2 Cold start...........................................82
+ 11.3 Negotiation of protocol version......................82
+ 11.4 Failure of a MG......................................83
+ 11.5 Failure of an MGC....................................84
+
+ 12 PACKAGE DEFINITION...................................85
+ 12.1 Guidelines for defining packages.....................85
+ 12.1.1 Package..............................................86
+
+
+ Groves et al Expires - October 2003 [Page 4]
+ Megaco Protocol version 2 April 2003
+
+
+ 12.1.2 Properties...........................................87
+ 12.1.3 Events...............................................88
+ 12.1.4 Signals..............................................88
+ 12.1.5 Statistics...........................................89
+ 12.1.6 Procedures...........................................89
+ 12.2 Guidelines to defining Parameters to Events and
+ Signals..........................................89
+ 12.3 Lists................................................90
+ 12.4 Identifiers..........................................90
+ 12.5 Package registration.................................91
+
+ 13 PROFILE DEFINITION...................................91
+
+ 14 IANA CONSIDERATIONS..................................92
+ 14.1 Packages.............................................92
+ 14.2 Error codes..........................................93
+ 14.3 ServiceChange reasons................................93
+ 14.4 Profiles.............................................94
+
+ ANNEX A BINARY ENCODING OF THE PROTOCOL......................95
+ A.1 Coding of wildcards..................................95
+ A.2 ASN.1 syntax specification...........................96
+
+ ANNEX B TEXT ENCODING OF THE PROTOCOL.......................120
+ B.1 Coding of wildcards.................................120
+ B.2 ABNF specification..................................120
+ B.4 Hexadecimal octet sequence..........................137
+
+ ANNEX C TAGS FOR MEDIA STREAM PROPERTIES....................138
+ C.1 General media attributes............................138
+ C.2 Mux properties......................................140
+ C.3 General bearer properties...........................140
+ C.4 General ATM properties..............................141
+ C.5 Frame Relay.........................................145
+ C.6 IP 146
+ C.7 ATM AAL2............................................146
+ C.8 ATM AAL1............................................148
+ C.9 Bearer capabilities.................................150
+ C.10 AAL5 properties.....................................161
+ C.11 SDP equivalents.....................................162
+ C.12 H.245...............................................164
+
+ ANNEX D TRANSPORT OVER IP...................................165
+ D.1 Transport over IP/UDP using Application Level Framing
+ (ALF)............................................165
+ D.1.1 Providing At-Most-Once functionality................165
+ D.1.2 Transaction identifiers and three-way handshake.....166
+ D.1.2.1 Transaction identifiers.............................166
+ D.1.2.2 Three-way handshake.................................166
+
+
+ Groves et al Expires - October 2003 [Page 5]
+ Megaco Protocol version 2 April 2003
+
+
+ D.1.3 Computing retransmission timers.....................167
+ D.1.4 Provisional responses...............................168
+ D.1.5 Repeating Requests, Responses and Acknowledgements..168
+ D.2 Using TCP...........................................170
+ D.2.1 Providing the At-Most-Once functionality............170
+ D.2.2 Transaction identifiers and three-way handshake.....170
+ D.2.3 Computing retransmission timers.....................170
+ D.2.4 Provisional responses...............................171
+ D.2.5 Ordering of commands................................171
+
+ ANNEX E BASIC PACKAGES......................................172
+ E.1 Generic.............................................172
+ E.2 Base Root Package...................................174
+ E.3 Tone Generator Package..............................178
+ E.4 Tone Detection Package..............................179
+ E.5 Basic DTMF Generator Package........................182
+ E.6 DTMF detection Package..............................184
+ E.7 Call Progress Tones Generator Package...............186
+ E.8 Call Progress Tones Detection Package...............187
+ E.9 Analog Line Supervision Package.....................188
+ E.10 Basic Continuity Package............................192
+ E.11 Network Package.....................................195
+ E.12 RTP Package.........................................197
+ E.13 TDM Circuit Package.................................199
+
+ APPENDIX I Example Call Flows..................................201
+ I.1 Residential Gateway to Residential Gateway Call.....201
+ I.1.1 Programming Residential GW Analog Line Terminations
+ for Idle Behaviour..............................201
+ I.1.2 Collecting Originator Digits and Initiating Termination
+ .................................................203
+
+ APPENDIX II CHANGES FROM RFC XXXX [draft-ietf-megaco-3015corr
+ -02.txt].........................................213
+
+ INTELLECTUAL PROPERTY RIGHTS....................................217
+ Acknowledgments.................................................218
+ Authors' Addresses..............................................219
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 6]
+ Megaco Protocol version 2 April 2003
+
+
+ 1 SCOPE
+
+ This document defines the protocols used between elements of a
+ physically decomposed multimedia gateway. There are no functional
+ differences from a system view between a decomposed gateway, with
+ distributed sub-components potentially on more than one physical
+ device, and a monolithic gateway such as described in Recommendation
+ H.246. This document does not define how gateways, multipoint control
+ units or interactive voice response units (IVRs) work. Instead it
+ creates a general framework that is suitable for these applications.
+
+ Packet network interfaces may include IP, ATM or possibly others. The
+ interfaces will support a variety of Switched Circuit Network (SCN)
+ signalling systems, including tone signalling, ISDN, ISUP, QSIG and
+ GSM. National variants of these signalling systems will be supported
+ where applicable.
+
+ Products claiming compliance with Version 1 of H.248.1 shall comply
+ with all of the mandatory requirements of H.248.1 originally approved
+ in 06/2000 and reissued in 03/2002. H.248.1 (03/2002) is common text
+ with RFC xxxx [draft-ietf-megaco-3015corr-03.txt].
+
+ Products claiming compliance with Version 2 of H.248.1 shall comply
+ with all of the mandatory requirements of H.248.1 approved on
+ 05/2002. H.248.1 (05/2002) is common text with this document.
+
+ Products shall indicate the version of the protocol in use by using
+ ServiceChangeVersion as �1� to refer to RFC xxxx/H.248.1 (03/2002)
+ and �2� to refer to this specification/H.248.1 (05/2002).
+
+
+ 2 REFERENCES
+
+ The following ITU-T Recommendations and other references contain
+ provisions which, through reference in this text, constitute
+ provisions of this Recommendation. At the time of publication, the
+ editions indicated were valid. All Recommendations and other
+ references are subject to revision; all users of this Recommendation
+ are therefore encouraged to investigate the possibility of applying
+ the most recent edition of the Recommendations and other references
+ listed below. A list of the currently valid ITU-T Recommendations is
+ regularly published.
+
+ 2.1 Normative references
+
+ - ITU-T Recommendation H.225.0 (2000), Call signalling protocols and
+ media stream packetization for packet-based multimedia
+ communication systems.
+
+
+
+ Groves et al Expires - October 2003 [Page 7]
+ Megaco Protocol version 2 April 2003
+
+
+ - ITU-T Recommendation H.235 (1998), Security and encryption for H-
+ Series (H.323 and other H.245-based) multimedia terminals.
+
+ - ITU-T Recommendation H.245 (1998), Control protocol for multimedia
+ communication.
+
+ - ITU-T Recommendation H.246 (1998), Interworking of H-series
+ multimedia terminals with H-series multimedia terminals and
+ voice/voiceband terminals on GSTN and ISDN.
+
+ - ITU-T Recommendation H.248.4 (2000), Transport over Stream Control
+ Transmission Protocol (SCTP).
+
+ - ITU-T Recommendation H.248.5 (2000), Transport over ATM.
+
+ - ITU-T Recommendation H.248.8 (2002), H.248 Error Codes and Service
+ Change Reasons.
+
+ - ITU-T Recommendation H.323 (1999), Packet-based multimedia
+ communication systems.
+
+ - ITU-T Recommendation I.363.1 (1996), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 1 AAL.
+
+ - ITU-T Recommendation I.363.2 (1997), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 2 AAL.
+
+ - ITU-T Recommendation I.363.5 (1996), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 5 AAL.
+
+ - ITU-T Recommendation I.366.1 (1998), Segmentation and Reassembly
+ Service Specific Convergence Sublayer for the AAL type 2.
+
+ - ITU-T Recommendation I.366.2 (1999), AAL type 2 service specific
+ convergence sublayer for trunking.
+
+ - ITU-T Recommendation I.371 (2000), Traffic control and congestion
+ control in B-ISDN.
+
+ - ITU-T Recommendation Q.763 (1999), Signalling System No. 7 - ISDN
+ user part formats and codes.
+
+ - ITU-T Recommendation Q.765.5 (2001), Application transport
+ mechanism - Bearer independent call control (BICC).
+
+ - ITU-T Recommendation Q.931 (1998), ISDN user-network interface
+ layer 3 specification for basic call control.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 8]
+ Megaco Protocol version 2 April 2003
+
+
+ - ITU-T Recommendation Q.2630.1 (1999), AAL type 2 signalling
+ protocol (Capability Set 1).
+
+ - ITU-T Recommendation Q.2931 (1995), Digital Subscriber Signalling
+ System No. 2 (DSS2) - User-Network Interface (UNI) Layer 3
+ specification for basic call/connection control.
+
+ - ITU-T Recommendation Q.2941.1 (1997), Digital Subscriber
+ Signalling System No. 2 - Generic identifier transport.
+
+ - ITU-T Recommendation Q.2961.1 (1995), Additional signalling
+ capabilities to support traffic parameters for the tagging option
+ and the sustainable call note parameter set.
+
+ - ITU-T Recommendation Q.2961.2 (1997), Additional traffic
+ parameters: Support of ATM transfer capability in the broadband
+ bearer capability information element.
+
+ - ITU-T Recommendation Q.2965.1 (1999), Digital subscriber
+ signalling system No. 2 - Support of Quality of Service classes.
+
+ - ITU-T Recommendation Q.2965.2 (1999), Digital subscriber
+ signalling system No. 2 - Signalling of individual Quality of
+ Service parameters.
+
+ - ITU-T Recommendation V.76 (1996), Generic multiplexer using V.42
+ LAPM-based procedures.
+
+ - ITU-T Recommendation X.213 (1995), Information technology - Open
+ Systems Interconnection - Network service definition plus
+ Amendment 1 (1997), Addition of the Internet protocol address
+ format identifier.
+
+ - ITU-T Recommendation X.680 (1997), Information technology -
+ Abstract Syntax Notation One (ASN.1): Specification of basic
+ notation.
+
+ - ITU-T Recommendation X.690 (1997), Information Technology - ASN.1
+ Encoding Rules: Specification of Basic Encoding Rules (BER),
+ Canonical Encoding Rules (CER) and Distinguished Encoding Rules
+ (DER).
+
+ - ATM Forum (1996), ATM User-Network Interface (UNI) Signalling
+ Specification - Version 4.0.
+
+ - RFC 1006, ISO Transport Service on top of the TCP, Version 3.
+
+ - RFC 2026, The Internet Standards Process -- Revision 3.
+
+
+
+ Groves et al Expires - October 2003 [Page 9]
+ Megaco Protocol version 2 April 2003
+
+
+ - RFC 2119, Key words for use in RFCs to Indicate Requirement
+ Levels.
+
+ - RFC 2234, Augmented BNF for Syntax Specifications: ABNF.
+
+ - RFC 2327, SDP: Session Description Protocol.
+
+ - RFC 2402, IP Authentication Header.
+
+ - RFC 2406, IP Encapsulating Security Payload (ESP).
+
+ 2.2 Informative references
+
+ - ITU-T Recommendation E.180/Q.35 (1998), Technical characteristics
+ of tones for the telephone service.
+
+ - ITU-T Recommendation G.711 (1988), Pulse Code Modulation (PCM) of
+ voice frequencies.
+
+ - ITU-T Recommendation H.221 (1999), Frame structure for a 64 to
+ 1920 kbit/s channel in audiovisual teleservices.
+
+ - ITU-T Recommendation H.223 (1996), Multiplexing protocol for low
+ bit rate multimedia communication.
+
+ - ITU-T Recommendation H.226 (1998), Channel aggregation protocol
+ for multilink operation on circuit-switched networks.
+
+ - ITU-T Recommendation Q.724 (1998), Signalling procedures.
+
+ - ITU-T Recommendation Q.764 (1999), Signalling system No. 7 - ISDN
+ user part signalling procedures.
+
+ - ITU-T Recommendation Q.1902.4 (2001), Bearer independent call
+ control protocol - Basic call procedures.
+
+ - RFC 768, User Datagram Protocol.
+
+ - RFC 791, Internet protocol.
+
+ - RFC 793, Transmission control protocol.
+
+ - RFC 1661, The Point-to-Point Protocol (PPP).
+
+ - RFC 1889, RTP: A Transport Protocol for Real-Time Applications.
+
+ - RFC 1890, RTP Profile for Audio and Video Conferences with Minimal
+ Control.
+
+
+
+ Groves et al Expires - October 2003 [Page 10]
+ Megaco Protocol version 2 April 2003
+
+
+ - RFC 2401, Security Architecture for the Internet Protocol.
+
+ - RFC 2543, SIP: Session Initiation Protocol.
+
+ - RFC 2460, Internet Protocol, Version 6 (IPv6) Specification.
+
+ - RFC 2805, Media Gateway Control Protocol Architecture and
+ Requirements.
+
+
+ 3 DEFINITIONS
+
+ This document defines the following terms:
+
+ Access gateway:
+ A type of gateway that provides a User-Network Interface (UNI) such
+ as ISDN.
+
+ Descriptor:
+ A syntactic element of the protocol that groups related properties.
+ For instance, the properties of a media flow on the MG can be set by
+ the MGC by including the appropriate descriptor in a command.
+
+ Media Gateway (MG):
+ The media gateway converts media provided in one type of network to
+ the format required in another type of network. For example, a MG
+ could terminate bearer channels from a switched circuit network (e.g.
+ DS0s) and media streams from a packet network (e.g. RTP streams in an
+ IP network). This gateway may be capable of processing audio, video
+ and T.120 alone or in any combination, and will be capable of full
+ duplex media translations. The MG may also play audio/video messages
+ and perform other IVR functions, or may perform media conferencing.
+
+ Media Gateway Controller (MGC):
+ Controls the parts of the call state that pertain to connection
+ control for media channels in a MG.
+
+ Multipoint Control Unit (MCU):
+ An entity that controls the setup and coordination of a multi-user
+ conference that typically includes processing of audio, video and
+ data.
+
+ Residential gateway:
+ A gateway that interworks an analogue line to a packet network. A
+ residential gateway typically contains one or two analogue lines and
+ is located at the customer premises.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 11]
+ Megaco Protocol version 2 April 2003
+
+
+ SCN FAS signalling gateway:
+ This function contains the SCN Signalling Interface that terminates
+ SS7, ISDN or other signalling links where the call control channel
+ and bearer channels are collocated in the same physical span.
+
+ SCN NFAS signalling gateway:
+ This function contains the SCN Signalling Interface that terminates
+ SS7 or other signalling links where the call control channels are
+ separated from bearer channels.
+
+ Stream:
+ Bidirectional media or control flow received/sent by a media gateway
+ as part of a call or conference.
+
+ Trunk:
+ A communication channel between two switching systems such as a DS0
+ on a T1 or E1 line.
+
+ Trunking gateway:
+ A gateway between SCN network and packet network that typically
+ terminates a large number of digital circuits.
+
+
+ 4 ABBREVIATIONS
+
+ This document uses the following abbreviations:
+
+ ALF Application Layer Framing
+
+ ATM Asynchronous Transfer Mode
+
+ CAS Channel Associated Signalling
+
+ DTMF Dual Tone Multi-Frequency
+
+ FAS Facility Associated Signalling
+
+ GSM Global System for Mobile communications
+
+ GW GateWay
+
+ IANA Internet Assigned Numbers Authority (superseded by Internet
+ Corporation for Assigned Names and Numbers (ICANN))
+
+ IP Internet Protocol
+
+ ISUP ISDN User Part
+
+ IVR Interactive Voice Response
+
+
+ Groves et al Expires - October 2003 [Page 12]
+ Megaco Protocol version 2 April 2003
+
+
+ MG Media Gateway
+
+ MGC Media Gateway Controller
+
+ NFAS Non-Facility Associated Signalling
+
+ PRI Primary Rate Interface
+
+ PSTN Public Switched Telephone Network
+
+ QoS Quality of Service
+
+ RTP Real-time Transport Protocol
+
+ SCN Switched Circuit Network
+
+ SG Signalling Gateway
+
+ SS7 Signalling System No. 7
+
+
+ 5 A NOTE ON CONVENTIONS
+
+ According to ITU-T practice, "SHOULD" refers to a suggested but
+ optional feature or procedure. "SHOULD" as used by the ITU-T is thus
+ a weaker requirement level than in IETF practice as defined in RFC
+ 2119 and cited at the beginning of this document. In view of this
+ difference, the present document calls out all instances of "SHOULD"
+ for review and replacement by "suggested" where that appears to be
+ the intent.
+
+ 6 CONNECTION MODEL
+
+ The connection model for the protocol describes the logical entities,
+ or objects, within the Media Gateway that can be controlled by the
+ Media Gateway Controller. The main abstractions used in the
+ connection model are Terminations and Contexts.
+
+ A Termination sources and/or sinks one or more streams. In a
+ multimedia conference, a Termination can be multimedia and sources or
+ sinks multiple media streams. The media stream parameters, as well as
+ bearer parameters are encapsulated within the Termination.
+
+ A Context is an association between a collection of Terminations.
+ There is a special type of Context, the null Context, which contains
+ all Terminations that are not associated to any other Termination.
+ For instance, in a decomposed access gateway, all idle lines are
+ represented by Terminations in the null Context.
+
+
+
+ Groves et al Expires - October 2003 [Page 13]
+ Megaco Protocol version 2 April 2003
+
+
+ Following is a graphical depiction of these concepts. The diagram of
+ Figure 1 gives several examples and is not meant to be an all-
+ inclusive illustration. The asterisk box in each of the Contexts
+ represents the logical association of Terminations implied by the
+ Context.
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context +-------------+ | |
+ | | | Termination | | |
+ | | |-------------| | |
+ | | +-------------+ +->| SCN Bearer |<---+->
+ | | | Termination | +-----+ | | Channel | | |
+ | | |-------------| | |---+ +-------------+ | |
+ <-+--->| RTP Stream |---| * | | |
+ | | | | | |---+ +-------------+ | |
+ | | +-------------+ +-----+ | | Termination | | |
+ | | | |-------------| | |
+ | | +->| SCN Bearer |<---+->
+ | | | Channel | | |
+ | | +-------------+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | |
+ | +------------------------------+ |
+ | (NULL Context) |Context | |
+ | +-------------+ | +-------------+ | |
+ | | Termination | | +-----+ | Termination | | |
+ | |-------------| | | | |-------------| | |
+ | | SCN Bearer | | | * |------| SCN Bearer |<---+->
+ | | Channel | | | | | Channel | | |
+ | +-------------+ | +-----+ +-------------+ | |
+ | +------------------------------+ |
+ | |
+ | |
+ | +-------------------------------------------------+ |
+ | |Context | |
+ | | +-------------+ +-------------+ | |
+ | | | Termination | +-----+ | Termination | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| SCN Bearer |---| * |------| SCN Bearer |<---+->
+ | | | Channel | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ | ___________________________________________________ |
+ +------------------------------------------------------+
+
+ Figure 1: Examples of Megaco/H.248 Connection Model
+
+
+ Groves et al Expires - October 2003 [Page 14]
+ Megaco Protocol version 2 April 2003
+
+
+
+
+ The example in Figure 2 shows an example of one way to accomplish a
+ call-waiting scenario in a decomposed access gateway, illustrating
+ the relocation of a Termination between Contexts. Terminations T1 and
+ T2 belong to Context C1 in a two-way audio call. A second audio call
+ is waiting for T1 from Termination T3. T3 is alone in Context C2. T1
+ accepts the call from T3, placing T2 on hold. This action results in
+ T1 moving into Context C2, as shown in Figure 3.
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context C1 | |
+ | | +-------------+ +-------------+ | |
+ | | | Term. T2 | +-----+ | Term. T1 | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| RTP Stream |---| * |------| SCN Bearer |<---+->
+ | | | | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | +-------------------------------------------------+ |
+ | |Context C2 | |
+ | | +-------------+ | |
+ | | +-----+ | Term. T3 | | |
+ | | | | |-------------| | |
+ | | | * |------| SCN Bearer |<---+->
+ | | | | | Channel | | |
+ | | +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ +------------------------------------------------------+
+
+ Figure 2: Example Call Waiting Scenario / Alerting Applied to T1
+
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context C1 | |
+ | | +-------------+ | |
+ | | | Term. T2 | +-----+ | |
+ | | |-------------| | | | |
+ <-+--->| RTP Stream |---| * | | |
+ | | | | | | | |
+ | | +-------------+ +-----+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | +-------------------------------------------------+ |
+
+
+ Groves et al Expires - October 2003 [Page 15]
+ Megaco Protocol version 2 April 2003
+
+
+ | |Context C2 | |
+ | | +-------------+ +-------------+ | |
+ | | | Term. T1 | +-----+ | Term. T3 | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| SCN Bearer |---| * |------| SCN Bearer |<---+->
+ | | | Channel | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ +------------------------------------------------------+
+
+ Figure 3. Example Call Waiting Scenario / Answer by T1
+
+
+
+ 6.1 Contexts
+
+ A Context is an association between a number of Terminations. The
+ Context describes the topology (who hears/sees whom) and the media
+ mixing and/or switching parameters if more than two Terminations are
+ involved in the association.
+
+ There is a special Context called the null Context. It contains
+ Terminations that are not associated to any other Termination.
+ Terminations in the null Context can have their parameters examined
+ or modified, and may have events detected on them.
+
+ In general, an Add command is used to add Terminations to Contexts.
+ If the MGC does not specify an existing Context to which the
+ Termination is to be added, the MG creates a new Context. A
+ Termination may be removed from a Context with a Subtract command,
+ and a Termination may be moved from one Context to another with a
+ Move command. A Termination SHALL exist in only one Context at a
+ time.
+
+ The maximum number of Terminations in a Context is a MG property.
+ Media gateways that offer only point-to-point connectivity might
+ allow at most two Terminations per Context. Media gateways that
+ support multipoint conferences might allow three or more Terminations
+ per Context.
+
+ 6.1.1 Context attributes and descriptors
+
+ The attributes of Contexts are:
+
+ - ContextID.
+
+ - The topology (who hears/sees whom).
+
+
+
+
+ Groves et al Expires - October 2003 [Page 16]
+ Megaco Protocol version 2 April 2003
+
+
+ The topology of a Context describes the flow of media between the
+ Terminations within a Context. In contrast, the mode of a
+ Termination (send/receive/...) describes the flow of the media at
+ the ingress/egress of the media gateway.
+
+ - The priority is used for a Context in order to provide the MG with
+ information about a certain precedence handling for a Context. The
+ MGC can also use the priority to control autonomously the traffic
+ precedence in the MG in a smooth way in certain situations (e.g.
+ restart), when a lot of Contexts must be handled simultaneously.
+ Priority 0 is the lowest priority and a priority of 15 is the
+ highest priority.
+
+ - An indicator for an emergency call is also provided to allow a
+ preference handling in the MG.
+
+ 6.1.2 Creating, deleting and modifying Contexts
+
+ The protocol can be used to (implicitly) create Contexts and modify
+ the parameter values of existing Contexts. The protocol has commands
+ to add Terminations to Contexts, subtract them from Contexts, and to
+ move Terminations between Contexts. Contexts are deleted implicitly
+ when the last remaining Termination is subtracted or moved out.
+
+ 6.2 Terminations
+
+ A Termination is a logical entity on a MG that sources and/or sinks
+ media and/or control streams. A Termination is described by a number
+ of characterizing Properties, which are grouped in a set of
+ Descriptors that are included in commands. Terminations have unique
+ identities (TerminationIDs), assigned by the MG at the time of their
+ creation.
+
+ Terminations representing physical entities have a semi-permanent
+ existence. For example, a Termination representing a TDM channel
+ might exist for as long as it is provisioned in the gateway.
+ Terminations representing ephemeral information flows, such as RTP
+ flows, would usually exist only for the duration of their use.
+
+ Ephemeral Terminations are created by means of an Add command. They
+ are destroyed by means of a Subtract command. In contrast, when a
+ physical Termination is Added to or Subtracted from a Context, it is
+ taken from or to the null Context, respectively.
+
+ Terminations may have signals applied to them (see 7.1.11).
+ Terminations may be programmed to detect Events, the occurrence of
+ which can trigger notification messages to the MGC, or action by the
+ MG. Statistics may be accumulated on a Termination. Statistics are
+
+
+
+ Groves et al Expires - October 2003 [Page 17]
+ Megaco Protocol version 2 April 2003
+
+
+ reported to the MGC upon request (by means of the AuditValue command,
+ see 7.2.5) and when the Termination is subtracted from a context.
+
+ Multimedia gateways may process multiplexed media streams. For
+ example, Recommendation H.221 describes a frame structure for
+ multiple media streams multiplexed on a number of digital 64 kbit/s
+ channels. Such a case is handled in the connection model in the
+ following way. For every bearer channel that carries part of the
+ multiplexed streams, there is a physical or ephemeral "bearer
+ Termination". The bearer Terminations that source/sink the digital
+ channels are connected to a separate Termination called the
+ "multiplexing Termination". The multiplexing termination is an
+ ephemeral termination representing a frame-oriented session. The
+ MultiplexDescriptor for this Termination describes the multiplex used
+ (e.g. H.221 for an H.320 session) and indicates the order in which
+ the contained digital channels are assembled into a frame.
+
+ Multiplexing terminations may be cascades (e.g., H.226 multiplex of
+ digital channels feeding into a H.223 multiplex supporting an H.324
+ session).
+
+ The individual media streams carried in the session are described by
+ StreamDescriptors on the multiplexing Termination. These media
+ streams can be associated with streams sourced/sunk by Terminations
+ in the Context other than the bearer Terminations supporting the
+ multiplexing Termination. Each bearer Termination supports only a
+ single data stream. These data streams do not appear explicitly as
+ streams on the multiplexing Termination and they are hidden from the
+ rest of the context.
+
+ Figures 4, 5, 6, and 6a illustrate typical applications of the
+ multiplexing termination and Multiplex Descriptor.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 18]
+ Megaco Protocol version 2 April 2003
+
+
+ +-----------------------------------+
+ | Context +-------+ |
+ +----+ | | |
+ Circuit 1 -|--| TC1|---------+ Tmux | |
+ | +----+ (Str 1) | | Audio +-----+
+ | | | +-----*-----+ |-----
+ | +----+ | H.22x | Stream 1 | |
+ Circuit 2 -|--| TC2|---------+ multi-| | TR1 |
+ | +----+ (Str 1) | plex | |(RTP)|
+ | | | | Video | |
+ | +----+ | +-----*-----+ |-----
+ Circuit 3 -|--| TC3|---------+ | Stream 2 | |
+ / +----+ (Str 1) | | +-----+
+ / | +-------+ |
+ / +-----------------\-----------------+
+ Audio, video, and control \
+ signals are carried in frames Tmux is an ephemeral with two
+ spanning the circuits. explicit Stream Descriptors
+ and a Multiplex Descriptor.
+
+ Figure 4: Multiplexed Termination Scenario - Circuit to Packet
+ (Asterisks * denote the centre of the context)
+
+
+
+ Context
+ +--------------------------------------+
+ | +-------+ +-------+ |
+ +----+ | | | | +----+
+ Circuit 1 ----| TC1|---+ Tmux1 | Audio | Tmux2 +---| TC4|---
+ +----+ | +---*----+ | +----+
+ | | | Str 1 | | |
+ +----+ | H.22x | | H.22x | +----+
+ Circuit 2 ----| TC2|---+ multi-| | multi-+---| TC5|---
+ +----+ | plex | | plex | +----+
+ | | | Video | | |
+ +----+ | +---*----+ | +----+
+ Circuit 3 ----| TC3|---+ | Str 2 | +---| TC6|---
+ +----+ | | | | +----+
+ | +-------+ +-------+ |
+ +-----------------\-----/--------------+
+ \ /
+ Tmux1 and Tmux2 are ephemerals each with two
+ . explicit Stream Descriptors and a Multiplex Descriptor.
+
+ Figure 5: Multiplexed Termination Scenario - Circuit to Circuit
+ (Asterisks * denote the centre of the context)
+
+
+
+
+ Groves et al Expires - October 2003 [Page 19]
+ Megaco Protocol version 2 April 2003
+
+
+
+ +-----------------------------------+
+ | Context +-------+ |
+ +----+ | | |
+ Circuit 1 -|--| TC1|---------+ Tmux | |
+ | +----+ (Str 1) | | Audio +-----+
+ | | | +-----*-----+ TR1 |-----
+ | +----+ | H.22x | Stream 1 |(RTP)|
+ Circuit 2 -|--| TC2|---------+ multi-| +-----+
+ | +----+ (Str 1) | plex | |
+ | | | | Video +-----+
+ | +----+ | +-----*-----+ TR2 |-----
+ Circuit 3 -|--| TC3|---------+ | Stream 2 |(RTP)|
+ / +----+ (Str 1) | | +-----+
+ / | +-------+ |
+ / +-----------------\-----------------+
+ Audio, video, and control \
+ signals are carried in frames Tmux is an ephemeral with two
+ spanning the circuits. explicit Stream Descriptors
+ and a Multiplex Descriptor.
+
+ Figure 6: Multiplexed Termination Scenario - Single to Multiple
+ Terminations
+ (Asterisks * denote the centre of the context)
+
+
+
+
+ Context
+ +---------------------------------------------+
+ | +-------+ +-------+ |
+ Cct 1 +----+ | | | | Audio +-----+
+ ----| TC1|---+ Tmux1 | | Tmux2 +-----*-----| TR1 |-----
+ +----+ | | | | Stream 1 |(RTP)|
+ | | | Data | | +-----+
+ Cct 2 +----+ | H.226 +-------+ H.223 | |
+ ----| TC2|---+ multi-|(Str 1)| multi-| Control +-----+
+ +----+ | plex | | plex +-----*-----+ Tctl|-----
+ | | | | | Stream 3 +-----+
+ Cct 3 +----+ | | | | |
+ ----| TC3|---+ | | | +-----+
+ +----+ | | | +-----*-----+ TR2 |-----
+ | +-------+ | | Video |(RTP)|
+ | +-------+ Stream 2 +-----+
+ | |
+ +---------------------------------------------+
+ Tmux1 has a Multiplex Descriptor and a single data stream.
+ Tmux2 has a Multiplex Descriptor with a single bearer and
+ three explicit Stream Descriptors.
+
+
+ Groves et al Expires - October 2003 [Page 20]
+ Megaco Protocol version 2 April 2003
+
+
+
+ Figure 6a: Multiplexed Termination Scenario - Cascaded Multiplexes
+ (Asterisks * denote the centre of the context)
+ Note: this figure does not appear in Rec. H.248.1.
+
+ ----
+
+ Unlike the multiplexing terminations described in the previous
+ paragraphs, multiplexed bearer terminations, which represent
+ multiplexed bearers such as ATM AAL Type 2 bearers, carry no media
+ streams. They are present strictly for the purpose of modeling the
+ creation and destruction of the actual bearer. When a new
+ multiplexed bearer is to be created, an ephemeral Termination is
+ created in a Context established for this purpose. When the
+ Termination is subtracted, the multiplexed bearer is destroyed.
+
+ 6.2.1 Termination dynamics
+
+ The protocol can be used to create new Terminations and to modify
+ property values of existing Terminations. These modifications include
+ the possibility of adding or removing events and/or signals. The
+ Termination properties, and events and signals are described in the
+ ensuing subclauses. An MGC can only release/modify Terminations and
+ the resources that the Termination represents, which it has
+ previously seized via e.g. the Add command.
+
+ 6.2.2 TerminationIDs
+
+ Terminations are referenced by a TerminationID, which is an arbitrary
+ schema chosen by the MG.
+
+ TerminationIDs of physical Terminations are provisioned in the Media
+ Gateway. The TerminationIDs may be chosen to have structure. For
+ instance, a TerminationID may consist of trunk group and a trunk
+ within the group.
+
+ A wildcarding mechanism using two types of wildcards can be used with
+ TerminationIDs. The two wildcards are ALL and CHOOSE. The former is
+ used to address multiple Terminations at once, while the latter is
+ used to indicate to a media gateway that it must select a Termination
+ satisfying the partially specified TerminationID. This allows, for
+ instance, that a MGC instructs a MG to choose a circuit within a
+ trunk group.
+
+ When ALL is used in the TerminationID of a command, the effect is
+ identical to repeating the command with each of the matching
+ TerminationIDs. The use of ALL does not address the ROOT termination.
+ Since each of these commands may generate a response, the size of the
+ entire response may be large. If individual responses are not
+
+
+ Groves et al Expires - October 2003 [Page 21]
+ Megaco Protocol version 2 April 2003
+
+
+ required, a wildcard response may be requested. In such a case, a
+ single response is generated, which contains the UNION of all of the
+ individual responses which otherwise would have been generated, with
+ duplicate values suppressed. For instance, given a Termination Ta
+ with properties p1=a, p2=b and Termination Tb with properties p2=c,
+ p3=d, a UNION response would consist of a wildcarded TerminationId
+ and the sequence of properties p1=a, p2=b,c and p3=d. Wildcard
+ response may be particularly useful in the Audit commands.
+
+ The encoding of the wildcarding mechanism is detailed in Annexes A
+ and B.
+
+ 6.2.3 Packages
+
+ Different types of gateways may implement Terminations that have
+ widely differing characteristics. Variations in Terminations are
+ accommodated in the protocol by allowing Terminations to have
+ optional Properties, Events, Signals and Statistics implemented by
+ MGs.
+
+ In order to achieve MG/MGC interoperability, such options are grouped
+ into Packages, and typically a Termination realizes a set of such
+ Packages. More information on definition of packages can be found in
+ clause 12. An MGC can audit a Termination to determine which Packages
+ it realizes.
+
+ Properties, Events, Signals and Statistics defined in Packages, as
+ well as parameters to them, are referenced by identifiers (Ids).
+ Identifiers are scoped. For each package, PropertyIds, EventIds,
+ SignalIds, StatisticsIds and ParameterIds have unique name spaces and
+ the same identifier may be used in each of them. Two PropertyIds in
+ different packages may also have the same identifier, etc.
+
+ To support a particular package the MG must support all properties,
+ signals, events and statistics defined in a package. It must also
+ support all Signal and Event parameters. The MG may support a subset
+ of the values listed in a package for a particular Property or
+ Parameter.
+
+ When packages are extended, the properties, events, signals and
+ statistics defined in the base package can be referred to using
+ either the extended package name or the base package name. For
+ example, if Package A defines event e1, and Package B extends Package
+ A, then B/e1 is an event for a termination implementing Package B. By
+ definition, the MG MUST also implement the base Package, but it is
+ optional to publish the base package as an allowed interface. If it
+ does publish A, then A would be reported on the Package Descriptor
+ in AuditValue as well as B, and event A/e1 would be available on a
+ termination. If the MG does not publish A, then only B/e1 would be
+
+
+ Groves et al Expires - October 2003 [Page 22]
+ Megaco Protocol version 2 April 2003
+
+
+ available. If published through AuditValue, A/e1 and B/e1 are the
+ same event.
+
+ For improved interoperability and backward compatibility, an MG MAY
+ publish all Packages supported by its Terminations, including base
+ Packages from which extended Packages are derived. An exception to
+ this is in cases where the base packages are expressly "Designed to
+ be extended only".
+
+ 6.2.4 Termination properties and descriptors
+
+ Terminations have properties. The properties have unique PropertyIDs.
+ Most properties have default values, which are explicitly defined in
+ this protocol specification or in a package (see clause 12) or set by
+ provisioning. If not provisioned otherwise, the properties in all
+ descriptors except TerminationState and LocalControl default to
+ empty/"no value" when a Termination is first created or returned to
+ the null Context. The default contents of the two exceptions are
+ described in 7.1.5 and 7.1.7.
+
+ The provisioning of a property value in the MG will override any
+ default value, be it supplied in this protocol specification or in a
+ package. Therefore if it is essential for the MGC to have full
+ control over the property values of a Termination, it SHOULD supply
+ explicit values when ADDing the Termination to a Context.
+ Alternatively, for a physical Termination the MGC can determine any
+ provisioned property values by auditing the Termination while it is
+ in the NULL Context.
+
+ There are a number of common properties for Terminations and
+ properties specific to media streams. The common properties are also
+ called the Termination state properties. For each media stream, there
+ are local properties and properties of the received and transmitted
+ flows.
+
+ Properties not included in the base protocol are defined in Packages.
+ These properties are referred to by a name consisting of the
+ PackageName and a PropertyId. Most properties have default values
+ described in the Package description. Properties may be read-only or
+ read/write. The possible values of a property may be audited, as can
+ their current values. For properties that are read/write, the MGC can
+ set their values. A property may be declared as "Global" which has a
+ single value shared by all Terminations realizing the package.
+ Related properties are grouped into descriptors for convenience.
+
+ When a Termination is added to a Context, the value of its read/write
+ properties can be set by including the appropriate descriptors as
+ parameters to the Add command. Similarly, a property of a Termination
+ in a Context may have its value changed by the Modify command.
+
+
+ Groves et al Expires - October 2003 [Page 23]
+ Megaco Protocol version 2 April 2003
+
+
+ Properties may also have their values changed when a Termination is
+ moved from one Context to another as a result of a Move command. In
+ some cases, descriptors are returned as output from a command.
+
+ In general, if a Descriptor is completely omitted from one of the
+ aforementioned Commands, the properties in that Descriptor retain
+ their prior values for the Termination(s) upon which the Command
+ acts. On the other hand, if some read/write properties are omitted
+ from a Descriptor in a Command (i.e., the Descriptor is only
+ partially specified), those properties will be reset to their default
+ values for the Termination(s) upon which the Command acts, unless the
+ package specifies other behavior. For more details, see clause 7.1
+ dealing with the individual Descriptors.
+
+ The following table lists all of the possible descriptors and their
+ use. Not all descriptors are legal as input or output parameters to
+ every command.
+
+ Descriptor name Description
+
+ Modem Identifies modem type and properties when
+ applicable(*).
+
+ Mux Describes multiplex type for multimedia
+ Terminations (e.g. H.221, H.223, H.225.0) and
+ Terminations forming the input mux.
+
+ Media A list of media stream specifications (see
+ 7.1.4).
+
+ TerminationState Properties of a Termination (which can be
+ defined in Packages) that are not stream
+ specific.
+
+ Stream A list of remote/local/localControl
+ descriptors for a single stream.
+
+ Local Contains properties that specify the media
+ flows that the MG receives from the remote
+ entity.
+
+ Remote Contains properties that specify the media
+ flows that the MG sends to the remote entity.
+
+ LocalControl Contains properties (which can be defined in
+ packages) that are of interest between the MG
+ and the MGC.
+
+
+
+ Groves et al Expires - October 2003 [Page 24]
+ Megaco Protocol version 2 April 2003
+
+
+ Descriptor name Description
+
+ Events Describes events to be detected by the MG and
+ what to do when an event is detected.
+
+ EventBuffer Describes events to be detected by the MG when
+ Event Buffering is active.
+
+ Signals Describes signals (see 7.1.11) applied to
+ Terminations.
+
+ Audit In Audit commands, identifies which
+ information is desired.
+
+ Packages In AuditValue, returns a list of Packages
+ realized by Termination.
+
+ DigitMap Defines patterns against which sequences of a
+ specified set of events are to be matched so
+ they can be reported as a group rather than
+ singly.
+
+ ServiceChange In ServiceChange, what, why service change
+ occurred, etc.
+
+ ObservedEvents In Notify or AuditValue, report of events
+ observed.
+
+ Statistics In Subtract and Audit, report of Statistics
+ kept on a Termination.
+
+ Topology Specifies flow directions between Terminations
+ in a Context.
+
+ Error Contains an error code and optionally error
+ text; it may occur in command replies and in
+ Notify requests.
+
+ (*) ModemDescriptor has been deprecated in Megaco v2/H.248.1
+ (05/2002).
+
+
+
+ 6.2.5 Root Termination
+
+ Occasionally, a command must refer to the gateway as an entity in
+ itself, rather than a Termination within it. A special TerminationID,
+ "Root" is reserved for this purpose. Packages may be defined on Root.
+
+
+ Groves et al Expires - October 2003 [Page 25]
+ Megaco Protocol version 2 April 2003
+
+
+ Root thus may have properties, events, signals and statistics.
+ Accordingly, the root TerminationID may appear in:
+
+ - a Modify command - to change a property, send a signal or set an
+ event
+
+ - a Notify command - to report an event
+
+ - an AuditValue return - to examine the values of properties and
+ statistics implemented on root
+
+ - an AuditCapability - to determine what properties of root are
+ implemented
+
+ - a ServiceChange - to declare the gateway in or out of service.
+
+ Any other use of the root TerminationID is an error. Error code 410 -
+ "Incorrect identifier" shall be returned in these cases.
+
+
+ 7 COMMANDS
+
+ The protocol provides commands for manipulating the logical entities
+ of the protocol connection model, Contexts and Terminations. Commands
+ provide control at the finest level of granularity supported by the
+ protocol. For example, Commands exist to add Terminations to a
+ Context, modify Terminations, subtract Terminations from a Context,
+ and audit properties of Contexts or Terminations. Commands provide
+ for complete control of the properties of Contexts and Terminations.
+ This includes specifying which events a Termination is to report,
+ which signals/actions are to be applied to a Termination and
+ specifying the topology of a Context (who hears/sees whom).
+
+ Most commands are for the specific use of the Media Gateway
+ Controller as command initiator in controlling Media Gateways as
+ command responders. The exceptions are the Notify and ServiceChange
+ commands: Notify is sent from Media Gateway to Media Gateway
+ Controller, and ServiceChange may be sent by either entity. Below is
+ an overview of the commands; they are explained in more detail in
+ 7.2.
+
+ 1) Add: The Add command adds a Termination to a Context. The Add
+ command on the first Termination in a Context is used to create a
+ Context.
+
+ 2) Modify: The Modify command modifies the properties, events and
+ signals of a Termination.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 26]
+ Megaco Protocol version 2 April 2003
+
+
+ 3) Subtract: The Subtract command disconnects a Termination from its
+ Context and returns statistics on the Termination's participation
+ in the Context. The Subtract command on the last Termination in a
+ Context deletes the Context.
+
+ 4) Move: The Move command atomically moves a Termination to another
+ Context.
+
+ 5) AuditValue: The AuditValue command returns the current state of
+ properties, events, signals and statistics of Terminations.
+
+ 6) AuditCapabilities: The AuditCapabilities command returns all the
+ possible values for Termination properties, events and signals
+ allowed by the Media Gateway.
+
+ 7) Notify: The Notify command allows the Media Gateway to inform the
+ Media Gateway Controller of the occurrence of events in the Media
+ Gateway.
+
+ 8) ServiceChange: The ServiceChange command allows the Media Gateway
+ to notify the Media Gateway Controller that a Termination or group
+ of Terminations is about to be taken out of service or has just
+ been returned to service. ServiceChange is also used by the MG to
+ announce its availability to a MGC (registration), and to notify
+ the MGC of impending or completed restart of the MG. The MGC may
+ announce a handover to the MG by sending it a ServiceChange
+ command. The MGC may also use ServiceChange to instruct the MG to
+ take a Termination or group of Terminations in or out of service.
+
+ These commands are detailed in 7.2.1 through 7.2.8.
+
+ 7.1 Descriptors
+
+ The parameters to a command are termed Descriptors. A descriptor
+ consists of a name and a list of items. Some items may have values.
+ Many Commands share common descriptors. This subclause enumerates
+ these descriptors. Descriptors may be returned as output from a
+ command. In any such return of descriptor contents, an empty
+ descriptor is represented by its name unaccompanied by any list.
+ Parameters and parameter usage specific to a given Command type are
+ described in the subclause that describes the Command.
+
+ 7.1.1 Specifying parameters
+
+ Command parameters are structured into a number of descriptors. In
+ general, the text format of descriptors is
+ DescriptorName=<someID>{parm=value, parm=value, ...}.
+
+ Parameters may be fully specified, overspecified or underspecified:
+
+
+ Groves et al Expires - October 2003 [Page 27]
+ Megaco Protocol version 2 April 2003
+
+
+ 1) Fully specified parameters have a single, unambiguous value that
+ the command initiator is instructing the command responder to use
+ for the specified parameter.
+
+ 2) Underspecified parameters, using the CHOOSE value, allow the
+ command responder to choose any value it can support.
+
+ 3) Overspecified parameters have a list of potential values. The list
+ order specifies the command initiator's order of preference of
+ selection. The command responder chooses one value from the
+ offered list and returns that value to the command initiator.
+
+ If a required descriptor other than the Audit descriptor is
+ unspecified (i.e. entirely absent) from a command, the previous
+ values set in that descriptor for that Termination, if any, are
+ retained. In commands other than Subtract, a missing Audit descriptor
+ is equivalent to an empty Audit descriptor. The Behaviour of the MG
+ with respect to unspecified parameters within a descriptor varies
+ with the descriptor concerned, as indicated in succeeding subclauses.
+ Whenever a parameter is underspecified or overspecified, the
+ descriptor containing the value chosen by the responder is included
+ as output from the command.
+
+ Each command specifies the TerminationId the command operates on.
+ This TerminationId may be "wildcarded". When the TerminationId of a
+ command is wildcarded, the effect shall be as if the command was
+ repeated with each of the TerminationIds matched.
+
+ 7.1.2 Modem descriptor
+
+ The Modem descriptor specifies the modem type and parameters, if any,
+ required for use in e.g. H.324 and text conversation. The descriptor
+ includes the following modem types: V.18, V.22, V.22 bis, V.32, V.32
+ bis, V.34, V.90, V.91, Synchronous ISDN, and allows for extensions.
+ By default, no Modem descriptor is present in a Termination.
+
+ Use of the ModemDescriptor is deprecated in Megaco v2/H.248.1
+ (05/2002) and subsequent versions. This means that the
+ ModemDescriptor shall not be included as part of transmitted content
+ and if received shall either be ignored or processed at the option of
+ the implementation. Modem type is to be specified as an attribute of
+ data streams in LocalDescriptor and RemoteDescriptor.
+
+ 7.1.3 Multiplex descriptor
+
+ In multimedia calls, a number of media streams are carried on a
+ (possibly different) number of bearers. The multiplex descriptor
+ associates the media and the bearers. The descriptor includes the
+ multiplex type:
+
+
+ Groves et al Expires - October 2003 [Page 28]
+ Megaco Protocol version 2 April 2003
+
+
+ - H.221;
+ - H.223;
+ - H.226;
+ - V.76;
+ - Nx64K;
+ - possible extensions,
+
+ and a set of TerminationIDs representing the multiplexed bearers, in
+ order. For example:
+
+ Mux = H.221{ MyT3/1/2, MyT3/2/13, MyT3/3/6, MyT3/21/22}
+
+ The Nx64K Multiplex type implements the Nx64K service (e.g. as
+ defined by Q.931 Information Transfer Rate or Q.763 Transmission
+ Medium Requirement). On the context side it supports a single stream
+ of wideband data. When a bearer termination is added implicitly to a
+ context as a result of the creation of an Nx64K multiplexing
+ termination, the streamDescriptor for the bearer termination shall
+ take on the same values as the streamDescriptor defined for the
+ Multiplex termination, except that the bearer termination bandwidth
+ shall be 64 kilobits per second.
+
+ 7.1.4 Media descriptor
+
+ The Media descriptor specifies the parameters for all the media
+ streams. These parameters are structured into two descriptors: a
+ TerminationState descriptor, which specifies the properties of a
+ Termination that are not stream dependent, and one or more Stream
+ descriptors each of which describes a single media stream.
+
+ A stream is identified by a StreamID. The StreamID is used to link
+ the streams in a Context that belong together. Multiple streams
+ exiting a Termination shall be synchronized with each other. Within
+ the Stream descriptor, there are up to three subsidiary descriptors:
+ LocalControl, Local, and Remote. The relationship between these
+ descriptors is thus:
+
+ Media descriptor
+ TerminationState Descriptor
+ Stream descriptor
+ LocalControl descriptor
+ Local descriptor
+ Remote descriptor
+
+ As a convenience, LocalControl, Local, or Remote descriptors may be
+ included in the Media descriptor without an enclosing Stream
+ descriptor. In this case, the StreamID is assumed to be 1.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 29]
+ Megaco Protocol version 2 April 2003
+
+
+ 7.1.5 TerminationState descriptor
+
+ The TerminationState descriptor contains the ServiceStates property,
+ the EventBufferControl property and properties of a Termination
+ (defined in Packages) that are not stream specific.
+
+ The ServiceStates property describes the overall state of the
+ Termination (not stream specific). A Termination can be in one of the
+ following states: "test", "out of service", or "in service". The
+ "test" state indicates that the Termination is being tested. The
+ state "out of service" indicates that the Termination cannot be used
+ for traffic. The state "in service" indicates that a Termination can
+ be used or is being used for normal traffic. "in service" is the
+ default state.
+
+ Values assigned to Properties may be simple values
+ (integer/string/enumeration) or may be underspecified, where more
+ than one value is supplied and the MG may make a choice:
+
+ - Alternative Values - multiple values in a list, one of which must
+ be selected
+
+ - Ranges - minimum and maximum values, any value between min and max
+ must be selected, boundary values included
+
+ - Greater Than/Less Than - value must be greater/less than specified
+ value
+
+ - CHOOSE Wildcard - the MG chooses from the allowed values for the
+ property
+
+ The EventBufferControl property specifies whether events are buffered
+ following detection of an event in the Events descriptor, or
+ processed immediately. See 7.1.9 for details.
+
+ 7.1.6 Stream descriptor
+
+ A Stream descriptor specifies the parameters of a single
+ bidirectional stream. These parameters are structured into three
+ descriptors: one that contains Termination properties specific to a
+ stream and one each for local and remote flows. The Stream Descriptor
+ includes a StreamID which identifies the stream. Streams are created
+ by specifying a new StreamID on one of the Terminations in a Context.
+ A stream is deleted by setting empty Local and Remote descriptors for
+ the stream with ReserveGroup and ReserveValue in LocalControl set to
+ "false" on all Terminations in the Context that previously supported
+ that stream.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 30]
+ Megaco Protocol version 2 April 2003
+
+
+ StreamIDs are of local significance between MGC and MG and they are
+ assigned by the MGC. Within a Context, StreamID is a means by which
+ to indicate which media flows are interconnected: streams with the
+ same StreamID are connected.
+
+ If a Termination is moved from one Context to another, the effect on
+ the Context to which the Termination is moved is the same as in the
+ case that a new Termination were added with the same StreamIDs as the
+ moved Termination.
+
+ 7.1.7 LocalControl descriptor
+
+ The LocalControl descriptor contains the Mode property, the
+ ReserveGroup and ReserveValue properties and properties of a
+ Termination (defined in Packages) that are stream specific, and are
+ of interest between the MG and the MGC. Values of properties may be
+ specified as in 7.1.1.
+
+ The allowed values for the mode property are send-only, receive-only,
+ send/receive, inactive and loop-back. "Send" and "receive" are with
+ respect to the exterior of the Context, so that, for example, a
+ stream set to mode=sendOnly does not pass received media into the
+ Context. The default value for the mode property is "Inactive".
+ Signals and Events are not affected by mode.
+
+ The boolean-valued Reserve properties, ReserveValue and ReserveGroup,
+ of a Termination indicate what the MG is expected to do when it
+ receives a Local and/or Remote descriptor.
+
+ If the value of a Reserve property is True, the MG SHALL reserve
+ resources for all alternatives specified in the Local and/or Remote
+ descriptors for which it currently has resources available. It SHALL
+ respond with the alternatives for which it reserves resources. If it
+ cannot not support any of the alternatives, it SHALL respond with a
+ reply to the MGC that contains empty Local and/or Remote descriptors.
+ If media begins to flow while more than a single alternative is
+ reserved, media packets may be sent/received on any of the
+ alternatives and must be processed, although only a single
+ alternative may be active at any given time.
+
+ If the value of a Reserve property is False, the MG SHALL choose one
+ of the alternatives specified in the Local descriptor (if present)
+ and one of the alternatives specified in the Remote descriptor (if
+ present). If the MG has not yet reserved resources to support the
+ selected alternative, it SHALL reserve the resources. If, on the
+ other hand, it already reserved resources for the Termination
+ addressed (because of a prior exchange with ReserveValue and/or
+ ReserveGroup equal to True), it SHALL release any excess resources it
+ reserved previously. Finally, the MG shall send a reply to the MGC
+
+
+ Groves et al Expires - October 2003 [Page 31]
+ Megaco Protocol version 2 April 2003
+
+
+ containing the alternatives for the Local and/or Remote descriptor
+ that it selected. If the MG does not have sufficient resources to
+ support any of the alternatives specified, is SHALL respond with
+ Error 510 - "Insufficient resources".
+
+ The default value of ReserveValue and ReserveGroup is False. More
+ information on the use of the two Reserve properties is provided in
+ 7.1.8.
+
+ A new setting of the LocalControl Descriptor completely replaces the
+ previous setting of that descriptor in the MG. Thus, to retain
+ information from the previous setting, the MGC must include that
+ information in the new setting. If the MGC wishes to delete some
+ information from the existing descriptor, it merely resends the
+ descriptor (in a Modify command) with the unwanted information
+ stripped out.
+
+ 7.1.8 Local and Remote descriptors
+
+ The MGC uses Local and Remote descriptors to reserve and commit MG
+ resources for media decoding and encoding for the given Stream(s) and
+ Termination to which they apply. The MG includes these descriptors in
+ its response to indicate what it is actually prepared to support. The
+ MG SHALL include additional properties and their values in its
+ response if these properties are mandatory yet not present in the
+ requests made by the MGC (e.g. by specifying detailed video encoding
+ parameters where the MGC only specified the payload type).
+
+ Local refers to the media received by the MG and Remote refers to the
+ media sent by the MG.
+
+ When text encoding the protocol, the descriptors consist of session
+ descriptions as defined in SDP (RFC 2327). In session descriptions
+ sent from the MGC to the MG, the following exceptions to the syntax
+ of RFC 2327 are allowed:
+
+ - the "s=", "t=" and "o=" lines are optional;
+
+ - the use of CHOOSE is allowed in place of a single parameter value;
+ and
+
+ - the use of alternatives is allowed in place of a single parameter
+ value.
+
+ A Stream Descriptor specifies a single bi-directional media stream
+ and so a single session description MUST NOT include more than one
+ media description ("m=" line). A Stream Descriptor may contain
+ additional session descriptions as alternatives. Each media stream
+ for a termination must appear in distinct Stream Descriptors. When
+
+
+ Groves et al Expires - October 2003 [Page 32]
+ Megaco Protocol version 2 April 2003
+
+
+ multiple session descriptions are provided in one descriptor, the
+ "v=" lines are required as delimiters; otherwise they are optional in
+ session descriptions sent to the MG. Implementations shall accept
+ session descriptions that are fully conformant to RFC 2327. When
+ binary encoding the protocol the descriptor consists of groups of
+ properties (tag-value pairs) as specified in Annex C. Each such group
+ may contain the parameters of a session description.
+
+ Below, the semantics of the Local and Remote descriptors are
+ specified in detail. The specification consists of two parts. The
+ first part specifies the interpretation of the contents of the
+ descriptor. The second part specifies the actions the MG must take
+ upon receiving the Local and Remote descriptors. The actions to be
+ taken by the MG depend on the values of the ReserveValue and
+ ReserveGroup properties of the LocalControl descriptor.
+
+ Either the Local or the Remote descriptor or both may be:
+
+ - unspecified (i.e. absent);
+
+ - empty;
+
+ - underspecified through use of CHOOSE in a property value;
+
+ - fully specified; or
+
+ - overspecified through presentation of multiple groups of
+ properties and possibly multiple property values in one or more of
+ these groups.
+
+ Where the descriptors have been passed from the MGC to the MG, they
+ are interpreted according to the rules given in 7.1.1, with the
+ following additional comments for clarification:
+
+ a) An unspecified Local or Remote descriptor is considered to be a
+ missing mandatory parameter. It requires the MG to use whatever
+ was last specified for that descriptor. It is possible that there
+ was no previously specified value, in which case the descriptor
+ concerned is ignored in further processing of the command.
+
+ b) An empty Local (Remote) descriptor in a message from the MGC
+ signifies a request to release any resources reserved for the
+ media flow received (sent).
+
+ c) If multiple groups of properties are present in a Local or Remote
+ descriptor or multiple values within a group, the order of
+ preference is descending.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 33]
+ Megaco Protocol version 2 April 2003
+
+
+ d) Underspecified or overspecified properties within a group of
+ properties sent by the MGC are requests for the MG to choose one
+ or more values which it can support for each of those properties.
+ In case of an overspecified property, the list of values is in
+ descending order of preference.
+
+ Subject to the above rules, subsequent action depends on the values
+ of the ReserveValue and ReserveGroup properties in LocalControl.
+
+ If ReserveGroup is True, the MG reserves the resources required to
+ support any of the requested property group alternatives that it can
+ currently support. If ReserveValue is True, the MG reserves the
+ resources required to support any of the requested property value
+ alternatives that it can currently support.
+
+ NOTE - If a Local or Remote descriptor contains multiple groups of
+ properties, and ReserveGroup is True, then the MG is requested to
+ reserve resources so that it can decode or encode the media stream
+ according to any of the alternatives. For instance, if the Local
+ descriptor contains two groups of properties, one specifying
+ packetized G.711 A-law audio and the other G.723.1 audio, the MG
+ reserves resources so that it can decode one audio stream encoded in
+ either G.711 A-law format or G.723.1 format. The MG does not have to
+ reserve resources to decode two audio streams simultaneously, one
+ encoded in G.711 A-law and one in G.723.1. The intention for the use
+ of ReserveValue is analogous.
+
+ If ReserveGroup is true or ReserveValue is True, then the following
+ rules apply:
+
+ - If the MG has insufficient resources to support all alternatives
+ requested by the MGC and the MGC requested resources in both Local
+ and Remote, the MG SHOULD reserve resources to support at least
+ one alternative each within Local and Remote.
+
+ - If the MG has insufficient resources to support at least one
+ alternative within a Local (Remote) descriptor received from the
+ MGC, it shall return an empty Local (Remote) in response.
+
+ - In its response to the MGC, when the MGC included Local and Remote
+ descriptors, the MG SHALL include Local and Remote descriptors for
+ all groups of properties and property values it reserved resources
+ for. If the MG is incapable of supporting at least one of the
+ alternatives within the Local (Remote) descriptor received from
+ the MGC, it SHALL return an empty Local (Remote) descriptor.
+
+ - If the Mode property of the LocalControl descriptor is RecvOnly,
+ SendRecv, or LoopBack, the MG must be prepared to receive media
+
+
+
+ Groves et al Expires - October 2003 [Page 34]
+ Megaco Protocol version 2 April 2003
+
+
+ encoded according to any of the alternatives included in its
+ response to the MGC.
+
+ If ReserveGroup is False and ReserveValue is False, then the MG
+ SHOULD apply the following rules to resolve Local and Remote to a
+ single alternative each:
+
+ - The MG chooses the first alternative in Local for which it is able
+ to support at least one alternative in Remote.
+
+ - If the MG is unable to support at least one Local and one Remote
+ alternative, it returns Error 510 - "Insufficient resources".
+
+ - The MG returns its selected alternative in each of Local and
+ Remote.
+
+ A new setting of a Local or Remote descriptor completely replaces the
+ previous setting of that descriptor in the MG. Thus, to retain
+ information from the previous setting, the MGC must include that
+ information in the new setting. If the MGC wishes to delete some
+ information from the existing descriptor, it merely resends the
+ descriptor (in a Modify command) with the unwanted information
+ stripped out.
+
+ 7.1.9 Events descriptor
+
+ The EventsDescriptor parameter contains a RequestIdentifier and a
+ list of events that the Media Gateway is requested to detect and
+ report. The RequestIdentifier is used to correlate the request with
+ the notifications that it may trigger. Requested events include, for
+ example, fax tones, continuity test results, and on-hook and off-hook
+ transitions. The RequestIdentifier is omitted if the EventsDescriptor
+ is empty (i.e. no events are specified).
+
+ Each event in the descriptor contains the Event name, an optional
+ streamID, an optional KeepActive flag, and optional parameters. The
+ Event name consists of a Package Name (where the event is defined)
+ and an EventID. The ALL wildcard may be used for the EventID,
+ indicating that all events from the specified package have to be
+ detected. The default streamID is 0, indicating that the event to be
+ detected is not related to a particular media stream. Events can have
+ parameters. This allows a single event description to have some
+ variation in meaning without creating large numbers of individual
+ events. Further event parameters are defined in the package.
+
+ If a digit map completion event is present or implied in the
+ EventsDescriptor, the EventDM parameter is used to carry either the
+ name or the value of the associated digit map. See 7.1.14 for further
+ details.
+
+
+ Groves et al Expires - October 2003 [Page 35]
+ Megaco Protocol version 2 April 2003
+
+
+ When an event is processed against the contents of an active Events
+ Descriptor and found to be present in that descriptor ("recognized"),
+ the default action of the MG is to send a Notify command to the MGC.
+ Notification may be deferred if the event is absorbed into the
+ current dial string of an active digit map (see 7.1.14). Any other
+ action is for further study. Moreover, event recognition may cause
+ currently active signals to stop, or may cause the current Events
+ and/or Signals descriptor to be replaced, as described at the end of
+ this subclause. Unless the Events Descriptor is replaced by another
+ Events Descriptor, it remains active after an event has been
+ recognized.
+
+ If the value of the EventBufferControl property equals LockStep,
+ following detection of such an event, normal handling of events is
+ suspended. Any event which is subsequently detected and occurs in the
+ EventBuffer descriptor is added to the end of the EventBuffer (a FIFO
+ queue), along with the time that it was detected. The MG SHALL wait
+ for a new EventsDescriptor to be loaded. A new EventsDescriptor can
+ be loaded either as the result of receiving a command with a new
+ EventsDescriptor, or by activating an embedded EventsDescriptor.
+
+ If EventBufferControl equals Off, the MG continues processing based
+ on the active EventsDescriptor.
+
+ In the case of an embedded EventsDescriptor being activated, the MG
+ continues event processing based on the newly activated
+ EventsDescriptor.
+
+ NOTE 1 - For purposes of EventBuffer handling, activation of an
+ embedded EventsDescriptor is equivalent to receipt of a new
+ EventsDescriptor.
+
+ When the MG receives a command with a new EventsDescriptor, one or
+ more events may have been buffered in the EventBuffer in the MG. The
+ value of EventBufferControl then determines how the MG treats such
+ buffered events.
+
+
+ Case 1
+
+ If EventBufferControl equals LockStep and the MG receives a new
+ EventsDescriptor, it will check the FIFO EventBuffer and take the
+ following actions:
+
+ 1) If the EventBuffer is empty, the MG waits for detection of events
+ based on the new EventsDescriptor.
+
+ 2) If the EventBuffer is non-empty, the MG processes the FIFO queue
+ starting with the first event:
+
+
+ Groves et al Expires - October 2003 [Page 36]
+ Megaco Protocol version 2 April 2003
+
+
+ a) If the event in the queue is in the events listed in the new
+ EventsDescriptor, the MG acts on the event and removes the
+ event from the EventBuffer. The time stamp of the Notify shall
+ be the time the event was actually detected. The MG then waits
+ for a new EventsDescriptor. While waiting for a new
+ EventsDescriptor, any events detected that appear in the
+ EventsBufferDescriptor will be placed in the EventBuffer. When
+ a new EventsDescriptor is received, the event processing will
+ repeat from step 1.
+
+ b) If the event is not in the new EventsDescriptor, the MG SHALL
+ discard the event and repeat from step 1.
+
+
+ Case 2
+
+ If EventBufferControl equals Off and the MG receives a new
+ EventsDescriptor, it processes new events with the new
+ EventsDescriptor.
+
+ If the MG receives a command instructing it to set the value of
+ EventBufferControl to Off, all events in the EventBuffer SHALL be
+ discarded.
+
+ The MG may report several events in a single Transaction as long as
+ this does not unnecessarily delay the reporting of individual events.
+
+ For procedures regarding transmitting the Notify command, refer to
+ the appropriate annex or Recommendation of the H.248 sub-series for
+ specific transport considerations.
+
+ The default value of EventBufferControl is Off.
+
+ NOTE 2 - Since the EventBufferControl property is in the
+ TerminationStateDescriptor, the MG might receive a command that
+ changes the EventBufferControl property and does not include an
+ EventsDescriptor.
+
+ Normally, recognition of an event shall cause any active signals to
+ stop. When KeepActive is specified in the event, the MG shall not
+ interrupt any signals active on the Termination on which the event is
+ detected.
+
+ An event can include an Embedded Signals descriptor and/or an
+ Embedded Events descriptor which, if present, replaces the current
+ Signals/Events descriptor when the event is recognized. It is
+ possible, for example, to specify that the dial-tone Signal be
+ generated when an off-hook Event is recognized, or that the dial-tone
+ Signal be stopped when a digit is recognized. A media gateway
+
+
+ Groves et al Expires - October 2003 [Page 37]
+ Megaco Protocol version 2 April 2003
+
+
+ controller shall not send EventsDescriptors with an event both marked
+ KeepActive and containing an embedded SignalsDescriptor.
+
+ Only one level of embedding is permitted. An embedded
+ EventsDescriptor SHALL NOT contain another embedded EventsDescriptor;
+ an embedded EventsDescriptor MAY contain an embedded
+ SignalsDescriptor.
+
+ An EventsDescriptor received by a media gateway replaces any previous
+ Events descriptor. Event notification in process shall complete, and
+ events detected after the command containing the new EventsDescriptor
+ executes, shall be processed according to the new EventsDescriptor.
+
+ An empty Events Descriptor disables all event recognition and
+ reporting. An empty EventBuffer Descriptor clears the EventBuffer
+ and disables all event accumulation in LockStep mode: the only events
+ reported will be those occurring while an Events Descriptor is
+ active. If an empty Events Descriptor is activated while the
+ Termination is operating in LockStep mode, the events buffer is
+ immediately cleared.
+
+ 7.1.10 EventBuffer descriptor
+
+ The EventBuffer descriptor contains a list of events, with their
+ parameters if any, that the MG is requested to detect and buffer when
+ EventBufferControl equals LockStep (see 7.1.9).
+
+ 7.1.11 Signals descriptor
+
+ Signals are MG generated media such as tones and announcements as
+ well as bearer-related signals such as hookswitch. More complex
+ signals may include a sequence of such simple signals interspersed
+ with and conditioned upon the receipt and analysis of media or
+ bearer-related signals. Examples include echoing of received data as
+ in Continuity Test package. Signals may also request preparation of
+ media content for future signals.
+
+ A SignalsDescriptor is a parameter that contains the set of signals
+ that the Media Gateway is asked to apply to a Termination. A
+ SignalsDescriptor contains a number of signals and/or sequential
+ signal lists. A SignalsDescriptor may contain zero signals and
+ sequential signal lists. Support of sequential signal lists is
+ optional.
+
+ Signals are defined in packages. Signals shall be named with a
+ Package name (in which the signal is defined) and a SignalID. No
+ wildcard shall be used in the SignalID. Signals that occur in a
+ SignalsDescriptor have an optional StreamID parameter (default is 0,
+ to indicate that the signal is not related to a particular media
+
+
+ Groves et al Expires - October 2003 [Page 38]
+ Megaco Protocol version 2 April 2003
+
+
+ stream), an optional signal type (see below), an optional duration
+ and possibly parameters defined in the package that defines the
+ signal. This allows a single signal to have some variation in
+ meaning, obviating the need to create large numbers of individual
+ signals.
+
+ Finally, the optional parameter "notifyCompletion" allows a MGC to
+ indicate that it wishes to be notified when the signal finishes
+ playout. The possible cases are that the signal timed out (or
+ otherwise completed on its own), that it was interrupted by an event,
+ that it was halted when a Signals descriptor was replaced, or that it
+ stopped or never started for other reasons. If the notifyCompletion
+ parameter is not included in a Signals descriptor, notification is
+ generated only if the signal stopped or was never started for other
+ reasons. For reporting to occur, the signal completion event (see
+ E.1.2) must be enabled in the currently active Events descriptor.
+
+ The duration is an integer value that is expressed in hundredths of a
+ second.
+
+ There are three types of signals:
+
+ - on/off - the signal lasts until it is turned off;
+
+ - timeout - the signal lasts until it is turned off or a specific
+ period of time elapses;
+
+ - brief - the signal will stop on its own unless a new Signals
+ descriptor is applied that causes it to stop; no timeout value is
+ needed.
+
+ If a signal of default type other than TO has its type overridden to
+ type TO in the Signals descriptor, the duration parameter must be
+ present.
+
+ If the signal type is specified in a SignalsDescriptor, it overrides
+ the default signal type (see 12.1.4). If duration is specified for an
+ on/off signal, it SHALL be ignored.
+
+ A sequential signal list consists of a signal list identifier and a
+ sequence of signals to be played sequentially. Only the trailing
+ element of the sequence of signals in a sequential signal list may be
+ an on/off signal. The duration of a sequential signal list is the sum
+ of the durations of the signals it contains.
+
+ Multiple signals and sequential signal lists in the same
+ SignalsDescriptor shall be played simultaneously.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 39]
+ Megaco Protocol version 2 April 2003
+
+
+ Signals are defined as proceeding from the Termination towards the
+ exterior of the Context unless otherwise specified in a package. When
+ the same Signal is applied to multiple Terminations within one
+ Transaction, the MG SHOULD consider using the same resource to
+ generate these Signals.
+
+ Production of a Signal on a Termination is stopped by application of
+ a new SignalsDescriptor, or detection of an Event on the Termination
+ (see 7.1.9).
+
+ A new SignalsDescriptor replaces any existing SignalsDescriptor. Any
+ signals applied to the Termination not in the replacement descriptor
+ shall be stopped, and new signals are applied, except as follows.
+ Signals present in the replacement descriptor and containing the
+ KeepActive flagshall be continued if they are currently playing and
+ have not already completed. If a replacement signal descriptor
+ contains a signal that is not currently playing and contains the
+ KeepActive flag, that signal SHALL be ignored. If the replacement
+ descriptor contains a sequential signal list with the same identifier
+ as the existing descriptor, then
+
+ - the signal type and sequence of signals in the sequential signal
+ list in the replacement descriptor shall be ignored; and
+
+ - the playing of the signals in the sequential signal list in the
+ existing descriptor shall not be interrupted.
+
+ 7.1.12 Audit descriptor
+
+ The Audit descriptor specifies what information is to be audited. The
+ Audit descriptor specifies the list of descriptors and-or individual
+ properties to be returned. Audit may be used in any command to force
+ the return of any descriptor containing the current values of its
+ properties, events, signals and statistics even if that descriptor
+ was not present in the command, or had no underspecified parameters.
+ Possible items in the Audit descriptor are:
+
+ - Modem (Deprecated, see clause 7.1.2)
+ - Mux
+ - Events
+ - Media
+ - Signals
+ - ObservedEvents
+ - DigitMap
+ - Statistics
+ - Packages
+ - EventBuffer
+ - Individual Audit Items:
+ - Media Properties
+
+
+ Groves et al Expires - October 2003 [Page 40]
+ Megaco Protocol version 2 April 2003
+
+
+ - Events
+ - Event Buffer
+ - Signals, Signal Lists
+ - Digit Maps
+ - Statistics
+ - Packages
+
+ Audit may be empty, in which case, no descriptors are returned. This
+ is useful in Subtract, to inhibit return of statistics, especially
+ when using wildcard.
+
+ 7.1.13 ServiceChange descriptor
+
+ The ServiceChangeDescriptor contains the following parameters:
+
+ - ServiceChangeMethod
+ - ServiceChangeReason
+ - ServiceChangeAddress
+ - ServiceChangeDelay
+ - ServiceChangeProfile
+ - ServiceChangeVersion
+ - ServiceChangeMGCId
+ - TimeStamp
+ - Extension
+
+ See 7.2.8.
+
+ 7.1.14 DigitMap descriptor
+
+ 7.1.14.1 DigitMap definition, creation, modification and deletion
+
+ A DigitMap is a dialing plan resident in the Media Gateway used for
+ detecting and reporting digit events received on a Termination. The
+ DigitMap descriptor contains a DigitMap name and the DigitMap to be
+ assigned. A digit map may be preloaded into the MG by management
+ action and referenced by name in an EventsDescriptor, may be defined
+ dynamically and subsequently referenced by name, or the actual
+ digitmap itself may be specified in the EventsDescriptor. It is
+ permissible for a digit map completion event within an Events
+ descriptor to refer by name to a DigitMap which is defined by a
+ DigitMap descriptor within the same command, regardless of the
+ transmitted order of the respective descriptors.
+
+ DigitMaps defined in a DigitMapDescriptor can occur in any of the
+ standard Termination manipulation Commands of the protocol. A
+ DigitMap, once defined, can be used on all Terminations specified by
+ the (possibly wildcarded) TerminationID in such a command. DigitMaps
+ defined on the root Termination are global and can be used on every
+ Termination in the MG, provided that a DigitMap with the same name
+
+
+ Groves et al Expires - October 2003 [Page 41]
+ Megaco Protocol version 2 April 2003
+
+
+ has not been defined on the given Termination. When a DigitMap is
+ defined dynamically in a DigitMap descriptor:
+
+ - A new DigitMap is created by specifying a name that is not yet
+ defined. The value shall be present.
+
+ - A DigitMap value is updated by supplying a new value for a name
+ that is already defined. Terminations presently using the digitmap
+ shall continue to use the old definition; subsequent
+ EventsDescriptors specifying the name, including any
+ EventsDescriptor in the command containing the DigitMap
+ descriptor, shall use the new one.
+
+ - A DigitMap is deleted by supplying an empty value for a name that
+ is already defined. Terminations presently using the digitmap
+ shall continue to use the old definition.
+
+ 7.1.14.2 DigitMap Timers
+
+ The collection of digits according to a DigitMap may be protected by
+ three timers, viz. a start timer (T), short timer (S), and long timer
+ (L).
+
+ 1) The start timer (T) is used prior to any digits having been
+ dialed. If the start timer is overridden with the value set to
+ zero (T=0), then the start timer shall be disabled. This implies
+ that the MG will wait indefinitely for digits.
+
+ 2) If the Media Gateway can determine that at least one more digit is
+ needed for a digit string to match any of the allowed patterns in
+ the digit map, then the interdigit timer value SHOULD be set to a
+ long (L) duration (e.g. 16 seconds).
+
+ 3) If the digit string has matched one of the patterns in a digit
+ map, but it is possible that more digits could be received which
+ would cause a match with a different pattern, then instead of
+ reporting the match immediately, the MG must apply the short timer
+ (S) and wait for more digits.
+
+ The timers are configurable parameters to a DigitMap. Default values
+ of these timers SHOULD be provisioned on the MG, but can be
+ overridden by values specified within the DigitMap.
+
+ 7.1.14.3 DigitMap Syntax
+
+ The formal syntax of the digit map is described by the DigitMap rule
+ in the formal syntax description of the protocol (see Annex A and
+ Annex B). A DigitMap, according to this syntax, is defined either by
+ a string or by a list of strings. Each string in the list is an
+
+
+ Groves et al Expires - October 2003 [Page 42]
+ Megaco Protocol version 2 April 2003
+
+
+ alternative event sequence, specified either as a sequence of digit
+ map symbols or as a regular expression of digit map symbols. These
+ digit map symbols, the digits "0" through "9" and letters "A" through
+ a maximum value depending on the signalling system concerned, but
+ never exceeding "K", correspond to specified events within a package
+ which has been designated in the Events descriptor on the Termination
+ to which the digit map is being applied. (The mapping between events
+ and digit map symbols is defined in the documentation for packages
+ associated with channel-associated signalling systems such as DTMF,
+ MF, or R2. Digits "0" through "9" MUST be mapped to the corresponding
+ digit events within the signalling system concerned. Letters SHOULD
+ be allocated in logical fashion, facilitating the use of range
+ notation for alternative events.)
+
+ The letter "x" is used as a wildcard, designating any event
+ corresponding to symbols in the range "0"-"9". The string may also
+ contain explicit ranges and, more generally, explicit sets of
+ symbols, designating alternative events any one of which satisfies
+ that position of the digit map. Finally, the dot symbol "." stands
+ for zero or more repetitions of the event selector (event, range of
+ events, set of alternative events, or wildcard) that precedes it. As
+ a consequence of the third timing rule above, inter-event timing
+ while matching a terminal dot symbol uses the short timer by default.
+
+ In addition to these event symbols, the string may contain "S" and
+ "L" inter-event timing specifiers and the "Z" duration modifier. "S"
+ and "L" respectively indicate that the MG SHOULD use the short (S)
+ timer or the long (L) timer for subsequent events, overriding the
+ timing rules described above. If an explicit timing specifier is in
+ effect in one alternative event sequence, but none is given in any
+ other candidate alternative, the timer value set by the explicit
+ timing specifier must be used. If all sequences with explicit timing
+ controls are dropped from the candidate set, timing reverts to the
+ default rules given above. Finally, if conflicting timing specifiers
+ are in effect in different alternative sequences, the long timer
+ shall be used.
+
+ A "Z" designates a long duration event: placed in front of the
+ symbol(s) designating the event(s) which satisfy a given digit
+ position, it indicates that that position is satisfied only if the
+ duration of the event exceeds the long-duration threshold. The value
+ of this threshold is assumed to be provisioned in the MG, but, like
+ the T, L, and S timers, can be overridden by specification within the
+ DigitMap.
+
+ 7.1.14.4 DigitMap Completion Event
+
+ A digit map is active while the Events descriptor which invoked it is
+ active and it has not completed. A digit map completes when:
+
+
+ Groves et al Expires - October 2003 [Page 43]
+ Megaco Protocol version 2 April 2003
+
+
+ - a timer has expired; or
+
+ - an alternative event sequence has been matched and no other
+ alternative event sequence in the digit map could be matched
+ through detection of an additional event (unambiguous match); or
+
+ - an event has been detected such that a match to a complete
+ alternative event sequence of the digit map will be impossible no
+ matter what additional events are received.
+
+ Upon completion, a digit map completion event as defined in the
+ package providing the events being mapped into the digit map shall be
+ generated. At that point the digit map is deactivated. Subsequent
+ events in the package are processed as follows:
+
+ - If EventBufferControl is ON, subsequent digit events are processed
+ in the same way as any other events;
+
+ - If EventBufferControl is OFF, if the active EventsDescriptor did
+ not change, and if individual digit events are not enabled within
+ that descriptor, then digit buffering will be initiated.
+ Buffering will continue until the buffering time specified in the
+ original digit map completion event has expired or until the
+ active EventsDescriptor is replaced.
+
+ The digit buffer shall take the logical form of a dial string which
+ includes the digit characters as represented in the digit map,
+ possibly preceded by 'Z'. The threshold value of tone duration used
+ to identify long events shall be the same as that used with the most
+ recently completed digit map.
+
+ Buffering time defaults to zero (no buffering) unless explicitly set
+ otherwise within the digit map completion event. If buffering ceases
+ due to buffering timer expiry, the contents of the digit buffer are
+ discarded.
+
+ If buffering was stopped by a new EventsDescriptor, then if that
+ EventsDescriptor contains a new digit map completion event from the
+ same package as the previous one, any buffered digits are processed
+ against the digit map as described below. Buffered digits not
+ consumed by the new digit map are handled as if they had were
+ observed after that map completed.
+
+ If instead the new EventsDescriptor enables the reporting of
+ individual digit events, the entire set of buffered digits shall
+ immediately be processed, the applicable events reported, and the
+ buffer cleared.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 44]
+ Megaco Protocol version 2 April 2003
+
+
+ Finally, if the new EventsDescriptor enables neither a digit map
+ completion event nor the reporting of individual digit events from
+ the package concerned, the buffer contents are discarded and
+ buffering is terminated.
+
+ 7.1.14.5 DigitMap Procedures
+
+ Pending completion, successive events shall be processed according to
+ the following rules:
+
+ 1) The "current dial string", an internal variable, is initially
+ empty. The set of candidate alternative event sequences includes
+ all of the alternatives specified in the digit map.
+
+ 2) At each step, if buffered digits are available, the oldest one
+ (with possible accompanying long digit (Z) qualifier) is removed
+ from the buffer and processing moves to the next step as if the
+ digit event had just been observed. Otherwise a timer is set to
+ wait for the next event, based either on the default timing rules
+ given above or on explicit timing specified in one or more
+ alternative event sequences. If the timer expires and a member of
+ the candidate set of alternatives is fully satisfied, a timeout
+ completion with full match is reported. If the timer expires and
+ part or none of any candidate alternative is satisfied, a timeout
+ completion with partial match is reported. In either case, if the
+ digit map completion event allows for detailed timeout reporting,
+ the reported dial string will end with 'L', 'S', or 'T' as
+ appropriate.
+
+ 3) If an event is detected before the timer expires, it is mapped to
+ a digit string symbol and provisionally added to the end of the
+ current dial string. The duration of the event (long or not long)
+ is noted if and only if this is relevant in the current symbol
+ position (because at least one of the candidate alternative event
+ sequences includes the "Z" modifier at this position in the
+ sequence).
+
+ 4) The current dial string is compared to the candidate alternative
+ event sequences. If and only if a sequence expecting a long-
+ duration event at this position is matched (i.e. the event had
+ long duration and met the specification for this position), then
+ any alternative event sequences not specifying a long duration
+ event at this position are discarded, and the current dial string
+ is modified by inserting a "Z" in front of the symbol representing
+ the latest event. Any sequence expecting a long-duration event at
+ this position but not matching the observed event is discarded
+ from the candidate set. If alternative event sequences not
+ specifying a long duration event in the given position remain in
+ the candidate set after application of the above rules, the
+
+
+ Groves et al Expires - October 2003 [Page 45]
+ Megaco Protocol version 2 April 2003
+
+
+ observed event duration is treated as irrelevant in assessing
+ matches to them.
+
+ 5) If exactly one candidate remains and it has been fully matched, a
+ completion event is generated indicating an unambiguous match. If
+ no candidates remain, the latest event is removed from the current
+ dial string and a completion event is generated indicating full
+ match if one of the candidates from the previous step was fully
+ satisfied before the latest event was detected, or partial match
+ otherwise. The event removed from the current dial string will
+ then be reported a separate event, buffered, or discarded
+ according to the rules described in the previous section. This
+ statement is qualified as follows:
+
+ a) The digit map completion event may specify that the removed
+ event be reported as a parameter of the completion event. This
+ occurs independently of subsequent processing of the digit
+ event.
+
+ b) The digit map completion event may specify that the extra digit
+ SHOULD be discarded. In this case, it is discarded
+ immediately. Any buffering or other processing applies only to
+ subsequent events.
+
+ 6) If no completion event is reported out of step 5, processing
+ returns to step 2.
+
+ 7.1.14.6 DigitMap Activation
+
+ A digit map is activated whenever a new Event descriptor is applied
+ to the Termination or embedded Event descriptor is activated, that
+ Event descriptor contains a digit map completion event. The digit map
+ completion event contains an eventDM field in the requested actions
+ field. Each new activation of a digit map begins at step 1 of the
+ above procedure, with a clear current dial string. Any previous
+ contents of the current dial string from an earlier activation are
+ lost.
+
+ A digit map completion event that does not contain an eventDM field
+ in its requested actions field is considered an error. Upon receipt
+ of such an event in an EventsDescriptor, a MG shall respond with an
+ error reponse, including Error 457 - "Missing parameter in signal or
+ event".
+
+ 7.1.14.7 Interaction Of DigitMap and Event Processing
+
+ While the digit map is activated, detection is enabled for all events
+ defined in the package containing the specified digit map completion
+ event. Normal event behaviour (e.g. stopping of signals unless the
+
+
+ Groves et al Expires - October 2003 [Page 46]
+ Megaco Protocol version 2 April 2003
+
+
+ digit completion event has the KeepActive flag enabled) continues to
+ apply for each such event detected, except that:
+
+ - the events in the package containing the specified digit map
+ completion event other than the completion event itself are not
+ individually notified and have no side-effects unless separately
+ enabled; and
+
+ - an event that triggers a partial match completion event is not
+ recognized and therefore has no side effects until reprocessed
+ following the recognition of the digit map completion event.
+ Similarly buffered digit events are not recognized and have no
+ side effects until processed.
+
+ 7.1.14.8 Wildcards
+
+ Note that if a package contains a digit map completion event, then an
+ event specification consisting of the package name with a wildcarded
+ ItemID (Property Name) will activate a digit map; to that end, the
+ event specification must include an eventDM field according to
+ section 7.1.14.6. If the package also contains the digit events
+ themselves, this form of event specification will cause the
+ individual events to be reported to the MGC as they are detected.
+
+ 7.1.14.9 Example
+
+ As an example, consider the following dial plan:
+
+ 0 Local operator
+
+ 00 Long-distance operator
+
+ xxxx Local extension number (starts
+ with 1-7)
+
+ 8xxxxxxx Local number
+
+ #xxxxxxx Off-site extension
+
+ *xx Star services
+
+ 91xxxxxxxxxx Long-distance number
+
+ 9011 + up to 15 digits International number
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 47]
+ Megaco Protocol version 2 April 2003
+
+
+ If the DTMF detection package described in E.6 is used to collect the
+ dialled digits, then the dialling plan shown above results in the
+ following digit map:
+
+ (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)
+
+ 7.1.15 Statistics descriptor
+
+ The Statistics Descriptor provides information describing the status
+ and usage of a Termination during its existence within a specific
+ Context. There is a set of standard statistics kept for each
+ Termination where appropriate (number of octets sent and received for
+ example). The particular statistical properties that are reported for
+ a given Termination are determined by the Packages realized by the
+ Termination. By default, statistics are reported when the Termination
+ is Subtracted from the Context. This behaviour can be overridden by
+ including an empty AuditDescriptor in the Subtract command.
+ Statistics may also be returned from the AuditValue command, or any
+ Add/Move/Modify command using the Audit descriptor.
+
+ Statistics are cumulative; reporting Statistics does not reset them.
+ Statistics are reset when a Termination is Subtracted from a Context.
+
+ 7.1.16 Packages descriptor
+
+ Used only with the AuditValue command, the PackageDescriptor returns
+ a list of Packages realized by the Termination.
+
+ 7.1.17 ObservedEvents descriptor
+
+ ObservedEvents is supplied with the Notify command to inform the MGC
+ of which event(s) were detected. Used with the AuditValue command,
+ the ObservedEventsDescriptor returns events in the event buffer which
+ have not been Notified. ObservedEvents contains the RequestIdentifier
+ of the EventsDescriptor that triggered the notification, the event(s)
+ detected, optionally the detection time(s) and any parameters of the
+ observed event. Detection times are reported with a precision of
+ hundredths of a second.
+
+ 7.1.18 Topology descriptor
+
+ A Topology descriptor is used to specify flow directions between
+ Terminations in a Context. Contrary to the descriptors in previous
+ subclauses, the Topology descriptor applies to a Context instead of a
+ Termination. The default topology of a Context is that each
+ Termination's transmission is received by all other Terminations. The
+ Topology descriptor is optional to implement. An MG that does not
+ support Topology descriptors, but receives a command containing one,
+ returns Error 444 - "Unsupported or unknown descriptor", and
+
+
+ Groves et al Expires - October 2003 [Page 48]
+ Megaco Protocol version 2 April 2003
+
+
+ optionally includes a string containing the name of the unsupported
+ Descriptor ("Topology") in the error text in the error descriptor.
+
+ The Topology descriptor occurs before the commands in an action. It
+ is possible to have an action containing only a Topology descriptor,
+ provided that the Context to which the action applies already exists.
+
+ A Topology descriptor consists of a sequence of tuples of associated
+ terminations of the form (T1, T2, association[,StreamId]). T1 and T2
+ specify Terminations within the Context, possibly using the ALL or
+ CHOOSE wildcard. If the optional StreamId field is used, the
+ association applies only to the particular stream between T1 and T2
+ labeled by the StreamId. If the StreamId field is omitted, the
+ topology applies to all streams in the termination. The association
+ specifies how media flows between these two Terminations as follows.
+
+ - (T1, T2, isolate) means that the Terminations matching T2 do not
+ receive media from the Terminations matching T1, nor vice versa.
+
+ - (T1, T2, oneway) means that the Terminations that match T2 receive
+ media from the Terminations matching T1, but not vice versa. In
+ this case use of the ALL wildcard such that there are Terminations
+ that match both T1 and T2 is not allowed.
+
+ - (T1, T2, bothway) means that the Terminations matching T2 receive
+ media from the Terminations matching T1, and vice versa. In this
+ case it is allowed to use wildcards such that there are
+ Terminations that match both T1 and T2. However, if there is a
+ Termination that matches both, no loopback is introduced.
+
+ CHOOSE wildcards may be used in T1 and T2 as well, under the
+ following restrictions:
+
+ - the action (see clause 8) of which the topology descriptor is part
+ contains an Add command in which a CHOOSE wildcard is used;
+
+ - if a CHOOSE wildcard occurs in T1 or T2, then a partial name SHALL
+ NOT be specified.
+
+ The CHOOSE wildcard in a Topology descriptor matches the
+ TerminationID that the MG assigns in the first Add command that uses
+ a CHOOSE wildcard in the same action. An existing Termination that
+ matches T1 or T2 in the Context to which a Termination is added, is
+ connected to the newly added Termination as specified by the Topology
+ descriptor. If a termination is not mentioned within a topology
+ descriptor, any topology associated with it remains unchanged. If,
+ however, a new termination is added into a context its association
+ with the other terminations within the context defaults to bothway,
+ unless a topology descriptor is given to change this (eg. if T3 is
+
+
+ Groves et al Expires - October 2003 [Page 49]
+ Megaco Protocol version 2 April 2003
+
+
+ added to a context with T1 and T2 with topology (T3, T1, oneway) it
+ will be connected bothway to T2).
+
+ If the topology is applied to one particular stream (T1, T2,
+ association, StreamId), the topology of other streams between the
+ terminations does not change.
+
+ A topology descriptor SHALL NOT include a combination of associations
+ between two terminations (Ti,Tj) with and without the optional
+ StreamID field, to avoid undefined behavior. For example (T1,T2,
+ bothway) and (T1,T2,isolate,S1) shall not appear in the same
+ descriptor. Upon receipt of such a topology descriptor, a MG shall
+ respond with an error response, including Error 421 - "Unknown action
+ or illegal combination of actions".
+
+ Figure 7, and the table following it and Figure 8 following it show
+ some examples of the effect of including topology descriptors in
+ actions. In these examples it is assumed that the topology
+ descriptors are applied in sequence.
+
+ +------------------+ +------------------+ +------------------+
+ | +----+ | | +----+ | | +----+ |
+ | | T2 | | | | T2 | | | | T2 | |
+ | +----+ | | +----+ | | +----+ |
+ | ^ ^ | | ^ | | ^ |
+ | | | | | | | | | |
+ | +--+ +--+ | | +---+ | | +--+ |
+ | | | | | | | | | |
+ | v v | | v | | | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ | | T1 |<-->| T3 | | | | T1 |<-->| T3 | | | | T1 |<-->| T3 | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ +------------------+ +------------------+ +------------------+
+ 1. No Topology Desc. 2. T1, T2, Isolate 3. T3, T2, Oneway
+
+ +------------------+ +------------------+ +------------------+
+ | +----+ | | +----+ | | +----+ |
+ | | T2 | | | | T2 | | | | T2 | |
+ | +----+ | | +----+ | | +----+ |
+ | | | | ^ | | ^ ^ |
+ | | | | | | | | | |
+ | +--+ | | +---+ | | +--+ +--+ |
+ | | | | | | | | | |
+ | v | | v | | v v |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ | | T1 |<-->| T3 | | | | T1 |<-->| T3 | | | | T1 |<-->| T3 | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ +------------------+ +------------------+ +------------------+
+ 4. T2, T3 oneway 5. T2, T3 bothway 6. T1, T2 bothway
+
+
+ Groves et al Expires - October 2003 [Page 50]
+ Megaco Protocol version 2 April 2003
+
+
+
+ Figure 7: Example topologies
+ Note: the direction of the arrow indicates the direction of flow
+
+
+ Topology Description
+
+ 1 No topology descriptors
+
+ When no topology descriptors are included, all
+ Terminations have a bothway connection to all other
+ Terminations.
+
+ 2 T1, T2 Isolate
+
+ Removes the connection between T1 and T2. T3 has a
+ bothway connection with both T1 and T2. T1 and T2
+ have bothway connection to T3.
+
+ 3 T3, T2 oneway
+
+ A oneway connection from T3 to T2 (i.e. T2 receives
+ media flow from T3). A bothway connection between T1
+ and T3.
+
+ 4 T2, T3 oneway
+
+ A oneway connection between T2 to T3. T1 and T3
+ remain bothway connected
+
+ 5 T2, T3 bothway
+
+ T2 is bothway connected to T3. This results in the
+ same as 2.
+
+ 6 T1, T2 bothway (T2, T3 bothway and T1, T3 bothway
+ may be implied or explicit). All Terminations have a
+ bothway connection to all other Terminations.
+
+
+ +----+ +----+ +----+
+ | T2 | | T2 | | T2 |
+ +----+ +----+ +----+
+ //\\ //\\ //\\
+ // \\ // \\ // \\
+ 1//2 1\\2 1//2 1\\2 1//2 1\\2
+ +---+ +---+ +---+ +---+ +---+ +---+
+ | | 1 | | | | 1 | | | | 1 | |
+
+
+ Groves et al Expires - October 2003 [Page 51]
+ Megaco Protocol version 2 April 2003
+
+
+ | |<->| | | |<->| | | |<--| |
+ |T1 | |T3 | |T1 | |T3 | |T1 | |T3 |
+ | | 2 | | | | 2 | | | | 2 | |
+ | |<->| | | |-->| | | |-->| |
+ | | | | | | | | | | | |
+ +---+ +---+ +---+ +---+ +---+ +---+
+
+ 1. No Topology Desc. 2. T1,T3, oneway,2 3. T3, T1,oneway,1
+
+ Figure 8: Example Topology at stream level
+
+
+
+ A oneway connection must be implemented in such a way that the other
+ Terminations in the Context are not aware of the change in topology.
+
+ 7.1.19 Error Descriptor
+
+ If a responder encounters an error when processing a transaction
+ request, it must include an error descriptor in its response. A
+ Notify request may contain an error descriptor as well.
+
+ An error descriptor consists of an IANA-registered error code,
+ optionally accompanied by an error text. H.248.8 contains a list of
+ valid error codes and error descriptions.
+
+ An error descriptor shall be specified at the "deepest level" that is
+ semantically appropriate for the error being described and that is
+ possible given any parsing problems with the original request. An
+ error descriptor may refer to a syntactical construct other than
+ where it appears. For example, Error 422 - "Syntax Error in Action",
+ could appear within a command even though it refers to the larger
+ construct - the action - and not the particular command within which
+ it appears.
+
+
+ 7.2 Command Application Programming Interface
+
+ Following is an Application Programming Interface (API) describing
+ the Commands of the protocol. This API is shown to illustrate the
+ Commands and their parameters and is not intended to specify
+ implementation (e.g. via use of blocking function calls). It
+ describes the input parameters in parentheses after the command name
+ and the return values in front of the Command. This is only for
+ descriptive purposes; the actual Command syntax and encoding are
+ specified in later subclauses. The order of parameters to commands is
+ not fixed. Descriptors may appear as parameters to commands in any
+ order. The descriptors SHALL be processed in the order in which they
+ appear.
+
+
+ Groves et al Expires - October 2003 [Page 52]
+ Megaco Protocol version 2 April 2003
+
+
+ Any reply to a command may contain an error descriptor; the API does
+ not specifically show this.
+
+ All parameters enclosed by square brackets ([. . .]) are considered
+ optional.
+
+ 7.2.1 Add
+
+ The Add Command adds a Termination to a Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor] (*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Add( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor] (*)
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (05/2002).
+
+ The TerminationID specifies the Termination to be added to the
+ Context. The Termination is either created, or taken from the null
+ Context. If a CHOOSE wildcard is used in the TerminationID, the
+ selected TerminationID will be returned. Wildcards may be used in an
+ Add, but such usage would be unusual. If the wildcard matches more
+ than one TerminationID, all possible matches are attempted, with
+ results reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified.
+
+ The optional MediaDescriptor describes all media streams.
+
+ The optional MuxDescriptor specifies a multiplexer if applicable. For
+ convenience, if a Multiplex descriptor is present in an Add command
+ and lists any Terminations that are not currently in the Context,
+ such Terminations are added to the Context as if individual Add
+
+
+ Groves et al Expires - October 2003 [Page 53]
+ Megaco Protocol version 2 April 2003
+
+
+ commands listing the Terminations were invoked. If an error occurs on
+ such an implied Add, error 471 - Implied Add for Multiplex failure
+ shall be returned and further processing of the command shall cease.
+
+ The EventsDescriptor parameter is optional. If present, it provides
+ the list of events that SHOULD be detected on the Termination.
+
+ The EventBufferDescriptor parameter is optional. If present, it
+ provides the list of events that the MG is requested to detect and
+ buffer when EventBufferControl equals LockStep.
+
+ The SignalsDescriptor parameter is optional. If present, it provides
+ the list of signals that SHOULD be applied to the Termination.
+
+ The DigitMapDescriptor parameter is optional. If present, it defines
+ a DigitMap definition that may be used in an EventsDescriptor.
+
+ The AuditDescriptor is optional. If present, the command will return
+ descriptors as specified in the AuditDescriptor.
+
+ All descriptors that can be modified could be returned by MG if a
+ parameter was underspecified or overspecified. ObservedEvents,
+ Statistics, and Packages, and the EventBuffer descriptors are
+ returned only if requested in the AuditDescriptor.
+
+ Add SHALL NOT be used on a Termination with a serviceState of
+ "OutofService".
+
+ 7.2.2 Modify
+
+ The Modify Command modifies the properties of a Termination.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor] (*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Modify( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor] (*)
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+
+
+ Groves et al Expires - October 2003 [Page 54]
+ Megaco Protocol version 2 April 2003
+
+
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (05/2002).
+
+
+
+ The TerminationID may be specific if a single Termination in the
+ Context is to be modified. Use of wildcards in the TerminationID may
+ be appropriate for some operations. If the wildcard matches more than
+ one TerminationID, all possible matches are attempted, with results
+ reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified. The CHOOSE option is an error,
+ as the Modify command may only be used on existing Terminations.
+
+ For convenience, if a Multiplex Descriptor is present in a Modify
+ command, then:
+
+ - if the new Multiplex Descriptor lists any Terminations that are
+ not currently in the Context, such Terminations are added to the
+ context as if individual Add commands listing the Terminations
+ were invoked.
+
+ - if any Terminations listed previously in the Multiplex Descriptor
+ are no longer present in the new Multiplex Descriptor, they are
+ subtracted from the context as if individual Subtract commands
+ listing the Terminations were invoked.
+
+ The remaining parameters to Modify are the same as those to Add.
+ Possible return values are the same as those to Add.
+
+ 7.2.3 Subtract
+
+ The Subtract Command disconnects a Termination from its Context and
+ returns statistics on the Termination's participation in the Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor] (*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+
+
+ Groves et al Expires - October 2003 [Page 55]
+ Megaco Protocol version 2 April 2003
+
+
+ Subtract(TerminationID
+ [, AuditDescriptor]
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (05/2002).
+
+ TerminationID in the input parameters represents the Termination that
+ is being subtracted. The TerminationID may be specific or may be a
+ wildcard value indicating that all (or a set of related) Terminations
+ in the Context of the Subtract Command are to be subtracted. If the
+ wildcard matches more than one TerminationID, all possible matches
+ are attempted, with results reported for each one. The order of
+ attempts when multiple TerminationIDs match is not specified.
+
+ The use of CHOOSE in the TerminationID is an error, as the Subtract
+ command may only be used on existing Terminations.
+
+ ALL may be used as the ContextID as well as the TerminationId in a
+ Subtract, which would have the effect of deleting all Contexts,
+ deleting all ephemeral Terminations, and returning all physical
+ Terminations to Null Context. Subtract of a termination from the Null
+ Context is not allowed.
+
+ For convenience, if a multiplexing Termination is the object of a
+ Subtract command, then any bearer Terminations listed in its
+ Multiplex Descriptor are subtracted from the context as if individual
+ Subtract commands listing the Terminations were invoked.
+
+ By default, the Statistics parameter is returned to report
+ information collected on the Termination or Terminations specified in
+ the Command. The information reported applies to the Termination's or
+ Terminations' existence in the Context from which it or they are
+ being subtracted.
+
+ The AuditDescriptor is optional. If present, the command will return
+ only those descriptors as specified in the AuditDescriptor, which may
+ be empty. If omitted, the Statistics descriptor is returned, by
+ default. Possible return values are the same as those to Add.
+
+ When a provisioned Termination is Subtracted from a Context, its
+ property values shall revert to:
+
+ - the default value, if specified for the property and not
+ overridden by provisioning;
+
+ - otherwise, the provisioned value.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 56]
+ Megaco Protocol version 2 April 2003
+
+
+ 7.2.4 Move
+
+ The Move Command moves a Termination to another Context from its
+ current Context in one atomic operation. The Move command is the only
+ command that refers to a Termination in a Context different from that
+ to which the command is applied. The Move command shall not be used
+ to move Terminations to or from the null Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor] (*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Move( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor] (*)
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (05/2002).
+
+ The TerminationID specifies the Termination to be moved. It may be
+ wildcarded, but CHOOSE shall not be used in the TerminationID. If the
+ wildcard matches more than one TerminationID, all possible matches
+ are attempted, with results reported for each one. The order of
+ attempts when multiple TerminationIDs match is not specified. The
+ Context to which the Termination is moved is indicated by the target
+ ContextId in the Action. If the last remaining Termination is moved
+ out of a Context, the Context is deleted.
+
+ The Move command does not affect the properties of the Termination on
+ which it operates, except those properties explicitly modified by
+ descriptors included in the Move command. The AuditDescriptor with
+ the Statistics option, for example, would return statistics on the
+ Termination just prior to the Move. Possible descriptors returned
+ from Move are the same as for Add.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 57]
+ Megaco Protocol version 2 April 2003
+
+
+ For convenience, if a multiplexing Termination is the object of a
+ Move command, then any bearer Terminations listed in its Multiplex
+ Descriptor are also moved as if individual Move commands listing the
+ Terminations were invoked.
+
+ Move SHALL NOT be used on a Termination with a serviceState of
+ "OutofService".
+
+ 7.2.5 AuditValue
+
+ The AuditValue Command returns the current values of properties,
+ events, signals and statistics associated with Terminations. An
+ AuditValue may request the contents of a descriptor or of a single
+ property, event, signal or statistics.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor] (*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ AuditValue(TerminationID,
+ AuditDescriptor
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (05/2002).
+
+ TerminationID may be specific or wildcarded. If the wildcard matches
+ more than one TerminationID, all possible matches are attempted, with
+ results reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified. If a wildcarded response is
+ requested, only one command return is generated, with the contents
+ containing the union of the values of all Terminations matching the
+ wildcard. This convention may reduce the volume of data required to
+ audit a group of Terminations. Use of CHOOSE is an error.
+
+ Descriptors or individual properties, signals, events and statistics
+ can be audited.
+
+ - An audit of a descriptor may be requested by identifying the
+ desired descriptor in the AuditDescriptor with no further
+ information.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 58]
+ Megaco Protocol version 2 April 2003
+
+
+ - To audit an individual property in the media descriptor the
+ relevant stream ID (optional), group ID (optional) and propertyID
+ are included. The current value of the property is returned. Group
+ ID is used in the case where the local control Reserve Group flag
+ is used. Group ID 1 corresponds to the first group (session
+ decription) reserved, Group ID 2 the next group etcetera.
+
+ - To audit a signal the relevant signal list ID and/or signal ID are
+ provided. Only if the signal is active the values of all the
+ signal parameters are returned including: the keepactive
+ indication, signal type, duration, signal completion indication
+ and package defined properties.
+
+ - To audit an event, the relevant stream id (optional), eventID,
+ requestID (optional) are provided. The values of all the event
+ parameters are returned including: event actions and packaged
+ defined parameters.
+
+ - To audit a statistic the identity of the statistic is provided.
+ The current value of the statistic is returned. The statistic is
+ not reset.
+
+ - To audit a package the identity and version of the package is
+ provided. All properties, signals, events and statistics defined
+ in that particular package are returned with their current value.
+
+ It is possible to audit multiple individual items in one request.
+
+ If a descriptor audit is requested, the appropriate descriptors, with
+ the current values for the Termination, are returned from AuditValue.
+ Values appearing in multiple instances of a descriptor are defined to
+ be alternate values supported, with each parameter in a descriptor
+ considered independent.
+
+ ObservedEvents returns a list of events in the EventBuffer. If the
+ ObservedEventsDescriptor is audited while a DigitMap is active, the
+ returned ObservedEvents descriptor also includes a digit map
+ completion event that shows the current dial string but does not show
+ a Termination method.
+
+ EventBuffer returns the set of events and associated parameter values
+ currently enabled in the EventBufferDescriptor. PackagesDescriptor
+ returns a list of packages realized by the Termination.
+ DigitMapDescriptor returns the name or value of the current DigitMap
+ for the Termination. DigitMap requested in an AuditValue command with
+ TerminationID ALL returns all DigitMaps in the gateway. Statistics
+ returns the current values of all statistics being kept on the
+ Termination. Specifying an empty Audit descriptor results in only the
+ TerminationID being returned. This may be useful to get a list of
+
+
+ Groves et al Expires - October 2003 [Page 59]
+ Megaco Protocol version 2 April 2003
+
+
+ TerminationIDs when used with wildcard. Annexes A and B provide a
+ special syntax for presenting such a list in condensed form, such
+ that the AuditValue command tag does not have to be repeated for each
+ TerminationID.
+
+ AuditValue results depend on the Context, viz. specific, null, or
+ wildcarded. (Note that ContextID All does not include the null
+ Context.) The TerminationID may be specific, or wildcarded.
+
+ The following are examples of what is returned in case the context
+ and/or the termination is wildcarded and a wildcarded response has
+ been specified.
+
+ Assume that the gateway has 4 terminations: t1/1, t1/2, t2/1 and
+ t2/2. Assume that terminations t1/* have implemented packages aaa and
+ bbb and that terminations t2/* have implemented packages ccc and ddd.
+ Assume that Context 1 has t1/1 and t2/1 in it and that Context 2 has
+ t1/2 and t2/2 in it.
+
+ The command:
+
+ Context=1{AuditValue=t1/1{Audit{Packages}}}
+
+ Returns:
+
+ Context=1{AuditValue=t1/1{Packages{aaa,bbb}}}
+
+ The command:
+
+ Context=*{AuditValue=t2/*{Audit{Packages}}}
+
+ Returns:
+
+ Context=1{AuditValue=t2/1{Packages{ccc,ddd}}},
+ Context=2{AuditValue=t2/2{Packages{ccc,ddd}}}
+
+ The command:
+
+ Context=*{W-AuditValue=t1/*{Audit{Packages}}}
+
+ Returns:
+
+ Context=*{W-AuditValue=t1/*{Packages{aaa,bbb}}}
+
+ Note: A wildcard response may also be used for other commands such as
+ Subtract.
+
+ The following illustrates other information that can be obtained with
+ the AuditValue Command:
+
+
+ Groves et al Expires - October 2003 [Page 60]
+ Megaco Protocol version 2 April 2003
+
+
+ ContextID TerminationID Information Obtained
+
+ Specific wildcard Audit of matching Terminations in a
+ Context
+
+ Specific specific Audit of a single Termination in a
+ Context
+
+ Null Root Audit of Media Gateway state and
+ events
+
+ Null wildcard Audit of all matching Terminations
+ in the null Context
+
+ Null specific Audit of a single Termination
+ outside of any Context
+
+ All wildcard Audit of all matching Terminations
+ and the Context to which they are
+ associated
+
+ All Root List of all ContextIds (the
+ ContextID list SHOULD be returned by
+ using multiple action replies, each
+ containing a ContextID from the
+ list)
+
+ All Specific (Non-null) ContextID in which the
+ Termination currently exists
+
+
+
+ 7.2.6 AuditCapabilities
+
+ The AuditCapabilities Command returns the possible values of
+ properties, events, signals and statistics associated with
+ Terminations. An AuditCapabilities may be requested for the contents
+ of a descriptor or for a single property, event, signal or
+ statistics.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor](*)
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+
+
+ Groves et al Expires - October 2003 [Page 61]
+ Megaco Protocol version 2 April 2003
+
+
+ [,StatisticsDescriptor]
+ AuditCapabilities(
+ TerminationID,
+ AuditDescriptor
+ )
+
+ (*) ModemDescriptor has been deprecated in H.248.1 (02/2002).
+
+ Descriptors or individual properties, signals, events and statistics
+ can be audited.
+
+ - An audit of a entire descriptor may be requested by identifying
+ the desired descriptor in the AuditDescriptor with no further
+ information.
+
+ - To audit an individual property in the media descriptor the
+ relevant stream ID (optional) and propertyID are included. A list
+ of possible values of the property are returned.
+
+ - To audit a signal the relevant signal list ID and/or signal ID are
+ provided. A list of possible values associated with each signal
+ parameter is returned (including: the keepactive indication,
+ signal type, duration, signal completion indication and package
+ defined properties).
+
+ - To audit an event the relevant stream id (optional), eventID,
+ requestID (optional) are provided. A list of possible values
+ associated with each event parameter is returned (including: event
+ actions and packaged defined parameters).
+
+ - To audit a statistic the identity of statistic is provided. The
+ possible values of the statistic are returned. The statistic is
+ not reset.
+
+ If a descriptor audit is requested the appropriate descriptors, with
+ the possible values for the Termination, are returned from
+ AuditCapabilities. Descriptors may be repeated where there are
+ multiple possible values.
+
+ If a wildcarded response is requested, only one command return is
+ generated, with the contents containing the union of the values of
+ all Terminations matching the wildcard. This convention may reduce
+ the volume of data required to audit a group of Terminations.
+
+ If a property, signal, event or statistic is audited, the appropriate
+ properties, signals events, and statistics with the capabilities of
+ the Termination are returned from AuditCapabilities.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 62]
+ Megaco Protocol version 2 April 2003
+
+
+ Interpretation of what capabilities are requested for various values
+ of ContextID and TerminationID is the same as in AuditValue.
+
+ The EventsDescriptor returns the list of possible events on the
+ Termination together with the list of all possible values for the
+ EventsDescriptor Parameters. EventBufferDescriptor returns the same
+ information as EventsDescriptor. The SignalsDescriptor returns the
+ list of possible signals that could be applied to the Termination
+ together with the list of all possible values for the Signals
+ Parameters. StatisticsDescriptor returns the names of the statistics
+ being kept on the termination. ObservedEventsDescriptor returns the
+ names of active events on the Termination. DigitMap and Packages are
+ not legal in AuditCapability.
+
+ The following illustrates other information that can be obtained with
+ the AuditCapabilties Command:
+
+ ContextID TerminationID Information Obtained
+
+ Specific wildcard Audit of matching Terminations in
+ a Context
+
+ Specific specific Audit of a single Termination in a
+ Context
+
+ Null Root Audit of MG state and events
+
+ Null wildcard Audit of all matching Terminations
+ in the Null Context
+
+ Null specific Audit of a single Termination
+ outside of any Context
+
+ All wildcard Audit of all matching Terminations
+ and the Context to which they are
+ associated
+
+ All Root Same as for AuditValue
+
+ All Specific Same as for AuditValue
+
+
+
+ 7.2.7 Notify
+
+ The Notify Command allows the Media Gateway to notify the Media
+ Gateway Controller of events occurring within the Media Gateway.
+
+
+
+ Groves et al Expires - October 2003 [Page 63]
+ Megaco Protocol version 2 April 2003
+
+
+ TerminationID
+ Notify(TerminationID,
+ ObservedEventsDescriptor,
+ [ErrorDescriptor]
+ )
+
+ The TerminationID parameter specifies the Termination issuing the
+ Notify Command. The TerminationID shall be a fully qualified name.
+
+ The ObservedEventsDescriptor contains the RequestID and a list of
+ events that the Media Gateway detected in the order that they were
+ detected. Each event in the list is accompanied by parameters
+ associated with the event and optionally an indication of the time
+ that the event was detected. Procedures for sending Notify commands
+ with RequestID equal to 0 are for further study.
+
+ Notify Commands with RequestID not equal to 0 shall occur only as the
+ result of detection of an event specified by an Events descriptor
+ which is active on the Termination concerned.
+
+ The RequestID returns the RequestID parameter of the EventsDescriptor
+ that triggered the Notify Command. It is used to correlate the
+ notification with the request that triggered it. The events in the
+ list must have been requested via the triggering EventsDescriptor or
+ embedded events descriptor unless the RequestID is 0 (which is for
+ further study).
+
+ The ErrorDescriptor may be sent in the Notify Command as a result of
+ Error 518 - "Event buffer full".
+
+ 7.2.8 ServiceChange
+
+ The ServiceChange Command allows the Media Gateway to notify the
+ Media Gateway Controller that a Termination or group of Terminations
+ is about to be taken out of service or has just been returned to
+ service. The Media Gateway Controller may indicate that
+ Termination(s) shall be taken out of or returned to service. The
+ Media Gateway may notify the MGC that the capability of a Termination
+ has changed. It also allows a MGC to hand over control of a MG to
+ another MGC.
+
+ TerminationID,
+ [ServiceChangeDescriptor]
+ ServiceChange(TerminationID,
+ ServiceChangeDescriptor
+ )
+
+ The TerminationID parameter specifies the Termination(s) that are
+ taken out of or returned to service. Wildcarding of Termination names
+
+
+ Groves et al Expires - October 2003 [Page 64]
+ Megaco Protocol version 2 April 2003
+
+
+ is permitted, with the exception that the CHOOSE mechanism shall not
+ be used. Use of the "Root" TerminationID indicates a ServiceChange
+ affecting the entire Media Gateway.
+
+ The ServiceChangeDescriptor contains the following parameters as
+ required:
+
+ - ServiceChangeMethod
+ - ServiceChangeReason
+ - ServiceChangeDelay
+ - ServiceChangeAddress
+ - ServiceChangeProfile
+ - ServiceChangeVersion
+ - ServiceChangeMgcId
+ - TimeStamp
+ - ServiceChangeInfo
+
+ The ServiceChangeMethod parameter specifies the type of ServiceChange
+ that will or has occurred:
+
+ 1) Graceful - indicates that the specified Terminations will be taken
+ out of service after the specified ServiceChangeDelay; established
+ connections are not yet affected, but the Media Gateway Controller
+ SHOULD refrain from establishing new connections and SHOULD
+ attempt to gracefully tear down existing connections on the
+ Termination(s) affected by the serviceChange command. The MG
+ SHOULD set Termination serviceState at the expiry of
+ ServiceChangeDelay or the removal of the Termination from an
+ active Context (whichever is first), to "out of service".
+
+ 2) Forced - indicates that the specified Terminations were taken
+ abruptly out of service and any established connections associated
+ with them may be lost. For non-Root terminations, the MGC is
+ responsible for cleaning up the Context (if any) with which the
+ failed Termination is associated. At a minimum the Termination
+ shall be subtracted from the Context. The Termination serviceState
+ SHOULD be "out of service". For the root termination, the MGC can
+ assume that all connections are lost on the MG and thus can
+ consider that all the terminations have been subtracted.
+
+ 3) Restart - indicates that service will be restored on the specified
+ Terminations after expiration of the ServiceChangeDelay. The
+ serviceState SHOULD be set to "inService" upon expiry of
+ ServiceChangeDelay.
+
+ 4) Disconnected - always applied with the Root TerminationID,
+ indicates that the MG lost communication with the MGC, but it was
+ subsequently restored to the same MGC (possibly after trying other
+ MGCs on a pre-provisioned list). Since MG state may have changed,
+
+
+ Groves et al Expires - October 2003 [Page 65]
+ Megaco Protocol version 2 April 2003
+
+
+ the MGC may wish to use the Audit command to resynchronize its
+ state with the MG's.
+
+ 5) Handoff - sent from the MGC to the MG, this reason indicates that
+ the MGC is going out of service and a new MGC association must be
+ established. Sent from the MG to the MGC, this indicates that the
+ MG is attempting to establish a new association in accordance with
+ a Handoff received from the MGC with which it was previously
+ associated.
+
+ 6) Failover - sent from MG to MGC to indicate the primary MG is out
+ of service and a secondary MG is taking over. This serviceChange
+ method is also sent from the MG to the MGC when the MG detects
+ that MGC has failed.
+
+ 7) Another value whose meaning is mutually understood between the MG
+ and the MGC.
+
+ The ServiceChangeReason parameter specifies the reason why the
+ ServiceChange has or will occur. It consists of an alphanumeric token
+ (IANA registered) and, optionally, an explanatory string.
+
+ The optional ServiceChangeAddress parameter specifies the address
+ (e.g. IP port number for IP networks) to be used for subsequent
+ communications. It can be specified in the input parameter descriptor
+ or the returned result descriptor. ServiceChangeAddress and
+ ServiceChangeMgcId parameters must not both be present in the
+ ServiceChangeDescriptor or the ServiceChangeResultDescriptor. The
+ ServiceChangeAddress provides an address to be used within the
+ Context of the association currently being negotiated, while the
+ ServiceChangeMgcId provides an alternate address where the MG SHOULD
+ seek to establish another association. Note that the use of
+ ServiceChangeAddress is not encouraged. MGCs and MGs must be able to
+ cope with the ServiceChangeAddress being either a full address or
+ just a port number in the case of TCP transports.
+
+ The optional ServiceChangeDelay parameter is expressed in seconds. If
+ the delay is absent or set to zero, the delay value SHOULD be
+ considered to be null. In the case of a "graceful"
+ ServiceChangeMethod, a null delay indicates that the Media Gateway
+ Controller SHOULD wait for the natural removal of existing
+ connections and SHOULD not establish new connections. For "graceful"
+ only, a null delay means the MG must not set serviceState "out of
+ service" until the Termination is in the null Context.
+
+ The optional ServiceChangeProfile parameter specifies the Profile (if
+ any) of the protocol supported. The ServiceChangeProfile includes the
+ version of the profile supported.
+
+
+
+ Groves et al Expires - October 2003 [Page 66]
+ Megaco Protocol version 2 April 2003
+
+
+ The optional ServiceChangeVersion parameter contains the protocol
+ version and is used if protocol version negotiation occurs (see
+ 11.3).
+
+ The optional TimeStamp parameter specifies the actual time as kept by
+ the sender. As such, it is not necessarily absolute time according
+ to, for example, a local time zone - it merely establishes an
+ arbitrary starting time against which all future timestamps
+ transmitted by a sender during this association shall be compared. It
+ can be used by the responder to determine how its notion of time
+ differs from that of its correspondent. TimeStamp is sent with a
+ precision of hundredths of a second.
+
+ The optional Extension parameter may contain any value whose meaning
+ is mutually understood by the MG and MGC.
+
+ The optional ServiceChangeInfo parameter may contain the
+ package/property/signal/event/statistic of the reason that caused the
+ service change.
+
+ A ServiceChange Command specifying the "Root" for the TerminationID
+ and ServiceChangeMethod equal to Restart is a registration command by
+ which a Media Gateway announces its existence to the Media Gateway
+ Controller. The Media Gateway may also register by specifying the
+ "Root" for the TerminationID and ServiceChangeMethod equal to
+ Failover when the MG detects MGC failures. The Media Gateway is
+ expected to be provisioned with the name of one primary and
+ optionally some number of alternate Media Gateway Controllers.
+ Acknowledgement of the ServiceChange Command completes the
+ registration process, except when the MGC has returned an alternative
+ ServiceChangeMgcId as described in the following paragraph. The MG
+ may specify the transport ServiceChangeAddress to be used by the MGC
+ for sending messages in the ServiceChangeAddress parameter in the
+ input ServiceChangeDescriptor. The MG may specify an address in the
+ ServiceChangeAddress parameter of the ServiceChange request, and the
+ MGC may also do so in the ServiceChange reply. In either case, the
+ recipient must use the supplied address as the destination for all
+ subsequent transaction requests within the association. At the same
+ time, as indicated in clause 9, transaction replies and pending
+ indications must be sent to the address from which the corresponding
+ requests originated. This must be done even if it implies extra
+ messaging because commands and responses cannot be packed together.
+ The TimeStamp parameter shall be sent with a registration command and
+ its response.
+
+ The Media Gateway Controller may return a ServiceChangeMgcId
+ parameter that describes the Media Gateway Controller that SHOULD
+ preferably be contacted for further service by the Media Gateway. In
+ this case the Media Gateway shall reissue the ServiceChange command
+
+
+ Groves et al Expires - October 2003 [Page 67]
+ Megaco Protocol version 2 April 2003
+
+
+ to the new Media Gateway Controller. The MGC specified in a
+ ServiceChangeMgcId, if provided, shall be contacted before any
+ further alternate MGCs. On a HandOff message from MGC to MG, the
+ ServiceChangeMgcId is the new MGC that will take over from the
+ current MGC.
+
+ The return from ServiceChange is empty except when the Root
+ terminationID is used. In that case it includes the following
+ parameters as required:
+
+ - ServiceChangeAddress, if the responding MGC wishes to specify a
+ new destination for messages from the MG for the remainder of the
+ association;
+
+ - ServiceChangeMgcId, if the responding MGC does not wish to sustain
+ an association with the MG;
+
+ - ServiceChangeProfile, if the responder wishes to negotiate the
+ profile to be used for the association. The profile (name and
+ version) is only returned in reply in the case that the MGC cannot
+ support the specified profiles in the ServiceChangeRequest. The
+ returned reply shall indicate the profile and version supported or
+ "NoProfile" if no profile is supported. Upon reception of a
+ profile in the reply the MG may continue the relationship with the
+ current MGC or contact secondary MGCs and establish a relationship
+ with them. If the profile is not returned the MGC will use the
+ capabilities specified by the Profile indicated in the service
+ change request;
+
+ - ServiceChangeVersion, if the responder wishes to negotiate the
+ version of the protocol to be used for the association.
+
+ The following ServiceChangeReasons are defined. This list may be
+ extended by an IANA registration as outlined in 14.3.
+
+ 900 Service Restored
+ 901 Cold Boot
+ 902 Warm Boot
+ 903 MGC Directed Change
+ 904 Termination malfunctioning
+ 905 Termination taken out of service
+ 906 Loss of lower layer connectivity (e.g. downstream sync)
+ 907 Transmission Failure
+ 908 MG Impending Failure
+ 909 MGC Impending Failure
+ 910 Media Capability Failure
+ 911 Modem Capability Failure
+ 912 Mux Capability Failure
+ 913 Signal Capability Failure
+
+
+ Groves et al Expires - October 2003 [Page 68]
+ Megaco Protocol version 2 April 2003
+
+
+ 914 Event Capability Failure
+ 915 State Loss
+ 916 Packages Change
+ 917 Capability Change
+
+
+
+ 7.2.9 Manipulating and Auditing Context Attributes
+
+ The commands of the protocol as discussed in the preceding subclauses
+ apply to Terminations. This subclause specifies the processing of
+ Context attributes.
+
+ An action may contain instructions for the manipulation and auditing
+ of Context properties (see clause 8).
+
+ The MGC may audit a specific Context to determine the current value
+ of individual context properties. The MGC may determine the current
+ values for all existing (non-NULL) Contexts by specifying ContextID
+ ALL in the Audit request. If context attributes are added or have
+ been modified by the same action as the Audit request the value/s
+ returned shall be after the action has been applied.
+
+ The following illustrates information that can be obtained with a
+ context Audit:
+
+ ContextID TerminationID Audit
+
+ Specific Not Applicable Context attribute's value in the
+ specified context.
+
+ Null Not Applicable Not Allowed
+
+ All Not Applicable Current values for all existing
+ (non-NULL) Contexts by specifying
+ ContextID ALL in the Audit request.
+
+ A response for ContextID ALL is
+ presented through an actionReply
+ per context.
+
+
+
+ An action may also include a request to change the attributes of a
+ Context.
+
+ The Context properties that may be included in an action reply are
+ used to return information to a MGC. This can be information
+
+
+ Groves et al Expires - October 2003 [Page 69]
+ Megaco Protocol version 2 April 2003
+
+
+ requested by an audit of Context attributes or details of the effect
+ of manipulation of a Context.
+
+ If a MG receives an action which contains both a request to audit
+ context attributes and a request to manipulate those attributes, the
+ response SHALL include the values of the attributes after processing
+ the manipulation request.
+
+ 7.2.10 Generic Command Syntax
+
+ The protocol can be encoded in a binary format or in a text format.
+ MGCs SHOULD support both encoding formats. MGs may support both
+ formats.
+
+ The protocol syntax for the binary format of the protocol is defined
+ in Annex A. Annex C specifies the encoding of the Local and Remote
+ descriptors for use with the binary format.
+
+ A complete ABNF of the text encoding of the protocol per RFC 2234 is
+ given in Annex B. SDP is used as the encoding of the Local and Remote
+ descriptors for use with the text encoding as modified in 7.1.8.
+
+
+ 8 TRANSACTIONS
+
+ Commands between the Media Gateway Controller and the Media Gateway
+ are grouped into Transactions, each of which is identified by a
+ TransactionID. Transactions consist of one or more Actions. An Action
+ consists of a non-empty series of Commands, Context property
+ modifications, or Context property audits that are limited to
+ operating within a single Context. Consequently, each Action
+ typically specifies a ContextID. However, there are two circumstances
+ where a specific ContextID is not provided with an Action. One is the
+ case of modification of a Termination outside of a Context. The other
+ is where the controller requests the gateway to create a new Context.
+ Figure 9 is a graphic representation of the Transaction, Action and
+ Command relationships.
+
+ +----------------------------------------------------------+
+ | Transaction x |
+ | +----------------------------------------------------+ |
+ | | Action 1 | |
+ | | +---------+ +---------+ +---------+ +---------+ | |
+ | | | Command | | Command | | Command | | Command | | |
+ | | | 1 | | 2 | | 3 | | 4 | | |
+ | | +---------+ +---------+ +---------+ +---------+ | |
+ | +----------------------------------------------------+ |
+ | |
+
+
+
+ Groves et al Expires - October 2003 [Page 70]
+ Megaco Protocol version 2 April 2003
+
+
+ | +----------------------------------------------------+ |
+ | | Action 2 | |
+ | | +---------+ | |
+ | | | Command | | |
+ | | | 1 | | |
+ | | +---------+ | |
+ | +----------------------------------------------------+ |
+ | |
+ | +----------------------------------------------------+ |
+ | | Action 3 | |
+ | | +---------+ +---------+ +---------+ | |
+ | | | Command | | Command | | Command | | |
+ | | | 1 | | 2 | | 3 | | |
+ | | +---------+ +---------+ +---------+ | |
+ | +----------------------------------------------------+ |
+ +----------------------------------------------------------+
+
+ Figure 9: Transactions, Actions and Commands
+
+ Transactions are presented as TransactionRequests. Corresponding
+ responses to a TransactionRequest are received in a single reply,
+ possibly preceded by a number of TransactionPending messages (see
+ 8.2.3).
+
+ Transactions guarantee ordered Command processing. That is, Commands
+ within a Transaction are executed sequentially. Ordering of
+ Transactions is NOT guaranteed - transactions may be executed in any
+ order, or simultaneously.
+
+ At the first failing Command in a Transaction, processing of the
+ remaining Commands in that Transaction stops. If a command contains a
+ wildcarded TerminationID, the command is attempted with each of the
+ actual TerminationIDs matching the wildcard. A response within the
+ TransactionReply is included for each matching TerminationID, even if
+ one or more instances generated an error. If any TerminationID
+ matching a wildcard results in an error when executed, any commands
+ following the wildcarded command are not attempted.
+
+ Commands may be marked as "Optional" which can override this
+ behaviour - if a command marked as Optional results in an error,
+ subsequent commands in the Transaction will be executed. If a command
+ fails, the MG shall as far as possible restore the state that existed
+ prior to the attempted execution of the command before continuing
+ with command processing.
+
+ A TransactionReply includes the results for all of the Commands in
+ the corresponding TransactionRequest. The TransactionReply includes
+ the return values for the Commands that were executed successfully,
+ and the Command and error descriptor for any Command that failed.
+
+
+ Groves et al Expires - October 2003 [Page 71]
+ Megaco Protocol version 2 April 2003
+
+
+ TransactionPending is used to periodically notify the receiver that a
+ Transaction has not completed yet, but is actively being processed.
+
+ Applications SHOULD implement an application level timer per
+ transaction. Expiration of the timer SHOULD cause a retransmission of
+ the request. Receipt of a Reply SHOULD cancel the timer. Receipt of
+ Pending SHOULD restart the timer.
+
+ 8.1 Common parameters
+
+ 8.1.1 Transaction Identifiers
+
+ Transactions are identified by a TransactionID, which is assigned by
+ sender and is unique within the scope of the sender. A response
+ containing an error descriptor to indicate that the TransactionID is
+ missing in a request shall use TransactionID 0 in the corresponding
+ TransactionReply.
+
+ 8.1.2 Context Identifiers
+
+ Contexts are identified by a ContextID, which is assigned by the
+ Media Gateway and is unique within the scope of the Media Gateway.
+ The Media Gateway Controller shall use the ContextID supplied by the
+ Media Gateway in all subsequent Transactions relating to that
+ Context. The protocol makes reference to a distinguished value that
+ may be used by the Media Gateway Controller when referring to a
+ Termination that is currently not associated with a Context, namely
+ the null ContextID.
+
+ The CHOOSE wildcard is used to request that the Media Gateway create
+ a new Context.
+
+ The MGC may use the ALL wildcard to address all Contexts on the MG.
+ The null Context is not included when the ALL wildcard is used.
+
+ The MGC shall not use partially specified ContextIDs containing the
+ CHOOSE or ALL wildcards.
+
+ 8.2 Transaction Application Programming Interface
+
+ Following is an Application Programming Interface (API) describing
+ the Transactions of the protocol. This API is shown to illustrate the
+ Transactions and their parameters and is not intended to specify
+ implementation (e.g. via use of blocking function calls). It will
+ describe the input parameters and return values expected to be used
+ by the various Transactions of the protocol from a very high level.
+ Transaction syntax and encodings are specified in later subclauses.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 72]
+ Megaco Protocol version 2 April 2003
+
+
+ 8.2.1 TransactionRequest
+
+ The TransactionRequest is invoked by the sender. There is one
+ Transaction per request invocation. A request contains one or more
+ Actions, each of which specifies its target Context and one or more
+ Commands per Context.
+
+ TransactionRequest(TransactionId {
+ ContextID {Command ... Command},
+ . . .
+ ContextID {Command ... Command } })
+
+ The TransactionID parameter must specify a value for later
+ correlation with the TransactionReply or TransactionPending response
+ from the receiver.
+
+ The ContextID parameter must specify a value to pertain to all
+ Commands that follow up to either the next specification of a
+ ContextID parameter or the end of the TransactionRequest, whichever
+ comes first.
+
+ The Command parameter represents one of the Commands mentioned in 7.2
+ (Command Application Programming Interface).
+
+ 8.2.2 TransactionReply
+
+ The TransactionReply is invoked by the receiver. There is one reply
+ invocation per transaction. A reply contains one or more Actions,
+ each of which must specify its target Context and one or more
+ Responses per Context. The TransactionReply is invoked by the
+ responder when it has processed the TransactionRequest.
+
+ A TransactionRequest has been processed:
+
+ - when all actions in that TransactionRequest have been processed;
+ or
+
+ - when an error is encountered in processing that
+ TransactionRequest, except when the error is in an optional
+ command.
+
+ A command has been processed when all descriptors in that command
+ have been processed.
+
+ A SignalsDescriptor is considered to have been processed when it has
+ been established that the descriptor is syntactically valid, the
+ requested signals are supported and they have been queued to be
+ applied.
+
+
+
+ Groves et al Expires - October 2003 [Page 73]
+ Megaco Protocol version 2 April 2003
+
+
+ An EventsDescriptor or EventBufferDescriptor is considered to have
+ been processed when it has been established that the descriptor is
+ syntactically valid, the requested events can be observed, any
+ embedded signals can be generated, any embedded events can be
+ detected, and the MG has been brought into a state in which the
+ events will be detected.
+
+ TransactionReply(TransactionID {
+ ContextID { Response ... Response },
+ . . .
+ ContextID { Response ... Response } })
+
+ The TransactionID parameter must be the same as that of the
+ corresponding TransactionRequest.
+
+ The ContextID parameter must specify a value to pertain to all
+ Responses for the action. The ContextID may be specific, all or null.
+
+ Each of the Response parameters represents a return value as
+ mentioned in 7.2, or an error descriptor if the command execution
+ encountered an error. Commands after the point of failure are not
+ processed and, therefore, Responses are not issued for them.
+
+ An exception to this occurs if a command has been marked as optional
+ in the Transaction request. If the optional command generates an
+ error, the transaction still continues to execute, so the Reply
+ would, in this case, have Responses after an Error.
+
+ Section 7.1.19 Error Descriptor specifies the generation of error
+ descriptors. The text below discusses several individual cases.
+
+ If the receiver encounters an error in processing a ContextID, the
+ requested Action response will consist of the Context ID and a single
+ error descriptor, 422 - "Syntax Error in Action".
+
+ If the receiver encounters an error such that it cannot determine a
+ legal Action, it will return a TransactionReply consisting of the
+ TransactionID and a single error descriptor, 422 - "Syntax Error in
+ Action". If the end of an action cannot be reliably determined but
+ one or more commands can be parsed, it will process them and then
+ send 422 - "Syntax Error in Action" as the last action for the
+ transaction. If the receiver encounters an error such that is cannot
+ determine a legal Transaction, it will return a TransactionReply with
+ a null TransactionID and a single error descriptor (403 - "Syntax
+ Error in Transaction").
+
+ If the end of a transaction cannot be reliably determined and one or
+ more Actions can be parsed, it will process them and then return 403
+ - "Syntax Error in Transaction" as the last action reply for the
+
+
+ Groves et al Expires - October 2003 [Page 74]
+ Megaco Protocol version 2 April 2003
+
+
+ transaction. If no Actions can be parsed, it will return 403 -
+ "Syntax Error in Transaction" as the only reply.
+
+ If the terminationID cannot be reliably determined, it will send 442
+ - "Syntax Error in Command" as the action reply.
+
+ If the end of a command cannot be reliably determined, it will return
+ 442 - "Syntax Error in Command" as the reply to the last action it
+ can parse.
+
+ 8.2.3 TransactionPending
+
+ The receiver invokes the TransactionPending. A TransactionPending
+ indicates that the Transaction is actively being processed, but has
+ not been completed. It is used to prevent the sender from assuming
+ the TransactionRequest was lost where the Transaction will take some
+ time to complete.
+
+ TransactionPending(TransactionID { } )
+
+ The TransactionID parameter must be the same as that of the
+ corresponding TransactionRequest. A property of root
+ (normalMGExecutionTime) is settable by the MGC to indicate the
+ interval within which the MGC expects a response to any transaction
+ from the MG. Another property (normalMGCExecutionTime) is settable by
+ the MGC to indicate the interval within which the MG SHOULD expect a
+ response to any transaction from the MGC. Senders may receive more
+ than one TransactionPending for a command. If a duplicate request is
+ received when pending, the responder may send a duplicate pending
+ immediately, or continue waiting for its timer to trigger another
+ TransactionPending.
+
+ A property of the root termination (MGOriginatedPendingLimit) is
+ settable by the MGC to indicate the number of TransactionPendings
+ that can be received from the MG. When the value expressed by this
+ property is exceeded, the MG shall stop the transaction processing
+ and send back a TransactionReply, otherwise the MGC can assume the
+ Transaction to be in error.
+
+ Another property of the root termination (MGCOriginatedPendingLimit)
+ is settable by the MGC to indicate the number of TransactionPendings
+ that can be received from the MGC. When the value expressed by this
+ property is exceeded, the MGC shall stop the transaction processing
+ and send back a TransactionReply otherwise the MG can assume the
+ Transaction to be in error.
+
+ The xxxOriginatedPendingLimit (MGOriginatedPendingLimit or
+ MGCOriginatedPendingLimit) may be exceeded either because of long
+ command processing or due to an error (e.g. a command caused a loop).
+
+
+ Groves et al Expires - October 2003 [Page 75]
+ Megaco Protocol version 2 April 2003
+
+
+ In both cases the receiver of the original TransactionRequest will
+ issue a TransactionReply with an error descriptor as a response
+ parameter in correspondence with either the offending long command or
+ the command that caused the error. Further commands in the
+ transaction shall not be processed. Error 506 - "Number of
+ TransactionPendings Exceeded" shall be used.
+
+ NOTE - To prevent a situation where the xxxOriginatedPendingLimit
+ (MGOriginatedPendingLimit or MGCOriginatedPendingLimit) is exceeded
+ due to an error and the receiver of the original TransactionRequest
+ keeps sending TransactionPending, the receiver of the original
+ TransactionRequest SHOULD implement a management protection mechanism
+ in order to trigger the appropriate recovery actions. The sender of
+ the original TransactionRequest may keep track of the number of
+ received Pendings and initiate corrective actions
+
+ 8.3 Messages
+
+ Multiple Transactions can be concatenated into a Message. Messages
+ have a header, which includes the identity of the sender. The Message
+ Identifier (MID) of a message is set to a provisioned name (e.g.
+ domain address/domain name/device name) of the entity transmitting
+ the message. Domain name is a suggested default. An H.248.1 entity
+ (MG/MGC) must consistently use the same MID in all messages it
+ originates for the duration of control association with the peer
+ (MGC/MG).
+
+ Every Message contains a Version Number identifying the version of
+ the protocol the message conforms to. Versions consist of one or two
+ digits, beginning with version 1. The current version of the protocol
+ is Version 2.
+
+ The transactions in a message are treated independently. There is no
+ order implied; there is no application or protocol acknowledgement of
+ a message. A message is essentially a transport mechanism. For
+ example, message X containing transaction requests A, B, and C may be
+ responded to with message Y containing replies to A and C and message
+ Z containing the reply to B. Likewise, message L containing request D
+ and message M containing request E may be responded to with message N
+ containing replies to both D and E.
+
+
+ 9 TRANSPORT
+
+ The transport mechanism for the protocol SHOULD allow the reliable
+ transport of transactions between a MGC and MG. The transport shall
+ remain independent of what particular commands are being sent and
+ shall be applicable to all application states. There are several
+ transports defined for the protocol, which are defined in Annexes to
+
+
+ Groves et al Expires - October 2003 [Page 76]
+ Megaco Protocol version 2 April 2003
+
+
+ this Recommendation and other Recommendations of the H.248 sub-series
+ (e.g. H.248.4 and H.248.5). Additional Transports may be defined as
+ additional Recommendations of the H.248 sub-series. For transport of
+ the protocol over IP, MGCs shall implement both TCP and UDP/ALF, a MG
+ shall implement TCP or UDP/ALF or both.
+
+ The MG is provisioned with a name or address (such as DNS name or IP
+ address) of a primary and zero or more secondary MGCs (see 7.2.8)
+ that is the address the MG uses to send messages to the MGC. If TCP
+ or UDP is used as the protocol transport and the port to which the
+ initial ServiceChange request is to be sent is not otherwise known,
+ that request SHOULD be sent to the default port number for the
+ protocol. This port number is 2944 for text-encoded operation or 2945
+ for binary-encoded operation, for either UDP or TCP. The MGC receives
+ the message containing the ServiceChange request from the MG and can
+ determine the MG's address from it. As described in 7.2.8, either the
+ MG or the MGC may supply an address in the ServiceChangeAddress
+ parameter to which subsequent transaction requests must be addressed,
+ but responses (including the response to the initial ServiceChange
+ request) must always be sent back to the address which was the source
+ of the corresponding request. For example, in IP networks, this is
+ the source address in the IP header and the source port number in the
+ TCP/UDP/SCTP header.
+
+ 9.1 Ordering of Commands
+
+ This Recommendation does not mandate that the underlying transport
+ protocol guarantees the sequencing of transactions sent to an entity.
+ This property tends to maximize the timeliness of actions, but it has
+ a few drawbacks. For example:
+
+ - Notify commands may be delayed and arrive at the MGC after the
+ transmission of a new command changing the EventsDescriptor.
+
+ - If a new command is transmitted before a previous one is
+ acknowledged, there is no guarantee that prior command will be
+ executed before the new one.
+
+ Media Gateway Controllers that want to guarantee consistent operation
+ of the Media Gateway may use the following rules. These rules are
+ with respect to commands that are in different transactions. Commands
+ that are in the same transaction are executed in order (see clause
+ 8).
+
+ 1) When a Media Gateway handles several Terminations, commands
+ pertaining to the different Terminations may be sent in parallel,
+ for example following a model where each Termination (or group of
+ Terminations) is controlled by its own process or its own thread.
+
+
+
+ Groves et al Expires - October 2003 [Page 77]
+ Megaco Protocol version 2 April 2003
+
+
+ 2) On a Termination, there SHOULD normally be at most one outstanding
+ command (Add or Modify or Move), unless the outstanding commands
+ are in the same transaction. However, a Subtract command may be
+ issued at any time. In consequence, a Media Gateway may sometimes
+ receive a Modify command that applies to a previously subtracted
+ Termination. Such commands SHOULD be ignored, and an error code
+ SHOULD be returned.
+
+ 3) For transports that do not guarantee in-sequence delivery of
+ messages (i.e. UDP), there SHOULD normally be on a given
+ Termination at most one outstanding Notify command at any time.
+
+ 4) In some cases, an implicitly or explicitly wildcarded Subtract
+ command that applies to a group of Terminations may step in front
+ of a pending Add command. The Media Gateway Controller SHOULD
+ individually delete all Terminations for which an Add command was
+ pending at the time of the global Subtract command. Also, new Add
+ commands for Terminations named by the wildcarding (or implied in
+ a Multiplex descriptor) SHOULD not be sent until the wildcarded
+ Subtract command is acknowledged.
+
+ 5) AuditValue and AuditCapability are not subject to any sequencing.
+
+ 6) ServiceChange shall always be the first command sent by a MG as
+ defined by the restart procedure. Any other command or response
+ must be delivered after this ServiceChange command.
+
+ These rules do not affect the command responder, which SHOULD always
+ respond to commands.
+
+ 9.2 Protection against Restart Avalanche
+
+ In the event that a large number of Media Gateways are powered on
+ simultaneously and they were to all initiate a ServiceChange
+ transaction, the Media Gateway Controller would very likely be
+ swamped, leading to message losses and network congestion during the
+ critical period of service restoration. In order to prevent such
+ avalanches, the following behaviour is suggested:
+
+ 1) When a Media Gateway is powered on, it SHOULD initiate a restart
+ timer to a random value, uniformly distributed between 0 and a
+ maximum waiting delay (MWD). Care SHOULD be taken to avoid
+ synchronicity of the random number generation between multiple
+ Media Gateways that would use the same algorithm.
+
+ 2) The Media Gateway SHOULD then wait for either the end of this
+ timer or the detection of a local user activity, such as for
+ example an off-hook transition on a residential Media Gateway.
+
+
+
+ Groves et al Expires - October 2003 [Page 78]
+ Megaco Protocol version 2 April 2003
+
+
+ 3) When the timer elapses, or when an activity is detected, the Media
+ Gateway SHOULD initiate the restart procedure.
+
+ The restart procedure simply requires the MG to guarantee that the
+ first message that the Media Gateway Controller sees from this MG is
+ a ServiceChange message informing the Media Gateway Controller about
+ the restart.
+
+ NOTE - The value of MWD is a configuration parameter that depends on
+ the type of the Media Gateway. The following reasoning may be used to
+ determine the value of this delay on residential gateways.
+
+ Media Gateway Controllers are typically dimensioned to handle the
+ peak hour traffic load, during which, in average, 10% of the lines
+ will be busy, placing calls whose average duration is typically 3
+ minutes. The processing of a call typically involves 5 to 6 Media
+ Gateway Controller transactions between each Media Gateway and the
+ Media Gateway Controller. This simple calculation shows that the
+ Media Gateway Controller is expected to handle 5 to 6 transactions
+ for each Termination, every 30 minutes on average, or, to put it
+ otherwise, about one transaction per Termination every 5 to 6 minutes
+ on average. This suggests that a reasonable value of MWD for a
+ residential gateway would be 10 to 12 minutes. In the absence of
+ explicit configuration, residential gateways SHOULD adopt a value of
+ 600 seconds for MWD.
+
+ The same reasoning suggests that the value of MWD SHOULD be much
+ shorter for trunking gateways or for business gateways, because they
+ handle a large number of Terminations, and also because the usage
+ rate of these Terminations is much higher than 10% during the peak
+ busy hour, a typical value being 60%. These Terminations, during the
+ peak hour, are this expected to contribute about one transaction per
+ minute to the Media Gateway Controller load. A reasonable algorithm
+ is to make the value of MWD per "trunk" Termination six times shorter
+ than the MWD per residential gateway, and also inversely proportional
+ to the number of Terminations that are being restarted. For example
+ MWD SHOULD be set to 2.5 seconds for a gateway that handles a T1
+ line, or to 60 milliseconds for a gateway that handles a T3 line.
+
+
+ 10 SECURITY CONSIDERATIONS
+
+ This clause covers security when using the protocol in an IP
+ environment.
+
+ 10.1 Protection of Protocol Connections
+
+ A security mechanism is clearly needed to prevent unauthorized
+ entities from using the protocol defined in this Recommendation for
+
+
+ Groves et al Expires - October 2003 [Page 79]
+ Megaco Protocol version 2 April 2003
+
+
+ setting up unauthorized calls or interfering with authorized calls.
+ The security mechanism for the protocol when transported over IP
+ networks is IPsec [RFC 2401 to RFC 2411].
+
+ The AH header [RFC 2402] affords data origin authentication,
+ connectionless integrity and optional anti-replay protection of
+ messages passed between the MG and the MGC. The ESP header [RFC 2406]
+ provides confidentiality of messages, if desired. For instance, the
+ ESP encryption service SHOULD be requested if the session
+ descriptions are used to carry session keys, as defined in SDP.
+
+ Implementations of the protocol defined in this Recommendation
+ employing the ESP header SHALL comply with section 5 of [RFC 2406],
+ which defines a minimum set of algorithms for integrity checking and
+ encryption. Similarly, implementations employing the AH header SHALL
+ comply with section 5 of [RFC 2402], which defines a minimum set of
+ algorithms for integrity checking using manual keys.
+
+ Implementations SHOULD use IKE [RFC 2409] to permit more robust
+ keying options. Implementations employing IKE SHOULD support
+ authentication with RSA signatures and RSA public key encryption.
+
+ 10.2 Interim AH scheme
+
+ Implementation of IPsec requires that the AH or ESP header be
+ inserted immediately after the IP header. This cannot be easily done
+ at the application level. Therefore, this presents a deployment
+ problem for the protocol defined in this Recommendation where the
+ underlying network implementation does not support IPsec.
+
+ As an interim solution, an optional AH header is defined within the
+ H.248.1 protocol header. The header fields are exactly those of the
+ SPI, SEQUENCE NUMBER and DATA fields as defined in [RFC 2402]. The
+ semantics of the header fields are the same as the "transport mode"
+ of [RFC 2402], except for the calculation of the Integrity Check
+ Value (ICV). In IPsec, the ICV is calculated over the entire IP
+ packet including the IP header. This prevents spoofing of the IP
+ addresses. To retain the same functionality, the ICV calculation
+ SHOULD be performed across all the transactions (concatenated) in the
+ message prepended by a synthesized IP header consisting of a 32-bit
+ source IP address, a 32-bit destination address and a 16-bit UDP
+ destination port encoded as 20 hex digits. When the interim AH
+ mechanism is employed when TCP is the transport Layer, the UDP Port
+ above becomes the TCP port, and all other operations are the same.
+
+ Implementations of the H.248.1 protocol SHALL implement IPsec where
+ the underlying operating system and the transport network supports
+ IPsec. Implementations of the protocol using IPv4 SHALL implement the
+ interim AH scheme. However, this interim scheme SHALL NOT be used
+
+
+ Groves et al Expires - October 2003 [Page 80]
+ Megaco Protocol version 2 April 2003
+
+
+ when the underlying network layer supports IPsec. IPv6
+ implementations are assumed to support IPsec and SHALL NOT use the
+ interim AH scheme.
+
+ All implementations of the interim AH mechanism SHALL comply with
+ section 5 of RFC 2402 which defines a minimum set of algorithms for
+ integrity checking using manual keys.
+
+ The interim AH interim scheme does not provide protection against
+ eavesdropping, thus forbidding third parties from monitoring the
+ connections set up by a given Termination. Also, it does not provide
+ protection against replay attacks. These procedures do not
+ necessarily protect against denial of service attacks by misbehaving
+ MGs or misbehaving MGCs. However, they will provide an identification
+ of these misbehaving entities, which SHOULD then be deprived of their
+ authorization through maintenance procedures.
+
+ 10.3 Protection of Media Connections
+
+ The protocol allows the MGC to provide MGs with "session keys" that
+ can be used to encrypt the audio messages, protecting against
+ eavesdropping.
+
+ A specific problem of packet networks is "uncontrolled barge-in".
+ This attack can be performed by directing media packets to the IP
+ address and UDP port used by a connection. If no protection is
+ implemented, the packets must be decompressed and the signals must be
+ played on the "line side".
+
+ A basic protection against this attack is to only accept packets from
+ known sources, checking for example that the IP source address and
+ UDP source port match the values announced in the Remote descriptor.
+ This has two inconveniences: it slows down connection establishment
+ and it can be fooled by source spoofing:
+
+ - To enable the address-based protection, the MGC must obtain the
+ remote session description of the egress MG and pass it to the
+ ingress MG. This requires at least one network round trip, and
+ leaves us with a dilemma: either allow the call to proceed without
+ waiting for the round trip to complete, and risk for example,
+ "clipping" a remote announcement, or wait for the full round trip
+ and settle for slower call-set up procedures.
+
+ - Source spoofing is only effective if the attacker can obtain valid
+ pairs of source destination addresses and ports, for example by
+ listening to a fraction of the traffic. To fight source spoofing,
+ one could try to control all access points to the network. But
+ this is in practice very hard to achieve.
+
+
+
+ Groves et al Expires - October 2003 [Page 81]
+ Megaco Protocol version 2 April 2003
+
+
+ An alternative to checking the source address is to encrypt and
+ authenticate the packets, using a secret key that is conveyed during
+ the call set-up procedure. This will not slow down the call set-up,
+ and provides strong protection against address spoofing.
+
+
+ 11 MG-MGC CONTROL INTERFACE
+
+ The control association between MG and MGC is initiated at MG cold
+ start, and announced by a ServiceChange message, but can be changed
+ by subsequent events, such as failures or manual service events.
+
+ NOTE - While the protocol does not have an explicit mechanism to
+ support multiple MGCs controlling a physical MG, it has been designed
+ to support the multiple logical MG (within a single physical MG) that
+ can be associated with different MGCs.
+
+ 11.1 Multiple Virtual MGs
+
+ A physical Media Gateway may be partitioned into one or more Virtual
+ MGs. A virtual MG consists of a set of statically partitioned
+ physical Terminations and/or sets of ephemeral Terminations. A
+ physical Termination is controlled by one MGC. The model does not
+ require that other resources be statically allocated, just
+ Terminations. The mechanism for allocating Terminations to virtual
+ MGs is a management method outside the scope of the protocol. Each of
+ the virtual MGs appears to the MGC as a complete MG client.
+
+ A physical MG may have only one network interface, which must be
+ shared across virtual MGs. In such a case, the packet/cell side
+ Termination is shared. It SHOULD be noted however, that in use, such
+ interfaces require an ephemeral instance of the Termination to be
+ created per flow, and thus sharing the Termination is
+ straightforward. This mechanism does lead to a complication, namely
+ that the MG must always know which of its controlling MGCs SHOULD be
+ notified if an event occurs on the interface.
+
+ In normal operation, the Virtual MG will be instructed by the MGC to
+ create network flows (if it is the originating side), or to expect
+ flow requests (if it is the terminating side), and no confusion will
+ arise. However, if an unexpected event occurs, the Virtual MG must
+ know what to do with respect to the physical resources it is
+ controlling.
+
+ If recovering from the event requires manipulation of a physical
+ interface's state, only one MGC SHOULD do so. These issues are
+ resolved by allowing any of the MGCs to create EventsDescriptors to
+ be notified of such events, but only one MGC can have read/write
+ access to the physical interface properties; all other MGCs have
+
+
+ Groves et al Expires - October 2003 [Page 82]
+ Megaco Protocol version 2 April 2003
+
+
+ read-only access. The management mechanism is used to designate which
+ MGC has read/write capability, and is designated the Master MGC.
+
+ Each virtual MG has its own Root Termination. In most cases the
+ values for the properties of the Root Termination are independently
+ settable by each MGC. Where there can only be one value, the
+ parameter is read-only to all but the Master MGC.
+
+ ServiceChange may only be applied to a Termination or set of
+ Terminations partitioned to the Virtual MG or created (in the case of
+ ephemeral Terminations) by that Virtual MG.
+
+ 11.2 Cold start
+
+ A MG is pre-provisioned by a management mechanism outside the scope
+ of this protocol with a primary and (optionally) an ordered list of
+ secondary MGCs. Upon a cold start of the MG, it will issue a
+ ServiceChange command with a "Restart" method, on the Root
+ Termination to its primary MGC. If the MGC accepts the MG, it sends a
+ Transaction Reply not including a ServiceChangeMgcId parameter. If
+ the MGC does not accept the MG�s registration, it sends a Transaction
+ Reply, providing the address of an alternate MGC to be contacted by
+ including a ServiceChangeMgcId parameter.
+
+ If the MG receives a Transaction Reply that includes a
+ ServiceChangeMgcId parameter, it sends a ServiceChange to the MGC
+ specified in the ServiceChangeMgcId. It continues this process until
+ it gets a controlling MGC to accept its registration, or it fails to
+ get a reply. Upon failure to obtain a reply, either from the primary
+ MGC, or a designated successor, the MG tries its pre-provisioned
+ secondary MGCs, in order. If the MG is unable to establish a control
+ relationship with any MGC, it shall wait a random amount of time as
+ described in 9.2 and then start contacting its primary, and if
+ necessary, its secondary MGCs again.
+
+ It is possible that the reply to a ServiceChange with Restart will be
+ lost, and a command will be received by the MG prior to the receipt
+ of the ServiceChange response. The MG shall issue Error 505 - Command
+ Received before Restart Response.
+
+ 11.3 Negotiation of protocol version
+
+ A ServiceChange command from a MG that registers with an MGC shall
+ contain the version number of the protocol supported by the MG in the
+ ServiceChangeVersion parameter. Regardless of the version placed in
+ the ServiceChangeVersion parameter the message containing the command
+ shall be encoded as a version 1 message. Upon receiving such a
+ message, if the MGC supports only a lower version, then the MGC shall
+ send a ServiceChangeReply with the lower version and thereafter all
+
+
+ Groves et al Expires - October 2003 [Page 83]
+ Megaco Protocol version 2 April 2003
+
+
+ the messages between MG and MGC shall conform to the lower version of
+ the protocol. If the MG is unable to comply and it has established a
+ transport connection to the MGC, it SHOULD close that connection. In
+ any event, it SHOULD reject all subsequent requests from the MGC with
+ Error 406 - "Version Not Supported".
+
+ If the MGC supports a higher version than the MG but is able to
+ support the lower version proposed by the MG, it shall send a
+ ServiceChangeReply with the lower version and thereafter all the
+ messages between MG and MGC shall conform to the lower version of the
+ protocol. If the MGC is unable to comply, it shall reject the
+ association, with Error 406 - "Version Not Supported".
+
+ Protocol version negotiation may also occur at "handoff" and
+ "failover" ServiceChanges.
+
+ When extending the protocol with new versions, the following rules
+ SHOULD be followed:
+
+ 1) Existing protocol elements, i.e. procedures, parameters,
+ descriptor, property, values, SHOULD not be changed unless a
+ protocol error needs to be corrected or it becomes necessary to
+ change the operation of the service that is being supported by the
+ protocol.
+
+ 2) The semantics of a command, a parameter, a descriptor, a property,
+ or a value SHOULD not be changed.
+
+ 3) Established rules for formatting and encoding messages and
+ parameters SHOULD not be modified.
+
+ 4) When information elements are found to be obsolete they can be
+ marked as not used. However, the identifier for that information
+ element will be marked as reserved. In that way it can not be used
+ in future versions.
+
+ 11.4 Failure of a MG
+
+ If a MG fails, but is capable of sending a message to the MGC, it
+ sends a ServiceChange with an appropriate method (graceful or forced)
+ and specifies the Root TerminationID. When it returns to service, it
+ sends a ServiceChange with a "Restart" method.
+
+ Allowing the MGC to send duplicate messages to both MGs accommodates
+ pairs of MGs that are capable of redundant failover of one of the
+ MGs. Only the Working MG shall accept or reject transactions. Upon
+ failover, the primary MG sends a ServiceChange command with a
+ "Failover" method and a "MG Impending Failure" reason. The MGC then
+ uses the secondary MG as the active MG. When the error condition is
+
+
+ Groves et al Expires - October 2003 [Page 84]
+ Megaco Protocol version 2 April 2003
+
+
+ repaired, the Working MG can send a "ServiceChange" with a "Restart"
+ method.
+
+ Note: Redundant failover MGs require a reliable transport, because
+ the protocol provides no means for a secondary MG running ALF to
+ acknowledge messages sent from the MGC.
+
+ 11.5 Failure of an MGC
+
+ If the MG detects a failure of its controlling MGC, it attempts to
+ contact the next MGC on its pre-provisioned list. It starts its
+ attempts at the beginning (primary MGC), unless that was the MGC that
+ failed, in which case it starts at its first secondary MGC. It sends
+ a ServiceChange message with a "Failover" method and a " MGC
+ Impending Failure" reason. If the MG is unable to establish a control
+ relationship with any MGC, it shall wait a random amount of time as
+ described in section 9.2 and then start again contacting its primary,
+ and (if necessary) its secondary MGCs. When contacting its previously
+ controlling MGC, the MG sends the ServiceChange message with
+ "Disconnected" method.
+
+ In partial failure, or for manual maintenance reasons, an MGC may
+ wish to direct its controlled MGs to use a different MGC. To do so,
+ it sends a ServiceChange method to the MG with a "HandOff" method,
+ and its designated replacement in ServiceChangeMgcId. If "HandOff" is
+ supported, the MG shall send a ServiceChange message with a "Handoff"
+ method and a "MGC directed change" reason to the designated MGC. If
+ it fails to get a reply from the designated MGC, the MG shall behave
+ as if its MGC failed, and start contacting secondary MGCs as
+ specified in the previous paragraph. If the MG is unable to establish
+ a control relationship with any MGC, it shall wait a random amount of
+ time as described in 9.2 and then start contacting its primary, and
+ if necessary, its secondary MGCs again.
+
+ No recommendation is made on how the MGCs involved in the Handoff
+ maintain state information; this is considered to be out of scope of
+ this Recommendation. The MGC and MG may take the following steps when
+ Handoff occurs. When the MGC initiates a HandOff, the handover SHOULD
+ be transparent to Operations on the Media Gateway. Transactions can
+ be executed in any order, and could be in progress when the
+ ServiceChange is executed. Accordingly, commands in progress continue
+ and replies to all commands from the original MGC must be sent to the
+ transport address from which they were sent. If the service
+ relationship with the sending MGC has ended, the replies SHOULD be
+ discarded. The MG may receive outstanding transaction replies from
+ the new MGC. No new messages shall be sent to the new MGC until the
+ control association is established. Repeated transaction requests
+ shall be directed to the new MGC. The MG shall maintain state on all
+ Terminations and Contexts.
+
+
+ Groves et al Expires - October 2003 [Page 85]
+ Megaco Protocol version 2 April 2003
+
+
+ It is possible that the MGC could be implemented in such a way that a
+ failed MGC is replaced by a working MGC where the identity of the new
+ MGC is the same as the failed one. In such a case, ServiceChangeMgcId
+ would be specified with the previous value and the MG shall behave as
+ if the value was changed, and send a ServiceChange message, as above.
+
+ Pairs of MGCs that are capable of redundant failover can notify the
+ controlled MGs of the failover by the above mechanism.
+
+
+ 12 PACKAGE DEFINITION
+
+ The primary mechanism for extension is by means of Packages. Packages
+ define additional Properties, Events, Signals and Statistics that may
+ occur on Terminations.
+
+ Packages defined by IETF will appear in separate RFCs.
+
+ Packages defined by ITU-T may appear in the relevant Recommendations
+ (e.g. as Recommendations of the H.248 sub-series).
+
+ 1) A public document or a standard forum document, which can be
+ referenced as the document that describes the package following
+ the guideline above, SHOULD be specified.
+
+ 2) The document shall specify the version of the Package that it
+ describes.
+
+ 3) The document SHOULD be available on a public web server and SHOULD
+ have a stable URL. The site SHOULD provide a mechanism to provide
+ comments and appropriate responses SHOULD be returned.
+
+ 12.1 Guidelines for defining packages
+
+ Packages define Properties, Events, Signals, and Statistics.
+
+ Packages may also define new error codes according to the guidelines
+ given in 13.2. This is a matter of documentary convenience: the
+ package documentation is submitted to IANA in support of the error
+ code registration. If a package is modified, it is unnecessary to
+ provide IANA with a new document reference in support of the error
+ code unless the description of the error code itself is modified.
+
+ Names of all such defined constructs shall consist of the PackageID
+ (which uniquely identifies the package) and the ID of the item (which
+ uniquely identifies the item in that package). In the text encoding
+ the two shall be separated by a forward slash ("/") character.
+ Example: togen/playtone is the text encoding to refer to the play
+ tone signal in the tone generation package.
+
+
+ Groves et al Expires - October 2003 [Page 86]
+ Megaco Protocol version 2 April 2003
+
+
+ A Package will contain the following sections:
+
+ 12.1.1 Package
+
+ Overall description of the package, specifying:
+
+ Package Name: only descriptive
+
+ PackageID: is an identifier
+
+ Description:
+
+ Version:
+
+ A new version of a package can only add additional Properties,
+ Events, Signals, Statistics and new possible values for an existing
+ parameter described in the original package. No deletions or
+ modifications shall be allowed. A version is an integer in the range
+ from 1 to 99.
+
+ Designed to be extended only (Optional): Yes
+
+ This indicates that the package has been expressly designed to be
+ extended by others, not to be directly referenced. For example, the
+ package may not have any function on its own or be nonsensical on its
+ own. The MG SHOULD NOT publish this PackageID when reporting
+ packages.
+
+ Extends (Optional): existing package Descriptor
+
+ A package may extend an existing package. The version of the original
+ package must be specified. When a package extends another package it
+ shall only add additional Properties, Events, Signals, Statistics and
+ new possible values for an existing parameter described in the
+ original package. An extended package shall not redefine or overload
+ an identifier defined in the original package and packages it may
+ have extended (multiple levels of extension). Hence, if package B
+ version 1 extends package A version 1, version 2 of B will not be
+ able to extend the A version 2 if A version 2 defines a name already
+ in B version 1.
+
+ 12.1.2 Properties
+
+ Properties defined by the package, specifying:
+
+ Property Name: only descriptive
+
+ PropertyID: is an identifier
+
+
+
+ Groves et al Expires - October 2003 [Page 87]
+ Megaco Protocol version 2 April 2003
+
+
+ Description:
+
+ Type: One of:
+
+ Boolean
+
+ String: UTF-8 string
+
+ Octet String: A number of octets. See Annex A and Annex B.3
+ for encoding
+
+ Integer: 4 byte signed integer
+
+ Double: 8 byte signed integer
+
+ Character: unicode UTF-8 encoding of a single letter. Could be
+ more than one octet.
+
+ Enumeration: one of a list of possible unique values (see 12.3)
+
+ Sub-list: a list of several values from a list. The type of
+ sub-list SHALL also be specified. The type shall be chosen
+ from the types specified in this section (with the exception of
+ sub-list). For example, Type: sub-list of enumeration. The
+ encoding of sub-lists is specified in Annexes A and B.3.
+
+ Possible values:
+
+ A package MUST specify either a specific set of values or a
+ description of how values are determined. A package MUST also
+ specify a default value or the default behaviour when the value is
+ omitted from its descriptor. For example, a package may specify that
+ procedures related to the property are suspended when it value is
+ omitted. A default value (but not procedures) may be specified as
+ provisionable.
+
+ Defined in:
+
+ Which H.248.1 descriptor the property is defined in. LocalControl is
+ for stream dependent properties. TerminationState is for stream
+ independent properties. These are expected to be the most common
+ cases, but it is possible for properties to be defined in other
+ descriptors.
+
+ Characteristics: Read/Write or both, and (optionally), global:
+
+ Indicates whether a property is read-only, or read-write, and if it
+ is global. If Global is omitted, the property is not global. If a
+
+
+
+ Groves et al Expires - October 2003 [Page 88]
+ Megaco Protocol version 2 April 2003
+
+
+ property is declared as global, the value of the property is shared
+ by all Terminations realizing the package.
+
+ 12.1.3 Events
+
+ Events defined by the package, specifying:
+
+ Event name: only descriptive
+
+ EventID: is an identifier
+
+ Description:
+
+ EventsDescriptor Parameters:
+
+ Parameters used by the MGC to configure the event, and found in the
+ EventsDescriptor. See 12.2.
+
+ ObservedEventsDescriptor Parameters:
+
+ Parameters returned to the MGC in Notify requests and in replies to
+ command requests from the MGC that audit ObservedEventsDescriptor,
+ and found in the ObservedEventsDescriptor. See 12.2.
+
+ 12.1.4 Signals
+
+ Signals defined by the package, specifying:
+
+ Signal Name: only descriptive
+
+ SignalID: is an identifier. SignalID is used in a
+ SignalsDescriptor
+
+ Description
+
+ SignalType: one of:
+
+ OO (On/Off)
+
+ TO (TimeOut)
+
+ BR (Brief)
+
+ NOTE - SignalType may be defined such that it is dependent on the
+ value of one or more parameters. The package MUST specify a default
+ signal type. If the default type is TO, the package MUST specify a
+ default duration which may be provisioned. A default duration is
+ meaningless for BR.
+
+
+
+ Groves et al Expires - October 2003 [Page 89]
+ Megaco Protocol version 2 April 2003
+
+
+ Duration: in hundredths of seconds
+
+ Additional Parameters: see 12.2
+
+ 12.1.5 Statistics
+
+ Statistics defined by the package, specifying:
+
+ Statistic name: only descriptive
+
+ StatisticID: is an identifier
+
+ StatisticID is used in a StatisticsDescriptor
+
+ Description:
+
+ Units: unit of measure, e.g. milliseconds, packets
+
+ 12.1.6 Procedures
+
+ Additional guidance on the use of the package.
+
+
+ 12.2 Guidelines to defining Parameters to Events and Signals
+
+ Parameter Name: only descriptive
+
+ ParameterID: is an identifier. The textual ParameterID of
+ parameters to Events and Signals shall not start with "EPA" and
+ "SPA", respectively. The textual ParameterID shall also not be
+ "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+ "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+ "DigitMap".
+
+ Type: One of:
+
+ Boolean
+
+ String: UTF-8 octet string
+
+ Octet String: A number of octets. See Annex A and Annex B.3
+ for encoding
+
+ Integer: 4-octet signed integer
+
+ Double: 8-octet signed integer
+
+ Character: unicode UTF-8 encoding of a single letter. Could be
+ more than one octet.
+
+
+ Groves et al Expires - October 2003 [Page 90]
+ Megaco Protocol version 2 April 2003
+
+
+ Enumeration: one of a list of possible unique values (see 12.3)
+
+ Sub-list: a list of several values from a list (not supported
+ for statistics). The type of sub-list SHALL also be specified.
+ The type shall be chosen from the types specified in this
+ section (with the exception of sub-list). For example, Type:
+ sub-list of enumeration. The encoding of sub-lists is
+ specified in Annexes A and B.3.
+
+ Possible values:
+
+ A package MUST specify either a specific set of values or a
+ description of how values are determined. A package MUST also
+ specify a default value or the default behavior when the value is
+ omitted from its descriptor. For example, a package may specify that
+ procedures related to the parameter are suspended when it value is
+ omitted. A default value (but not procedures) may be specified as
+ provisionable.
+
+ Description:
+
+ 12.3 Lists
+
+ Possible values for parameters include enumerations. Enumerations may
+ be defined in a list. It is recommended that the list be IANA
+ registered so that packages that extend the list can be defined
+ without concern for conflicting names.
+
+ 12.4 Identifiers
+
+ Identifiers in text encoding shall be strings of up to 64 characters,
+ containing no spaces, starting with an alphabetic character and
+ consisting of alphanumeric characters and/or digits, and possibly
+ including the special character underscore ("_").
+
+ Identifiers in binary encoding are 2 octets long.
+
+ Both text and binary values shall be specified for each identifier,
+ including identifiers used as values in enumerated types.
+
+ 12.5 Package registration
+
+ A package can be registered with IANA for interoperability reasons.
+ See clause 13 for IANA considerations.
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 91]
+ Megaco Protocol version 2 April 2003
+
+
+ 13 PROFILE DEFINITION
+
+ Profiles may be specified to further define how the H.248.1 protocol
+ is used and what functionality is supported by a MG. The profile
+ itself specifies what options associated with H.248.1 have been used.
+ For example: transport and packages used for an application.
+
+ A profile is identified by a name (IANA registered) and a Version. A
+ name shall be a string up to 64 characters long. Version shall be 1
+ to 99.
+
+ The profile itself is a document that indicates the options for a
+ particular application. There is no set format for this document. The
+ only mandatory element is that there SHOULD be a section indicating
+ the Name and Version and a summary of the profile.
+
+ Whilst the first two points below are the only mandatory sections,
+ the following points SHOULD be considered for inclusion:
+
+ - Profile Identification: The name and version of the profile that
+ is sent in the service change command.
+
+ - Summary: A description of what the profile is.
+
+ - Naming Conventions:
+
+ - MGC/MG Naming Conventions: Addressing associated with the names
+ of the MGC / MG.
+
+ - Termination Names: The termination identity structure.
+
+ - Digit Map Names: The names of any digit maps.
+
+ - Topology Descriptor: Is the topology descriptor used by this
+ profile?
+
+ - TimeStamps: Specifies whether timestamps will be used in the
+ ServiceChange and/or Notify commands.
+
+ - Transaction Timers: Specifies the values of the transaction
+ timers.
+
+ - Transport: Specifies what H.248 sub-series transports are
+ supported by the profile.
+
+ - Encoding: Specifies what encoding is supported by the profile.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 92]
+ Megaco Protocol version 2 April 2003
+
+
+ - Mandatory support of SDP and H.248.1 Annex C information elements:
+ Specifies what SDP attributes and H.248.1 Annex C information
+ elements are to be supported.
+
+ - Packages: Specifies the packages that are supported in this
+ profile.
+
+ Mandatory: specifies the packages that shall be supported in this
+ profile.
+
+ Optional: specifies the packages that may be supported in the
+ profile.
+
+ Package Provisioning Information: specifies the values of properties
+ which are specified as provisioned (e.g. names and number of cycles
+ for an H.248.7 announcement).
+
+ - Security: Specifies the security mechanisms used.
+
+ - Procedures: Specifies the procedures that are associated with the
+ profile.
+
+
+ 14 IANA CONSIDERATIONS
+
+ 14.1 Packages
+
+ The following considerations SHALL be met to register a package with
+ IANA:
+
+ 1) A unique string name, unique serial number and version number is
+ registered for each package. The string name is used with text
+ encoding. The serial number shall be used with binary encoding.
+ Serial Numbers 0x8000 to 0xFFFF are reserved for private use.
+ Serial number 0 is reserved.
+
+ 2) A contact name, email and postal addresses for that contact shall
+ be specified. The contact information shall be updated by the
+ defining organization as necessary.
+
+ 3) A reference to a document that describes the package, which SHOULD
+ be public:
+
+ The document shall specify the version of the Package that it
+ describes.
+
+ If the document is public, it SHOULD be located on a public web
+ server and SHOULD have a stable URL. The site SHOULD provide a
+
+
+
+ Groves et al Expires - October 2003 [Page 93]
+ Megaco Protocol version 2 April 2003
+
+
+ mechanism to provide comments and appropriate responses SHOULD be
+ returned.
+
+ 4) Packages registered by other than recognized standards bodies
+ shall have a minimum package name length of 8 characters.
+
+ 5) All other package names are first come-first served if all other
+ conditions are met.
+
+ 14.2 Error codes
+
+ The following considerations SHALL be met to register an error code
+ with IANA:
+
+ 1) An error number and a one-line (80-character maximum) string is
+ registered for each error.
+
+ 2) A complete description of the conditions under which the error is
+ detected shall be included in a publicly available document. The
+ description shall be sufficiently clear to differentiate the error
+ from all other existing error codes.
+
+ 3) The document SHOULD be available on a public web server and SHOULD
+ have a stable URL.
+
+ 4) Error numbers registered by recognized standards bodies shall have
+ 3- or 4-character error numbers.
+
+ 5) Error numbers registered by all other organizations or individuals
+ shall have 4-character error numbers.
+
+ 6) An error number shall not be redefined nor modified except by the
+ organization or individual that originally defined it, or their
+ successors or assigns.
+
+ 14.3 ServiceChange reasons
+
+ The following considerations SHALL be met to register service change
+ reason with IANA:
+
+ 1) A one-phrase, 80-character maximum, unique reason code is
+ registered for each reason.
+
+ 2) A complete description of the conditions under which the reason is
+ used is detected shall be included in a publicly available
+ document. The description shall be sufficiently clear to
+ differentiate the reason from all other existing reasons.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 94]
+ Megaco Protocol version 2 April 2003
+
+
+ 3) The document SHOULD be available on a public web server and SHOULD
+ have a stable URL.
+
+ 14.4 Profiles
+
+ The following considerations SHALL be met to register a Profile with
+ IANA:
+
+ 1) A unique string name and version number (version may be omitted
+ when the profile name contains a wildcard) is registered for each
+ profile.
+
+ 2) A contact name, email and postal addresses for that contact shall
+ be specified. The contact information shall be updated by the
+ defining organization as necessary.
+
+ 3) Profiles registered by other than recognized standards bodies
+ shall have a minimum profile name length of 6 characters.
+
+ 4) Profile names containing a wildcard "*"on the end of their names
+ shall be accepted if the first 6 characters are fully specified.
+ It is assumed that the organisation that was issued with the
+ Profile name will manage the namespace associated with the
+ wildcard. IANA shall not issue other profiles names within "name*"
+ range.
+
+ All other Profile names are first come-first served if all other
+ conditions are met.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 95]
+ Megaco Protocol version 2 April 2003
+
+
+ ANNEX A BINARY ENCODING OF THE PROTOCOL
+
+ This annex specifies the syntax of messages using the notation
+ defined in Recommendation X.680; Information technology - Abstract
+ Syntax Notation One (ASN.1): Specification of basic notation.
+ Messages shall be encoded for transmission by applying the basic
+ encoding rules specified in Recommendation X.690, Information
+ Technology - ASN.1 Encoding Rules: Specification of Basic Encoding
+ Rules (BER), Canonical Encoding Rules (CER) and Distinguished
+ Encoding Rules.
+
+ A.1 Coding of wildcards
+
+ The use of wildcards ALL and CHOOSE is allowed in the protocol. This
+ allows a MGC to partially specify Termination IDs and to let the MG
+ choose from the values that conform to the partial specification.
+ Termination IDs may encode a hierarchy of names. This hierarchy is
+ provisioned. For instance, a TerminationID may consist of a trunk
+ group, a trunk within the group and a circuit. Wildcarding must be
+ possible at all levels. The following paragraphs explain how this is
+ achieved.
+
+ The ASN.1 description uses octet strings of up to 8 octets in length
+ for Termination IDs. This means that Termination IDs consist of at
+ most 64 bits. A fully specified Termination ID may be preceded by a
+ sequence of wildcarding fields. A wildcarding field is one octet in
+ length. Bit 7 (the most significant bit) of this octet specifies what
+ type of wildcarding is invoked: if the bit value equals 1, then the
+ ALL wildcard is used; if the bit value if 0, then the CHOOSE wildcard
+ is used. Bit 6 of the wildcarding field specifies whether the
+ wildcarding pertains to one level in the hierarchical naming scheme
+ (bit value 0) or to the level of the hierarchy specified in the
+ wildcarding field plus all lower levels (bit value 1). Bits 0 through
+ 5 of the wildcarding field specify the bit position in the
+ Termination ID at which the wildcarding starts.
+
+ We illustrate this scheme with some examples. In these examples, the
+ most significant bit in a string of bits appears on the left hand
+ side.
+
+ Assume that Termination IDs are three octets long and that each octet
+ represents a level in a hierarchical naming scheme. A valid
+ Termination ID is:
+
+ 00000001 00011110 01010101.
+
+ Addressing ALL names with prefix 00000001 00011110 is done as
+ follows:
+
+
+
+ Groves et al Expires - October 2003 [Page 96]
+ Megaco Protocol version 2 April 2003
+
+
+ wildcarding field: 10000111
+
+ Termination ID: 00000001 00011110 xxxxxxxx.
+
+ The values of the bits labeled "x" is irrelevant and shall be ignored
+ by the receiver.
+
+ Indicating to the receiver that it must choose a name with 00011110
+ as the second octet is done as follows:
+
+ wildcarding fields: 00010111 followed by 00000111
+
+ Termination ID: xxxxxxxx 00011110 xxxxxxxx.
+
+ The first wildcard field indicates a CHOOSE wildcard for the level in
+ the naming hierarchy starting at bit 23, the highest level in our
+ assumed naming scheme. The second wildcard field indicates a CHOOSE
+ wildcard for the level in the naming hierarchy starting at bit 7, the
+ lowest level in our assumed naming scheme.
+
+ Finally, a CHOOSE-wildcarded name with the highest level of the name
+ equal to 00000001 is specified as follows:
+
+ wildcard field: 01001111
+
+ Termination ID: 0000001 xxxxxxxx xxxxxxxx .
+
+ Bit value 1 at bit position 6 of the first octet of the wildcard
+ field indicates that the wildcarding pertains to the specified level
+ in the naming hierarchy and all lower levels.
+
+ Context IDs may also be wildcarded. In the case of Context IDs,
+ however, specifying partial names is not allowed. Context ID 0x0
+ SHALL be used to indicate the NULL Context, Context ID 0xFFFFFFFE
+ SHALL be used to indicate a CHOOSE wildcard, and Context ID
+ 0xFFFFFFFF SHALL be used to indicate an ALL wildcard.
+
+ TerminationID 0xFFFFFFFFFFFFFFFF SHALL be used to indicate the ROOT
+ Termination.
+
+ A.2 ASN.1 syntax specification
+
+ This subclause contains the ASN.1 specification of the H.248.1
+ protocol syntax.
+
+ NOTE 1 - In case a transport mechanism is used that employs
+ application level framing, the definition of Transaction below
+ changes. Refer to the annex or to the Recommendation of the H.248
+
+
+
+ Groves et al Expires - October 2003 [Page 97]
+ Megaco Protocol version 2 April 2003
+
+
+ sub-series defining the transport mechanism for the definition that
+ applies in that case.
+
+ NOTE 2 - The ASN.1 specification below contains a clause defining
+ TerminationIDList as a sequence of TerminationIDs. The length of this
+ sequence SHALL be one, except possibly when used in
+ contextAuditResult.
+
+ NOTE 3 - This syntax specification does not enforce all restrictions
+ on element inclusions and values. Some additional restrictions are
+ stated in comments and other restrictions appear in the text of this
+ recommendation. These additional restrictions are part of the
+ protocol even though not enforced by this specification.
+
+ NOTE 4 - The ASN.1 module in this Annex uses octet string types to
+ encode values for property parameter, signal parameter and event
+ parameter values and statistics. The actual types of these values
+ vary and are specified in Annex C or the relevant package definition.
+
+ A value is first BER-encoded based on its type using the table below.
+ The result of this BER-encoding is then encoded as an ASN.1 octet
+ string, "double wrapping" the value. The format specified in Annex C
+ or the package relates to BER encoding according to the following
+ table:
+
+ Type Specified in Package ASN.1 BER Type
+
+ String IA5String or UTF8String
+ (Note 4)
+
+ Integer (4 Octet) INTEGER
+
+ Double (8 octet signed int) INTEGER (Note 3)
+
+ Character (UTF-8, Note 1) IA5String
+
+ Enumeration ENUMERATED
+
+ Boolean BOOLEAN
+
+ Unsigned Integer (Note 2) INTEGER (Note 3)
+
+ Octet (String) OCTET STRING
+
+ Note 1: Can be more than one byte
+
+ Note 2: Unsigned integer is referenced in Annex C
+
+
+
+ Groves et al Expires - October 2003 [Page 98]
+ Megaco Protocol version 2 April 2003
+
+
+ Note 3: The BER encoding of INTEGER does not imply the
+ use of 4 bytes.
+
+ Note 4: String SHOULD be encoded as IA5String when the
+ contents are all ASCII characters, but as UTF8String
+ if it contains any non-ASCII characters.
+
+
+
+ See ITU-T Rec. X.690, 8.7, for the definition of the encoding of an
+ octet string value.
+
+
+ MEDIA-GATEWAY-CONTROL {itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version2(2)}
+ DEFINITIONS AUTOMATIC TAGS ::=
+ BEGIN
+
+
+ MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+ AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+ SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+ SequenceNum ::= OCTET STRING(SIZE(4))
+
+ AuthData ::= OCTET STRING (SIZE (12..32))
+
+ Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 2.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+
+
+
+ Groves et al Expires - October 2003 [Page 99]
+ Megaco Protocol version 2 April 2003
+
+
+ ...
+ }
+
+ MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+ DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ PathName ::= IA5String(SIZE (1..64))
+ -- See A.3
+
+ Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+
+
+ Groves et al Expires - October 2003 [Page 100]
+ Megaco Protocol version 2 April 2003
+
+
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+ TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+ TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+ TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+ }
+
+ TransactionResponseAck ::= SEQUENCE OF TransactionAck
+ TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ ErrorCode ::= INTEGER(0..65535)
+ -- See clause 14 for IANA considerations with respect to error codes
+
+
+
+ Groves et al Expires - October 2003 [Page 101]
+ Megaco Protocol version 2 April 2003
+
+
+ ErrorText ::= IA5String
+
+ ContextID ::= INTEGER(0..4294967295)
+
+ -- Context NULL Value: 0
+ -- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+ -- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+ }
+
+ ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+ }
+
+ CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+
+
+ Groves et al Expires - October 2003 [Page 102]
+ Megaco Protocol version 2 April 2003
+
+
+ Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+ CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+ TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+ AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+
+
+ Groves et al Expires - October 2003 [Page 103]
+ Megaco Protocol version 2 April 2003
+
+
+ }
+
+ AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+
+ AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+ SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+ AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+ AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+ AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+
+
+ Groves et al Expires - October 2003 [Page 104]
+ Megaco Protocol version 2 April 2003
+
+
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+ TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+ AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+ AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+ IndAuditParameter ::= CHOICE
+ {
+ indaudmediaDescriptor IndAudMediaDescriptor,
+ indaudeventsDescriptor IndAudEventsDescriptor,
+ indaudeventBufferDescriptor IndAudEventBufferDescriptor,
+ indaudsignalsDescriptor IndAudSignalsDescriptor,
+ indauddigitMapDescriptor IndAudDigitMapDescriptor,
+ indaudstatisticsDescriptor IndAudStatisticsDescriptor,
+ indaudpackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+
+ Groves et al Expires - October 2003 [Page 105]
+ Megaco Protocol version 2 April 2003
+
+
+
+ IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+ IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+ IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+ IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+ IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+ IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+
+
+ Groves et al Expires - October 2003 [Page 106]
+ Megaco Protocol version 2 April 2003
+
+
+ IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+ IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+ IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+ IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+ IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+ IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+ IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+ IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapNameOPTIONAL
+ }
+
+
+ Groves et al Expires - October 2003 [Page 107]
+ Megaco Protocol version 2 April 2003
+
+
+
+ IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+ IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+ NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+ EventName ::= PkgdName
+
+ EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+
+
+ Groves et al Expires - October 2003 [Page 108]
+ Megaco Protocol version 2 April 2003
+
+
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+ -- For ServiceChangeResult, no parameters are mandatory. Hence the
+ -- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+ WildcardField ::= OCTET STRING(SIZE(1))
+
+ TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+ -- See A.1 for explanation of wildcarding mechanism.
+ -- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+ TerminationIDList ::= SEQUENCE OF TerminationID
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 109]
+ Megaco Protocol version 2 April 2003
+
+
+ MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+ StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+ StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+ LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+ StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+ -- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+ -- by an MGC the interpretation is as follows:
+ -- empty sequence means CHOOSE
+ -- one element sequence specifies value
+ -- If the sublist field is not selected, a longer sequence means
+
+
+ Groves et al Expires - October 2003 [Page 110]
+ Megaco Protocol version 2 April 2003
+
+
+ -- "choose one of the values" (i.e. value1 OR value2 OR ...)
+ -- If the sublist field is selected,
+ -- a sequence with more than one element encodes the value of a
+ -- list-valued property (i.e. value1 AND value2 AND ...).
+ -- The relation field may only be selected if the value sequence
+ -- has length 1. It indicates that the MG has to choose a value
+ -- for the property. E.g. x > 3 (using the greaterThan
+ -- value for relation) instructs the MG to choose any value larger
+ -- than 3 for property x.
+ -- The range field may only be selected if the value sequence
+ -- has length 2. It indicates that the MG has to choose a value
+ -- in the range between the first octet in the value sequence and
+ -- the trailing octet in the value sequence, including the
+ -- boundary values.
+ -- When sent by the MG, only responses to an AuditCapability request
+ -- may contain multiple values, a range, or a relation field.
+
+ PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+ Name ::= OCTET STRING(SIZE(2))
+
+ PkgdName ::= OCTET STRING(SIZE(4))
+ -- represents Package Name (2 octets) plus Property, Event,
+ -- Signal Names or Statistics ID. (2 octets)
+ -- To wildcard a package use 0xFFFF for first two octets, choose
+ -- is not allowed. To reference native property tag specified in
+ -- Annex C, use 0x0000 as first two octets.
+ -- To wildcard a Property, Event, Signal, or Statistics ID, use
+ -- 0xFFFF for last two octets, choose is not allowed.
+ -- Wildcarding of Package Name is permitted only if Property,
+ -- Event, Signal, or Statistics ID are
+ -- also wildcarded.
+
+ Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+
+
+ Groves et al Expires - October 2003 [Page 111]
+ Megaco Protocol version 2 April 2003
+
+
+ ...
+ }
+
+ LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+ PropertyGroup ::= SEQUENCE OF PropertyParm
+
+ TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+ EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+ MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+ MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+
+
+ Groves et al Expires - October 2003 [Page 112]
+ Megaco Protocol version 2 April 2003
+
+
+ nx64k(4)
+ }
+
+ StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+ EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+ RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+ RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+ EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+ SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+ SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+
+
+ Groves et al Expires - October 2003 [Page 113]
+ Megaco Protocol version 2 April 2003
+
+
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+ SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+ EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+ EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+ SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+ SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+ SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+ Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+
+
+ Groves et al Expires - October 2003 [Page 114]
+ Megaco Protocol version 2 April 2003
+
+
+ }
+
+ SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+ SignalName ::= PkgdName
+
+ NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+ SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+ -- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+ -- ALL is represented by 0xffffffff.
+
+ RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+
+
+ Groves et al Expires - October 2003 [Page 115]
+ Megaco Protocol version 2 April 2003
+
+
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+ DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+ DigitMapName ::= Name
+
+ DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+
+
+ Groves et al Expires - October 2003 [Page 116]
+ Megaco Protocol version 2 April 2003
+
+
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL
+ }
+
+ ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+ PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+
+ Groves et al Expires - October 2003 [Page 117]
+ Megaco Protocol version 2 April 2003
+
+
+
+ PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+ StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+ StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+ NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+ NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+ H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+ TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+ Value ::= SEQUENCE OF OCTET STRING
+
+
+
+
+ Groves et al Expires - October 2003 [Page 118]
+ Megaco Protocol version 2 April 2003
+
+
+ END
+
+
+
+
+ A.3 Digit maps and path names
+
+ From a syntactic viewpoint, digit maps are strings with syntactic
+ restrictions imposed upon them. The syntax of valid digit maps is
+ specified in ABNF [RFC 2234]. The syntax for digit maps presented in
+ this subclause is for illustrative purposes only. The definition of
+ digitMap in Annex B takes precedence in the case of differences
+ between the two.
+
+ digitMap = (digitString
+ / LWSP "(" LWSP digitStringList LWSP ")" LWSP)
+
+ digitStringList = digitString *( LWSP "|" LWSP digitString )
+
+ digitString = 1*(digitStringElement)
+
+ digitStringElement = digitPosition [DOT]
+
+ digitPosition = digitMapLetter / digitMapRange
+
+ digitMapRange = ("x" / (LWSP "[" LWSP digitLetter LWSP "]" LWSP))
+
+ digitLetter = *((DIGIT "-" DIGIT) /digitMapLetter)
+
+ digitMapLetter = DIGIT ;digits 0-9
+ / %x41-4B / %x61-6B ;a-k and A-K
+ / "L"/ "S" / "T" ;Inter-event timers
+ ;(long, short, start)
+ / "Z" ;Long duration event
+
+ DOT = %x2E ; "."
+ LWSP = *(WSP / COMMENT / EOL)
+ WSP = SP / HTAB
+ COMMENT = ";" *(SafeChar / RestChar / WSP) EOL
+ EOL = (CR [LF]) / LF
+ SP = %x20
+ HTAB = %x09
+ CR = %x0D
+ LF = %x0A
+
+ SafeChar = DIGIT / ALPHA / "+" / "-" / "&" / "!" / "_" / "/" /
+ "'" / "?" / "@" / "^" / "`" / "~" / "*" / "$" / "\" /
+ "(" / ")" / "%" / "."
+
+
+
+ Groves et al Expires - October 2003 [Page 119]
+ Megaco Protocol version 2 April 2003
+
+
+ RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+ "<" / ">" / "=" / %x22
+
+ DIGIT = %x30-39 ; digits 0 through 9
+ ALPHA = %x41-5A / %x61-7A ; A-Z, a-z
+
+ A path name is also a string with syntactic restrictions imposed upon
+ it. The ABNF production defining it is copied from Annex B.
+
+ ; Total length of pathNAME must not exceed 64 chars.
+ pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ ["@" pathDomainName ]
+
+ ; ABNF allows two or more consecutive "." although it is meaningless
+ ; in a path domain name.
+ pathDomainName = (ALPHA / DIGIT / "*" )
+ *63(ALPHA / DIGIT / "-" / "*" / ".")
+
+ NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 120]
+ Megaco Protocol version 2 April 2003
+
+
+ ANNEX B TEXT ENCODING OF THE PROTOCOL
+
+ B.1 Coding of wildcards
+
+ In a text encoding of the protocol, while TerminationIDs are
+ arbitrary, by judicious choice of names, the wildcard character, "*"
+ may be made more useful. When the wildcard character is encountered,
+ it will "match" all TerminationIDs having the same previous and
+ following characters (if appropriate). For example, if there were
+ TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+ R13/3/* would match all of them. There are some circumstances where
+ ALL Terminations must be referred to. The TerminationID "*" suffices,
+ and is referred to as ALL. The CHOOSE TerminationID "$" may be used
+ to signal to the MG that it has to create an ephemeral Termination or
+ select an idle physical Termination.
+
+ B.2 ABNF specification
+
+ The protocol syntax is presented in ABNF according to RFC 2234.
+
+ Note 1 - This syntax specification does not enforce all restrictions
+ on element inclusions and values. Some additional restrictions are
+ stated in comments and other restrictions appear in the text of this
+ recommendation. These additional restrictions are part of the
+ protocol even though not enforced by this specification.
+
+ Note 2 - The syntax is context-dependent. For example, "Add" can be
+ the AddToken or a NAME depending on the context in which it occurs.
+
+ Everything in the ABNF and text encoding is case insensitive. This
+ includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+ per RFC 2327.
+
+ ; NOTE -- The ABNF in this section uses the VALUE construct (or lists
+ ; of VALUE constructs) to encode various package element values
+ ; (properties, signal parameters, etc.). The types of these values
+ ; vary and are specified the relevant package definition. Several
+ ; such types are described in section 12.2.
+ ;
+ ; The ABNF specification for VALUE allows a quotedString form or a
+ ; collection of SafeChars. The encoding of package element values
+ ; into ABNF VALUES is specified below. If a type's encoding allows
+ ; characters other than SafeChars, the quotedString form MUST be used
+ ; for all values of that type, even for specific values that consist
+ ; only of SafeChars.
+ ;
+ ; String: A string MUST use the quotedString form of VALUE and can
+ ; contain anything allowable in the quotedString form.
+ ;
+
+
+ Groves et al Expires - October 2003 [Page 121]
+ Megaco Protocol version 2 April 2003
+
+
+ ; Integer, Double, and Unsigned Integer: Decimal values can be
+ ; encoded using characters 0-9. Hexadecimal values must be prefixed
+ ; with '0x' and can use characters 0-9,a-f,A-F. An octal format is
+ ; not supported. Negative integers start with '-' and MUST be
+ ; Decimal. The SafeChar form of VALUE MUST be used.
+ ;
+ ; Character: A UTF-8 encoding of a single letter surrounded by
+ ; double quotes.
+ ;
+ ; Enumeration: An enumeration MUST use the SafeChar form of VALUE
+ ; and can contain anything allowable in the SafeChar form.
+ ;
+ ; Boolean: Boolean values are encoded as "on" and "off" and are
+ ; case insensitive. The SafeChar form of VALUE MUST be used.
+ ;
+ ; Future types: Any defined types MUST fit within
+ ; the ABNF specification of VALUE. Specifically, if a type's
+ ; encoding allows characters other than SafeChars, the quotedString
+ ; form MUST be used for all values of that type, even for specific
+ ; values that consist only of SafeChars.
+ ;
+ ; Note that there is no way to use the double quote character within
+ ; a value.
+ ;
+ ; Note that SDP disallows whitespace at the beginning of a line,
+ ; Megaco ABNF allows whitespace before the beginning of the SDP in
+ ; the Local/Remote descriptor. Parsers SHOULD accept whitespace
+ ; between the LBRKT following the Local/Remote token and the
+ ; beginning of the SDP.
+
+ megacoMessage = LWSP [authenticationHeader SEP ] message
+
+ authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+ SequenceNum COLON AuthData
+
+ SecurityParmIndex = "0x" 8(HEXDIG)
+ SequenceNum = "0x" 8(HEXDIG)
+ AuthData = "0x" 24*64(HEXDIG)
+
+ message = MegacopToken SLASH Version SEP mId SEP messageBody
+ ; The version of the protocol defined here is equal to 2.
+
+ messageBody = ( errorDescriptor / transactionList )
+
+ transactionList = 1*( transactionRequest / transactionReply /
+ transactionPending / transactionResponseAck )
+ ; Use of response acks is dependent on underlying transport
+
+
+
+
+ Groves et al Expires - October 2003 [Page 122]
+ Megaco Protocol version 2 April 2003
+
+
+ transactionPending = PendingToken EQUAL TransactionID
+ LBRKT RBRKT
+
+ transactionResponseAck = ResponseAckToken LBRKT transactionAck
+ *(COMMA transactionAck) RBRKT
+ transactionAck = TransactionID / (TransactionID "-" TransactionID)
+
+ transactionRequest = TransToken EQUAL TransactionID LBRKT
+ actionRequest *(COMMA actionRequest) RBRKT
+
+ actionRequest = CtxToken EQUAL ContextID LBRKT ((
+ contextRequest [COMMA commandRequestList])
+ / commandRequestList) RBRKT
+
+ contextRequest = ((contextProperties [COMMA contextAudit])
+ / contextAudit)
+
+ contextProperties = contextProperty *(COMMA contextProperty)
+
+ ; at-most-once
+ contextProperty = (topologyDescriptor / priority / EmergencyToken)
+
+ contextAudit = ContextAuditToken LBRKT
+ contextAuditProperties *(COMMA contextAuditProperties) RBRKT
+
+ ; at-most-once
+ contextAuditProperties = ( TopologyToken / EmergencyToken /
+ PriorityToken )
+
+ ; "O-" indicates an optional command
+ ; "W-" indicates a wildcarded response to a command
+ commandRequestList= ["O-"] ["W-"] commandRequest *
+ (COMMA ["O-"] ["W-"]commandRequest)
+
+ commandRequest = ( ammRequest / subtractRequest / auditRequest /
+ notifyRequest / serviceChangeRequest)
+
+ transactionReply = ReplyToken EQUAL TransactionID LBRKT
+ [ ImmAckRequiredToken COMMA]
+ ( errorDescriptor / actionReplyList ) RBRKT
+
+ actionReplyList = actionReply *(COMMA actionReply )
+
+ actionReply = CtxToken EQUAL ContextID LBRKT
+ ( errorDescriptor / commandReply ) /
+ (commandReply COMMA errorDescriptor) ) RBRKT
+
+ commandReply = (( contextProperties [COMMA commandReplyList] ) /
+ commandReplyList )
+
+
+ Groves et al Expires - October 2003 [Page 123]
+ Megaco Protocol version 2 April 2003
+
+
+
+
+ commandReplyList = commandReplys *(COMMA commandReplys )
+
+ commandReplys = (serviceChangeReply / auditReply / ammsReply /
+ notifyReply )
+
+ ;Add Move and Modify have the same request parameters
+ ammRequest = (AddToken / MoveToken / ModifyToken ) EQUAL
+ TerminationID [LBRKT ammParameter *(COMMA
+ ammParameter) RBRKT]
+
+ ;at-most-once
+ ammParameter = (mediaDescriptor / modemDescriptor /
+ muxDescriptor / eventsDescriptor /
+ signalsDescriptor / digitMapDescriptor /
+ eventBufferDescriptor / auditDescriptor)
+
+ ammsReply = (AddToken / MoveToken / ModifyToken /
+ SubtractToken ) EQUAL TerminationID [ LBRKT
+ terminationAudit RBRKT ]
+
+ subtractRequest = SubtractToken EQUAL TerminationID
+ [ LBRKT auditDescriptor RBRKT]
+
+ auditRequest = (AuditValueToken / AuditCapToken ) EQUAL
+ TerminationID LBRKT auditDescriptor RBRKT
+
+ auditReply = (AuditValueToken / AuditCapToken )
+ ( contextTerminationAudit / auditOther)
+
+ auditOther = EQUAL TerminationID [LBRKT terminationAudit RBRKT]
+
+ terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+
+ contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+ LBRKT errorDescriptor RBRKT )
+
+ auditReturnParameter = (mediaDescriptor / modemDescriptor /
+ muxDescriptor / eventsDescriptor / signalsDescriptor /
+ digitMapDescriptor / observedEventsDescriptor /
+ eventBufferDescriptor / statisticsDescriptor /
+ packagesDescriptor / errorDescriptor / auditItem)
+
+ auditDescriptor = AuditToken LBRKT [ auditItem *(COMMA auditItem) ]
+ RBRKT
+
+ notifyRequest = NotifyToken EQUAL TerminationID
+ LBRKT ( observedEventsDescriptor
+
+
+ Groves et al Expires - October 2003 [Page 124]
+ Megaco Protocol version 2 April 2003
+
+
+ [ COMMA errorDescriptor ] ) RBRKT
+
+ notifyReply = NotifyToken EQUAL TerminationID
+ [ LBRKT errorDescriptor RBRKT ]
+
+ serviceChangeRequest = ServiceChangeToken EQUAL TerminationID
+ LBRKT serviceChangeDescriptor RBRKT
+
+ serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+ [LBRKT (errorDescriptor /
+ serviceChangeReplyDescriptor) RBRKT]
+
+ errorDescriptor = ErrorToken EQUAL ErrorCode
+ LBRKT [quotedString] RBRKT
+
+ ErrorCode = 1*4(DIGIT) ; could be extended
+
+
+ TransactionID = UINT32
+
+ ;The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+ ContextID = (UINT32 / "*" / "-" / "$")
+
+ TerminationID = "ROOT" / pathNAME / "$" / "*"
+
+ terminationIDList = LBRKT TerminationID *(COMMA TerminationID) RBRKT
+
+
+ mId = (( domainAddress / domainName )
+ [":" portNumber]) / mtpAddress / deviceName
+
+ ; ABNF allows two or more consecutive "." although it is meaningless
+ ; in a domain name.
+ domainName = "<" (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" /
+ ".") ">"
+
+ deviceName = pathNAME
+
+ domainAddress = "[" (IPv4address / IPv6address) "]"
+
+ ;RFC2373 contains the definition of IP6Addresses.
+ IPv6address = hexpart [ ":" IPv4address ]
+
+ IPv4address = V4hex DOT V4hex DOT V4hex DOT V4hex
+ V4hex = 1*3(DIGIT) ; "0".."255"
+
+ ; this production, while occurring in RFC2373, is not referenced
+ ; IPv6prefix = hexpart SLASH 1*2DIGIT
+ hexpart = hexseq "::" [ hexseq ] / "::" [ hexseq ] / hexseq
+
+
+ Groves et al Expires - October 2003 [Page 125]
+ Megaco Protocol version 2 April 2003
+
+
+ hexseq = hex4 *( ":" hex4)
+ hex4 = 1*4HEXDIG
+
+ portNumber = UINT16
+
+ ; Addressing structure of mtpAddress:
+ ; 25 - 15 0
+ ; | PC | NI |
+ ; 24 - 14 bits 2 bits
+ ; Note: 14 bits are defined for international use.
+ ; Two national options exist where the point code is 16 or 24 bits.
+ ; To octet align the mtpAddress the MSBs shall be encoded as 0s.
+ ; An octet shall be represented by 2 hex digits.
+ mtpAddress = MTPToken LBRKT 4*8 (HEXDIG) RBRKT
+
+ ; Total length of pathNAME must not exceed 64 chars.
+ pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ ["@" pathDomainName ]
+
+ ; ABNF allows two or more consecutive "." although it is meaningless
+ ; in a path domain name.
+ pathDomainName = (ALPHA / DIGIT / "*" )
+ *63(ALPHA / DIGIT / "-" / "*" / ".")
+
+
+ mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+
+ ; at-most one terminationStateDescriptor
+ ; and either streamParm(s) or streamDescriptor(s) but not both
+ mediaParm = (streamParm / streamDescriptor /
+ terminationStateDescriptor)
+
+ ; at-most-once per item
+ streamParm = ( localDescriptor / remoteDescriptor /
+ localControlDescriptor )
+
+ streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+ *(COMMA streamParm) RBRKT
+
+ localControlDescriptor = LocalControlToken LBRKT localParm
+ *(COMMA localParm) RBRKT
+
+ ; at-most-once per item except for propertyParm
+ localParm = ( streamMode / propertyParm / reservedValueMode
+ / reservedGroupMode )
+
+ reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+ reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+
+
+
+ Groves et al Expires - October 2003 [Page 126]
+ Megaco Protocol version 2 April 2003
+
+
+ streamMode = ModeToken EQUAL streamModes
+
+ streamModes = (SendonlyToken / RecvonlyToken / SendrecvToken /
+ InactiveToken / LoopbackToken )
+
+ propertyParm = pkgdName parmValue
+ parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+ alternativeValue = ( VALUE
+ / LSBRKT VALUE *(COMMA VALUE) RSBRKT
+ ; sublist (i.e. A AND B AND ...)
+ / LBRKT VALUE *(COMMA VALUE) RBRKT
+ ; alternatives (i.e. A OR B OR ...)
+ / LSBRKT VALUE COLON VALUE RSBRKT )
+ ; range
+
+ INEQUAL = LWSP (">" / "<" / "#" ) LWSP
+ LSBRKT = LWSP "[" LWSP
+ RSBRKT = LWSP "]" LWSP
+
+ ; Note - The octet zero is not among the permitted characters in
+ ; octet string. As the current definition is limited to SDP, and a
+ ; zero octet would not be a legal character in SDP, this is not a
+ ; concern.
+ localDescriptor = LocalToken LBRKT octetString RBRKT
+
+ remoteDescriptor = RemoteToken LBRKT octetString RBRKT
+
+ eventBufferDescriptor= EventBufferToken [ LBRKT eventSpec
+ *( COMMA eventSpec) RBRKT ]
+
+ eventSpec = pkgdName [ LBRKT eventSpecParameter
+ *(COMMA eventSpecParameter) RBRKT ]
+
+ eventSpecParameter = (eventStream / eventOther)
+
+ eventBufferControl = BufferToken EQUAL ( "OFF" / LockStepToken )
+
+ terminationStateDescriptor = TerminationStateToken LBRKT
+ terminationStateParm *( COMMA terminationStateParm ) RBRKT
+
+ ; at-most-once per item except for propertyParm
+ terminationStateParm =(propertyParm / serviceStates /
+ eventBufferControl )
+
+ serviceStates = ServiceStatesToken EQUAL ( TestToken /
+ OutOfSvcToken / InSvcToken )
+
+ muxDescriptor = MuxToken EQUAL MuxType terminationIDList
+
+
+
+ Groves et al Expires - October 2003 [Page 127]
+ Megaco Protocol version 2 April 2003
+
+
+ MuxType = ( H221Token / H223Token / H226Token / V76Token
+ / extensionParameter / Nx64kToken )
+
+ StreamID = UINT16
+
+ pkgdName = (PackageName SLASH ItemID) ;specific item
+ / (PackageName SLASH "*") ;all items in package
+ / ("*" SLASH "*") ; all items supported by the MG
+ PackageName = NAME
+ ItemID = NAME
+
+ eventsDescriptor = EventsToken [ EQUAL RequestID LBRKT
+ requestedEvent *( COMMA requestedEvent ) RBRKT ]
+
+ requestedEvent = pkgdName [ LBRKT eventParameter
+ *( COMMA eventParameter ) RBRKT ]
+
+ ; at-most-once each of KeepActiveToken , eventDM and eventStream
+ ;at most one of either embedWithSig or embedNoSig but not both
+ ;KeepActiveToken and embedWithSig must not both be present
+ eventParameter = ( embedWithSig / embedNoSig / KeepActiveToken
+ /eventDM / eventStream / eventOther )
+
+ embedWithSig = EmbedToken LBRKT signalsDescriptor
+ [COMMA embedFirst ] RBRKT
+
+ embedNoSig = EmbedToken LBRKT embedFirst RBRKT
+
+ ; at-most-once of each
+ embedFirst = EventsToken [ EQUAL RequestID LBRKT
+ secondRequestedEvent *(COMMA secondRequestedEvent) RBRKT ]
+
+ secondRequestedEvent = pkgdName [ LBRKT secondEventParameter
+ *( COMMA secondEventParameter ) RBRKT ]
+
+ ; at-most-once each of embedSig , KeepActiveToken, eventDM or
+ ; eventStream
+ ; KeepActiveToken and embedSig must not both be present
+ secondEventParameter = ( embedSig / KeepActiveToken / eventDM /
+ eventStream / eventOther )
+
+ embedSig = EmbedToken LBRKT signalsDescriptor RBRKT
+
+ eventStream = StreamToken EQUAL StreamID
+
+ eventOther = eventParameterName parmValue
+
+ eventParameterName = NAME
+
+
+
+ Groves et al Expires - October 2003 [Page 128]
+ Megaco Protocol version 2 April 2003
+
+
+ eventDM = DigitMapToken EQUAL(( digitMapName ) /
+ (LBRKT digitMapValue RBRKT ))
+
+ signalsDescriptor = SignalsToken LBRKT [ signalParm
+ *(COMMA signalParm)] RBRKT
+
+ signalParm = signalList / signalRequest
+
+ signalRequest = signalName [ LBRKT sigParameter
+ *(COMMA sigParameter) RBRKT ]
+
+ signalList = SignalListToken EQUAL signalListId LBRKT
+ signalListParm *(COMMA signalListParm) RBRKT
+
+ signalListId = UINT16
+
+ ;exactly once signalType, at most once duration and every signal
+ ;parameter
+ signalListParm = signalRequest
+
+ signalName = pkgdName
+
+ ;at-most-once sigStream, at-most-once sigSignalType,
+ ;at-most-once sigDuration, every signalParameterName at most once
+ sigParameter = sigStream / sigSignalType / sigDuration / sigOther
+ / notifyCompletion / KeepActiveToken
+
+ sigStream = StreamToken EQUAL StreamID
+
+ sigOther = sigParameterName parmValue
+
+ sigParameterName = NAME
+
+ sigSignalType = SignalTypeToken EQUAL signalType
+
+ signalType = (OnOffToken / TimeOutToken / BriefToken)
+
+ sigDuration = DurationToken EQUAL UINT16
+
+ notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+ notificationReason *(COMMA notificationReason) RBRKT)
+
+ notificationReason = ( TimeOutToken / InterruptByEventToken
+ / InterruptByNewSignalsDescrToken
+ / OtherReasonToken )
+
+ observedEventsDescriptor = ObservedEventsToken EQUAL RequestID
+ LBRKT observedEvent *(COMMA observedEvent) RBRKT
+
+
+
+ Groves et al Expires - October 2003 [Page 129]
+ Megaco Protocol version 2 April 2003
+
+
+ ;time per event, because it might be buffered
+ observedEvent = [ TimeStamp LWSP COLON] LWSP
+ pkgdName [ LBRKT observedEventParameter
+ *(COMMA observedEventParameter) RBRKT ]
+
+ ;at-most-once eventStream, every eventParameterName at most once
+ observedEventParameter = eventStream / eventOther
+
+ ; For an AuditCapReply with all events, the RequestID SHOULD be ALL.
+ RequestID = ( UINT32 / "*" )
+
+ modemDescriptor = ModemToken (( EQUAL modemType) /
+ (LSBRKT modemType *(COMMA modemType) RSBRKT))
+ [ LBRKT propertyParm
+ *(COMMA propertyParm) RBRKT ]
+
+ ; at-most-once except for extensionParameter
+ modemType = (V32bisToken / V22bisToken / V18Token /
+ V22Token / V32Token / V34Token / V90Token /
+ V91Token / SynchISDNToken / extensionParameter)
+
+ digitMapDescriptor = DigitMapToken EQUAL
+ ( ( LBRKT digitMapValue RBRKT )
+ / (digitMapName [ LBRKT digitMapValue RBRKT ]) )
+
+ digitMapName = NAME
+
+ digitMapValue = ["T" COLON Timer COMMA] ["S" COLON Timer COMMA]
+ ["L" COLON Timer COMMA] ["Z" COLON Timer COMMA]
+ digitMap
+
+ Timer = 1*2DIGIT
+ ; Units are seconds for T, S, and L timers, and hundreds of
+ ; milliseconds for Z timer. Thus T, S, and L range from 1 to 99
+ ; seconds and Z from 100 ms to 9.9 s
+
+ digitMap = (digitString
+ / LWSP "(" LWSP digitStringList LWSP ")" LWSP)
+
+ digitStringList = digitString *( LWSP "|" LWSP digitString )
+
+ digitString = 1*(digitStringElement)
+
+ digitStringElement = digitPosition [DOT]
+
+ digitPosition = digitMapLetter / digitMapRange
+ digitMapRange = ("x" / (LWSP "[" LWSP digitLetter LWSP "]" LWSP))
+
+ digitLetter = *((DIGIT "-" DIGIT ) / digitMapLetter)
+
+
+ Groves et al Expires - October 2003 [Page 130]
+ Megaco Protocol version 2 April 2003
+
+
+
+ digitMapLetter = DIGIT ;Basic event symbols
+ / %x41-4B / %x61-6B ; a-k, A-K
+ / "L" / "S" / "T" ;Inter-event timers
+ ; (long, short, start)
+ / "Z" ;Long duration modifier
+
+ ; at-most-once, and DigitMapToken and PackagesToken are not allowed
+ ; in AuditCapabilities command
+ auditItem = ( MuxToken / ModemToken / MediaToken /
+ SignalsToken / EventBufferToken /
+ DigitMapToken / StatsToken / EventsToken /
+ ObservedEventsToken / PackagesToken ) /
+ indAudterminationAudit)
+
+ indAudterminationAudit = indAudauditReturnParameter
+ *(COMMA indAudauditReturnParameter)
+
+ indAudauditReturnParameter = (indAudmediaDescriptor / /
+ indAudeventsDescriptor /
+ indAudsignalsDescriptor /
+ indAuddigitMapDescriptor /
+ indAudeventBufferDescriptor /
+ indAudstatisticsDescriptor /
+ indAudpackagesDescriptor)
+
+
+ indAudmediaDescriptor = MediaToken LBRKT indAudmediaParm RBRKT
+
+ ; at-most-once per item
+ ; and either streamParm or streamDescriptor but not both
+ indAudmediaParm = (indAudstreamParm / indAudstreamDescriptor /
+ indAudterminationStateDescriptor)
+
+ ; at-most-once
+ indAudstreamParm = ( indAudlocalControlDescriptor )
+ ; SDP too complex to pull out individual pieces for audit,
+ ; hence no individual audit for Local and Remote
+
+ indAudstreamDescriptor = StreamToken EQUAL StreamID
+ LBRKT indAudstreamParm RBRKT
+
+ indAudlocalControlDescriptor = LocalControlToken
+ LBRKT indAudlocalParm RBRKT
+
+ ; at-most-once per item
+ indAudlocalParm = ( ModeToken / pkgdName /
+ ReservedValueToken /
+ ReservedGroupToken )
+
+
+ Groves et al Expires - October 2003 [Page 131]
+ Megaco Protocol version 2 April 2003
+
+
+
+
+ indAudterminationStateDescriptor = TerminationStateToken
+ LBRKT indAudterminationStateParm RBRKT
+
+ ; at-most-once per item
+ indAudterminationStateParm =(pkgdName / ServiceStatesToken /
+ BufferToken)
+
+ indAudeventBufferDescriptor= EventBufferToken
+ LBRKT indAudeventSpec RBRKT
+
+ indAudeventSpec = pkgdName [ LBRKT indAudeventSpecParameter RBRKT ]
+
+ indAudeventSpecParameter = (eventStream / eventParameterName)
+
+ indAudeventsDescriptor = EventsToken EQUAL RequestID
+ LBRKT indAudrequestedEvent RBRKT
+
+ indAudrequestedEvent = pkgdName
+
+ indAudsignalsDescriptor = SignalsToken
+ LBRKT [ indAudsignalParm ] RBRKT
+
+ indAudsignalParm = indAudsignalList / indAudsignalRequest
+ indAudsignalRequest = signalName
+
+ indAudsignalList = SignalListToken EQUAL signalListId
+ LBRKTindAudsignalListParm RBRKT
+
+ indAudsignalListParm = indAudsignalRequest
+
+ indAuddigitMapDescriptor = DigitMapToken EQUAL (digitMapName )
+
+ indAudstatisticsDescriptor = StatsToken LBRKT pkgdName RBRKT
+
+ indAudpackagesDescriptor = PackagesToken LBRKT packagesItem RBRKT
+
+
+ serviceChangeDescriptor = ServicesToken LBRKT serviceChangeParm
+ *(COMMA serviceChangeParm) RBRKT
+
+ ; each parameter at-most-once
+ ; at most one of either serviceChangeAddress or serviceChangeMgcId
+ ; but not both
+ ; serviceChangeMethod and serviceChangeReason are REQUIRED
+ serviceChangeParm = (serviceChangeMethod / serviceChangeReason /
+ serviceChangeDelay / serviceChangeAddress /
+ serviceChangeProfile / extension / TimeStamp /
+
+
+ Groves et al Expires - October 2003 [Page 132]
+ Megaco Protocol version 2 April 2003
+
+
+ serviceChangeMgcId / serviceChangeVersion /
+ auditItem)
+
+ serviceChangeReplyDescriptor = ServicesToken LBRKT
+ servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+
+ ; at-most-once. Version is REQUIRED on first ServiceChange response
+ ; at most one of either serviceChangeAddress or serviceChangeMgcId
+ ; but not both
+ servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+ serviceChangeProfile / serviceChangeVersion /
+ TimeStamp)
+
+ serviceChangeMethod = MethodToken EQUAL (FailoverToken /
+ ForcedToken / GracefulToken / RestartToken /
+ DisconnectedToken / HandOffToken /
+ extensionParameter)
+
+ ; A serviceChangeReason consists of a numeric reason code
+ ; and an optional text description.
+ ; A serviceChangeReason MUST be encoded using the quotedString
+ ; form of VALUE.
+ ; The quotedString SHALL contain a decimal reason code,
+ ; optionally followed by a single space character and a
+ ; textual description string.
+ serviceChangeReason = ReasonToken EQUAL VALUE
+
+ serviceChangeDelay = DelayToken EQUAL UINT32
+
+ serviceChangeAddress = ServiceChangeAddressToken EQUAL ( mId /
+ portNumber )
+
+ serviceChangeMgcId = MgcIdToken EQUAL mId
+
+ serviceChangeProfile = ProfileToken EQUAL NAME SLASH Version
+
+ serviceChangeVersion = VersionToken EQUAL Version
+
+ extension = extensionParameter parmValue
+
+ packagesDescriptor = PackagesToken LBRKT packagesItem
+ *(COMMA packagesItem) RBRKT
+
+ Version = 1*2(DIGIT)
+
+ packagesItem = NAME "-" UINT16
+
+ TimeStamp = Date "T" Time ; per ISO 8601:1988
+ ; Date = yyyymmdd
+
+
+ Groves et al Expires - October 2003 [Page 133]
+ Megaco Protocol version 2 April 2003
+
+
+ Date = 8(DIGIT)
+ ; Time = hhmmssss
+ Time = 8(DIGIT)
+
+ statisticsDescriptor = StatsToken LBRKT statisticsParameter
+ *(COMMA statisticsParameter ) RBRKT
+
+ ;at-most-once per item
+ statisticsParameter = pkgdName [EQUAL VALUE]
+
+ topologyDescriptor = TopologyToken LBRKT topologyTriple
+ *(COMMA topologyTriple) RBRKT
+
+ topologyTriple = terminationA COMMA
+ terminationB COMMA topologyDirection
+ [COMMA eventStream ]
+ terminationA = TerminationID
+ terminationB = TerminationID
+
+ topologyDirection = BothwayToken / IsolateToken / OnewayToken
+
+ priority = PriorityToken EQUAL UINT16
+
+ extensionParameter = "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+
+ ; octetString is used to describe SDP defined in RFC2327.
+ ; Caution SHOULD be taken if CRLF in RFC2327 is used.
+ ; To be safe, use EOL in this ABNF.
+ ; Whenever "}" appears in SDP, it is escaped by "\", e.g. "\}"
+ octetString = *(nonEscapeChar)
+ nonEscapeChar = ( "\}" / %x01-7C / %x7E-FF )
+
+ ; Note - The double-quote character is not allowed in quotedString.
+ quotedString = DQUOTE *(SafeChar / RestChar/ WSP) DQUOTE
+
+ UINT16 = 1*5(DIGIT) ; %x0-FFFF
+ UINT32 = 1*10(DIGIT) ; %x0-FFFFFFFF
+
+ NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ VALUE = quotedString / 1*(SafeChar)
+
+ SafeChar = DIGIT / ALPHA / "+" / "-" / "&" /
+ "!" / "_" / "/" / "'" / "?" / "@" /
+ "^" / "`" / "~" / "*" / "$" / "\" /
+ "(" / ")" / "%" / "|" / "."
+
+ EQUAL = LWSP %x3D LWSP ; "="
+ COLON = %x3A ; ":"
+ LBRKT = LWSP %x7B LWSP ; "{"
+
+
+ Groves et al Expires - October 2003 [Page 134]
+ Megaco Protocol version 2 April 2003
+
+
+ RBRKT = LWSP %x7D LWSP ; "}"
+ COMMA = LWSP %x2C LWSP ; ","
+ DOT = %x2E ; "."
+ SLASH = %x2F ; "/"
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ DIGIT = %x30-39 ; 0-9
+ DQUOTE = %x22 ; " (Double Quote)
+ HEXDIG = ( DIGIT / "A" / "B" / "C" / "D" / "E" / "F" )
+ SP = %x20 ; space
+ HTAB = %x09 ; horizontal tab
+ CR = %x0D ; Carriage return
+ LF = %x0A ; linefeed
+ LWSP = *( WSP / COMMENT / EOL )
+ EOL = (CR [LF] / LF )
+ WSP = SP / HTAB ; white space
+ SEP = ( WSP / EOL / COMMENT) LWSP
+ COMMENT = ";" *(SafeChar/ RestChar / WSP / %x22) EOL
+ RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+ "<" / ">" / "="
+
+ ; New Tokens added to sigParameter must take the format of SPA*
+ ; * may be of any form i.e. SPAM
+ ; New Tokens added to eventParameter must take the form of EPA*
+ ; * may be of any form i.e. EPAD
+
+ AddToken = ("Add" / "A")
+ AuditToken = ("Audit" / "AT")
+ AuditCapToken = ("AuditCapability" / "AC")
+ AuditValueToken = ("AuditValue" / "AV")
+ AuthToken = ("Authentication" / "AU")
+ BothwayToken = ("Bothway" / "BW")
+ BriefToken = ("Brief" / "BR")
+ BufferToken = ("Buffer" / "BF")
+ CtxToken = ("Context" / "C")
+ ContextAuditToken = ("ContextAudit" / "CA")
+ DigitMapToken = ("DigitMap" / "DM")
+ DisconnectedToken = ("Disconnected" / "DC")
+ DelayToken = ("Delay" / "DL")
+ DurationToken = ("Duration" / "DR")
+ EmbedToken = ("Embed" / "EM")
+ EmergencyToken = ("Emergency" / "EG")
+ ErrorToken = ("Error" / "ER")
+ EventBufferToken = ("EventBuffer" / "EB")
+ EventsToken = ("Events" / "E")
+ FailoverToken = ("Failover" / "FL")
+ ForcedToken = ("Forced" / "FO")
+ GracefulToken = ("Graceful" / "GR")
+ H221Token = ("H221" )
+ H223Token = ("H223" )
+
+
+ Groves et al Expires - October 2003 [Page 135]
+ Megaco Protocol version 2 April 2003
+
+
+ H226Token = ("H226" )
+ HandOffToken = ("HandOff" / "HO")
+ ImmAckRequiredToken = ("ImmAckRequired" / "IA")
+ InactiveToken = ("Inactive" / "IN")
+ IsolateToken = ("Isolate" / "IS")
+ InSvcToken = ("InService" / "IV")
+ InterruptByEventToken = ("IntByEvent" / "IBE")
+ InterruptByNewSignalsDescrToken
+ = ("IntBySigDescr" / "IBS")
+ KeepActiveToken = ("KeepActive" / "KA")
+ LocalToken = ("Local" / "L")
+ LocalControlToken = ("LocalControl" / "O")
+ LockStepToken = ("LockStep" / "SP")
+ LoopbackToken = ("Loopback" / "LB")
+ MediaToken = ("Media" / "M")
+ MegacopToken = ("MEGACO" / "!")
+ MethodToken = ("Method" / "MT")
+ MgcIdToken = ("MgcIdToTry" / "MG")
+ ModeToken = ("Mode" / "MO")
+ ModifyToken = ("Modify" / "MF")
+ ModemToken = ("Modem" / "MD")
+ MoveToken = ("Move" / "MV")
+ MTPToken = ("MTP")
+ MuxToken = ("Mux" / "MX")
+ NotifyToken = ("Notify" / "N")
+ NotifyCompletionToken = ("NotifyCompletion" / "NC")
+ Nx64kToken = ("Nx64Kservice" / "N64")
+ ObservedEventsToken = ("ObservedEvents" / "OE")
+ OnewayToken = ("Oneway" / "OW")
+ OnOffToken = ("OnOff" / "OO")
+ OtherReasonToken = ("OtherReason" / "OR")
+ OutOfSvcToken = ("OutOfService" / "OS")
+ PackagesToken = ("Packages" / "PG")
+ PendingToken = ("Pending" / "PN")
+ PriorityToken = ("Priority" / "PR")
+ ProfileToken = ("Profile" / "PF")
+ ReasonToken = ("Reason" / "RE")
+ RecvonlyToken = ("ReceiveOnly" / "RC")
+ ReplyToken = ("Reply" / "P")
+ RestartToken = ("Restart" / "RS")
+ RemoteToken = ("Remote" / "R")
+ ReservedGroupToken = ("ReservedGroup" / "RG")
+ ReservedValueToken = ("ReservedValue" / "RV")
+ SendonlyToken = ("SendOnly" / "SO")
+ SendrecvToken = ("SendReceive" / "SR")
+ ServicesToken = ("Services" / "SV")
+ ServiceStatesToken = ("ServiceStates" / "SI")
+ ServiceChangeToken = ("ServiceChange" / "SC")
+ ServiceChangeAddressToken = ("ServiceChangeAddress" / "AD")
+
+
+ Groves et al Expires - October 2003 [Page 136]
+ Megaco Protocol version 2 April 2003
+
+
+ SignalListToken = ("SignalList" / "SL")
+ SignalsToken = ("Signals" / "SG")
+ SignalTypeToken = ("SignalType" / "SY")
+ StatsToken = ("Statistics" / "SA")
+ StreamToken = ("Stream" / "ST")
+ SubtractToken = ("Subtract" / "S")
+ SynchISDNToken = ("SynchISDN" / "SN")
+ TerminationStateToken = ("TerminationState" / "TS")
+ TestToken = ("Test" / "TE")
+ TimeOutToken = ("TimeOut" / "TO")
+ TopologyToken = ("Topology" / "TP")
+ TransToken = ("Transaction" / "T")
+ ResponseAckToken = ("TransactionResponseAck" / "K")
+ V18Token = ("V18")
+ V22Token = ("V22")
+ V22bisToken = ("V22b")
+ V32Token = ("V32")
+ V32bisToken = ("V32b")
+ V34Token = ("V34")
+ V76Token = ("V76")
+ V90Token = ("V90")
+ V91Token = ("V91")
+ VersionToken = ("Version" / "V")
+
+
+ B.3 Hexadecimal octet coding
+
+ Hexadecimal octet coding is a means for representing a string of
+ octets as a string of hexadecimal digits, with two digits
+ representing each octet. This octet encoding SHOULD be used when
+ encoding octet strings in the text version of the protocol.
+
+ For each octet, the 8-bit sequence is encoded as two hexadecimal
+ digits. Bit 0 is the first transmitted; bit 7 is the last.
+
+ Bits 7-4 are encoded as the first hexadecimal digit, with Bit 7 as
+ MSB and Bit 4 as LSB. Bits 3-0 are encoded as the second hexadecimal
+ digit, with Bit 3 as MSB and Bit 0 as LSB.
+
+ Examples:
+
+ Octet bit pattern Hexadecimal
+ coding
+
+ 00011011 D8
+
+ 11100100 27
+
+
+
+
+ Groves et al Expires - October 2003 [Page 137]
+ Megaco Protocol version 2 April 2003
+
+
+ 10000011 10100010 11001000 C1451390
+ 00001001
+
+
+
+ B.4 Hexadecimal octet sequence
+
+ A hexadecimal octet sequence is an even number of hexadecimal digits,
+ terminated by a <CR> character.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 138]
+ Megaco Protocol version 2 April 2003
+
+
+ ANNEX C TAGS FOR MEDIA STREAM PROPERTIES
+
+ Parameters for Local, Remote and LocalControl descriptors are
+ specified as tag-value pairs if binary encoding is used for the
+ protocol. This annex contains the property names (PropertyID), the
+ tags (Property tag), type of the property (Type) and the values
+ (Value). Values presented in the Value field when the field contains
+ references shall be regarded as "information". The reference contains
+ the normative values. If a value field does not contain a reference,
+ then the values in that field can be considered as "normative".
+
+ Tags are given as hexadecimal numbers in this annex. When setting the
+ value of a property, a MGC may underspecify the value according to
+ one of the mechanisms specified in 7.1.1.
+
+ It is optional to support the properties in this Annex or any of its
+ sub-sections. For example, only three properties from C.3 and only
+ five properties from C.8 might be implemented.
+
+ For type "enumeration" the value is represented by the value in
+ brackets, e.g. Send(0), Receive(1). Annex C properties with the types
+ "N bits" or "M Octets" SHOULD be treated as octet strings when
+ encoding the protocol. Properties with "N bit integer" shall be
+ treated as an integers. "String" shall be treated as an IA5String
+ when encoding the protocol.
+
+ When a type is smaller than one octet, the value shall be stored in
+ the low-order bits of an octet string of size 1.
+
+
+ C.1 General media attributes
+
+
+ PropertyID Property Type Value
+ tag
+
+ Media 1001 Enumeration Audio(0), Video(1), Data(2)
+
+ Transmission 1002 Enumeration Send(0), Receive(1),
+ mode Send&Receive(2)
+
+ Number of 1003 Unsigned 0-255
+ Channels integer
+
+ Sampling 1004 Unsigned 0-2^32
+ rate integer
+
+
+
+
+ Groves et al Expires - October 2003 [Page 139]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ Bitrate 1005 Integer (0..4294967295)
+
+ NOTE - Units of 100 bit/s.
+
+ ACodec 1006 Octet string Audio Codec Type:
+
+ Ref.: ITU-T Q.765.5
+
+ Non-ITU-T codecs are defined
+ with the appropriate
+ standards organization under
+ a defined Organizational
+ Identitifier.
+
+ Samplepp 1007 Unsigned Maximum samples or frames
+ integer per packet: 0..65535
+
+ Silencesupp 1008 Boolean Silence Suppression:
+ True/False
+
+ Encrypttype 1009 Octet string Ref.: ITU-T H.245
+
+ Encryptkey 100A Octet string Encryption key
+ size
+ (0..65535) Ref.: ITU-T H.235
+
+ Echocanc 100B Not Used. See H.248.1 E.13
+ for an example of possible
+ Echo Control properties.
+
+ Gain 100C Unsigned Gain in dB: 0..65535
+ integer
+
+ Jitterbuff 100D Unsigned Jitter buffer size in ms:
+ integer 0..65535
+
+ PropDelay 100E Unsigned Propagation Delay: 0..65535
+ integer
+ Maximum propagation delay in
+ milliseconds for the bearer
+ connection between two media
+ gateways. The maximum delay
+ will be dependent on the
+ bearer technology.
+
+
+
+ Groves et al Expires - October 2003 [Page 140]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ RTPpayload 100F Integer Payload type in RTP Profile
+ for Audio and Video
+ Conferences with Minimal
+ Control
+
+ Ref.: RFC 1890
+
+
+
+
+ C.2 Mux properties
+
+
+ PropertyID Property Type Value
+ tag
+
+ H222 2001 Octet H222LogicalChannelParameters
+ string
+ Ref.: ITU-T H.245
+
+ H223 2002 Octet H223LogicalChannelParameters
+ string
+ Ref.: ITU-T H.245
+
+ V76 2003 Octet V76LogicalChannelParameters
+ string
+ Ref.: ITU-T H.245
+
+ H2250 2004 Octet H2250LogicalChannelParameters
+ string
+ Ref.: ITU-T H.245
+
+
+
+
+ C.3 General bearer properties
+
+
+ PropertyID Property Type Value
+ tag
+
+ Mediatx 3001 Enumerati Media Transport Type
+ on
+ TDM Circuit(0), ATM(1), FR(2),
+
+
+
+ Groves et al Expires - October 2003 [Page 141]
+ Megaco Protocol version 2 April 2003
+
+
+ Ipv4(3), Ipv6(4), ...
+
+ BIR 3002 4 octets Value depends on transport
+ technology
+
+ NSAP 3003 1-20 See NSAP.
+ octets
+ Ref.: Annex A/X.213
+
+
+
+
+ C.4 General ATM properties
+
+
+ PropertyID Property Type Value
+ tag
+
+ AESA 4001 20 octets ATM End System Address
+
+ VPVC 4002 4 octets: VPCI/VCI
+ VPCI in
+ first two Ref.: ITU-T Q.2931
+ least
+ significant
+ octets, VCI
+ in second
+ two octets
+
+ SC 4003 Enumeration Service Category: CBR(0), nrt-
+ VBR1(1), nrt-VBR2(2), nrt-
+ VBR3(3), rt-VBR1(4),
+ rt-VBR2(5), rt-VBR3(6),
+ UBR1(7), UBR2(8), ABR(9).
+
+ Ref.: ATM Forum UNI 4.0
+
+ BCOB 4004 5-bit Broadband Bearer Class
+ integer
+ Ref.: ITU-T Q.2961.2
+
+ BBTC 4005 7-bit Broadband Transfer Capability
+ integer
+ Ref.: ITU-T Q.2961.1
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 142]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ ATC 4006 Enumeration I.371 ATM Traffic Capability
+
+ DBR(0), SBR1(1), SBR2(2),
+ SBR3(3), ABT/IT(4), ABT/DT(5),
+ ABR(6)
+
+ Ref.: ITU-T I.371
+
+ STC 4007 2 bits Susceptibility to clipping:
+
+ Bits
+ 21
+ --
+ 00 not susceptible to clipping
+ 01 susceptible to clipping
+
+ Ref.: ITU-T Q.2931
+
+ UPCC 4008 2 bits User Plane Connection
+ configuration:
+
+ Bits
+ 21
+ --
+ 00 point-to-point
+ 01 point-to-multipoint
+
+ Ref.: ITU-T Q.2931
+
+ PCR0 4009 24-bit Peak Cell Rate (For CLP = 0)
+ integer
+ Ref.: ITU-T Q.2931
+
+ SCR0 400A 24-bit Sustainable Cell Rate
+ integer (For CLP = 0)
+
+ Ref.: ITU-T Q.2961.1
+
+ MBS0 400B 24-bit Maximum Burst Size
+ integer (For CLP = 0)
+
+ Ref.: ITU-T Q.2961.1
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 143]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ PCR1 400C 24-bit Peak Cell Rate (For
+ integer CLP = 0 + 1)
+
+ Ref.: ITU-T Q.2931
+
+ SCR1 400D 24-bit Sustainable Cell Rate
+ integer (For CLP = 0 + 1)
+
+ Ref.: ITU-T Q.2961.1
+
+ MBS1 400E 24-bit Maximum Burst Size
+ integer (For CLP = 0 + 1)
+
+ Ref.: ITU-T Q.2961.1
+
+ BEI 400F Boolean Best Effort Indicator
+
+ Value 1 indicates that BEI is
+ to be included in the ATM
+ signaling; value 0 indicates
+ that BEI is not to be included
+ in the ATM signaling.
+
+ Ref.: ATM Forum UNI 4.0
+
+ TI 4010 Boolean Tagging Indicator
+
+ Value 0 indicates that tagging
+ is not allowed; value 1
+ indicates that tagging is
+ requested.
+
+ Ref.: ITU-T Q.2961.1
+
+ FD 4011 Boolean Frame Discard
+
+ Value 0 indicates that no
+ frame discard is allowed;
+ value 1 indicates that frame
+ discard is allowed.
+
+ Ref.: ATM Forum UNI 4.0
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 144]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ A2PCDV 4012 24-bit Acceptable 2-point CDV
+ integer
+ Ref.: ITU-T Q.2965.2
+
+ C2PCDV 4013 24-bit Cumulative 2-point CDV
+ integer
+ Ref.: ITU-T Q.2965.2
+
+ APPCDV 4014 24-bit Acceptable P-P CDV
+ integer
+ Ref.: ATM Forum UNI 4.0
+
+ CPPCDV 4015 24-bit Cumulative P-P CDV
+ integer
+ Ref.: ATM Forum UNI 4.0
+
+ ACLR 4016 8-bit Acceptable Cell Loss Ratio
+ integer
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ MEETD 4017 16-bit Maximum End-to-end transit
+ integer delay
+
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ CEETD 4018 16-bit Cumulative End-to-end transit
+ integer delay
+
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ QosClass 4019 Integer 0-5 QoS Class
+
+ QoS Meaning
+ Class
+
+ 0 Default QoS
+ associated with the
+ ATC as defined in
+ ITU-T Q.2961.2
+
+ 1 Stringent
+
+
+
+ Groves et al Expires - October 2003 [Page 145]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ 2 Tolerant
+
+ 3 Bi-level
+
+ 4 Unbounded
+
+ 5 Stringent Bi-level
+
+ Ref.: ITU-T Q.2965.1
+
+ AALtype 401A 1 octet AAL Type
+
+ Bits
+ 87654321
+ --------
+ 00000000 AAL for voice
+ 00000001 AAL type 1
+ 00000010 AAL type 2
+ 00000011 AAL type 3/4
+ 00000101 AAL type 5
+ 00010000 user-defined AAL
+
+ Ref.: ITU-T Q.2931
+
+
+
+
+ C.5 Frame Relay
+
+
+ PropertyID Property Type Value
+ tag
+
+ DLCI 5001 Unsigned Data link connection id
+ integer
+
+ CID 5002 Unsigned sub-channel id
+ integer
+
+ SID/ 5003 Unsigned silence insertion
+ Noiselevel integer descriptor
+
+ Primary 5004 Unsigned Primary Payload Type
+ Payload type integer
+
+
+
+ Groves et al Expires - October 2003 [Page 146]
+ Megaco Protocol version 2 April 2003
+
+
+ Covers FAX and codecs
+
+
+
+ C.6 IP
+
+
+ PropertyID Property Type Value
+ tag
+
+ IPv4 6001 32 bits Ipv4Address
+ Ipv4Address Ref.: IETF RFC 791
+
+ IPv6 6002 128 bits IPv6 Address
+ Ref.: IETF RFC 2460
+
+ Port 6003 Unsigned 0..65535
+ integer
+
+ Porttype 6004 Enumerated TCP(0), UDP(1), SCTP(2)
+
+
+
+ C.7 ATM AAL2
+
+
+ PropertyID Property Type Value
+ tag
+
+ AESA 7001 20 octets AAL2 service endpoint
+ address as defined in the
+ referenced Recommendation.
+
+ ESEA
+
+ NSEA
+
+ Ref.: ITU-T Q.2630.1
+
+ BIR See C.3 4 octets Served user generated
+ reference as defined in the
+ referenced Recommendation.
+
+ SUGR
+
+ Ref.: ITU-T Q.2630.1
+
+
+
+
+ Groves et al Expires - October 2003 [Page 147]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ ALC 7002 12 octets AAL2 link characteristics as
+ defined in the referenced
+ Recommendation.
+
+ Maximum/Average CPS-SDU bit
+ rate;
+
+ Maximum/Average CPS-SDU size
+
+ Ref.: ITU-T Q.2630.1
+
+ SSCS 7003 I.366.2: Service specific convergence
+ sublayer information as
+ Audio defined in:
+ (8 octets); - ITU-T Q.2630.1,
+ Multirate and used in:
+ (3 octets),
+ or - ITU-T I.366.2:
+ Audio/Multirate;
+ I.366.1:
+ - ITU-T I.366.1:
+ SAR-assured SAR-assured/-unassured.
+ (14 octets);
+ SAR-unassured Ref.: ITU-T Q.2630.1,
+ (7 octets). I.366.1 and I.366.2
+
+ SUT 7004 1..254 octets Served user transport
+ parameter as defined in the
+ referenced Recommendation.
+
+ Ref.: ITU-T Q.2630.1
+
+ TCI 7005 Boolean Test connection indicator as
+ defined in the referenced
+ Recommendation.
+
+ Ref.: ITU-T Q.2630.1
+
+ Timer_CU 7006 32-bit Timer-CU
+ integer
+ Milliseconds to hold
+ partially filled cell before
+ sending.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 148]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ MaxCPSSDU 7007 8-bit integer Maximum Common Part Sublayer
+ Service Data Unit
+
+ Ref.: ITU-T Q.2630.1
+
+ CID 7008 8 bits subchannel id: 0-255
+
+ Ref.: ITU-T I.363.2
+
+
+
+ C.8 ATM AAL1
+
+
+ Property Property Type Value
+ ID tag
+
+ BIR See table 4-29 GIT (Generic Identifier Transport)
+ in C.3 octets
+ Ref.: ITU-T Q.2941.1
+
+ AAL1ST 8001 1 octet AAL1 Subtype
+
+ Bits
+ 87654321
+ --------
+ 00000000 null
+ 00000001 voiceband signal
+ transport on 64 kbit/s
+ 00000010 circuit transport
+ 00000100 high-quality audio signal
+ transport
+ 00000101 video signal transport
+
+ Ref.: ITU-T Q.2931
+
+ CBRR 8002 1 octet CBR Rate
+
+ Bits
+ 87654321
+ --------
+ 00000001 64 kbit/s
+ 00000100 1544 kbit/s
+ 00000101 6312 kbit/s
+ 00000110 32 064 kbit/s
+
+
+ Groves et al Expires - October 2003 [Page 149]
+ Megaco Protocol version 2 April 2003
+
+
+ Property Property Type Value
+ ID tag
+
+ 00000111 44 736 kbit/s
+ 00001000 97 728 kbit/s
+ 00010000 2048 kbit/s
+ 00010001 8448 kbit/s
+ 00010010 34 368 kbit/s
+ 00010011 139 264 kbit/s
+ 01000000 n x 64 kbit/s
+ 01000001 n x 8 kbit/s
+
+ Ref.: ITU-T Q.2931
+
+ MULT See table Multiplier, or n x 64k/8k/300
+ in C.9
+ Ref.: ITU-T Q.2931
+
+ SCRI 8003 1 octet Source Clock Frequency Recovery
+ Method
+
+ Bits
+ 87654321
+ --------
+ 00000000 null
+ 00000001 SRTS
+ 00000010 ACM
+
+ Ref.: ITU-T Q.2931
+
+ ECM 8004 1 octet Error Correction Method
+
+ Bits
+ 87654321
+ --------
+ 00000000 null
+ 00000001 FEC - Loss
+ 00000010 FEC - Delay
+
+ Ref.: ITU-T Q.2931
+
+ SDTB 8005 16-bit Structured Data Transfer Blocksize
+ integer
+ Block size of SDT CBR service
+
+ Ref.: ITU-T I.363.1
+
+
+
+
+ Groves et al Expires - October 2003 [Page 150]
+ Megaco Protocol version 2 April 2003
+
+
+ Property Property Type Value
+ ID tag
+
+ PFCI 8006 8-bit Partially filled cells identifier
+ integer
+ 1-47
+
+ Ref.: ITU-T I.363.1
+
+
+
+ C.9 Bearer capabilities
+
+ The table entries referencing Recommendation Q.931 refer to the
+ encoding in the bearer capability information element of Q.931, not
+ to the low layer information element.
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ TMR 9001 1 octet Transmission Medium Requirement
+ (Q.763)
+
+ Bits
+ 87654321
+ --------
+ 00000000 speech
+ 00000001 spare
+ 00000010 64 kbit/s unrestricted
+ 00000011 3.1 kHz audio
+ 00000100 reserved for alternate
+ speech (service 2) /
+ 64 kbit/s unrestricted
+ (service 1)
+ 00000101 reserved for alternate
+ 64 kbit/s unrestricted
+ (service 1) / speech
+ (service 2)
+ 00000110 64 kbit/s preferred
+ 00000111 2 x 64 kbit/s
+ unrestricted
+ 00001000 384 kbit/s unrestricted
+ 00001001 1536 kbit/s unrestricted
+ 00001010 1920 kbit/s unrestricted
+ 00001011
+ through spare
+ 00001111
+
+
+ Groves et al Expires - October 2003 [Page 151]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 00010000 3 x 64 kbit/s
+ through through
+ 00101010 29 x 64 kbit/s
+ unrestricted
+ 00101011
+ through spare
+ 11111111
+
+ Ref.: ITU-T Q.763
+
+ TMRSR 9002 1 octet Transmission Medium Requirement
+ Subrate
+
+ 0 unspecified
+
+ 1 8 kbit/s
+ 2 16 kbit/s
+ 3 32 kbit/s
+
+ Contcheck 9003 Boolean Continuity Check
+
+ 0 continuity check not required
+ on this circuit
+
+ 1 continuity check required on
+ this circuit
+
+ Ref.: ITU-T Q.763
+
+ ITC 9004 5 bits Information Transfer Capability
+
+ Bits
+ 54321
+ -----
+
+ 00000 Speech
+
+ 01000 Unrestricted digital
+ information
+
+ 01001 Restricted digital
+ information
+
+ 10000 3.1 kHz audio
+
+
+
+ Groves et al Expires - October 2003 [Page 152]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 10001 Unrestricted digital
+ information with
+ tones/announcements
+
+ 11000 Video
+
+ All other values are reserved.
+
+ Ref.: ITU-T Q.763
+
+ TransMode 9005 2 bits Transfer Mode
+
+ Bits
+ 21
+ --
+ 00 Circuit mode
+ 10 Packet mode
+
+ Ref.: ITU-T Q.931
+
+ TransRate 9006 5 bits Transfer Rate
+
+ Bits
+ 54321
+ -----
+ 00000 This code shall be used
+ for packet mode calls
+ 10000 64 kbit/s
+ 10001 2 x 64 kbit/s
+ 10011 384 kbit/s
+ 10101 1536 kbit/s
+ 10111 1920 kbit/s
+ 11000 Multirate (64 kbit/s
+ base rate)
+
+ Ref.: ITU-T Q.931
+
+ MULT 9007 7 bits Rate Multiplier
+
+ Any value from 2 to n (maximum
+ number of B-channels)
+
+ Ref.: ITU-T Q.931
+
+
+
+
+ Groves et al Expires - October 2003 [Page 153]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ layer1prot 9008 5 bits User Information Layer 1 Protocol
+
+ Bits
+ 54321
+ -----
+ 00001 ITU-T standardized rate
+ adaption V.110 and X.30.
+ 00010 Rec. G.711 mu-law
+ 00011 Rec. G.711 A-law
+ 00100 Rec. G.726 32 kbit/s ADPCM
+ and Rec. I.460
+ 00101 Rec. H.221 and H.242
+ 00110 Rec. H.223 and H.245
+ 00111 Non-ITU-T standardized
+ rate adaption.
+ 01000 ITU-T standardized rate
+ adaption V.120.
+ 01001 ITU-T standardized rate
+ adaption X.31 HDLC flag
+ stuffing
+
+ All other values are reserved.
+
+ Ref.: ITU Recommendation Q.931
+ syncasync 9009 Boolean Synchronous/Asynchronous
+
+ 0 Synchronous data
+ 1 Asynchronous data
+
+ Ref.: ITU-T Q.931
+
+ negotiatio 900A Boolean Negotiation
+ n
+ 0 In-band negotiation possible
+ 1 In-band negotiation not possible
+
+ Ref.: ITU-T Q.931
+
+ Userrate 900B 5 bits User Rate
+
+ 54321
+ -----
+ 00000 Rate is indicated by E-bits
+ specified in Rec. I.460 or
+ may be negotiated in-band
+
+
+ Groves et al Expires - October 2003 [Page 154]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 00001 0.6 kbit/s Recs. V.6 & X.1
+ 00010 1.2 kbit/s Rec. V.6
+ 00011 2.4 kbit/s Recs. V.6 & X.1
+ 00100 3.6 kbit/s Rec. V.6
+ 00101 4.8 kbit/s Recs. V.6 & X.1
+ 00110 7.2 kbit/s Rec. V.6
+ 00111 8 kbit/s Rec. I.460
+ 01000 9.6 kbit/s Recs. V.6 & X.1
+ 01001 14.4 kbit/s Rec. V.6
+ 01010 16 kbit/s Rec. I.460
+ 01011 19.2 kbit/s Rec. V.6
+ 01100 32 kbit/s Rec. I.460
+ 01101 38.4 kbit/s Rec. V.110
+ 01110 48 kbit/s Recs. V.6 & X.1
+ 01111 56 kbit/s Rec. V.6
+ 10010 57.6 kbit/s Rec. V.14
+ extended
+ 10011 28.8 kbit/s Rec. V.110
+ 10100 24 kbit/s Rec. V.110
+ 10101 0.1345 kbit/s Rec. X.1
+ 10110 0.100 kbit/s Rec. X.1
+
+ Recommendations V.6 and X.1:
+ 10111 0.075/1.2 kbit/s
+ 11000 1.2/0.075 kbit/s
+ 11001 0.050 kbit/s
+ 11010 0.075 kbit/s
+ 11011 0.110 kbit/s
+ 11100 0.150 kbit/s
+ 11101 0.200 kbit/s
+ 11110 0.300 kbit/s
+
+ 11111 12 kbit/s Rec. V.6
+
+ All other values are reserved.
+
+ Ref.: ITU-T Q.931
+
+ INTRATE 900C 2 bits Intermediate Rate
+
+ Bits
+ 21
+ --
+ 00 Not used
+ 01 8 kbit/s
+
+
+
+ Groves et al Expires - October 2003 [Page 155]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 10 16 kbit/s
+ 11 32 kbit/s
+
+ Ref.: ITU-T Q.931
+
+ nictx 900D Boolean Network Independent Clock (NIC) on
+ transmission
+
+ 0 Not required to send data with
+ network independent clock
+
+ 1 Required to send data with
+ network independent clock
+
+ Ref.: ITU-T Q.931
+
+ nicrx 900E Boolean Network independent clock (NIC) on
+ reception
+
+ 0 Cannot accept data with network
+ independent clock (i.e. sender
+ does not support this optional
+ procedure)
+
+ 1 Can accept data with network
+ independent clock (i.e. sender
+ does support this optional
+ procedure)
+
+ Ref.: ITU-T Q.931
+
+ flowconttx 900F Boolean Flow Control on transmission (Tx)
+
+ 0 Not required to send data with
+ flow control mechanism
+
+ 1 Required to send data with flow
+ control mechanism
+
+ Ref.: ITU-T Q.931
+
+ flowcontrx 9010 Boolean Flow control on reception (Rx)
+
+ 0 Cannot accept data with flow
+ control mechanism (i.e. sender
+
+
+ Groves et al Expires - October 2003 [Page 156]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ does not support this optional
+ procedure)
+
+ 1 Can accept data with flow
+ control mechanism (i.e. sender
+ does support this optional
+ procedure)
+
+ Ref.: ITU-T Q.931
+
+ rateadapth 9011 Boolean Rate adaption header/no header
+ dr
+ 0 Rate adaption header not
+ included
+
+ 1 Rate adaption header included
+
+ Ref.: ITU-T Q.931
+
+ multiframe 9012 Boolean Multiple frame establishment
+ support in data link
+
+ 0 Multiple frame establishment
+ not supported. Only UI frames
+ allowed
+
+ 1 Multiple frame establishment
+ supported
+
+ Ref.: ITU-T Q.931
+
+ OPMODE 9013 Boolean Mode of operation
+
+ 0 Bit transparent mode of
+ operation
+
+ 1 Protocol sensitive mode of
+ operation
+
+ Ref.: ITU-T Q.931
+
+ llidnegot 9014 Boolean Logical link identifier
+ negotiation
+
+
+
+
+ Groves et al Expires - October 2003 [Page 157]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 0 Default, LLI = 256 only
+
+ 1 Full protocol negotiation
+
+ Ref.: ITU-T Q.931
+
+ assign 9015 Boolean Assignor/assignee
+
+ 0 Message originator is "default
+ assignee"
+
+ 1 Message originator is "assignor
+ only"
+
+ Ref.: ITU-T Q.931
+
+ inbandneg 9016 Boolean In-band/out-band negotiation
+
+ 0 Negotiation is done with USER
+ INFORMATION messages on a
+ temporary signalling connection
+
+ 1 Negotiation is done in-band
+ using logical link zero
+
+ Ref.: ITU-T Q.931
+
+ stopbits 9017 2 bits Number of stop bits
+
+ Bits
+ 21
+ --
+ 00 Not used
+ 01 1 bit
+ 10 1.5 bits
+ 11 2 bits
+
+ Ref.: ITU-T Q.931
+
+ databits 9018 2 bits Number of data bits excluding
+ parity bit if present
+
+ Bits
+ 21
+ --
+
+
+ Groves et al Expires - October 2003 [Page 158]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 00 Not used
+ 01 5 bits
+ 10 7 bits
+ 11 8 bits
+
+ Ref.: ITU-T Q.931
+
+ parity 9019 3 bits Parity information
+
+ Bits
+ 321
+ ---
+ 000 Odd
+ 010 Even
+ 011 None
+ 100 Forced to 0
+ 101 Forced to 1
+
+ All other values are reserved.
+
+ Ref.: ITU-T Q.931
+
+ duplexmode 901A Boolean Mode duplex
+
+ 0 Half duplex
+ 1 Full duplex
+
+ Ref.: ITU-T Q.931
+
+ modem 901B 6 bits Modem Type
+
+ Bits
+ 654321
+ ------
+ 000000
+ through National use
+ 000101
+
+ 010001 Recommendation V.21
+ 010010 Recommendation V.22
+ 010011 Recommendation V.22 bis
+ 010100 Recommendation V.23
+ 010101 Recommendation V.26
+ 011001 Recommendation V.26 bis
+ 010111 Recommendation V.26 ter
+
+
+ Groves et al Expires - October 2003 [Page 159]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 011000 RecommendationV.27
+ 011001 Recommendation V.27 bis
+ 011010 Recommendation V.27 ter
+ 011011 Recommendation V.29
+ 011101 Recommendation V.32
+ 011110 Recommendation V.34
+
+ 100000
+ through National use
+ 101111
+
+ 110000
+ through User specified
+ 111111
+
+ Ref.: ITU-T Q.931
+
+ layer2prot 901C 5 bits User information layer 2 protocol
+
+ Bits
+ 54321
+ -----
+
+ 00010 Rec. Q.921 / I.441
+
+ 00110 Rec. X.25, link layer
+
+ 01100 LAN logical link control
+
+ (ISO/IEC 8802-2)
+
+ All other values are reserved.
+
+ Ref.: ITU-T Q.931
+
+ layer3prot 901D 5 bits User information layer 3 protocol
+
+ Bits
+ 54321
+ -----
+
+ 00010 ITU-T Q.931
+
+ 00110 ITU-T X.25, packet layer
+
+
+
+
+ Groves et al Expires - October 2003 [Page 160]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 01011 ISO/IEC TR 9577 (Protocol
+ identification in the
+ network layer)
+
+ All other values are reserved.
+
+ Ref.: ITU-T Q.931
+
+ addlayer3p 901E Octet Additional User Information layer
+ rot 3 protocol
+
+ Bits Bits
+ 4321 4321
+ ---- ----
+
+ 1100 1100 Internet Protocol
+ (RFC 791)
+ (ISO/IEC TR 9577)
+
+ 1100 1111 Point-to-point
+ Protocol (RFC 1661)
+
+ Ref.: ITU-T Q.931
+
+ DialledN 901F 30 Dialled Number
+ octets
+
+ DiallingN 9020 30 Dialling Number
+ octets
+
+ ECHOCI 9021 Not Used. See H.248.1 E.13 for an
+ example of possible Echo Control
+ properties.
+
+ NCI 9022 1 octet Nature of Connection Indicators
+
+ Bits
+ 21 Satellite Indicator
+ --
+ 00 no satellite circuit in the
+ connection
+ 01 one satellite circuit in the
+ connection
+ 10 two satellite circuits in the
+ connection
+
+
+ Groves et al Expires - October 2003 [Page 161]
+ Megaco Protocol version 2 April 2003
+
+
+ Property
+ PropertyID Type Value
+ tag
+
+ 11 spare
+
+ Bits
+ 43 Continuity check indicator
+ --
+ 00 continuity check not required
+ 01 continuity check required on
+ this circuit
+ 10 continuity check performed on
+ a previous circuit
+ 11 spare
+
+ Bit
+ 5 Echo control device indicator
+ -
+ 0 outgoing echo control device
+ not included
+ 1 outgoing echo control device
+ included
+
+ Bits
+ 8 7 6 Spare
+
+ Ref.: ITU-T Q.763
+
+ USI 9023 Octet User Service Information
+ string
+ Ref.: ITU-T Q.763 Clause 3.57
+
+
+
+ C.10 AAL5 properties
+
+
+ PropertyID Property Type Value
+ tag
+
+ FMSDU A001 32-bit Forward Maximum CPCS-SDU Size:
+ integer
+ Maximum CPCS-SDU size sent in
+ the direction from the calling
+ user to the called user.
+
+ Ref.: ITU-T Q.2931
+
+
+
+ Groves et al Expires - October 2003 [Page 162]
+ Megaco Protocol version 2 April 2003
+
+
+ BMSDU A002 32-bit Backwards Maximum CPCS-SDU
+ integer Size:
+
+ Maximum CPCS-SDU size sent in
+ the direction from the called
+ user to the calling user.
+
+ Ref.: ITU-T Q.2931
+
+ SSCS See See table See table in C.7
+ table in in C.7
+ C.7 Additional values:
+
+ VPI/VCI
+
+
+
+ C.11 SDP equivalents
+
+
+ PropertyID Property Type Value
+ tag
+
+ SDP_V B001 String Protocol Version
+
+ Ref.: RFC 2327
+
+ SDP_O B002 String Owner/creator and session ID
+
+ Ref.: RFC 2327
+
+ SDP_S B003 String Session name
+
+ Ref.: RFC 2327
+
+ SDP_I B004 String Session identifier
+
+ Ref.: RFC 2327
+
+ SDP_U B005 String URI of descriptor
+
+ Ref.: RFC 2327
+
+ SDC_E B006 String email address
+
+ Ref.: RFC 2327
+
+
+
+
+ Groves et al Expires - October 2003 [Page 163]
+ Megaco Protocol version 2 April 2003
+
+
+ SDP_P B007 String phone number
+
+ Ref.: RFC 2327
+
+ SDP_C B008 String Connection information
+
+ Ref.: RFC 2327
+
+ SDP_B B009 String Bandwidth Information
+
+ Ref.: RFC 2327
+
+ SDP_Z B00A String Time zone adjustment
+
+ Ref.: RFC 2327
+
+ SDP_K B00B String Encryption Key
+
+ Ref.: RFC 2327
+
+ SDP_A B00C String Zero or more session
+ attributes
+
+ Ref.: RFC 2327
+
+ SDP_T B00D String Active Session Time
+
+ Ref.: RFC 2327
+
+ SDP_R B00E String Zero or more repeat times
+
+ Reference: RFC 2327
+
+ SDP_M B00F String Media type, port, transport
+ and format
+
+ Ref.: RFC 2327
+
+
+
+ C.12 H.245
+
+
+ PropertyID Property Type Value
+ tag
+
+ OLC C001 Octet The value of H.245
+ OpenLogicalChannel
+
+
+ Groves et al Expires - October 2003 [Page 164]
+ Megaco Protocol version 2 April 2003
+
+
+ PropertyID Property Type Value
+ tag
+
+ string structure.
+
+ Ref.: ITU-T H.245
+
+ OLCack C002 Octet The value of H.245
+ string OpenLogicalChannelAck
+ structure.
+
+ Ref.: ITU-T H.245
+
+ OLCcnf C003 Octet The value of H.245
+ string OpenLogicalChannelConfirm
+ structure.
+
+ Ref.: ITU-T H.245
+
+ OLCrej C004 Octet The value of H.245
+ string OpenLogicalChannelReject
+ structure.
+
+ Ref.: ITU-T H.245
+
+ CLC C005 Octet The value of H.245
+ string CloseLogicalChannel
+ structure.
+
+ Ref.: ITU-T H.245
+
+ CLCack C006 Octet The value of H.245
+ string CloseLogicalChannelAck
+ structure.
+
+ Ref.: ITU-T H.245
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 165]
+ Megaco Protocol version 2 April 2003
+
+
+ ANNEX D TRANSPORT OVER IP
+
+ D.1 Transport over IP/UDP using Application Level Framing (ALF)
+
+ Protocol messages defined in this Recommendation may be transmitted
+ over UDP. When no port is provided by the peer (see 7.2.8), commands
+ SHOULD be sent to the default port number: 2944 for text-encoded
+ operation, or 2945 for binary-encoded operation. Responses must be
+ sent to the address and port from which the corresponding commands
+ were sent.
+
+ ALF is a set of techniques that allows an application, as opposed to
+ a stack, to affect how messages are sent to the other side. A typical
+ ALF technique is to allow an application to change the order of
+ messages sent when there is a queue after it has queued them. There
+ is no formal specification for ALF. The procedures in Annex D.1
+ contain a minimum suggested set of ALF behaviours
+
+ Implementors using IP/UDP with ALF SHOULD be aware of the
+ restrictions of the MTU on the maximum message size.
+
+ D.1.1 Providing At-Most-Once functionality
+
+ Messages, being carried over UDP, may be subject to losses. In the
+ absence of a timely response, commands are repeated. Most commands
+ are not idempotent. The state of the MG would become unpredictable
+ if, for example, Add commands were executed several times. The
+ transmission procedures shall thus provide an "At-Most-Once"
+ functionality.
+
+ Peer protocol entities are expected to keep in memory a list of the
+ responses that they sent to recent transactions and a list of the
+ transactions that are currently outstanding. The transaction
+ identifier of each incoming message is compared to the transaction
+ identifiers of the recent responses sent to the same MId. If a match
+ is found, the entity does not execute the transaction, but simply
+ repeats the response. If no match is found, the message will be
+ compared to the list of currently outstanding transactions. If a
+ match is found in that list, indicating a duplicate transaction, the
+ entity does not execute the transaction (see D.1.4 for procedures on
+ sending TransactionPending).
+
+ The procedure uses a long timer value, noted LONG-TIMER in the
+ following. The timer SHOULD be set larger than the maximum duration
+ of a transaction, which SHOULD take into account the maximum number
+ of repetitions, the maximum value of the repetition timer and the
+ maximum propagation delay of a packet in the network. A suggested
+ value is 30 seconds.
+
+
+
+ Groves et al Expires - October 2003 [Page 166]
+ Megaco Protocol version 2 April 2003
+
+
+ The copy of the responses may be destroyed either LONG-TIMER seconds
+ after the response is issued, or when the entity receives a
+ confirmation that the response has been received, through the
+ "Response Acknowledgement parameter". For transactions that are
+ acknowledged through this parameter, the entity shall keep a copy of
+ the transaction-id for LONG-TIMER seconds after the response is
+ issued, in order to detect and ignore duplicate copies of the
+ transaction request that could be produced by the network.
+
+ D.1.2 Transaction identifiers and three-way handshake
+
+ D.1.2.1 Transaction identifiers
+
+ Transaction identifiers are 32-bit integer numbers. A Media Gateway
+ Controller may decide to use a specific number space for each of the
+ MGs that they manage, or to use the same number space for all MGs
+ that belong to some arbitrary group. MGCs may decide to share the
+ load of managing a large MG between several independent processes.
+ These processes will share the same transaction number space. There
+ are multiple possible implementations of this sharing, such as having
+ a centralized allocation of transaction identifiers, or pre-
+ allocating non-overlapping ranges of identifiers to different
+ processes. The implementations shall guarantee that unique
+ transaction identifiers are allocated to all transactions that
+ originate from a logical MGC (identical mId). MGs can simply detect
+ duplicate transactions by looking at the transaction identifier and
+ mId only.
+
+ D.1.2.2 Three-way handshake
+
+ The TransactionResponse Acknowledgement parameter can be found in any
+ message. It carries a set of "confirmed transaction-id ranges".
+ Entities may choose to delete the copies of the responses to
+ transactions whose id is included in "confirmed transaction-id
+ ranges" received in the transaction response messages. They SHOULD
+ silently discard further commands when the transaction-id falls
+ within these ranges.
+
+ The "confirmed transaction-id ranges" values shall not be used if
+ more than LONG-TIMER seconds have elapsed since the MG issued its
+ last response to that MGC, or when a MG resumes operation. In this
+ situation, transactions SHOULD be accepted and processed, without any
+ test on the transaction id.
+
+ Messages that carry the "Transaction Response Acknowledgement"
+ parameter may be transmitted in any order. The entity shall retain
+ the "confirmed transaction-id ranges" receivedfor LONG-TIMER seconds.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 167]
+ Megaco Protocol version 2 April 2003
+
+
+ In the binary encoding, if only the firstAck is present in a response
+ acknowledgement (see A.2), only one transaction is acknowledged. If
+ both firstAck and lastAck are present, then the range of transactions
+ from firstAck to lastAck is acknowledged. In the text encoding, a
+ horizontal dash is used to indicate a range of transactions being
+ acknowledged (see B.2).
+
+ D.1.3 Computing retransmission timers
+
+ It is the responsibility of the requesting entity to provide suitable
+ timeouts for all outstanding transactions, and to retry transactions
+ when timeouts have been exceeded. Furthermore, when repeated
+ transactions fail to be acknowledged, it is the responsibility of the
+ requesting entity to seek redundant services and/or clear existing or
+ pending connections.
+
+ The specification purposely avoids specifying any value for the
+ retransmission timers. These values are typically network dependent.
+ The retransmission timers SHOULD normally estimate the timer value by
+ measuring the time spent between the sending of a command and the
+ return of a response. Implementations SHALL ensure that the algorithm
+ used to calculate retransmission timing performs an exponentially
+ increasing backoff of the retransmission timeout for each
+ retransmission or repetition after the first one.
+
+ NOTE - One possibility is to use the algorithm implemented in TCP-IP,
+ which uses two variables:
+
+ - The average acknowledgement delay (AAD), estimated through an
+ exponentially smoothed average of the observed delays.
+
+ - The average deviation (ADEV), estimated through an exponentially
+ smoothed average of the absolute value of the difference between
+ the observed delay and the current average. The retransmission
+ timer, in TCP, is set to the sum of the average delay plus N times
+ the average deviation. The maximum value of the timer SHOULD
+ however be bounded for the protocol defined in this
+ Recommendation, in order to guarantee that no repeated packet
+ would be received by the gateways after LONG-TIMER seconds. A
+ suggested maximum value is 4 seconds.
+
+ After any retransmission, the entity SHOULD do the following:
+
+ - It SHOULD double the estimated value of the average delay, AAD.
+
+ - It SHOULD compute a random value, uniformly distributed between
+ 0.5 AAD and AAD.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 168]
+ Megaco Protocol version 2 April 2003
+
+
+ - It SHOULD set the retransmission timer to the sum of that random
+ value and N times the average deviation.
+
+ This procedure has two effects. Because it includes an exponentially
+ increasing component, it will automatically slow down the stream of
+ messages in case of congestion. Because it includes a random
+ component, it will break the potential synchronization between
+ notifications triggered by the same external event.
+
+ D.1.4 Provisional responses
+
+ Executing some transactions may require a long time. Long execution
+ times may interact with the timer-based retransmission procedure.
+ This may result either in an inordinate number of retransmissions, or
+ in timer values that become too long to be efficient. Entities that
+ can predict that a transaction will require a long execution time may
+ send a provisional response, "Transaction Pending". They SHOULD send
+ this response if they receive a repetition of a transaction that is
+ still being executed.
+
+ Entities that receive a Transaction Pending shall switch to a
+ different repetition timer for repeating requests. The root
+ Termination has a property (ProvisionalResponseTimerValue), which can
+ be set to the requested maximum number of milliseconds between
+ receipt of a command and transmission of the TransactionPending
+ response. Upon receipt of a final response following receipt of
+ provisional responses, an immediate confirmation shall be sent, and
+ normal repetition timers shall be used thereafter. An entity that
+ sends a provisional response, SHALL include the immAckRequired field
+ in the ensuing final response, indicating that an immediate
+ confirmation is expected. Receipt of a Transaction Pending after
+ receipt of a reply shall be ignored.
+
+ D.1.5 Repeating Requests, Responses and Acknowledgements
+
+ The protocol is organized as a set of transactions, each of which is
+ composed request and a response, commonly referred to as an
+ acknowledgement. The protocol messages, being carried over UDP, may
+ be subject to losses. In the absence of a timely response,
+ transactions are repeated. Entities are expected to keep in memory a
+ list of the responses that they sent to recent transactions, i.e. a
+ list of all the responses they sent over the last LONG-TIMER seconds,
+ and a list of the transactions that are currently being executed.
+
+ The repetition mechanism is used to guard against three types of
+ possible errors:
+
+ - transmission errors, when for example a packet is lost due to
+ noise on a line or congestion in a queue;
+
+
+ Groves et al Expires - October 2003 [Page 169]
+ Megaco Protocol version 2 April 2003
+
+
+ - component failure, when for example an interface to a entity
+ becomes unavailable;
+
+ - entity failure, when for example an entire entity become
+ unavailable.
+
+ The entities SHOULD be able to derive from the past history an
+ estimate of the packet loss rate due to transmission errors. In a
+ properly configured system, this loss rate SHOULD be kept very low,
+ typically less than 1%. If a Media Gateway Controller or a Media
+ Gateway has to repeat a message more than a few times, it is very
+ legitimate to assume that something else than a transmission error is
+ occurring. For example, given a loss rate of 1%, the probability that
+ five consecutive transmission attempts fail is 1 in 100 billion, an
+ event that SHOULD occur less than once every 10 days for a Media
+ Gateway Controller that processes 1000 transactions per second.
+ (Indeed, the number of repetition that is considered excessive SHOULD
+ be a function of the prevailing packet loss rate.) We SHOULD note
+ that the "suspicion threshold", which we will call "Max1", is
+ normally lower than the "disconnection threshold", which SHOULD be
+ set to a larger value.
+
+ A classic retransmission algorithm would simply count the number of
+ successive repetitions, and conclude that the association is broken
+ after retransmitting the packet an excessive number of times
+ (typically between 7 and 11 times.) In order to account for the
+ possibility of an undetected or in progress "failover", we modify the
+ classic algorithm so that if the Media Gateway receives a valid
+ ServiceChange message announcing a failover, it will start
+ transmitting outstanding commands to that new MGC. Responses to
+ commands are still transmitted to the source address of the command.
+
+ In order to automatically adapt to network load, this Recommendation
+ specifies exponentially increasing timers. If the initial timer is
+ set to 200 milliseconds, the loss of a fifth retransmission will be
+ detected after about 6 seconds. This is probably an acceptable
+ waiting delay to detect a failover. The repetitions SHOULD continue
+ after that delay not only in order to perhaps overcome a transient
+ connectivity problem, but also in order to allow some more time for
+ the execution of a failover (waiting a total delay of 30 seconds is
+ probably acceptable).
+
+ It is, however, important that the maximum delay of retransmissions
+ be bounded. Prior to any retransmission, it is checked that the time
+ elapsed since the sending of the initial datagram is no greater than
+ T-MAX. If more than T-MAX time has elapsed, the MG concludes that the
+ MGC has failed, and it begins its recovery process as described in
+ section 11.5. If the MG retries to connect to the current MGC it
+ shall use a ServiceChange with ServiceChangeMethod set to
+
+
+ Groves et al Expires - October 2003 [Page 170]
+ Megaco Protocol version 2 April 2003
+
+
+ Disconnected so that the new MGC will be aware that the MG lost one
+ or more transactions. The value T-MAX is related to the LONG-TIMER
+ value: the LONG-TIMER value is obtained by adding to T MAX the
+ maximum propagation delay in the network.
+
+ D.2 Using TCP
+
+ Protocol messages as defined in this Recommendation may be
+ transmitted over TCP. When no port is specified by the other side
+ (see 7.2.8), the commands SHOULD be sent to the default port. The
+ defined protocol has messages as the unit of transfer, while TCP is a
+ stream-oriented protocol. TPKT, according to RFC 1006, SHALL be used
+ to delineate messages within the TCP stream.
+
+ In a transaction-oriented protocol, there are still ways for
+ transaction requests or responses to be lost. As such, it is
+ recommended that entities using TCP transport implement application
+ level timers for each request and each response, similar to those
+ specified for application level framing over UDP.
+
+ D.2.1 Providing the At-Most-Once functionality
+
+ Messages, being carried over TCP, are not subject to transport
+ losses, but loss of a transaction request or its reply may
+ nonetheless be noted in real implementations. In the absence of a
+ timely response, commands are repeated. Most commands are not
+ idempotent. The state of the MG would become unpredictable if, for
+ example, Add commands were executed several times.
+
+ To guard against such losses, it is recommended that entities follow
+ the procedures in D.1.1.
+
+ D.2.2 Transaction identifiers and three-way handshake
+
+ For the same reasons, it is possible that transaction replies may be
+ lost even with a reliable delivery protocol such as TCP. It is
+ recommended that entities follow the procedures in D.1.2.2.
+
+ D.2.3 Computing retransmission timers
+
+ With reliable delivery, the incidence of loss of a transaction
+ request or reply is expected to be very low. Therefore, only simple
+ timer mechanisms are required. Exponential back-off algorithms SHOULD
+ not be necessary, although they could be employed where, as in an
+ MGC, the code to do so is already required, since MGCs must implement
+ ALF/UDP as well as TCP.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 171]
+ Megaco Protocol version 2 April 2003
+
+
+ D.2.4 Provisional responses
+
+ As with UDP, executing some transactions may require a long time.
+ Entities that can predict that a transaction will require a long
+ execution time may send a provisional response, "Transaction
+ Pending". They SHOULD send this response if they receive a repetition
+ of a transaction that is still being executed.
+
+ Entities that receive a Transaction Pending shall switch to a longer
+ repetition timer for that transaction.
+
+ Entities shall retain Transactions and replies until they are
+ confirmed. The basic procedure of D.1.4 SHOULD be followed, but
+ simple timer values SHOULD be sufficient. There is no need to send an
+ immediate confirmation upon receipt of a final response.
+
+ D.2.5 Ordering of commands
+
+ TCP provides ordered delivery of transactions. No special procedures
+ are required. It SHOULD be noted that ALF/UDP allows sending entity
+ to modify its behaviour under congestion, and in particular, could
+ reorder transactions when congestion is encountered. TCP could not
+ achieve the same results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 172]
+ Megaco Protocol version 2 April 2003
+
+
+ ANNEX E BASIC PACKAGES
+
+ This annex contains definitions of some packages for use with
+ Recommendation H.248.1.
+
+ E.1 Generic
+
+ PackageID: g (0x0001)
+ Version: 1
+ Extends: None
+
+ Description:
+ Generic package for commonly encountered items
+
+ E.1.1 Properties
+
+ None
+
+ E.1.2 Events
+
+ Cause
+
+ EventID: cause (0x0001)
+
+ Generic error event
+
+ EventsDescriptor parameters: None
+
+ ObservedEvents Descriptor Parameters:
+
+ General Cause
+
+ ParameterID: Generalcause (0x0001)
+
+ This parameter groups the failures into six groups, which
+ the MGC may act upon.
+
+ Type: enumeration
+
+ Possible values:
+ "NR" Normal Release (0x0001)
+ "UR" Unavailable Resources (0x0002)
+ "FT" Failure, Temporary (0x0003)
+ "FP" Failure, Permanent (0x0004)
+ "IW" Interworking Error (0x0005)
+ "UN" Unsupported (0x0006)
+
+ Failure Cause
+
+
+
+ Groves et al Expires - October 2003 [Page 173]
+ Megaco Protocol version 2 April 2003
+
+
+ ParameterID: Failurecause (0x0002)
+
+ Possible values: OCTET STRING
+
+ Description: The Failure Cause is the value generated by the
+ Released equipment, i.e. a released network connection. The
+ concerned value is defined in the appropriate bearer control
+ protocol.
+
+
+ Signal Completion
+
+ EventID: sc (0x0002)
+
+ Indicates the termination of a signal for which the
+ notifyCompletion parameter was set to enable reporting of a
+ completion event. For further procedural description, see 7.1.1,
+ 7.1.17 and 7.2.7.
+
+ EventsDescriptor parameters: None
+
+ ObservedEvents Descriptor parameters:
+
+ Signal Identity
+
+ ParameterID: SigID (0x0001)
+
+ This parameter identifies the signal which has terminated.
+ For a signal that is contained in a signal list, the signal
+ list identity parameter SHOULD also be returned indicating
+ the appropriate list.
+
+ Type: Binary: octet (string), Text: string
+
+ Possible values: a signal which has terminated. A signal
+ shall be identified using the pkgdName syntax without
+ wildcarding.
+
+ Termination Method
+
+ ParameterID: Meth (0x0002)
+
+ Indicates the means by which the signal terminated.
+
+ Type: enumeration
+
+ Possible values:
+ "TO" (0x0001) Signal timed out or otherwise completed on
+ its own
+
+
+ Groves et al Expires - October 2003 [Page 174]
+ Megaco Protocol version 2 April 2003
+
+
+ "EV" (0x0002) Interrupted by event
+ "SD" (0x0003) Halted by new Signals descriptor
+ "NC" (0x0004) Not completed, other cause
+
+ Signal List ID
+
+ ParameterID: SLID (0x0003)
+
+ Indicates to which signal list a signal belongs. The
+ SignalList ID is only returned in cases where the signal
+ resides in a signal list.
+
+ Type: integer
+
+ Possible values: any integer
+
+ E.1.3 Signals
+
+ None.
+
+ E.1.4 Statistics
+
+ None.
+
+
+
+ E.2 Base Root Package
+
+ Base Root Package
+
+ PackageID: root (0x0002)
+ Version: 2
+ Extends: None
+
+ Description:
+
+ This package defines Gateway wide properties.
+
+ E.2.1 Properties
+
+ MaxNumberOfContexts
+
+ PropertyID: maxNumberOfContexts (0x0001)
+
+ The value of this property gives the maximum number of contexts
+ that can exist at any time. The NULL context is not included in
+ this number.
+
+ Type: double
+
+
+ Groves et al Expires - October 2003 [Page 175]
+ Megaco Protocol version 2 April 2003
+
+
+ Possible values: 1 and up
+
+ Defined in: TerminationState
+
+ Characteristics: read only
+
+
+ MaxTerminationsPerContext
+
+ PropertyID: maxTerminationsPerContext (0x0002)
+
+ The maximum number of allowed terminations in a context, see 6.1
+
+ Type: integer
+
+ Possible values: any integer
+
+ Defined in: TerminationState
+
+ Characteristics: read only
+
+
+ normalMGExecutionTime
+
+ PropertyId: normalMGExecutionTime (0x0003)
+
+ Settable by the MGC to indicate the interval within which the MGC
+ expects a response to any transaction from the MG (exclusive of
+ network delay)
+
+ Type: integer
+
+ Possible values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+
+ normalMGCExecutionTime
+
+ PropertyId: normalMGCExecutionTime (0x0004)
+
+ Settable by the MGC to indicate the interval within which the MG
+ SHOULD expects a response to any transaction from the MGC
+ (exclusive of network delay)
+
+ Type: integer
+
+
+
+ Groves et al Expires - October 2003 [Page 176]
+ Megaco Protocol version 2 April 2003
+
+
+ Possible values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+
+ MGProvisionalResponseTimerValue
+
+ PropertyId: MGProvisionalResponseTimerValue (0x0005)
+
+ Indicates the time within which the MGC SHOULD expect a Pending
+ Response from the MG if a Transaction cannot be completed.
+ Initially set to normalMGExecutionTime plus network delay, but may
+ be lowered.
+
+ Type: Integer
+
+ Possible Values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+
+ MGCProvisionalResponseTimerValue
+
+ PropertyId: MGCProvisionalResponseTimerValue (0x0006)
+
+ Indicates the time within which the MG SHOULD expect a Pending
+ Response from the MGC if a Transaction cannot be completed.
+ Initially set to normalMGCExecutionTime plus network delay, but
+ may be lowered.
+
+ Type: Integer
+
+ Possible Values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+
+ MGCOriginatedPendingLimit
+
+ PropertyId: MGCOriginatedPendingLimit (0x0007)
+
+ Indicates the number of TransactionPendings that can be received
+ from the MGC. Once this limit is exceeded the MGC SHOULD issue a
+
+
+ Groves et al Expires - October 2003 [Page 177]
+ Megaco Protocol version 2 April 2003
+
+
+ TransactionReply with Error 506 Number of TransactionPendings
+ Exceeded, otherwise the MG can assume the Transaction to be in
+ error.
+
+ Type: Integer
+
+ Possible Values: any possible integer
+
+ Defined in: TerminationState
+
+ Characteristics: Read/Write
+
+
+ MGOriginatedPendingLimit
+
+ PropertyId: MGOriginatedPendingLimit (0x0008)
+
+ Indicates the number of TransactionPendings that can be received
+ from the MG. Once this limit is exceeded the MG SHOULD issue a
+ TransactionReply with Error 506 Number of TransactionPendings
+ Exceeded, otherwise the MGC can assume the Transaction to be in
+ error.
+
+ Type: Integer
+
+ Possible Values: any possible integer
+
+ Defined in: TerminationState
+
+ Characteristics: Read/Write
+
+ E.2.2 Events
+
+ None.
+
+ E.2.3 Signals
+
+ None.
+
+ E.2.4 Statistics
+
+ None.
+
+ E.2.5 Procedures
+
+ None.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 178]
+ Megaco Protocol version 2 April 2003
+
+
+ E.3 Tone Generator Package
+
+ PackageID: tonegen (0x0003)
+ Version: 1
+ Extends: None
+
+ Description:
+
+ This package defines signals to generate audio tones. This package
+ does not specify parameter values. It is intended to be extendable.
+ Generally, tones are defined as an individual signal with a
+ parameter, ind, representing "interdigit" time delay, and a tone id
+ to be used with playtones. A tone id SHOULD be kept consistent with
+ any tone generation for the same tone. MGs are expected to be
+ provisioned with the characteristics of appropriate tones for the
+ country in which the MG is located.
+
+ Designed to be extended only: Yes
+
+ E.3.1 Properties
+
+ None.
+
+ E.3.2 Events
+
+ None.
+
+ E.3.3 Signals
+
+ Play tone
+
+ SignalID: pt (0x0001)
+
+ Plays audio tone over an audio channel
+
+ Signal Type: Brief
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ Tone id list
+
+ ParameterID: tl (0x0001)
+
+ Type: list of tone ids
+
+ List of tones to be played in sequence. The list SHALL
+ contain one or more tone ids.
+
+
+ Groves et al Expires - October 2003 [Page 179]
+ Megaco Protocol version 2 April 2003
+
+
+ Inter signal duration
+
+ ParameterID: ind (0x0002)
+
+ Type: integer
+
+ Timeout between two consecutive tones in milliseconds
+
+ No tone ids are specified in this package. Packages that extend this
+ package can add possible values for tone id as well as adding
+ individual tone signals.
+
+ E.3.4 Statistics
+
+ None.
+
+ E.3.5 Procedures
+
+ None.
+
+
+
+ E.4 Tone Detection Package
+
+ PackageID: tonedet (0x0004)
+ Version: 1
+ Extends: None
+
+ Designed to be extended only: Yes
+
+ This Package defines events for audio tone detection. Tones are
+ selected by name (tone id). MGs are expected to be provisioned with
+ the characteristics of appropriate tones for the country in which the
+ MG is located.
+
+ This package does not specify parameter values. It is intended to be
+ extendable.
+
+ E.4.1 Properties
+
+ None.
+
+ E.4.2 Events
+
+ Start tone detected
+
+ EventID: std, 0x0001
+
+
+
+
+ Groves et al Expires - October 2003 [Page 180]
+ Megaco Protocol version 2 April 2003
+
+
+ Detects the start of a tone. The characteristics of positive tone
+ detection are implementation dependent.
+
+ EventsDescriptor parameters:
+
+ Tone id list
+
+ ParameterID: tl (0x0001)
+
+ Type: list of tone ids
+
+ Possible values: The only tone id defined in this package is
+ "wild card" which is "*" in text encoding and 0x0000 in
+ binary. Extensions to this package would add possible values
+ for tone id. If tl is "wild card", any tone id is detected.
+
+ ObservedEventsDescriptor parameters:
+
+ Tone id
+
+ ParameterID: tid (0x0003)
+
+ Type: enumeration
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this package
+ would add additional possible values for tone id.
+
+
+ End tone detected
+
+ EventID: etd, 0x0002
+
+ Detects the end of a tone.
+
+ EventDescriptor parameters:
+
+ Tone id list
+
+ ParameterID: tl (0x0001)
+
+ Type: enumeration or list of enumerated types
+
+ Possible values: No possible values are specified in this
+ package. Extensions to this package would add possible
+ values for tone id.
+
+ ObservedEventsDescriptor parameters:
+
+
+
+ Groves et al Expires - October 2003 [Page 181]
+ Megaco Protocol version 2 April 2003
+
+
+ Tone id
+
+ ParameterID: tid (0x0003)
+
+ Type: enumeration
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this package
+ would add possible values for tone id.
+
+ Duration
+
+ ParameterId: dur (0x0002)
+
+ Type: integer, in milliseconds
+
+ This parameter contains the duration of the tone from first
+ detection until it stopped.
+
+
+ Long tone detected
+
+ EventID: ltd, 0x0003
+
+ Detects that a tone has been playing for at least a certain amount
+ of time
+
+ EventDescriptor parameters:
+
+ Tone id list
+
+ ParameterID: tl (0x0001)
+
+ Type: enumeration or list
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this package
+ would add possible values for tone id.
+
+ Duration:
+
+ ParameterID: dur (0x0002)
+
+ Type: integer, duration to test against
+
+ Possible values: any legal integer, expressed in
+ milliseconds
+
+
+
+
+ Groves et al Expires - October 2003 [Page 182]
+ Megaco Protocol version 2 April 2003
+
+
+ ObservedEventsDescriptor parameters:
+
+ Tone id:
+
+ ParameterID: tid (0x0003)
+
+ Type: Enumeration
+
+ Possible values: No possible values are specified in this
+ package. Extensions to this package would add possible
+ values for tone id.
+
+ E.4.3 Signals
+
+ None.
+
+ E.4.4 Statistics
+
+ None.
+
+ E.4.5 Procedures
+
+ None.
+
+
+
+ E.5 Basic DTMF Generator Package
+
+ PackageID: dg (0x0005)
+ Version: 1
+ Extends: tonegen version 1
+
+ This package defines the basic DTMF tones as signals and extends the
+ allowed values of parameter tl of playtone in tonegen.
+
+ E.5.1 Properties
+
+ None.
+
+ E.5.2 Events
+
+ None.
+
+ E.5.3 Signals
+
+ DTMF character 0
+
+ SignalID: d0 (0x0010)
+
+
+
+ Groves et al Expires - October 2003 [Page 183]
+ Megaco Protocol version 2 April 2003
+
+
+ Generate DTMF 0 tone. The physical characteristic of DTMF 0 is
+ defined in the gateway.
+
+ Signal Type: Brief
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ None
+
+ Additional values:
+
+ d0 (0x0010) is defined as a tone id for playtone
+
+ The other DTMF characters are specified in exactly the same
+ way. A table with all signal names and signal IDs is included.
+ Note that each DTMF character is defined as both a signal and a
+ tone id, thus extending the basic tone generation package. Also
+ note that DTMF SignalIds are different from the names used in a
+ digit map.
+
+ Signal name Signal ID/Tone id
+
+ DTMF character 0 d0 (0x0010)
+ DTMF character 1 d1 (0x0011)
+ DTMF character 2 d2 (0x0012)
+ DTMF character 3 d3 (0x0013)
+ DTMF character 4 d4 (0x0014)
+ DTMF character 5 d5 (0x0015)
+ DTMF character 6 d6 (0x0016)
+ DTMF character 7 d7 (0x0017)
+ DTMF character 8 d8 (0x0018)
+ DTMF character 9 d9 (0x0019)
+ DTMF character * ds (0x0020)
+ DTMF character # do (0x0021)
+ DTMF character A da (0x001a)
+ DTMF character B db (0x001b)
+ DTMF character C dc (0x001c)
+ DTMF character D dd (0x001d)
+
+ E.5.4 Statistics
+
+ None.
+
+ E.5.5 Procedures
+
+ None.
+
+
+
+ Groves et al Expires - October 2003 [Page 184]
+ Megaco Protocol version 2 April 2003
+
+
+
+
+ E.6 DTMF detection Package
+
+ PackageID: dd (0x0006)
+ Version: 1
+ Extends: tonedet version 1
+
+ This package defines the basic DTMF tones detection. This Package
+ extends the possible values of tone id in the "start tone detected"
+ "end tone detected" and "long tone detected" events.
+
+ Additional tone id values are all tone ids described in package dg
+ (basic DTMF generator package).
+
+ The following table maps DTMF events to digit map symbols as
+ described in 7.1.14.
+
+ DTMF Event Symbol
+
+ d0 "0"
+ d1 "1"
+ d2 "2"
+ d3 "3"
+ d4 "4"
+ d5 "5"
+ d6 "6"
+ d7 "7"
+ d8 "8"
+ d9 "9"
+ da "A" or "a"
+ db "B" or "b"
+ dc "C" or "c"
+ dd "D" or "d"
+ ds "E" or "e"
+ do "F" or "f"
+
+
+ E.6.1 Properties
+
+ None.
+
+ E.6.2 Events
+
+ DTMF digits
+
+ EventIds are defined with the same names as the SignalIds defined in
+ the table found in E.5.3.
+
+
+
+ Groves et al Expires - October 2003 [Page 185]
+ Megaco Protocol version 2 April 2003
+
+
+
+
+ DigitMap Completion Event
+
+ EventID: ce, 0x0004
+
+ Generated when a digit map completes as described in 7.1.14.
+
+ EventsDescriptor parameters: None.
+
+ ObservedEventsDescriptor parameters:
+
+ DigitString
+
+ ParameterID: ds (0x0001)
+
+ Type: string of digit map symbols (possibly empty) returned
+ as a quotedString
+
+ Possible values: a sequence of the characters "0" through
+ "9", "A" through "F", and the long duration modifier "Z".
+
+ Description: the portion of the current dial string as
+ described in 7.1.14 which matched part or all of an
+ alternative event sequence specified in the digit map.
+
+ Termination Method
+
+ ParameterID: Meth (0x0003)
+
+ Type: enumeration
+
+ Possible values:
+
+ "UM" (0x0001) Unambiguous match
+
+ "PM" (0x0002) Partial match, completion by timer expiry or
+ unmatched event
+
+ "FM" (0x0003) Full match, completion by timer expiry or
+ unmatched event
+
+ Description: indicates the reason for generation of the
+ event. See the procedures in 7.1.14.
+
+ E.6.3 Signals
+
+ None.
+
+
+
+ Groves et al Expires - October 2003 [Page 186]
+ Megaco Protocol version 2 April 2003
+
+
+ E.6.4 Statistics
+
+ None.
+
+ E.6.5 Procedures
+
+ Digit map processing is activated only if an events descriptor is
+ activated that contains a digit map completion event as defined in
+ Section E.6.2 and that digit map completion event contains an eventDM
+ field in the requested actions as defined in Section 7.1.9. Other
+ parameters such as KeepActive or embedded events of signals
+ descriptors may also be present in the events descriptor and do not
+ affect the activation of digit map processing.
+
+
+
+ E.7 Call Progress Tones Generator Package
+
+ PackageID: cg, 0x0007
+ Version: 1
+ Extends: tonegen version 1
+
+ This package defines the basic call progress tones as signals and
+ extends the allowed values of the tl parameter of playtone in
+ tonegen.
+
+ E.7.1 Properties
+
+ None.
+
+ E.7.2 Events
+
+ None.
+
+ E.7.3 Signals
+
+ Dial Tone
+
+ SignalID: dt (0x0030)
+
+ Generate dial tone. The physical characteristic of dial tone is
+ available in the gateway.
+
+ Signal Type: TimeOut
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+
+
+ Groves et al Expires - October 2003 [Page 187]
+ Megaco Protocol version 2 April 2003
+
+
+ None
+
+ Additional values:
+
+ dt (0x0030) is defined as a tone id for playtone
+
+ The other tones of this package are defined in exactly the same way.
+ A table with all signal names and signal IDs is included. Note that
+ each tone is defined as both a signal and a tone id, thus extending
+ the basic tone generation package.
+
+ Signal Name Signal ID/tone id
+
+ Dial Tone dt (0x0030)
+
+ Ringing Tone rt (0x0031)
+
+ Busy Tone bt (0x0032)
+
+ Congestion Tone ct (0x0033)
+
+ Special Information Tone sit(0x0034)
+
+ (Recording) Warning Tone wt (0x0035)
+
+ Payphone Recognition Tone prt (0x0036)
+
+ Call Waiting Tone cw (0x0037)
+
+ Caller Waiting Tone cr (0x0038)
+
+
+
+ E.7.4 Statistics
+
+ None.
+
+ E.7.5 Procedures
+
+ NOTE - The required set of tone ids corresponds to those defined in
+ Recommendation E.180/Q.35. See Recommendation E.180/Q.35 for
+ definition of the meanings of these tones.
+
+
+
+ E.8 Call Progress Tones Detection Package
+
+ PackageID: cd (0x0008)
+ Version: 1
+
+
+ Groves et al Expires - October 2003 [Page 188]
+ Megaco Protocol version 2 April 2003
+
+
+ Extends: tonedet version 1
+
+ This package defines the basic call progress detection tones. This
+ package extends the possible values of tone id in the "start tone
+ detected", "end tone detected" and "long tone detected" events.
+
+ Additional values
+
+ tone id values are defined for start tone detected, end tone
+ detected and long tone detected with the same values as those in
+ package cg (call progress tones generation package).
+
+ The required set of tone ids corresponds to Recommendation
+ E.180/Q.35. See Recommendation E.180/Q.35 for definition of the
+ meanings of these tones.
+
+ E.8.1 Properties
+
+ None.
+
+ E.8.2 Events
+
+ Events are defined as in the call progress tones generator package
+ (cg) for the tones listed in the table of E.7.3.
+
+ E.8.3 Signals
+
+ None.
+
+ E.8.4 Statistics
+
+ None.
+
+ E.8.5 Procedures
+
+ None.
+
+
+
+ E.9 Analog Line Supervision Package
+
+ PackageID: al, 0x0009
+ Version: 1
+ Extends: None
+
+ This package defines events and signals for an analog line.
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 189]
+ Megaco Protocol version 2 April 2003
+
+
+ E.9.1 Properties
+
+ None
+
+ E.9.2 Events
+
+ onhook
+
+ EventID: on (0x0004)
+
+ Detects handset going on hook. Whenever an events descriptor is
+ activated that requests monitoring for an on-hook event and the
+ line is already on-hook, then the MG shall behave according to the
+ setting of the "strict" parameter.
+
+ EventDescriptor parameters
+
+ Strict Transition
+ ParameterID: strict (0x0001)
+
+ Type: enumeration
+
+ Possible values:
+
+ "exact" (0x00): only an actual hook state transition to on-
+ hook is to be recognized;
+
+ "state" (0x01): the event is to be recognized either if the
+ hook state transition is detected or if the hook state is
+ already on-hook;
+
+ "failWrong" (0x02): if the hook state is already on-hook,
+ the command fails and an error is reported.
+
+ ObservedEventsDescriptor parameters
+
+ Initial State
+ ParameterID: init (0x0002)
+
+ Type: Boolean
+
+ Possible values:
+
+ "True" means that the event was reported because the line
+ was already on-hook when the events descriptor containing
+ this event was activated;
+
+ "False" means that the event represents an actual state
+ transition to on-hook.
+
+
+ Groves et al Expires - October 2003 [Page 190]
+ Megaco Protocol version 2 April 2003
+
+
+
+ offhook
+
+ EventID: of (0x0005)
+
+ Detects handset going off hook. Whenever an events descriptor is
+ activated that requests monitoring for an off-hook event and the
+ line is already off-hook, then the MG shall behave according to
+ the setting of the "strict" parameter.
+
+ EventDescriptor parameters
+
+ Strict Transition
+ ParameterID: strict (0x0001)
+
+ Type: enumeration
+
+ Possible values:
+
+ "exact" (0x00): only an actual hook state transition to off-
+ hook is to be recognized;
+
+ "state" (0x01): the event is to be recognized either if the
+ hook state transition is detected or if the hook state is
+ already off-hook;
+
+ "failWrong" (0x02): if the hook state is already off-hook,
+ the command fails and an error is reported.
+
+ ObservedEventsDescriptor parameters
+
+ Initial State
+ ParameterID: init (0x0002)
+
+ Type: Boolean
+
+ Possible values:
+
+ "True" means that the event was reported because the line
+ was already off-hook when the events descriptor containing
+ this event was activated;
+
+ "False" means that the event represents an actual state
+ transition to off-hook.
+
+
+
+ flashhook
+
+
+
+ Groves et al Expires - October 2003 [Page 191]
+ Megaco Protocol version 2 April 2003
+
+
+ EventID: fl, 0x0006
+
+ Detects handset flash. A flash occurs when an onhook is followed
+ by an offhook between a minimum and maximum duration.
+
+ EventDescriptor parameters
+
+ Minimum duration
+
+ ParameterID: mindur (0x0004)
+
+ Type: integer in milliseconds
+
+ Default value is provisioned.
+
+ Maximum duration
+
+ ParameterID: maxdur (0x0005)
+
+ Type: integer in milliseconds
+
+ Default value is provisioned.
+
+ ObservedEventsDescriptor parameters
+
+ None
+
+ E.9.3 Signals
+
+ ring
+
+ SignalID: ri, 0x0002
+
+ Applies ringing on the line
+
+ Signal Type: TimeOut
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ Cadence
+
+ ParameterID: cad (0x0006)
+
+ Type: list of integers representing durations of alternating
+ on and off segments, constituting a complete ringing cycle
+ starting with an on. Units in milliseconds
+
+
+
+ Groves et al Expires - October 2003 [Page 192]
+ Megaco Protocol version 2 April 2003
+
+
+ Default is fixed or provisioned. Restricted function MGs may
+ ignore cadence values they are incapable of generating.
+
+ Frequency
+
+ ParameterID: freq (0x0007)
+
+ Type: integer in Hz
+
+ Default is fixed or provisioned. Restricted function MGs may
+ ignore frequency values they are incapable of generating.
+
+ E.9.4 Statistics
+
+ None
+
+ E.9.5 Procedures
+
+ If the MGC sets an EventsDescriptor containing a hook state
+ transition event (on-hook or off-hook) with the "strict" (0x0001)
+ parameter set to "failWrong", and the hook state is already what the
+ transition implies, the execution of the command containing that
+ EventsDescriptor fails. The MG SHALL include error code 540
+ "Unexpected initial hook state" in its reponse.
+
+ E.9.6 Error code
+
+ This package defines a new error code:
+
+ 540 - Unexpected initial hook state
+
+ The procedure for use of this code is given in E.9.5.
+
+
+
+ E.10 Basic Continuity Package
+
+ PackageID: ct (0x000a)
+ Version: 1
+ Extends: None
+
+ This package defines events and signals for continuity test. The
+ continuity test includes provision of either a loopback or
+ transceiver functionality.
+
+ E.10.1 Properties
+
+ None.
+
+
+
+ Groves et al Expires - October 2003 [Page 193]
+ Megaco Protocol version 2 April 2003
+
+
+ E.10.2 Events
+
+ Completion
+
+ EventID: cmp, 0x0005
+
+ This event detects test completion of continuity test.
+
+ EventDescriptor parameters
+
+ None
+
+ ObservedEventsDescriptor parameters
+
+ Result
+
+ ParameterID: res (0x0008)
+
+ Type: enumeration
+
+ Possible values: success (0x0001), failure (0x0000)
+
+ E.10.3 Signals
+
+ Continuity test
+
+ SignalID: ct (0x0003)
+
+ Initiates sending of continuity test tone on the termination to
+ which it is applied.
+
+ Signal Type: TimeOut
+
+ Default value is provisioned
+
+ Additional parameters:
+
+ None
+
+
+ Respond
+
+ SignalID: rsp (0x0004)
+
+ The signal is used to respond to a continuity test. See E.10.5 for
+ further explanation.
+
+ Signal Type: On/Off
+
+
+
+ Groves et al Expires - October 2003 [Page 194]
+ Megaco Protocol version 2 April 2003
+
+
+ Default duration is provisioned
+
+ Additional parameters:
+
+ None
+
+ E.10.4 Statistics
+
+ None.
+
+ E.10.5 Procedures
+
+ When a MGC wants to initiate a continuity test, it sends a command to
+ the MG containing:
+
+ - a signals descriptor with the ct signal; and
+
+ - an events descriptor containing the cmp event.
+
+ Upon reception of a command containing the ct signal and cmp event,
+ the MG initiates the continuity test tone for the specified
+ Termination. If the return tone is detected and any other required
+ conditions are satisfied before the signal times out, the cmp event
+ shall be generated with the value of the result parameter equal to
+ success. In all other cases, the cmp event shall be generated with
+ the value of the result parameter equal to failure.
+
+ When a MGC wants the MG to respond to a continuity test, it sends a
+ command to the MG containing a signals descriptor with the rsp
+ signal. Upon reception of a command with the rsp signal, the MG
+ either applies a loopback or (for 2-wire circuits) awaits reception
+ of a continuity test tone. In the loopback case, any incoming
+ information shall be reflected back as outgoing information. In the
+ 2-wire case, any time the appropriate test tone is received, the
+ appropriate response tone SHOULD be sent. The MGC determines when to
+ remove the rsp signal.
+
+ When a continuity test is performed on a Termination, no echo devices
+ or codecs shall be active on that Termination.
+
+ Performing voice path assurance as part of continuity testing is
+ provisioned by bilateral agreement between network operators.
+
+ (Informative Note) Example tones and test procedure details are given
+ in Q.724 sections 7 and 8, Q.764 section 2.1.8 and Q.1902.4.
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 195]
+ Megaco Protocol version 2 April 2003
+
+
+ E.11 Network Package
+
+ PackageID: nt (0x000b)
+ Version: 1
+ Extends: None
+
+ This package defines properties of network terminations independent
+ of network type.
+
+ E.11.1 Properties
+
+ Maximum Jitter Buffer
+
+ PropertyID: jit (0x0007)
+
+ This property puts a maximum size on the jitter buffer.
+
+ Type: integer in milliseconds
+
+ Possible values: This property is specified in milliseconds.
+
+ Defined in: LocalControlDescriptor
+
+ Characteristics: read/write
+
+ E.11.2 Events
+
+ network failure
+
+ EventID: netfail, 0x0005
+
+ The termination generates this event upon detection of a failure
+ due to external or internal network reasons.
+
+ EventDescriptor parameters
+
+ None
+
+ ObservedEventsDescriptor parameters
+
+ cause
+
+ ParameterID: cs (0x0001)
+
+ Type: string
+
+ Possible values: any text string
+
+
+
+
+ Groves et al Expires - October 2003 [Page 196]
+ Megaco Protocol version 2 April 2003
+
+
+ This parameter may be included with the failure event to
+ provide diagnostic information on the reason of failure.
+
+
+ quality alert
+
+ EventID: qualert, 0x0006
+
+ This event allows the MG to indicate a loss of quality of the
+ network connection. The MG may do this by measuring packet loss,
+ interarrival jitter, propogation delay and then indicating this
+ using a percentage of quality loss.
+
+ EventDescriptor parameters
+
+ Threshold
+
+ ParameterId: th (0x0001)
+
+ Type: integer
+
+ Possible values: 0 to 99
+
+ Description: threshold for percent of quality loss measured,
+ calculated based on a provisioned method, that could take
+ into consideration packet loss, jitter, and delay for
+ example. Event is triggered when calculation exceeds the
+ threshold.
+
+ ObservedEventsDescriptor parameters
+
+ Threshold
+
+ ParameterId: th (0x0001)
+
+ Type: integer
+
+ Possible values: 0 to 99
+
+ Description: percent of quality loss measured, calculated
+ based on a provisioned method, that could take into
+ consideration packet loss, jitter, and delay for example.
+
+ E.11.3 Signals
+
+ None.
+
+ E.11.4 Statistics
+
+
+
+ Groves et al Expires - October 2003 [Page 197]
+ Megaco Protocol version 2 April 2003
+
+
+ Duration
+
+ StatisticsID: dur (0x0001)
+
+ Description: provides duration of time the termination has been in
+ the Context.
+
+ Type: double, in milliseconds
+
+ Octets Sent
+
+ StatisticID: os (0x0002)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Octets Received
+
+ StatisticID: or (0x0003)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ E.11.5 Procedures
+
+ None.
+
+
+
+ E.12 RTP Package
+
+ PackageID: rtp (0x000c)
+ Version: 1
+ Extends: Network Package version 1
+
+ This package is used to support packet-based multimedia data transfer
+ by means of the Real-time Transport Protocol (RTP) [RFC 1889].
+
+ E.12.1 Properties
+
+ None.
+
+ E.12.2 Events
+
+ Payload Transition
+
+ EventID: pltrans, 0x0001
+
+
+ Groves et al Expires - October 2003 [Page 198]
+ Megaco Protocol version 2 April 2003
+
+
+ This event detects and notifies when there is a transition of the
+ RTP payload format from one format to another.
+
+ EventDescriptor parameters
+
+ None
+
+ ObservedEventsDescriptor parameters
+
+ ParameterName: rtppayload
+
+ ParameterID: rtppltype, 0x01
+
+ Type: list of enumerated types.
+
+ Possible values: The encoding method shall be specified by
+ using one or several valid encoding names, as defined in the
+ RTP AV Profile or registered with IANA.
+
+ E.12.3 Signals
+
+ None.
+
+ E.12.4 Statistics
+
+ Packets Sent
+
+ StatisticID: ps (0x0004)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Packets Received
+
+ StatisticID: pr (0x0005)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Packet Loss
+
+ StatisticID: pl (0x0006)
+
+ Describes the current rate of packet loss on an RTP stream, as
+ defined in IETF RFC 1889. Packet loss is expressed as percentage
+ value: number of packets lost in the interval between two
+
+
+
+ Groves et al Expires - October 2003 [Page 199]
+ Megaco Protocol version 2 April 2003
+
+
+ reception reports, divided by the number of packets expected
+ during that interval.
+
+ Type: double
+
+ Possible values: a 32-bit whole number and a 32-bit fraction.
+
+ Jitter
+
+ StatisticID: jit (0x0007)
+
+ Requests the current value of the interarrival jitter on an RTP
+ stream as defined in IETF RFC 1889. Jitter measures the variation
+ in interarrival time for RTP data packets.
+
+ Delay
+
+ StatisticID:delay (0x0008)
+
+ Requests the current value of packet propagation delay expressed
+ in timestamp units. Same as average latency.
+
+ E.12.5 Procedures
+
+ None.
+
+
+
+ E.13 TDM Circuit Package
+
+ PackageID: tdmc (0x000d)
+ Version: 1
+ Extends: Network Package version 1
+
+ This package may be used by any termination that supports gain and
+ echo control. It was originally intended for use on TDM circuits but
+ may be more widely used.
+
+ New versions or extensions of this package SHOULD take non-TDM use
+ into account.
+
+ E.13.1 Properties
+
+ Echo Cancellation
+
+ PropertyID: ec (0x0008)
+
+ Type: boolean
+
+
+
+ Groves et al Expires - October 2003 [Page 200]
+ Megaco Protocol version 2 April 2003
+
+
+ Possible values:
+
+ "on" (when the echo cancellation is requested) and
+
+ "off" (when it is turned off.)
+
+ The default is provisioned.
+
+ Defined in: LocalControlDescriptor
+
+ Characteristics: read/write
+
+ Gain Control
+
+ PropertyID: gain (0x000a)
+
+ Gain control, or usage of of signal level adaptation and noise
+ level reduction is used to adapt the level of the signal. However,
+ it is necessary, for example for modem calls, to turn off this
+ function.
+
+ Type: integer
+
+ Possible values:
+
+ The gain control parameter may either be specified as
+ "automatic" (0xffffffff), or as an explicit number of decibels
+ of gain (any other integer value). The default is provisioned
+ in the MG.
+
+ Defined in: LocalControlDescriptor
+
+ Characteristics: read/write
+
+ E.13.2 Events
+
+ None.
+
+ E.13.3 Signals
+
+ None.
+
+ E.13.4 Statistics
+ None.
+
+ E.13.5 Procedures
+ None.
+
+
+
+
+ Groves et al Expires - October 2003 [Page 201]
+ Megaco Protocol version 2 April 2003
+
+
+ APPENDIX I Example Call Flows
+
+ All H.248.1 implementors must read the normative part of this
+ document carefully before implementing from it. No one SHOULD use the
+ examples in this appendix as stand-alone explanations of how to
+ create protocol messages.
+
+ The examples in this appendix use SDP for encoding of the Local and
+ Remote stream descriptors. SDP is defined in RFC 2327. If there is
+ any discrepancy between the SDP in the examples, and RFC 2327, the
+ RFC SHOULD be consulted for correctness. Audio profiles used are
+ those defined in RFC 1890, and others registered with IANA. For
+ example, G.711 A-law is called PCMA in SDP, and is assigned profile
+ 0. G.723.1 is called G723 and is profile 4; H.263 is called H263 and
+ is profile 34. See also http://www.iana.org/assignments/rtp-
+ parameters.
+
+ I.1 Residential Gateway to Residential Gateway Call
+
+ This example scenario illustrates the use of the elements of the
+ protocol to set up a Residential Gateway to Residential Gateway call
+ over an IP-based network. For simplicity, this example assumes that
+ both Residential Gateways involved in the call are controlled by the
+ same Media Gateway Controller.
+
+ I.1.1 Programming Residential GW Analog Line Terminations for Idle
+ Behaviour
+
+ The following illustrates the API invocations from the Media Gateway
+ Controller and Media Gateways to get the Terminations in this
+ scenario programmed for idle behaviour. Both the originating and
+ terminating Media Gateways have idle AnalogLine Terminations
+ programmed to look for call initiation events (i.e. offhook) by using
+ the Modify Command with the appropriate parameters. The null Context
+ is used to indicate that the Terminations are not yet involved in a
+ Context. The ROOT termination is used to indicate the entire MG
+ instead of a termination within the MG.
+
+ In this example, MG1 has the IP address 124.124.124.222, MG2 is
+ 125.125.125.111, and the MGC is 123.123.123.4. The default Megaco
+ port is 55555 for all three.
+
+ 1) An MG registers with an MGC using the ServiceChange command:
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]
+ Transaction = 9998 {
+ Context = - {
+
+
+ Groves et al Expires - October 2003 [Page 202]
+ Megaco Protocol version 2 April 2003
+
+
+ ServiceChange = ROOT {Services {
+ Method=Restart,
+ ServiceChangeAddress=55555, Profile=ResGW/1}
+ }
+ }
+ }
+
+ 2) The MGC sends a reply:
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Reply = 9998 {
+ Context = - {ServiceChange = ROOT {
+ Services {ServiceChangeAddress=55555, Profile=ResGW/1} } }
+ }
+
+ 3) The MGC programs a Termination in the NULL context. The
+ terminationId is A4444, the streamId is 1, the requestId in the
+ Events descriptor is 2222. The mId is the identifier of the sender of
+ this message, in this case, it is the IP address and port
+ [123.123.123.4]:55555. Mode for this stream is set to SendReceive.
+ "al" is the analog line supervision package. Local and Remote are
+ assumed to be provisioned.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media { Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ },
+ }
+ },
+ Events = 2222 {al/of (strict=state)}
+ }
+ }
+ }
+
+ The dialplan script could have been loaded into the MG previously.
+ Its function would be to wait for the OffHook, turn on dialtone and
+ start collecting DTMF digits. However in this example, we use the
+ digit map, which is put into place after the offhook is detected
+ (step 5 below).
+
+
+ Groves et al Expires - October 2003 [Page 203]
+ Megaco Protocol version 2 April 2003
+
+
+ Note that the embedded EventsDescriptor could have been used to
+ combine steps 3 and 4 with steps 8 and 9, eliminating steps 6 and 7.
+
+ 4) The MG1 accepts the Modify with this reply:
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Reply = 9999 {
+ Context = - {Modify = A4444}
+ }
+
+ 5) A similar exchange happens between MG2 and the MGC, resulting in
+ an idle Termination called A5555.
+
+ I.1.2 Collecting Originator Digits and Initiating Termination
+
+ The following builds upon the previously shown conditions. It
+ illustrates the transactions from the Media Gateway Controller and
+ originating Media Gateway (MG1) to get the originating Termination
+ (A4444) through the stages of digit collection required to initiate a
+ connection to the terminating Media Gateway (MG2).
+
+ 6) MG1 detects an offhook event from User 1 and reports it to the
+ Media Gateway Controller via the Notify Command.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {ObservedEvents =2222 {
+ 19990729T22000000:al/of(init=false)}}
+ }
+ }
+
+ 7) And the Notify is acknowledged.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Reply = 10000 {
+ Context = - {Notify = A4444}
+ }
+
+ 8) The MGC Modifies the Termination to play dial tone, to look for
+ digits according to Dialplan0 and to look for the on-hook event now.
+
+ MGC to MG1:
+
+
+ Groves et al Expires - October 2003 [Page 204]
+ Megaco Protocol version 2 April 2003
+
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on(strict=state), dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap= Dialplan0{
+ (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)}
+ }
+ }
+ }
+
+ 9) And the Modify is acknowledged.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Reply = 10001 {
+ Context = - {Modify = A4444}
+ }
+
+ 10) Next, digits are accumulated by MG1 as they are dialed by User
+ 1. Dialtone is stopped upon detection of the first digit. When an
+ appropriate match is made of collected digits against the currently
+ programmed Dialplan for A4444, another Notify is sent to the Media
+ Gateway Controller.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {ObservedEvents =2223 {
+ 19990729T22010001:dd/ce{ds="916135551212",Meth=UM}}}
+ }
+ }
+
+ 11) And the Notify is acknowledged.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Reply = 10002 {
+ Context = - {Notify = A4444}
+ }
+
+
+
+
+ Groves et al Expires - October 2003 [Page 205]
+ Megaco Protocol version 2 April 2003
+
+
+ 12) The controller then analyses the digits and determines that a
+ connection needs to be made from MG1 to MG2. Both the TDM termination
+ A4444, and an RTP termination are added to a new Context in MG1. Mode
+ is ReceiveOnly since Remote descriptor values are not yet specified.
+ Preferred codecs are in the MGC's preferred order of choice.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0
+ c=IN IP4 $
+ m=audio $ RTP/AVP 4
+ a=ptime:30
+ v=0
+ c=IN IP4 $
+ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+ }
+
+ NOTE - The MGC states its preferred parameter values as a series of
+ SDP blocks in Local. The MG fills in the Local descriptor in the
+ Reply.
+
+ 13) MG1 acknowledges the new Termination and fills in the Local IP
+ address and UDP port. It also makes a choice for the codec based on
+ the MGC preferences in Local. MG1 sets the RTP port to 2222.
+
+ MG1->MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+
+
+ Groves et al Expires - October 2003 [Page 206]
+ Megaco Protocol version 2 April 2003
+
+
+ Add=A4445{
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 00
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }
+
+ 14) The MGC will now associate A5555 with a new Context on MG2, and
+ establish an RTP Stream (i.e. A5556 will be assigned), SendReceive
+ connection through to the originating user, User 1. The MGC also sets
+ ring on A5555.
+
+ MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 50003 {
+ Context = $ {
+ Add = A5555 { Media {
+ Stream = 1 {
+ LocalControl {Mode = SendReceive} }},
+ Events=1234{al/of(strict=state)},
+ Signals {al/ri}
+ },
+ Add = $ {Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0
+ c=IN IP4 $
+ m=audio $ RTP/AVP 4
+ a=ptime:30
+ },
+ Remote {
+ v=0
+
+
+ Groves et al Expires - October 2003 [Page 207]
+ Megaco Protocol version 2 April 2003
+
+
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }
+
+ 15) This is acknowledged. The stream port number is different from
+ the control port number. In this case it is 1111 (in SDP).
+
+ MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555
+ Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556{
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 7736844526 7736842807 IN IP4 125.125.125.111
+ s=-
+ t= 00
+ c=IN IP4 125.125.125.111
+ m=audio 1111 RTP/AVP 4
+ }
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+
+ 16) The above IPAddr and UDPport need to be given to MG1 now.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+
+
+ Groves et al Expires - October 2003 [Page 208]
+ Megaco Protocol version 2 April 2003
+
+
+ Remote {
+ v=0
+ o=- 7736844526 7736842807 IN IP4 125.125.125.111
+ s=-
+ t= 00
+ c=IN IP4 125.125.125.111
+ m=audio 1111 RTP/AVP 4
+ }
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Reply = 10005 {
+ Context = 2000 {Modify = A4444, Modify = A4445}
+ }
+
+ 17) The two gateways are now connected and User 1 hears the
+ RingBack. The MG2 now waits until User2 picks up the receiver and
+ then the two-way call is established.
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555
+ Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {ObservedEvents =1234 {
+ 19990729T22020002:al/of(init=false)}}
+ }
+ }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Reply = 50005 {
+ Context = - {Notify = A5555}
+ }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {al/on(strict=state)},
+
+
+ Groves et al Expires - October 2003 [Page 209]
+ Megaco Protocol version 2 April 2003
+
+
+ Signals { } ; to turn off ringing
+ }
+ }
+ }
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555
+ Reply = 50006 {
+ Context = 5000 {Modify = A4445}
+ }
+
+ 18) Change mode on MG1 to SendReceive, and stop the ringback.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode=SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals { }
+ }
+ }
+ }
+
+ from MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+ Reply = 10006 {
+ Context = 2000 {Modify = A4445, Modify = A4444}}
+
+ 19) The MGC decides to Audit the RTP termination on MG2.
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 50007 {
+ Context = - {AuditValue = A5556{
+ Audit{Media, DigitMap, Events, Signals, Packages, Statistics }}
+ }
+ }
+
+
+
+ Groves et al Expires - October 2003 [Page 210]
+ Megaco Protocol version 2 April 2003
+
+
+ 20) The MG2 replies.
+
+ MEGACO/1 [125.125.125.111]:55555
+ Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState { ServiceStates = InService,
+ Buffer = OFF },
+ Stream = 1 {
+ LocalControl { Mode = SendReceive,
+ nt/jit=40 },
+ Local {
+ v=0
+ o=- 7736844526 7736842807 IN IP4 125.125.125.111
+ s=-
+ t= 00
+ c=IN IP4 125.125.125.111
+ m=audio 1111 RTP/AVP 4
+ a=ptime:30
+ },
+ Remote {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 00
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ } } },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics { rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 } ; avg latency
+ }
+ }
+ }
+
+ 21) When the MGC receives an onhook signal from one of the MGs, it
+ brings down the call. In this example, the user at MG2 hangs up
+ first.
+
+
+
+ Groves et al Expires - October 2003 [Page 211]
+ Megaco Protocol version 2 April 2003
+
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555
+ Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {ObservedEvents =1235 {
+ 19990729T24020002:al/on(init=false)}
+ }
+ }
+ }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Reply = 50008 {
+ Context = - {Notify = A5555}
+ }
+
+ 22) The MGC now sends both MGs a Subtract to take down the call.
+ Only the subtracts to MG2 are shown here. Each termination has its
+ own set of statistics that it gathers. An MGC may not need to request
+ both to be returned. A5555 is a physical termination, and A5556 is an
+ RTP termination.
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555
+ Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {Audit{Statistics}},
+ Subtract = A5556 {Audit{Statistics}}
+ }
+ }
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555
+ Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+
+
+ Groves et al Expires - October 2003 [Page 212]
+ Megaco Protocol version 2 April 2003
+
+
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+ }
+
+ 23) The MGC now sets up both MG1 and MG2 to be ready to detect the
+ next off-hook event. See step 1. Note that this could be the default
+ state of a termination in the null context, and if this were the
+ case, no message need be sent from the MGC to the MG. Once a
+ termination returns to the null context, it goes back to the default
+ termination values for that termination.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 213]
+ Megaco Protocol version 2 April 2003
+
+
+ APPENDIX II CHANGES FROM RFC XXXX [draft-ietf-megaco-3015corr-02.txt]
+
+ Section Source Description
+
+ Abstract PTT Describes changes between v1 and v2.
+
+ 1 Edit Added instructions on indication of versions in
+ ServiceChangeVersion.
+
+ 2.1 Edit Added references to H.248.4, H.248.5.
+
+ 5 PTT New approach to discrepancy between ITU-T and IETF
+ definition of "SHOULD".
+
+ 6 para 2 List Deleted "modem" [parameters] from last sentence.
+
+ 6.2 para Edit Replaced "taken out of the call it is in" with
+ 4 "subtracted from a context".
+
+ 6.2 Edit Rewritten to clarify.
+ final
+ para
+
+ 6.2.4 List Added note that use of Modem descriptor is
+ table deprecated.
+
+ 6.2.5 AVD Added ability to set signals on ROOT. Affects first
+ para, Modify.
+
+ 6.2.5 Edit Added clarifying phrase "as an entity in itself".
+ first
+ para
+
+ 7.1.2 List Added para spelling out deprecation of Modem
+ descriptor.
+
+ 7.1.3 AVD Added Nx64K multiplex type with description.
+
+ 7.1.7 Edit Removed "under" in last sentence, so that all cases
+ first of specification can be seen to apply.
+ para
+
+ 7.1.12 AVD Added ability to specify individual property, event,
+ signal or statistics to be audited.
+
+ 7.1.12 List Noted deprecation of Modem descriptor.
+
+ 7.1.14.3 AVD Added ability to specify value of "long duration"
+
+
+
+ Groves et al Expires - October 2003 [Page 214]
+ Megaco Protocol version 2 April 2003
+
+
+ threshold within the digit map itself.
+
+ 7.1.14.4 AVD Added text requiring digit buffering and spelling
+ out procedures, if EventBufferControl is OFF.
+
+ 7.1.14.5 AVD Added text on handling of buffered digits.
+ step 2)
+
+ 7.1.14.5 AVD Added provision for inclusion of indication of which
+ step 2) timer expired if digit map completion event allows
+ this.
+
+ 7.1.14.5 AVD Added text providing alternatives for handling of
+ step 5) excess digits.
+
+ 7.1.14.7 AVD Added text on applicability of this clause to
+ final buffered digits.
+ bullet
+
+ 7.1.18 AVD Added ability to specify topology by stream: mention
+ in para 3, new paras before introduction to figures,
+ new Figure 8.
+
+ 7.2.1, List Deprecation of Modem descriptor noted.
+ 7.2.2,
+ 7.2.3,
+ 7.2.4,
+ 7.2.5,
+ 7.2.6
+
+ 7.2.5, AVD Added ability to audit individual property, event,
+ 7.2.6 signal or statistics. Added detailed instructions
+ for this.
+
+ 7.2.8 AVD Added ability to indicate capability change to be
+ audited: added ServiceChangeInfo to bulleted list of
+ contents of ServiceChange descriptor, added para
+ explaining what it is for.
+
+ 7.2.8 Edit Para following new ServiceChangeInfo para: cleanup
+ of wording in second sentence on registration with
+ Failover method.
+
+ 7.2.8 AVD Bullet dealing with ServiceChangeProfile on
+ registration: added text on procedures associated
+ with profiles.
+
+ 7.2.8 AVD Added 916 and 917 ServiceChangeReasons.
+
+
+
+ Groves et al Expires - October 2003 [Page 215]
+ Megaco Protocol version 2 April 2003
+
+
+ 7.2.9 AVD Added text describing the auditing of context
+ properties.
+
+ 7.3 Edit Deleted. Explanation of error descriptors is now in
+ section 7.1.19, and error codes are documented in
+ H.248.8.
+
+ 8.2.3 AVD Added text on properties and procedures to limite
+ the number of pending notices sent for a given
+ transaction.
+
+ 8.3 Edit Added sentence indicating that messages conforming
+ second to this document specify version 2 of the protocol.
+ para
+
+ 9 Edit Added mention of H.248.4 and H.248.5 (were
+ transport-related Annexes to H.248).
+
+ 11 AAP Second para demoted to Note to resolve objection
+ during ITU-T Last Call process.
+
+ 11.3 Edit Modified first sentence to refer specifically to
+ ServiceChange commands constituting registrations.
+ [Hidden issue: reestablishment of contact with
+ Disconnected method does not constitute
+ registration.] Added second sentence requiring that
+ the registration message always conform to version 1
+ [to ensure interoperability before common working
+ version can be established].
+
+ 12.1.1 Edit Slight clarification of "designed to be extended
+ only" description.
+
+ 13 AVD New section providing extended description of
+ profile contents and registration.
+
+ 14 and Edit Renumbered as a result of the new Profile section.
+ sub-
+ sections
+
+ 14.4 AVD IANA considerations for profiles added.
+
+ A.2 Edit Added object identifier including version to ASN.1
+ header.
+
+ A.2 AVD Production TopologyRequest: added optional streamId.
+
+ A.2 AVD Production AuditDescriptor: added auditPropertyToken
+
+
+
+ Groves et al Expires - October 2003 [Page 216]
+ Megaco Protocol version 2 April 2003
+
+
+ term for more specific audit items.
+
+ A.2 AVD New productions IndAuditParameter through
+ IndAudPackagesDescriptor added for more specific
+ audit items.
+
+ A.2 AVD Production MuxType: added nx64k.
+
+ A.2 AVD Production DigitMapValue: added durationTimer term.
+
+ A.2 AVD Production ServiceChangeParm: added
+ serviceChangeInfo term.
+
+ A.3 AVD Production digitMapLetter: added "T" for start
+ timer.
+
+ A.3 Edit Production pathDomainName: added "*" and ".".
+
+ B.2 Edit Production message: version changed to 2 in comment.
+
+ B.2 Post- Production transactionAck: TransactionID
+ edit capitalized.
+
+ B.2 PTT Productions contextID, terminationID, and
+ terminationIDList reordered: grouped with
+ TransactionID to make fundamental productions more
+ visible.
+
+ B.2 AVD Production MuxType: added Nx64kToken.
+
+ B.2 AVD Production digitMapValue: added ["Z" COLON Timer
+ COMMA] alternative.
+
+ B.2 AVD Production digitMapLetter: added "T" (start timer)
+ alternative.
+
+ B.2 AVD Production auditItem: added indAudterminationAudit
+ term.
+
+ B.2 AVD New productions indAudterminationAudit through
+ indAudpackagesDescriptor added for more specific
+ auditing.
+
+ B.2 AVD Production ServiceChangeParm: term auditItem added
+ to indicate nature of capability change.
+
+ B.2 AVD Production topologyTriple: optional eventStream
+ (sic) term added.
+
+
+
+ Groves et al Expires - October 2003 [Page 217]
+ Megaco Protocol version 2 April 2003
+
+
+ B.2 AVD New production Nx64kToken.
+
+ C.1 Edit ACodec: reference corrected to Q.765.5
+
+ E.2.1 Edit Editorial correction to informal name of property
+ maxNumberOfContexts.
+
+ E.2.1 AVD Added properties to govern TransactionPending
+ retransmissions.
+
+ E.4 Edit Added extend-only package usage indicator.
+
+ E.7.3 Edit Added "recording" qualifier to warning tone.
+ table
+
+ E.11.2 Edit For quality alert event: replaced "property" with
+ "event" in description.
+
+ Appendix Edit Expanded on codec examples. Added reference to IANA
+ I second registry for RTP payload types.
+ para
+
+
+
+
+
+
+
+
+
+
+
+
+ INTELLECTUAL PROPERTY RIGHTS
+
+ The ITU draws attention to the possibility that the practice or
+ implementation of this Recommendation may involve the use of a
+ claimed Intellectual Property Right. The ITU takes no position
+ concerning the evidence, validity or applicability of claimed
+ Intellectual Property Rights, whether asserted by ITU members or
+ others outside of the Recommendation development process.
+
+ As of the date of approval of this Recommendation, the ITU had
+ received notice of intellectual property, protected by patents, which
+ may be required to implement this Recommendation. However,
+ implementors are cautioned that this may not represent the latest
+ information and are therefore strongly urged to consult the TSB
+ patent database.
+
+
+
+ Groves et al Expires - October 2003 [Page 218]
+ Megaco version 2 April 2003
+
+
+ The IETF has also received notice of intellectual property claims
+ relating to Megaco/H.248.1. Please consult the IETF IPR
+ announcements at http://www.ietf.org/ipr.html.
+
+
+ Acknowledgments
+
+ Megaco/H.248.1 is the result of hard work by many people in both the
+ IETF and in ITU-T Study Group 16. This section records those who
+ played a prominent role in ITU-T meetings, on the Megaco list, or
+ both.
+
+ Megaco/H.248 owes a large initial debt to the MGCP protocol (RFC
+ 2705), and thus to its authors, Mauricio Arango, Andrew Dugan, Ike
+ Elliott, Christian Huitema, and Scott Pickett. Flemming Andreasen
+ does not appear on this list of authors, but was a major contributor
+ to the development of both MGCP and Megaco/H.248.1. RFC 3435 (MGCP)
+ has an extensive acknowledgement of many other people who worked on
+ media gateway control before Megaco got started.
+
+ The authors of the first Megaco RFCs (2885, then 3015) were Fernando
+ Cuervo, Nancy Greene, Abdallah Rayhan, Christian Huitema, Brian
+ Rosen, and John Segers. Christian Groves conceived and was editor of
+ Annex C. The people most active on the Megaco list in the period
+ leading up to the completion of RFC 2885 were Brian Rosen, Tom
+ Taylor, Nancy Greene, Christian Huitema, Matt Holdrege, Chip Sharp,
+ John Segers, Michael Thomas, Henry Sinnreich, and Paul Sijben. The
+ people who sacrificed sleep and meals to complete the massive amount
+ of work required in the decisive Study Group 16 meeting of February,
+ 2000, were Michael Brown, Ranga Dendi, Larry Forni, Glen Freundlich,
+ Christian Groves, Alf Heidemark, Steve Magnell, Selvam Rengasami,
+ Rich Rubin, Klaus Sambor, John Segers, Chip Sharp, Tom Taylor, and
+ Stephen Terrill.
+
+ The most active people on the Megaco list in the period since the
+ February 2000 have been Tom Taylor, Brian Rosen, Christian Groves,
+ Madhu Babu Brahmanapally, Troy Cauble, Terry Anderson, Chuong Nguyen,
+ and Kevin Boyle, but many other people have been regular
+ contributors. Brian Rosen did tremendous service in putting together
+ the Megaco interoperability tests. On the Study Group 16 side, the
+ editorial team for the final document in February, 2002 included
+ Christian Groves, Marcello Pantaleo, Terry Anderson, Peter Leis,
+ Kevin Boyle, and Tom Taylor.
+
+ Tom Taylor as Megaco Chair managed the day to day operation of the
+ Megaco list, with Brian Rosen taking an equal share of the burden for
+ most of the last three years. Glen Freundlich as the Study Group 16
+ Rapporteur ran the ITU-T meetings and ensured that all of the work at
+ hand was completed. Without Glen's determination the Megaco/H.248
+
+
+ Groves et al Expires - October 2003 [Page 219]
+ Megaco version 2 April 2003
+
+
+ standard would have taken at least half a year longer to produce.
+ Christian Groves filled in ably as Rapporteur when Glen could no
+ longer take part.
+
+
+ Authors' Addresses
+
+ Terry L Anderson
+ Lucent Technologies/INS/Voice Over IP Access Networks
+ Rm 2G-219A, 101 Crawfords Corner Rd, Holmdel, NJ 07733-3030
+ Phone: +1.732.949.5628
+
+ Christian Groves
+ Ericsson AsiaPacificLab Australia
+ 37/360 Elizabeth St
+ Melbourne, Victoria 3000
+ Australia
+
+ Marcello Pantaleo
+ Ericsson Eurolab Deutschland
+ Ericsson Allee 1
+ 52134 Herzogenrath, Germany
+
+ Tom Taylor
+ Nortel Networks
+ 1852 Lorraine Ave,
+ Ottawa, Ontario
+ Canada K1H 6Z8
+ Phone: +1 613 736 0961
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Groves et al Expires - October 2003 [Page 220] \ No newline at end of file
diff --git a/lib/megaco/doc/standard/implementors_guide_v10-13.pdf b/lib/megaco/doc/standard/implementors_guide_v10-13.pdf
new file mode 100644
index 0000000000..c743c808a9
--- /dev/null
+++ b/lib/megaco/doc/standard/implementors_guide_v10-13.pdf
Binary files differ
diff --git a/lib/megaco/doc/standard/rfc2327.txt b/lib/megaco/doc/standard/rfc2327.txt
new file mode 100644
index 0000000000..ce77de6128
--- /dev/null
+++ b/lib/megaco/doc/standard/rfc2327.txt
@@ -0,0 +1,2355 @@
+
+
+
+
+
+
+Network Working Group M. Handley
+Request for Comments: 2327 V. Jacobson
+Category: Standards Track ISI/LBNL
+ April 1998
+
+
+ SDP: Session Description Protocol
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+Abstract
+
+ This document defines the Session Description Protocol, SDP. SDP is
+ intended for describing multimedia sessions for the purposes of
+ session announcement, session invitation, and other forms of
+ multimedia session initiation.
+
+ This document is a product of the Multiparty Multimedia Session
+ Control (MMUSIC) working group of the Internet Engineering Task
+ Force. Comments are solicited and should be addressed to the working
+ group's mailing list at [email protected] and/or the authors.
+
+1. Introduction
+
+ On the Internet multicast backbone (Mbone), a session directory tool
+ is used to advertise multimedia conferences and communicate the
+ conference addresses and conference tool-specific information
+ necessary for participation. This document defines a session
+ description protocol for this purpose, and for general real-time
+ multimedia session description purposes. This memo does not describe
+ multicast address allocation or the distribution of SDP messages in
+ detail. These are described in accompanying memos. SDP is not
+ intended for negotiation of media encodings.
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 1]
+
+RFC 2327 SDP April 1998
+
+
+2. Background
+
+ The Mbone is the part of the internet that supports IP multicast, and
+ thus permits efficient many-to-many communication. It is used
+ extensively for multimedia conferencing. Such conferences usually
+ have the property that tight coordination of conference membership is
+ not necessary; to receive a conference, a user at an Mbone site only
+ has to know the conference's multicast group address and the UDP
+ ports for the conference data streams.
+
+ Session directories assist the advertisement of conference sessions
+ and communicate the relevant conference setup information to
+ prospective participants. SDP is designed to convey such information
+ to recipients. SDP is purely a format for session description - it
+ does not incorporate a transport protocol, and is intended to use
+ different transport protocols as appropriate including the Session
+ Announcement Protocol [4], Session Initiation Protocol [11], Real-
+ Time Streaming Protocol [12], electronic mail using the MIME
+ extensions, and the Hypertext Transport Protocol.
+
+ SDP is intended to be general purpose so that it can be used for a
+ wider range of network environments and applications than just
+ multicast session directories. However, it is not intended to
+ support negotiation of session content or media encodings - this is
+ viewed as outside the scope of session description.
+
+3. Glossary of Terms
+
+ The following terms are used in this document, and have specific
+ meaning within the context of this document.
+
+ Conference
+ A multimedia conference is a set of two or more communicating users
+ along with the software they are using to communicate.
+
+ Session
+ A multimedia session is a set of multimedia senders and receivers
+ and the data streams flowing from senders to receivers. A
+ multimedia conference is an example of a multimedia session.
+
+ Session Advertisement
+ See session announcement.
+
+ Session Announcement
+ A session announcement is a mechanism by which a session
+ description is conveyed to users in a proactive fashion, i.e., the
+ session description was not explicitly requested by the user.
+
+
+
+
+Handley & Jacobson Standards Track [Page 2]
+
+RFC 2327 SDP April 1998
+
+
+ Session Description
+ A well defined format for conveying sufficient information to
+ discover and participate in a multimedia session.
+
+3.1. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119.
+
+4. SDP Usage
+
+4.1. Multicast Announcements
+
+ SDP is a session description protocol for multimedia sessions. A
+ common mode of usage is for a client to announce a conference session
+ by periodically multicasting an announcement packet to a well known
+ multicast address and port using the Session Announcement Protocol
+ (SAP).
+
+ SAP packets are UDP packets with the following format:
+
+ |--------------------|
+ | SAP header |
+ |--------------------|
+ | text payload |
+ |//////////
+
+
+ The header is the Session Announcement Protocol header. SAP is
+ described in more detail in a companion memo [4]
+
+ The text payload is an SDP session description, as described in this
+ memo. The text payload should be no greater than 1 Kbyte in length.
+ If announced by SAP, only one session announcement is permitted in a
+ single packet.
+
+4.2. Email and WWW Announcements
+
+ Alternative means of conveying session descriptions include
+ electronic mail and the World Wide Web. For both email and WWW
+ distribution, the use of the MIME content type "application/sdp"
+ should be used. This enables the automatic launching of applications
+ for participation in the session from the WWW client or mail reader
+ in a standard manner.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 3]
+
+RFC 2327 SDP April 1998
+
+
+ Note that announcements of multicast sessions made only via email or
+ the World Wide Web (WWW) do not have the property that the receiver
+ of a session announcement can necessarily receive the session because
+ the multicast sessions may be restricted in scope, and access to the
+ WWW server or reception of email is possible outside this scope. SAP
+ announcements do not suffer from this mismatch.
+
+5. Requirements and Recommendations
+
+ The purpose of SDP is to convey information about media streams in
+ multimedia sessions to allow the recipients of a session description
+ to participate in the session. SDP is primarily intended for use in
+ an internetwork, although it is sufficiently general that it can
+ describe conferences in other network environments.
+
+ A multimedia session, for these purposes, is defined as a set of
+ media streams that exist for some duration of time. Media streams
+ can be many-to-many. The times during which the session is active
+ need not be continuous.
+
+ Thus far, multicast based sessions on the Internet have differed from
+ many other forms of conferencing in that anyone receiving the traffic
+ can join the session (unless the session traffic is encrypted). In
+ such an environment, SDP serves two primary purposes. It is a means
+ to communicate the existence of a session, and is a means to convey
+ sufficient information to enable joining and participating in the
+ session. In a unicast environment, only the latter purpose is likely
+ to be relevant.
+
+ Thus SDP includes:
+
+ o Session name and purpose
+
+ o Time(s) the session is active
+
+ o The media comprising the session
+
+ o Information to receive those media (addresses, ports, formats and
+ so on)
+
+ As resources necessary to participate in a session may be limited,
+ some additional information may also be desirable:
+
+ o Information about the bandwidth to be used by the conference
+
+ o Contact information for the person responsible for the session
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 4]
+
+RFC 2327 SDP April 1998
+
+
+ In general, SDP must convey sufficient information to be able to join
+ a session (with the possible exception of encryption keys) and to
+ announce the resources to be used to non-participants that may need
+ to know.
+
+5.1. Media Information
+
+ SDP includes:
+
+ o The type of media (video, audio, etc)
+
+ o The transport protocol (RTP/UDP/IP, H.320, etc)
+
+ o The format of the media (H.261 video, MPEG video, etc)
+
+ For an IP multicast session, the following are also conveyed:
+
+ o Multicast address for media
+
+ o Transport Port for media
+
+ This address and port are the destination address and destination
+ port of the multicast stream, whether being sent, received, or both.
+
+ For an IP unicast session, the following are conveyed:
+
+ o Remote address for media
+
+ o Transport port for contact address
+
+ The semantics of this address and port depend on the media and
+ transport protocol defined. By default, this is the remote address
+ and remote port to which data is sent, and the remote address and
+ local port on which to receive data. However, some media may define
+ to use these to establish a control channel for the actual media
+ flow.
+
+5.2. Timing Information
+
+ Sessions may either be bounded or unbounded in time. Whether or not
+ they are bounded, they may be only active at specific times.
+
+ SDP can convey:
+
+ o An arbitrary list of start and stop times bounding the session
+
+ o For each bound, repeat times such as "every Wednesday at 10am for
+ one hour"
+
+
+
+Handley & Jacobson Standards Track [Page 5]
+
+RFC 2327 SDP April 1998
+
+
+ This timing information is globally consistent, irrespective of local
+ time zone or daylight saving time.
+
+5.3. Private Sessions
+
+ It is possible to create both public sessions and private sessions.
+ Private sessions will typically be conveyed by encrypting the session
+ description to distribute it. The details of how encryption is
+ performed are dependent on the mechanism used to convey SDP - see [4]
+ for how this is done for session announcements.
+
+ If a session announcement is private it is possible to use that
+ private announcement to convey encryption keys necessary to decode
+ each of the media in a conference, including enough information to
+ know which encryption scheme is used for each media.
+
+5.4. Obtaining Further Information about a Session
+
+ A session description should convey enough information to decide
+ whether or not to participate in a session. SDP may include
+ additional pointers in the form of Universal Resources Identifiers
+ (URIs) for more information about the session.
+
+5.5. Categorisation
+
+ When many session descriptions are being distributed by SAP or any
+ other advertisement mechanism, it may be desirable to filter
+ announcements that are of interest from those that are not. SDP
+ supports a categorisation mechanism for sessions that is capable of
+ being automated.
+
+5.6. Internationalization
+
+ The SDP specification recommends the use of the ISO 10646 character
+ sets in the UTF-8 encoding (RFC 2044) to allow many different
+ languages to be represented. However, to assist in compact
+ representations, SDP also allows other character sets such as ISO
+ 8859-1 to be used when desired. Internationalization only applies to
+ free-text fields (session name and background information), and not
+ to SDP as a whole.
+
+6. SDP Specification
+
+ SDP session descriptions are entirely textual using the ISO 10646
+ character set in UTF-8 encoding. SDP field names and attributes names
+ use only the US-ASCII subset of UTF-8, but textual fields and
+ attribute values may use the full ISO 10646 character set. The
+ textual form, as opposed to a binary encoding such as ASN/1 or XDR,
+
+
+
+Handley & Jacobson Standards Track [Page 6]
+
+RFC 2327 SDP April 1998
+
+
+ was chosen to enhance portability, to enable a variety of transports
+ to be used (e.g, session description in a MIME email message) and to
+ allow flexible, text-based toolkits (e.g., Tcl/Tk ) to be used to
+ generate and to process session descriptions. However, since the
+ total bandwidth allocated to all SAP announcements is strictly
+ limited, the encoding is deliberately compact. Also, since
+ announcements may be transported via very unreliable means (e.g.,
+ email) or damaged by an intermediate caching server, the encoding was
+ designed with strict order and formatting rules so that most errors
+ would result in malformed announcements which could be detected
+ easily and discarded. This also allows rapid discarding of encrypted
+ announcements for which a receiver does not have the correct key.
+
+ An SDP session description consists of a number of lines of text of
+ the form <type>=<value> <type> is always exactly one character and is
+ case-significant. <value> is a structured text string whose format
+ depends on <type>. It also will be case-significant unless a
+ specific field defines otherwise. Whitespace is not permitted either
+ side of the `=' sign. In general <value> is either a number of fields
+ delimited by a single space character or a free format string.
+
+ A session description consists of a session-level description
+ (details that apply to the whole session and all media streams) and
+ optionally several media-level descriptions (details that apply onto
+ to a single media stream).
+
+ An announcement consists of a session-level section followed by zero
+ or more media-level sections. The session-level part starts with a
+ `v=' line and continues to the first media-level section. The media
+ description starts with an `m=' line and continues to the next media
+ description or end of the whole session description. In general,
+ session-level values are the default for all media unless overridden
+ by an equivalent media-level value.
+
+ When SDP is conveyed by SAP, only one session description is allowed
+ per packet. When SDP is conveyed by other means, many SDP session
+ descriptions may be concatenated together (the `v=' line indicating
+ the start of a session description terminates the previous
+ description). Some lines in each description are required and some
+ are optional but all must appear in exactly the order given here (the
+ fixed order greatly enhances error detection and allows for a simple
+ parser). Optional items are marked with a `*'.
+
+Session description
+ v= (protocol version)
+ o= (owner/creator and session identifier).
+ s= (session name)
+ i=* (session information)
+
+
+
+Handley & Jacobson Standards Track [Page 7]
+
+RFC 2327 SDP April 1998
+
+
+ u=* (URI of description)
+ e=* (email address)
+ p=* (phone number)
+ c=* (connection information - not required if included in all media)
+ b=* (bandwidth information)
+ One or more time descriptions (see below)
+ z=* (time zone adjustments)
+ k=* (encryption key)
+ a=* (zero or more session attribute lines)
+ Zero or more media descriptions (see below)
+
+Time description
+ t= (time the session is active)
+ r=* (zero or more repeat times)
+
+Media description
+ m= (media name and transport address)
+ i=* (media title)
+ c=* (connection information - optional if included at session-level)
+ b=* (bandwidth information)
+ k=* (encryption key)
+ a=* (zero or more media attribute lines)
+
+ The set of `type' letters is deliberately small and not intended to
+ be extensible -- SDP parsers must completely ignore any announcement
+ that contains a `type' letter that it does not understand. The
+ `attribute' mechanism ("a=" described below) is the primary means for
+ extending SDP and tailoring it to particular applications or media.
+ Some attributes (the ones listed in this document) have a defined
+ meaning but others may be added on an application-, media- or
+ session-specific basis. A session directory must ignore any
+ attribute it doesn't understand.
+
+ The connection (`c=') and attribute (`a=') information in the
+ session-level section applies to all the media of that session unless
+ overridden by connection information or an attribute of the same name
+ in the media description. For instance, in the example below, each
+ media behaves as if it were given a `recvonly' attribute.
+
+ An example SDP description is:
+
+ v=0
+ o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
+ s=SDP Seminar
+ i=A Seminar on the session description protocol
+ u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
+ [email protected] (Mark Handley)
+ c=IN IP4 224.2.17.12/127
+
+
+
+Handley & Jacobson Standards Track [Page 8]
+
+RFC 2327 SDP April 1998
+
+
+ t=2873397496 2873404696
+ a=recvonly
+ m=audio 49170 RTP/AVP 0
+ m=video 51372 RTP/AVP 31
+ m=application 32416 udp wb
+ a=orient:portrait
+
+ Text records such as the session name and information are bytes
+ strings which may contain any byte with the exceptions of 0x00 (Nul),
+ 0x0a (ASCII newline) and 0x0d (ASCII carriage return). The sequence
+ CRLF (0x0d0a) is used to end a record, although parsers should be
+ tolerant and also accept records terminated with a single newline
+ character. By default these byte strings contain ISO-10646
+ characters in UTF-8 encoding, but this default may be changed using
+ the `charset' attribute.
+
+ Protocol Version
+
+ v=0
+
+ The "v=" field gives the version of the Session Description Protocol.
+ There is no minor version number.
+
+ Origin
+
+ o=<username> <session id> <version> <network type> <address type>
+ <address>
+
+ The "o=" field gives the originator of the session (their username
+ and the address of the user's host) plus a session id and session
+ version number.
+
+ <username> is the user's login on the originating host, or it is "-"
+ if the originating host does not support the concept of user ids.
+ <username> must not contain spaces. <session id> is a numeric string
+ such that the tuple of <username>, <session id>, <network type>,
+ <address type> and <address> form a globally unique identifier for
+ the session.
+
+ The method of <session id> allocation is up to the creating tool, but
+ it has been suggested that a Network Time Protocol (NTP) timestamp be
+ used to ensure uniqueness [1].
+
+ <version> is a version number for this announcement. It is needed
+ for proxy announcements to detect which of several announcements for
+ the same session is the most recent. Again its usage is up to the
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 9]
+
+RFC 2327 SDP April 1998
+
+
+ creating tool, so long as <version> is increased when a modification
+ is made to the session data. Again, it is recommended (but not
+ mandatory) that an NTP timestamp is used.
+
+ <network type> is a text string giving the type of network.
+ Initially "IN" is defined to have the meaning "Internet". <address
+ type> is a text string giving the type of the address that follows.
+ Initially "IP4" and "IP6" are defined. <address> is the globally
+ unique address of the machine from which the session was created.
+ For an address type of IP4, this is either the fully-qualified domain
+ name of the machine, or the dotted-decimal representation of the IP
+ version 4 address of the machine. For an address type of IP6, this
+ is either the fully-qualified domain name of the machine, or the
+ compressed textual representation of the IP version 6 address of the
+ machine. For both IP4 and IP6, the fully-qualified domain name is
+ the form that SHOULD be given unless this is unavailable, in which
+ case the globally unique address may be substituted. A local IP
+ address MUST NOT be used in any context where the SDP description
+ might leave the scope in which the address is meaningful.
+
+ In general, the "o=" field serves as a globally unique identifier for
+ this version of this session description, and the subfields excepting
+ the version taken together identify the session irrespective of any
+ modifications.
+
+ Session Name
+
+ s=<session name>
+
+ The "s=" field is the session name. There must be one and only one
+ "s=" field per session description, and it must contain ISO 10646
+ characters (but see also the `charset' attribute below).
+
+ Session and Media Information
+
+ i=<session description>
+
+ The "i=" field is information about the session. There may be at
+ most one session-level "i=" field per session description, and at
+ most one "i=" field per media. Although it may be omitted, this is
+ discouraged for session announcements, and user interfaces for
+ composing sessions should require text to be entered. If it is
+ present it must contain ISO 10646 characters (but see also the
+ `charset' attribute below).
+
+ A single "i=" field can also be used for each media definition. In
+ media definitions, "i=" fields are primarily intended for labeling
+ media streams. As such, they are most likely to be useful when a
+
+
+
+Handley & Jacobson Standards Track [Page 10]
+
+RFC 2327 SDP April 1998
+
+
+ single session has more than one distinct media stream of the same
+ media type. An example would be two different whiteboards, one for
+ slides and one for feedback and questions.
+
+ URI
+
+ u=<URI>
+
+ o A URI is a Universal Resource Identifier as used by WWW clients
+
+ o The URI should be a pointer to additional information about the
+ conference
+
+ o This field is optional, but if it is present it should be specified
+ before the first media field
+
+ o No more than one URI field is allowed per session description
+
+
+ Email Address and Phone Number
+
+ e=<email address>
+ p=<phone number>
+
+ o These specify contact information for the person responsible for
+ the conference. This is not necessarily the same person that
+ created the conference announcement.
+
+ o Either an email field or a phone field must be specified.
+ Additional email and phone fields are allowed.
+
+ o If these are present, they should be specified before the first
+ media field.
+
+ o More than one email or phone field can be given for a session
+ description.
+
+ o Phone numbers should be given in the conventional international
+
+ format - preceded by a "+ and the international country code.
+ There must be a space or a hyphen ("-") between the country code
+ and the rest of the phone number. Spaces and hyphens may be used
+ to split up a phone field to aid readability if desired. For
+ example:
+
+ p=+44-171-380-7777 or p=+1 617 253 6011
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 11]
+
+RFC 2327 SDP April 1998
+
+
+ o Both email addresses and phone numbers can have an optional free
+ text string associated with them, normally giving the name of the
+ person who may be contacted. This should be enclosed in
+ parenthesis if it is present. For example:
+
+ [email protected] (Mark Handley)
+
+ The alternative RFC822 name quoting convention is also allowed for
+ both email addresses and phone numbers. For example,
+
+ e=Mark Handley <[email protected]>
+
+ The free text string should be in the ISO-10646 character set with
+ UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings
+ if the appropriate charset session-level attribute is set.
+
+ Connection Data
+
+ c=<network type> <address type> <connection address>
+
+ The "c=" field contains connection data.
+
+ A session announcement must contain one "c=" field in each media
+ description (see below) or a "c=" field at the session-level. It may
+ contain a session-level "c=" field and one additional "c=" field per
+ media description, in which case the per-media values override the
+ session-level settings for the relevant media.
+
+ The first sub-field is the network type, which is a text string
+ giving the type of network. Initially "IN" is defined to have the
+ meaning "Internet".
+
+ The second sub-field is the address type. This allows SDP to be used
+ for sessions that are not IP based. Currently only IP4 is defined.
+
+ The third sub-field is the connection address. Optional extra
+ subfields may be added after the connection address depending on the
+ value of the <address type> field.
+
+ For IP4 addresses, the connection address is defined as follows:
+
+ o Typically the connection address will be a class-D IP multicast
+
+ group address. If the session is not multicast, then the
+ connection address contains the fully-qualified domain name or the
+ unicast IP address of the expected data source or data relay or
+ data sink as determined by additional attribute fields. It is not
+ expected that fully-qualified domain names or unicast addresses
+
+
+
+Handley & Jacobson Standards Track [Page 12]
+
+RFC 2327 SDP April 1998
+
+
+ will be given in a session description that is communicated by a
+ multicast announcement, though this is not prohibited. If a
+ unicast data stream is to pass through a network address
+ translator, the use of a fully-qualified domain name rather than an
+ unicast IP address is RECOMMENDED. In other cases, the use of an
+ IP address to specify a particular interface on a multi-homed host
+ might be required. Thus this specification leaves the decision as
+ to which to use up to the individual application, but all
+ applications MUST be able to cope with receiving both formats.
+
+ o Conferences using an IP multicast connection address must also have
+ a time to live (TTL) value present in addition to the multicast
+ address. The TTL and the address together define the scope with
+ which multicast packets sent in this conference will be sent. TTL
+ values must be in the range 0-255.
+
+ The TTL for the session is appended to the address using a slash as
+ a separator. An example is:
+
+ c=IN IP4 224.2.1.1/127
+
+ Hierarchical or layered encoding schemes are data streams where the
+ encoding from a single media source is split into a number of
+ layers. The receiver can choose the desired quality (and hence
+ bandwidth) by only subscribing to a subset of these layers. Such
+ layered encodings are normally transmitted in multiple multicast
+ groups to allow multicast pruning. This technique keeps unwanted
+ traffic from sites only requiring certain levels of the hierarchy.
+ For applications requiring multiple multicast groups, we allow the
+ following notation to be used for the connection address:
+
+ <base multicast address>/<ttl>/<number of addresses>
+
+ If the number of addresses is not given it is assumed to be one.
+ Multicast addresses so assigned are contiguously allocated above
+ the base address, so that, for example:
+
+ c=IN IP4 224.2.1.1/127/3
+
+ would state that addresses 224.2.1.1, 224.2.1.2 and 224.2.1.3 are
+ to be used at a ttl of 127. This is semantically identical to
+ including multiple "c=" lines in a media description:
+
+ c=IN IP4 224.2.1.1/127
+ c=IN IP4 224.2.1.2/127
+ c=IN IP4 224.2.1.3/127
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 13]
+
+RFC 2327 SDP April 1998
+
+
+ Multiple addresses or "c=" lines can only be specified on a per-
+ media basis, and not for a session-level "c=" field.
+
+ It is illegal for the slash notation described above to be used for
+ IP unicast addresses.
+
+ Bandwidth
+
+ b=<modifier>:<bandwidth-value>
+
+ o This specifies the proposed bandwidth to be used by the session or
+ media, and is optional.
+
+ o <bandwidth-value> is in kilobits per second
+
+ o <modifier> is a single alphanumeric word giving the meaning of the
+ bandwidth figure.
+
+ o Two modifiers are initially defined:
+
+ CT Conference Total: An implicit maximum bandwidth is associated with
+ each TTL on the Mbone or within a particular multicast
+ administrative scope region (the Mbone bandwidth vs. TTL limits are
+ given in the MBone FAQ). If the bandwidth of a session or media in
+ a session is different from the bandwidth implicit from the scope,
+ a `b=CT:...' line should be supplied for the session giving the
+ proposed upper limit to the bandwidth used. The primary purpose of
+ this is to give an approximate idea as to whether two or more
+ conferences can co-exist simultaneously.
+
+ AS Application-Specific Maximum: The bandwidth is interpreted to be
+ application-specific, i.e., will be the application's concept of
+ maximum bandwidth. Normally this will coincide with what is set on
+ the application's "maximum bandwidth" control if applicable.
+
+ Note that CT gives a total bandwidth figure for all the media at
+ all sites. AS gives a bandwidth figure for a single media at a
+ single site, although there may be many sites sending
+ simultaneously.
+
+ o Extension Mechanism: Tool writers can define experimental bandwidth
+ modifiers by prefixing their modifier with "X-". For example:
+
+ b=X-YZ:128
+
+ SDP parsers should ignore bandwidth fields with unknown modifiers.
+ Modifiers should be alpha-numeric and, although no length limit is
+ given, they are recommended to be short.
+
+
+
+Handley & Jacobson Standards Track [Page 14]
+
+RFC 2327 SDP April 1998
+
+
+ Times, Repeat Times and Time Zones
+
+ t=<start time> <stop time>
+
+ o "t=" fields specify the start and stop times for a conference
+ session. Multiple "t=" fields may be used if a session is active
+ at multiple irregularly spaced times; each additional "t=" field
+ specifies an additional period of time for which the session will
+ be active. If the session is active at regular times, an "r="
+ field (see below) should be used in addition to and following a
+ "t=" field - in which case the "t=" field specifies the start and
+ stop times of the repeat sequence.
+
+ o The first and second sub-fields give the start and stop times for
+ the conference respectively. These values are the decimal
+ representation of Network Time Protocol (NTP) time values in
+ seconds [1]. To convert these values to UNIX time, subtract
+ decimal 2208988800.
+
+ o If the stop-time is set to zero, then the session is not bounded,
+ though it will not become active until after the start-time. If
+ the start-time is also zero, the session is regarded as permanent.
+
+ User interfaces should strongly discourage the creation of
+ unbounded and permanent sessions as they give no information about
+ when the session is actually going to terminate, and so make
+ scheduling difficult.
+
+ The general assumption may be made, when displaying unbounded
+ sessions that have not timed out to the user, that an unbounded
+ session will only be active until half an hour from the current
+ time or the session start time, whichever is the later. If
+ behaviour other than this is required, an end-time should be given
+ and modified as appropriate when new information becomes available
+ about when the session should really end.
+
+ Permanent sessions may be shown to the user as never being active
+ unless there are associated repeat times which state precisely when
+ the session will be active. In general, permanent sessions should
+ not be created for any session expected to have a duration of less
+ than 2 months, and should be discouraged for sessions expected to
+ have a duration of less than 6 months.
+
+ r=<repeat interval> <active duration> <list of offsets from start-
+ time>
+
+ o "r=" fields specify repeat times for a session. For example, if
+ a session is active at 10am on Monday and 11am on Tuesday for one
+
+
+
+Handley & Jacobson Standards Track [Page 15]
+
+RFC 2327 SDP April 1998
+
+
+ hour each week for three months, then the <start time> in the
+ corresponding "t=" field would be the NTP representation of 10am on
+ the first Monday, the <repeat interval> would be 1 week, the
+ <active duration> would be 1 hour, and the offsets would be zero
+ and 25 hours. The corresponding "t=" field stop time would be the
+ NTP representation of the end of the last session three months
+ later. By default all fields are in seconds, so the "r=" and "t="
+ fields might be:
+
+ t=3034423619 3042462419
+ r=604800 3600 0 90000
+
+ To make announcements more compact, times may also be given in units
+ of days, hours or minutes. The syntax for these is a number
+ immediately followed by a single case-sensitive character.
+ Fractional units are not allowed - a smaller unit should be used
+ instead. The following unit specification characters are allowed:
+
+ d - days (86400 seconds)
+ h - minutes (3600 seconds)
+ m - minutes (60 seconds)
+ s - seconds (allowed for completeness but not recommended)
+
+ Thus, the above announcement could also have been written:
+
+ r=7d 1h 0 25h
+
+ Monthly and yearly repeats cannot currently be directly specified
+ with a single SDP repeat time - instead separate "t" fields should
+ be used to explicitly list the session times.
+
+ z=<adjustment time> <offset> <adjustment time> <offset> ....
+
+ o To schedule a repeated session which spans a change from daylight-
+ saving time to standard time or vice-versa, it is necessary to
+ specify offsets from the base repeat times. This is required
+ because different time zones change time at different times of day,
+ different countries change to or from daylight time on different
+ dates, and some countries do not have daylight saving time at all.
+
+ Thus in order to schedule a session that is at the same time winter
+ and summer, it must be possible to specify unambiguously by whose
+ time zone a session is scheduled. To simplify this task for
+ receivers, we allow the sender to specify the NTP time that a time
+ zone adjustment happens and the offset from the time when the
+ session was first scheduled. The "z" field allows the sender to
+ specify a list of these adjustment times and offsets from the base
+ time.
+
+
+
+Handley & Jacobson Standards Track [Page 16]
+
+RFC 2327 SDP April 1998
+
+
+ An example might be:
+
+ z=2882844526 -1h 2898848070 0
+
+ This specifies that at time 2882844526 the time base by which the
+ session's repeat times are calculated is shifted back by 1 hour,
+ and that at time 2898848070 the session's original time base is
+ restored. Adjustments are always relative to the specified start
+ time - they are not cumulative.
+
+ o If a session is likely to last several years, it is expected
+ that
+ the session announcement will be modified periodically rather than
+ transmit several years worth of adjustments in one announcement.
+
+ Encryption Keys
+
+ k=<method>
+ k=<method>:<encryption key>
+
+ o The session description protocol may be used to convey encryption
+ keys. A key field is permitted before the first media entry (in
+ which case it applies to all media in the session), or for each
+ media entry as required.
+
+ o The format of keys and their usage is outside the scope of this
+ document, but see [3].
+
+ o The method indicates the mechanism to be used to obtain a usable
+ key by external means, or from the encoded encryption key given.
+
+ The following methods are defined:
+
+ k=clear:<encryption key>
+ The encryption key (as described in [3] for RTP media streams
+ under the AV profile) is included untransformed in this key
+ field.
+
+ k=base64:<encoded encryption key>
+ The encryption key (as described in [3] for RTP media streams
+ under the AV profile) is included in this key field but has been
+ base64 encoded because it includes characters that are
+ prohibited in SDP.
+
+ k=uri:<URI to obtain key>
+ A Universal Resource Identifier as used by WWW clients is
+ included in this key field. The URI refers to the data
+ containing the key, and may require additional authentication
+
+
+
+Handley & Jacobson Standards Track [Page 17]
+
+RFC 2327 SDP April 1998
+
+
+ before the key can be returned. When a request is made to the
+ given URI, the MIME content-type of the reply specifies the
+ encoding for the key in the reply. The key should not be
+ obtained until the user wishes to join the session to reduce
+ synchronisation of requests to the WWW server(s).
+
+ k=prompt
+ No key is included in this SDP description, but the session or
+ media stream referred to by this key field is encrypted. The
+ user should be prompted for the key when attempting to join the
+ session, and this user-supplied key should then be used to
+ decrypt the media streams.
+
+ Attributes
+
+ a=<attribute>
+ a=<attribute>:<value>
+
+ Attributes are the primary means for extending SDP. Attributes may
+ be defined to be used as "session-level" attributes, "media-level"
+ attributes, or both.
+
+ A media description may have any number of attributes ("a=" fields)
+ which are media specific. These are referred to as "media-level"
+ attributes and add information about the media stream. Attribute
+ fields can also be added before the first media field; these
+ "session-level" attributes convey additional information that applies
+ to the conference as a whole rather than to individual media; an
+ example might be the conference's floor control policy.
+
+ Attribute fields may be of two forms:
+
+ o property attributes. A property attribute is simply of the form
+ "a=<flag>". These are binary attributes, and the presence of the
+ attribute conveys that the attribute is a property of the session.
+ An example might be "a=recvonly".
+
+ o value attributes. A value attribute is of the form
+ "a=<attribute>:<value>". An example might be that a whiteboard
+ could have the value attribute "a=orient:landscape"
+
+ Attribute interpretation depends on the media tool being invoked.
+ Thus receivers of session descriptions should be configurable in
+ their interpretation of announcements in general and of attributes in
+ particular.
+
+ Attribute names must be in the US-ASCII subset of ISO-10646/UTF-8.
+
+
+
+
+Handley & Jacobson Standards Track [Page 18]
+
+RFC 2327 SDP April 1998
+
+
+ Attribute values are byte strings, and MAY use any byte value except
+ 0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default, attribute values
+ are to be interpreted as in ISO-10646 character set with UTF-8
+ encoding. Unlike other text fields, attribute values are NOT
+ normally affected by the `charset' attribute as this would make
+ comparisons against known values problematic. However, when an
+ attribute is defined, it can be defined to be charset-dependent, in
+ which case it's value should be interpreted in the session charset
+ rather than in ISO-10646.
+
+ Attributes that will be commonly used can be registered with IANA
+ (see Appendix B). Unregistered attributes should begin with "X-" to
+ prevent inadvertent collision with registered attributes. In either
+ case, if an attribute is received that is not understood, it should
+ simply be ignored by the receiver.
+
+ Media Announcements
+
+ m=<media> <port> <transport> <fmt list>
+
+ A session description may contain a number of media descriptions.
+ Each media description starts with an "m=" field, and is terminated
+ by either the next "m=" field or by the end of the session
+ description. A media field also has several sub-fields:
+
+ o The first sub-field is the media type. Currently defined media are
+ "audio", "video", "application", "data" and "control", though this
+ list may be extended as new communication modalities emerge (e.g.,
+ telepresense). The difference between "application" and "data" is
+ that the former is a media flow such as whiteboard information, and
+ the latter is bulk-data transfer such as multicasting of program
+ executables which will not typically be displayed to the user.
+ "control" is used to specify an additional conference control
+ channel for the session.
+
+ o The second sub-field is the transport port to which the media
+ stream will be sent. The meaning of the transport port depends on
+ the network being used as specified in the relevant "c" field and
+ on the transport protocol defined in the third sub-field. Other
+ ports used by the media application (such as the RTCP port, see
+ [2]) should be derived algorithmically from the base media port.
+
+ Note: For transports based on UDP, the value should be in the range
+ 1024 to 65535 inclusive. For RTP compliance it should be an even
+ number.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 19]
+
+RFC 2327 SDP April 1998
+
+
+ For applications where hierarchically encoded streams are being
+ sent to a unicast address, it may be necessary to specify multiple
+ transport ports. This is done using a similar notation to that
+ used for IP multicast addresses in the "c=" field:
+
+ m=<media> <port>/<number of ports> <transport> <fmt list>
+
+ In such a case, the ports used depend on the transport protocol.
+ For RTP, only the even ports are used for data and the
+ corresponding one-higher odd port is used for RTCP. For example:
+
+ m=video 49170/2 RTP/AVP 31
+
+ would specify that ports 49170 and 49171 form one RTP/RTCP pair and
+ 49172 and 49173 form the second RTP/RTCP pair. RTP/AVP is the
+ transport protocol and 31 is the format (see below).
+
+ It is illegal for both multiple addresses to be specified in the
+ "c=" field and for multiple ports to be specified in the "m=" field
+ in the same session description.
+
+ o The third sub-field is the transport protocol. The transport
+ protocol values are dependent on the address-type field in the "c="
+ fields. Thus a "c=" field of IP4 defines that the transport
+ protocol runs over IP4. For IP4, it is normally expected that most
+ media traffic will be carried as RTP over UDP. The following
+ transport protocols are preliminarily defined, but may be extended
+ through registration of new protocols with IANA:
+
+ - RTP/AVP - the IETF's Realtime Transport Protocol using the
+ Audio/Video profile carried over UDP.
+
+ - udp - User Datagram Protocol
+
+ If an application uses a single combined proprietary media format
+ and transport protocol over UDP, then simply specifying the
+ transport protocol as udp and using the format field to distinguish
+ the combined protocol is recommended. If a transport protocol is
+ used over UDP to carry several distinct media types that need to be
+ distinguished by a session directory, then specifying the transport
+ protocol and media format separately is necessary. RTP is an
+ example of a transport-protocol that carries multiple payload
+ formats that must be distinguished by the session directory for it
+ to know how to start appropriate tools, relays, mixers or
+ recorders.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 20]
+
+RFC 2327 SDP April 1998
+
+
+ The main reason to specify the transport-protocol in addition to
+ the media format is that the same standard media formats may be
+ carried over different transport protocols even when the network
+ protocol is the same - a historical example is vat PCM audio and
+ RTP PCM audio. In addition, relays and monitoring tools that are
+ transport-protocol-specific but format-independent are possible.
+
+ For RTP media streams operating under the RTP Audio/Video Profile
+ [3], the protocol field is "RTP/AVP". Should other RTP profiles be
+ defined in the future, their profiles will be specified in the same
+ way. For example, the protocol field "RTP/XYZ" would specify RTP
+ operating under a profile whose short name is "XYZ".
+
+ o The fourth and subsequent sub-fields are media formats. For audio
+ and video, these will normally be a media payload type as defined
+ in the RTP Audio/Video Profile.
+
+ When a list of payload formats is given, this implies that all of
+ these formats may be used in the session, but the first of these
+ formats is the default format for the session.
+
+ For media whose transport protocol is not RTP or UDP the format
+ field is protocol specific. Such formats should be defined in an
+ additional specification document.
+
+ For media whose transport protocol is RTP, SDP can be used to
+ provide a dynamic binding of media encoding to RTP payload type.
+ The encoding names in the RTP AV Profile do not specify unique
+ audio encodings (in terms of clock rate and number of audio
+ channels), and so they are not used directly in SDP format fields.
+ Instead, the payload type number should be used to specify the
+ format for static payload types and the payload type number along
+ with additional encoding information should be used for dynamically
+ allocated payload types.
+
+ An example of a static payload type is u-law PCM coded single
+ channel audio sampled at 8KHz. This is completely defined in the
+ RTP Audio/Video profile as payload type 0, so the media field for
+ such a stream sent to UDP port 49232 is:
+
+ m=video 49232 RTP/AVP 0
+
+ An example of a dynamic payload type is 16 bit linear encoded
+ stereo audio sampled at 16KHz. If we wish to use dynamic RTP/AVP
+ payload type 98 for such a stream, additional information is
+ required to decode it:
+
+ m=video 49232 RTP/AVP 98
+
+
+
+Handley & Jacobson Standards Track [Page 21]
+
+RFC 2327 SDP April 1998
+
+
+ a=rtpmap:98 L16/16000/2
+
+ The general form of an rtpmap attribute is:
+
+ a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding
+ parameters>]
+
+ For audio streams, <encoding parameters> may specify the number of
+ audio channels. This parameter may be omitted if the number of
+ channels is one provided no additional parameters are needed. For
+ video streams, no encoding parameters are currently specified.
+
+ Additional parameters may be defined in the future, but
+ codecspecific parameters should not be added. Parameters added to
+ an rtpmap attribute should only be those required for a session
+ directory to make the choice of appropriate media too to
+ participate in a session. Codec-specific parameters should be
+ added in other attributes.
+
+ Up to one rtpmap attribute can be defined for each media format
+ specified. Thus we might have:
+
+ m=audio 49230 RTP/AVP 96 97 98
+ a=rtpmap:96 L8/8000
+ a=rtpmap:97 L16/8000
+ a=rtpmap:98 L16/11025/2
+
+ RTP profiles that specify the use of dynamic payload types must
+ define the set of valid encoding names and/or a means to register
+ encoding names if that profile is to be used with SDP.
+
+ Experimental encoding formats can also be specified using rtpmap.
+ RTP formats that are not registered as standard format names must
+ be preceded by "X-". Thus a new experimental redundant audio
+ stream called GSMLPC using dynamic payload type 99 could be
+ specified as:
+
+ m=video 49232 RTP/AVP 99
+ a=rtpmap:99 X-GSMLPC/8000
+
+ Such an experimental encoding requires that any site wishing to
+ receive the media stream has relevant configured state in its
+ session directory to know which tools are appropriate.
+
+ Note that RTP audio formats typically do not include information
+ about the number of samples per packet. If a non-default (as
+ defined in the RTP Audio/Video Profile) packetisation is required,
+ the "ptime" attribute is used as given below.
+
+
+
+Handley & Jacobson Standards Track [Page 22]
+
+RFC 2327 SDP April 1998
+
+
+ For more details on RTP audio and video formats, see [3].
+
+ o Formats for non-RTP media should be registered as MIME content
+ types as described in Appendix B. For example, the LBL whiteboard
+ application might be registered as MIME content-type application/wb
+ with encoding considerations specifying that it operates over UDP,
+ with no appropriate file format. In SDP this would then be
+ expressed using a combination of the "media" field and the "fmt"
+ field, as follows:
+
+ m=application 32416 udp wb
+
+ Suggested Attributes
+
+ The following attributes are suggested. Since application writers
+ may add new attributes as they are required, this list is not
+ exhaustive.
+
+ a=cat:<category>
+ This attribute gives the dot-separated hierarchical category of
+ the session. This is to enable a receiver to filter unwanted
+ sessions by category. It would probably have been a compulsory
+ separate field, except for its experimental nature at this time.
+ It is a session-level attribute, and is not dependent on charset.
+
+ a=keywds:<keywords>
+ Like the cat attribute, this is to assist identifying wanted
+ sessions at the receiver. This allows a receiver to select
+ interesting session based on keywords describing the purpose of
+ the session. It is a session-level attribute. It is a charset
+ dependent attribute, meaning that its value should be interpreted
+ in the charset specified for the session description if one is
+ specified, or by default in ISO 10646/UTF-8.
+
+ a=tool:<name and version of tool>
+ This gives the name and version number of the tool used to create
+ the session description. It is a session-level attribute, and is
+ not dependent on charset.
+
+ a=ptime:<packet time>
+ This gives the length of time in milliseconds represented by the
+ media in a packet. This is probably only meaningful for audio
+ data. It should not be necessary to know ptime to decode RTP or
+ vat audio, and it is intended as a recommendation for the
+ encoding/packetisation of audio. It is a media attribute, and is
+ not dependent on charset.
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 23]
+
+RFC 2327 SDP April 1998
+
+
+ a=recvonly
+ This specifies that the tools should be started in receive-only
+ mode where applicable. It can be either a session or media
+ attribute, and is not dependent on charset.
+
+ a=sendrecv
+ This specifies that the tools should be started in send and
+ receive mode. This is necessary for interactive conferences with
+ tools such as wb which defaults to receive only mode. It can be
+ either a session or media attribute, and is not dependent on
+ charset.
+
+ a=sendonly
+ This specifies that the tools should be started in send-only
+ mode. An example may be where a different unicast address is to
+ be used for a traffic destination than for a traffic source. In
+ such a case, two media descriptions may be use, one sendonly and
+ one recvonly. It can be either a session or media attribute, but
+ would normally only be used as a media attribute, and is not
+ dependent on charset.
+
+ a=orient:<whiteboard orientation>
+ Normally this is only used in a whiteboard media specification.
+ It specifies the orientation of a the whiteboard on the screen.
+ It is a media attribute. Permitted values are `portrait',
+ `landscape' and `seascape' (upside down landscape). It is not
+ dependent on charset
+
+ a=type:<conference type>
+ This specifies the type of the conference. Suggested values are
+ `broadcast', `meeting', `moderated', `test' and `H332'.
+ `recvonly' should be the default for `type:broadcast' sessions,
+ `type:meeting' should imply `sendrecv' and `type:moderated'
+ should indicate the use of a floor control tool and that the
+ media tools are started so as to "mute" new sites joining the
+ conference.
+
+ Specifying the attribute type:H332 indicates that this loosely
+ coupled session is part of a H.332 session as defined in the ITU
+ H.332 specification [10]. Media tools should be started
+ `recvonly'.
+
+ Specifying the attribute type:test is suggested as a hint that,
+ unless explicitly requested otherwise, receivers can safely avoid
+ displaying this session description to users.
+
+ The type attribute is a session-level attribute, and is not
+ dependent on charset.
+
+
+
+Handley & Jacobson Standards Track [Page 24]
+
+RFC 2327 SDP April 1998
+
+
+ a=charset:<character set>
+ This specifies the character set to be used to display the
+ session name and information data. By default, the ISO-10646
+ character set in UTF-8 encoding is used. If a more compact
+ representation is required, other character sets may be used such
+ as ISO-8859-1 for Northern European languages. In particular,
+ the ISO 8859-1 is specified with the following SDP attribute:
+
+ a=charset:ISO-8859-1
+
+ This is a session-level attribute; if this attribute is present,
+ it must be before the first media field. The charset specified
+ MUST be one of those registered with IANA, such as ISO-8859-1.
+ The character set identifier is a US-ASCII string and MUST be
+ compared against the IANA identifiers using a case-insensitive
+ comparison. If the identifier is not recognised or not
+ supported, all strings that are affected by it SHOULD be regarded
+ as byte strings.
+
+ Note that a character set specified MUST still prohibit the use
+ of bytes 0x00 (Nul), 0x0A (LF) and 0x0d (CR). Character sets
+ requiring the use of these characters MUST define a quoting
+ mechanism that prevents these bytes appearing within text fields.
+
+ a=sdplang:<language tag>
+ This can be a session level attribute or a media level attribute.
+ As a session level attribute, it specifies the language for the
+ session description. As a media level attribute, it specifies
+ the language for any media-level SDP information field associated
+ with that media. Multiple sdplang attributes can be provided
+ either at session or media level if multiple languages in the
+ session description or media use multiple languages, in which
+ case the order of the attributes indicates the order of
+ importance of the various languages in the session or media from
+ most important to least important.
+
+ In general, sending session descriptions consisting of multiple
+ languages should be discouraged. Instead, multiple descriptions
+ should be sent describing the session, one in each language.
+ However this is not possible with all transport mechanisms, and
+ so multiple sdplang attributes are allowed although not
+ recommended.
+
+ The sdplang attribute value must be a single RFC 1766 language
+ tag in US-ASCII. It is not dependent on the charset attribute.
+ An sdplang attribute SHOULD be specified when a session is of
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 25]
+
+RFC 2327 SDP April 1998
+
+
+ sufficient scope to cross geographic boundaries where the
+ language of recipients cannot be assumed, or where the session is
+ in a different language from the locally assumed norm.
+
+ a=lang:<language tag>
+ This can be a session level attribute or a media level attribute.
+ As a session level attribute, it specifies the default language
+ for the session being described. As a media level attribute, it
+ specifies the language for that media, overriding any session-
+ level language specified. Multiple lang attributes can be
+ provided either at session or media level if multiple languages
+ if the session description or media use multiple languages, in
+ which case the order of the attributes indicates the order of
+ importance of the various languages in the session or media from
+ most important to least important.
+
+ The lang attribute value must be a single RFC 1766 language tag
+ in US-ASCII. It is not dependent on the charset attribute. A
+ lang attribute SHOULD be specified when a session is of
+ sufficient scope to cross geographic boundaries where the
+ language of recipients cannot be assumed, or where the session is
+ in a different language from the locally assumed norm.
+
+ a=framerate:<frame rate>
+ This gives the maximum video frame rate in frames/sec. It is
+ intended as a recommendation for the encoding of video data.
+ Decimal representations of fractional values using the notation
+ "<integer>.<fraction>" are allowed. It is a media attribute, is
+ only defined for video media, and is not dependent on charset.
+
+ a=quality:<quality>
+ This gives a suggestion for the quality of the encoding as an
+ integer value.
+
+ The intention of the quality attribute for video is to specify a
+ non-default trade-off between frame-rate and still-image quality.
+ For video, the value in the range 0 to 10, with the following
+ suggested meaning:
+
+ 10 - the best still-image quality the compression scheme can
+ give.
+
+ 5 - the default behaviour given no quality suggestion.
+
+ 0 - the worst still-image quality the codec designer thinks is
+ still usable.
+
+ It is a media attribute, and is not dependent on charset.
+
+
+
+Handley & Jacobson Standards Track [Page 26]
+
+RFC 2327 SDP April 1998
+
+
+ a=fmtp:<format> <format specific parameters>
+ This attribute allows parameters that are specific to a
+ particular format to be conveyed in a way that SDP doesn't have
+ to understand them. The format must be one of the formats
+ specified for the media. Format-specific parameters may be any
+ set of parameters required to be conveyed by SDP and given
+ unchanged to the media tool that will use this format.
+
+ It is a media attribute, and is not dependent on charset.
+
+6.1. Communicating Conference Control Policy
+
+ There is some debate over the way conference control policy should be
+ communicated. In general, the authors believe that an implicit
+ declarative style of specifying conference control is desirable where
+ possible.
+
+ A simple declarative style uses a single conference attribute field
+ before the first media field, possibly supplemented by properties
+ such as `recvonly' for some of the media tools. This conference
+ attribute conveys the conference control policy. An example might be:
+
+ a=type:moderated
+
+ In some cases, however, it is possible that this may be insufficient
+ to communicate the details of an unusual conference control policy.
+ If this is the case, then a conference attribute specifying external
+ control might be set, and then one or more "media" fields might be
+ used to specify the conference control tools and configuration data
+ for those tools. An example is an ITU H.332 session:
+
+ c=IN IP4 224.5.6.7
+ a=type:H332
+ m=audio 49230 RTP/AVP 0
+ m=video 49232 RTP/AVP 31
+ m=application 12349 udp wb
+ m=control 49234 H323 mc
+ c=IN IP4 134.134.157.81
+
+ In this example, a general conference attribute (type:H332) is
+ specified stating that conference control will be provided by an
+ external H.332 tool, and a contact addresses for the H.323 session
+ multipoint controller is given.
+
+ In this document, only the declarative style of conference control
+ declaration is specified. Other forms of conference control should
+ specify an appropriate type attribute, and should define the
+ implications this has for control media.
+
+
+
+Handley & Jacobson Standards Track [Page 27]
+
+RFC 2327 SDP April 1998
+
+
+7. Security Considerations
+
+ SDP is a session description format that describes multimedia
+ sessions. A session description should not be trusted unless it has
+ been obtained by an authenticated transport protocol from a trusted
+ source. Many different transport protocols may be used to distribute
+ session description, and the nature of the authentication will differ
+ from transport to transport.
+
+ One transport that will frequently be used to distribute session
+ descriptions is the Session Announcement Protocol (SAP). SAP
+ provides both encryption and authentication mechanisms but due to the
+ nature of session announcements it is likely that there are many
+ occasions where the originator of a session announcement cannot be
+ authenticated because they are previously unknown to the receiver of
+ the announcement and because no common public key infrastructure is
+ available.
+
+ On receiving a session description over an unauthenticated transport
+ mechanism or from an untrusted party, software parsing the session
+ should take a few precautions. Session description contain
+ information required to start software on the receivers system.
+ Software that parses a session description MUST not be able to start
+ other software except that which is specifically configured as
+ appropriate software to participate in multimedia sessions. It is
+ normally considered INAPPROPRIATE for software parsing a session
+ description to start, on a user's system, software that is
+ appropriate to participate in multimedia sessions, without the user
+ first being informed that such software will be started and giving
+ their consent. Thus a session description arriving by session
+ announcement, email, session invitation, or WWW page SHOULD not
+ deliver the user into an {it interactive} multimedia session without
+ the user being aware that this will happen. As it is not always
+ simple to tell whether a session is interactive or not, applications
+ that are unsure should assume sessions are interactive.
+
+ In this specification, there are no attributes which would allow the
+ recipient of a session description to be informed to start multimedia
+ tools in a mode where they default to transmitting. Under some
+ circumstances it might be appropriate to define such attributes. If
+ this is done an application parsing a session description containing
+ such attributes SHOULD either ignore them, or inform the user that
+ joining this session will result in the automatic transmission of
+ multimedia data. The default behaviour for an unknown attribute is
+ to ignore it.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 28]
+
+RFC 2327 SDP April 1998
+
+
+ Session descriptions may be parsed at intermediate systems such as
+ firewalls for the purposes of opening a hole in the firewall to allow
+ the participation in multimedia sessions. It is considered
+ INAPPROPRIATE for a firewall to open such holes for unicast data
+ streams unless the session description comes in a request from inside
+ the firewall.
+
+ For multicast sessions, it is likely that local administrators will
+ apply their own policies, but the exclusive use of "local" or "site-
+ local" administrative scope within the firewall and the refusal of
+ the firewall to open a hole for such scopes will provide separation
+ of global multicast sessions from local ones.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 29]
+
+RFC 2327 SDP April 1998
+
+
+Appendix A: SDP Grammar
+
+ This appendix provides an Augmented BNF grammar for SDP. ABNF is
+ defined in RFC 2234.
+
+
+ announcement = proto-version
+ origin-field
+ session-name-field
+ information-field
+ uri-field
+ email-fields
+ phone-fields
+ connection-field
+ bandwidth-fields
+ time-fields
+ key-field
+ attribute-fields
+ media-descriptions
+
+ proto-version = "v=" 1*DIGIT CRLF
+ ;this memo describes version 0
+
+ origin-field = "o=" username space
+ sess-id space sess-version space
+ nettype space addrtype space
+ addr CRLF
+
+ session-name-field = "s=" text CRLF
+
+ information-field = ["i=" text CRLF]
+
+ uri-field = ["u=" uri CRLF]
+
+ email-fields = *("e=" email-address CRLF)
+
+ phone-fields = *("p=" phone-number CRLF)
+
+
+ connection-field = ["c=" nettype space addrtype space
+ connection-address CRLF]
+ ;a connection field must be present
+ ;in every media description or at the
+ ;session-level
+
+
+ bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
+
+
+
+
+Handley & Jacobson Standards Track [Page 30]
+
+RFC 2327 SDP April 1998
+
+
+ time-fields = 1*( "t=" start-time space stop-time
+ *(CRLF repeat-fields) CRLF)
+ [zone-adjustments CRLF]
+
+
+ repeat-fields = "r=" repeat-interval space typed-time
+ 1*(space typed-time)
+
+
+ zone-adjustments = time space ["-"] typed-time
+ *(space time space ["-"] typed-time)
+
+
+ key-field = ["k=" key-type CRLF]
+
+
+ key-type = "prompt" |
+ "clear:" key-data |
+ "base64:" key-data |
+ "uri:" uri
+
+
+ key-data = email-safe | "~" | "
+
+
+ attribute-fields = *("a=" attribute CRLF)
+
+
+ media-descriptions = *( media-field
+ information-field
+ *(connection-field)
+ bandwidth-fields
+ key-field
+ attribute-fields )
+
+
+ media-field = "m=" media space port ["/" integer]
+ space proto 1*(space fmt) CRLF
+
+
+ media = 1*(alpha-numeric)
+ ;typically "audio", "video", "application"
+ ;or "data"
+
+ fmt = 1*(alpha-numeric)
+ ;typically an RTP payload type for audio
+ ;and video media
+
+
+
+
+Handley & Jacobson Standards Track [Page 31]
+
+RFC 2327 SDP April 1998
+
+
+ proto = 1*(alpha-numeric)
+ ;typically "RTP/AVP" or "udp" for IP4
+
+
+ port = 1*(DIGIT)
+ ;should in the range "1024" to "65535" inclusive
+ ;for UDP based media
+
+
+ attribute = (att-field ":" att-value) | att-field
+
+
+ att-field = 1*(alpha-numeric)
+
+
+ att-value = byte-string
+
+
+ sess-id = 1*(DIGIT)
+ ;should be unique for this originating username/host
+
+
+ sess-version = 1*(DIGIT)
+ ;0 is a new session
+
+
+ connection-address = multicast-address
+ | addr
+
+
+ multicast-address = 3*(decimal-uchar ".") decimal-uchar "/" ttl
+ [ "/" integer ]
+ ;multicast addresses may be in the range
+ ;224.0.0.0 to 239.255.255.255
+
+ ttl = decimal-uchar
+
+ start-time = time | "0"
+
+ stop-time = time | "0"
+
+ time = POS-DIGIT 9*(DIGIT)
+ ;sufficient for 2 more centuries
+
+
+ repeat-interval = typed-time
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 32]
+
+RFC 2327 SDP April 1998
+
+
+ typed-time = 1*(DIGIT) [fixed-len-time-unit]
+
+
+ fixed-len-time-unit = "d" | "h" | "m" | "s"
+
+
+ bwtype = 1*(alpha-numeric)
+
+ bandwidth = 1*(DIGIT)
+
+
+ username = safe
+ ;pretty wide definition, but doesn't include space
+
+
+ email-address = email | email "(" email-safe ")" |
+ email-safe "<" email ">"
+
+
+ email = ;defined in RFC822
+
+
+ uri= ;defined in RFC1630
+
+
+ phone-number = phone | phone "(" email-safe ")" |
+ email-safe "<" phone ">"
+
+
+ phone = "+" POS-DIGIT 1*(space | "-" | DIGIT)
+ ;there must be a space or hyphen between the
+ ;international code and the rest of the number.
+
+
+ nettype = "IN"
+ ;list to be extended
+
+
+ addrtype = "IP4" | "IP6"
+ ;list to be extended
+
+
+ addr = FQDN | unicast-address
+
+
+ FQDN = 4*(alpha-numeric|"-"|".")
+ ;fully qualified domain name as specified in RFC1035
+
+
+
+
+Handley & Jacobson Standards Track [Page 33]
+
+RFC 2327 SDP April 1998
+
+
+ unicast-address = IP4-address | IP6-address
+
+
+ IP4-address = b1 "." decimal-uchar "." decimal-uchar "." b4
+ b1 = decimal-uchar
+ ;less than "224"; not "0" or "127"
+ b4 = decimal-uchar
+ ;not "0"
+
+ IP6-address = ;to be defined
+
+
+ text = byte-string
+ ;default is to interpret this as IS0-10646 UTF8
+ ;ISO 8859-1 requires a "a=charset:ISO-8859-1"
+ ;session-level attribute to be used
+
+
+ byte-string = 1*(0x01..0x09|0x0b|0x0c|0x0e..0xff)
+ ;any byte except NUL, CR or LF
+
+
+ decimal-uchar = DIGIT
+ | POS-DIGIT DIGIT
+ | ("1" 2*(DIGIT))
+ | ("2" ("0"|"1"|"2"|"3"|"4") DIGIT)
+ | ("2" "5" ("0"|"1"|"2"|"3"|"4"|"5"))
+
+
+ integer = POS-DIGIT *(DIGIT)
+
+
+ alpha-numeric = ALPHA | DIGIT
+
+
+ DIGIT = "0" | POS-DIGIT
+
+
+ POS-DIGIT = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+
+
+ ALPHA = "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"|"i"|"j"|"k"|
+ "l"|"m"|"n"|"o "|"p"|"q"|"r"|"s"|"t"|"u"|"v"|
+ "w"|"x"|"y"|"z"|"A"|"B"|"C "|"D"|"E"|"F"|"G"|
+ "H"|"I"|"J"|"K"|"L"|"M"|"N"|"O"|"P"|" Q"|"R"|
+ "S"|"T"|"U"|"V"|"W"|"X"|"Y"|"Z"
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 34]
+
+RFC 2327 SDP April 1998
+
+
+ email-safe = safe | space | tab
+
+
+ safe = alpha-numeric |
+ "'" | "'" | "-" | "." | "/" | ":" | "?" | """ |
+ "#" | "$" | "&" | "*" | ";" | "=" | "@" | "[" |
+ "]" | "^" | "_" | "`" | "{" | "|" | "}" | "+" |
+ "~" | "
+
+
+ space = %d32
+ tab = %d9
+ CRLF = %d13.10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 35]
+
+RFC 2327 SDP April 1998
+
+
+Appendix B: Guidelines for registering SDP names with IANA
+
+ There are seven field names that may be registered with IANA. Using
+ the terminology in the SDP specification BNF, they are "media",
+ "proto", "fmt", "att-field", "bwtype", "nettype" and "addrtype".
+
+ "media" (eg, audio, video, application, data).
+
+ Packetized media types, such as those used by RTP, share the
+ namespace used by media types registry [RFC 2048] (i.e. "MIME
+ types"). The list of valid media names is the set of top-level
+ MIME content types. The set of media is intended to be small and
+ not to be extended except under rare circumstances. (The MIME
+ subtype corresponds to the "fmt" parameter below).
+
+ "proto"
+
+ In general this should be an IETF standards-track transport
+ protocol identifier such as RTP/AVP (rfc 1889 under the rfc 1890
+ profile).
+
+ However, people will want to invent their own proprietary
+ transport protocols. Some of these should be registered as a
+ "fmt" using "udp" as the protocol and some of which probably
+ can't be.
+
+ Where the protocol and the application are intimately linked,
+ such as with the LBL whiteboard wb which used a proprietary and
+ special purpose protocol over UDP, the protocol name should be
+ "udp" and the format name that should be registered is "wb". The
+ rules for formats (see below) apply to such registrations.
+
+ Where the proprietary transport protocol really carries many
+ different data formats, it is possible to register a new protocol
+ name with IANA. In such a case, an RFC MUST be produced
+ describing the protocol and referenced in the registration. Such
+ an RFC MAY be informational, although it is preferable if it is
+ standards-track.
+
+ "fmt"
+
+ The format namespace is dependent on the context of the "proto"
+ field, so a format cannot be registered without specifying one or
+ more transport protocols that it applies to.
+
+ Formats cover all the possible encodings that might want to be
+ transported in a multimedia session.
+
+
+
+
+Handley & Jacobson Standards Track [Page 36]
+
+RFC 2327 SDP April 1998
+
+
+ For RTP formats that have been assigned static payload types, the
+ payload type number is used. For RTP formats using a dynamic
+ payload type number, the dynamic payload type number is given as
+ the format and an additional "rtpmap" attribute specifies the
+ format and parameters.
+
+ For non-RTP formats, any unregistered format name may be
+ registered through the MIME-type registration process [RFC 2048].
+ The type given here is the MIME subtype only (the top-level MIME
+ content type is specified by the media parameter). The MIME type
+ registration SHOULD reference a standards-track RFC which
+ describes the transport protocol for this media type. If there
+ is an existing MIME type for this format, the MIME registration
+ should be augmented to reference the transport specification for
+ this media type. If there is not an existing MIME type for this
+ format, and there exists no appropriate file format, this should
+ be noted in the encoding considerations as "no appropriate file
+ format".
+
+ "att-field" (Attribute names)
+
+ Attribute field names MAY be registered with IANA, although this
+ is not compulsory, and unknown attributes are simply ignored.
+
+ When an attribute is registered, it must be accompanied by a
+ brief specification stating the following:
+
+ o contact name, email address and telephone number
+
+ o attribute-name (as it will appear in SDP)
+
+ o long-form attribute name in English
+
+ o type of attribute (session level, media level, or both)
+
+ o whether the attribute value is subject to the charset
+ attribute.
+
+ o a one paragraph explanation of the purpose of the attribute.
+
+ o a specification of appropriate attribute values for this
+ attribute.
+
+ IANA will not sanity check such attribute registrations except to
+ ensure that they do not clash with existing registrations.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 37]
+
+RFC 2327 SDP April 1998
+
+
+ Although the above is the minimum that IANA will accept, if the
+ attribute is expected to see widespread use and interoperability
+ is an issue, authors are encouraged to produce a standards-track
+ RFC that specifies the attribute more precisely.
+
+ Submitters of registrations should ensure that the specification
+ is in the spirit of SDP attributes, most notably that the
+ attribute is platform independent in the sense that it makes no
+ implicit assumptions about operating systems and does not name
+ specific pieces of software in a manner that might inhibit
+ interoperability.
+
+ "bwtype" (bandwidth specifiers)
+
+ A proliferation of bandwidth specifiers is strongly discouraged.
+
+ New bandwidth specifiers may be registered with IANA. The
+ submission MUST reference a standards-track RFC specifying the
+ semantics of the bandwidth specifier precisely, and indicating
+ when it should be used, and why the existing registered bandwidth
+ specifiers do not suffice.
+
+ "nettype" (Network Type)
+
+ New network types may be registered with IANA if SDP needs to be
+ used in the context of non-internet environments. Whilst these
+ are not normally the preserve of IANA, there may be circumstances
+ when an Internet application needs to interoperate with a non-
+ internet application, such as when gatewaying an internet
+ telephony call into the PSTN. The number of network types should
+ be small and should be rarely extended. A new network type
+ cannot be registered without registering at least one address
+ type to be used with that network type. A new network type
+ registration MUST reference an RFC which gives details of the
+ network type and address type and specifies how and when they
+ would be used. Such an RFC MAY be Informational.
+
+ "addrtype" (Address Type)
+
+ New address types may be registered with IANA. An address type
+ is only meaningful in the context of a network type, and any
+ registration of an address type MUST specify a registered network
+ type, or be submitted along with a network type registration. A
+ new address type registration MUST reference an RFC giving
+ details of the syntax of the address type. Such an RFC MAY be
+ Informational. Address types are not expected to be registered
+ frequently.
+
+
+
+
+Handley & Jacobson Standards Track [Page 38]
+
+RFC 2327 SDP April 1998
+
+
+ Registration Procedure
+
+ To register a name the above guidelines should be followed regarding
+ the required level of documentation that is required. The
+ registration itself should be sent to IANA. Attribute registrations
+ should include the information given above. Other registrations
+ should include the following additional information:
+
+ o contact name, email address and telephone number
+
+ o name being registered (as it will appear in SDP)
+
+ o long-form name in English
+
+ o type of name ("media", "proto", "fmt", "bwtype", "nettype", or
+ "addrtype")
+
+ o a one paragraph explanation of the purpose of the registered name.
+
+ o a reference to the specification (eg RFC number) of the registered
+ name.
+
+ IANA may refer any registration to the IESG or to any appropriate
+ IETF working group for review, and may request revisions to be made
+ before a registration will be made.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 39]
+
+RFC 2327 SDP April 1998
+
+
+Appendix C: Authors' Addresses
+
+ Mark Handley
+ Information Sciences Institute
+ c/o MIT Laboratory for Computer Science
+ 545 Technology Square
+ Cambridge, MA 02139
+ United States
+ electronic mail: [email protected]
+
+ Van Jacobson
+ MS 46a-1121
+ Lawrence Berkeley Laboratory
+ Berkeley, CA 94720
+ United States
+ electronic mail: [email protected]
+
+Acknowledgments
+
+ Many people in the IETF MMUSIC working group have made comments and
+ suggestions contributing to this document. In particular, we would
+ like to thank Eve Schooler, Steve Casner, Bill Fenner, Allison
+ Mankin, Ross Finlayson, Peter Parnes, Joerg Ott, Carsten Bormann, Rob
+ Lanphier and Steve Hanna.
+
+References
+
+ [1] Mills, D., "Network Time Protocol (version 3) specification and
+ implementation", RFC 1305, March 1992.
+
+ [2] Schulzrinne, H., Casner, S., Frederick, R. and V. Jacobson, "RTP:
+ A Transport Protocol for Real-Time Applications", RFC 1889, January
+ 1996.
+
+ [3] Schulzrinne, H., "RTP Profile for Audio and Video Conferences
+ with Minimal Control", RFC 1890, January 1996
+
+ [4] Handley, M., "SAP - Session Announcement Protocol", Work in
+ Progress.
+
+ [5] V. Jacobson, S. McCanne, "vat - X11-based audio teleconferencing
+ tool" vat manual page, Lawrence Berkeley Laboratory, 1994.
+
+ [6] The Unicode Consortium, "The Unicode Standard -- Version 2.0",
+ Addison-Wesley, 1996.
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 40]
+
+RFC 2327 SDP April 1998
+
+
+ [7] ISO/IEC 10646-1:1993. International Standard -- Information
+ technol- ogy -- Universal Multiple-Octet Coded Character Set (UCS) --
+ Part 1: Architecture and Basic Multilingual Plane. Five amendments
+ and a techn- ical corrigendum have been published up to now. UTF-8
+ is described in Annex R, published as Amendment 2.
+
+ [8] Goldsmith, D., and M. Davis, "Using Unicode with MIME", RFC 1641,
+ July 1994.
+
+ [9] Yergeau, F., "UTF-8, a transformation format of Unicode and ISO
+ 10646", RFC 2044, October 1996.
+
+ [10] ITU-T Recommendation H.332 (1998): "Multimedia Terminal for
+ Receiving Internet-based H.323 Conferences", ITU, Geneva.
+
+ [11] Handley, M., Schooler, E., and H. Schulzrinne, "Session
+ Initiation Protocol (SIP)", Work in Progress.
+
+ [12] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming
+ Protocol (RTSP)", RFC 2326, April 1998.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 41]
+
+RFC 2327 SDP April 1998
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley & Jacobson Standards Track [Page 42]
+
diff --git a/lib/megaco/doc/standard/rfc3266.txt b/lib/megaco/doc/standard/rfc3266.txt
new file mode 100644
index 0000000000..f047f12a1f
--- /dev/null
+++ b/lib/megaco/doc/standard/rfc3266.txt
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group S. Olson
+Request for Comments: 3266 Microsoft
+Updates: 2327 G. Camarillo
+Category: Standards Track Ericsson
+ A. B. Roach
+ dynamicsoft
+ June 2002
+
+
+ Support for IPv6 in Session Description Protocol (SDP)
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document describes the use of Internet Protocol Version 6 (IPv6)
+ addresses in conjunction with the Session Description Protocol (SDP).
+ Specifically, this document clarifies existing text in SDP with
+ regards to the syntax of IPv6 addresses.
+
+1. Introduction
+
+ SDP is intended for describing multimedia sessions for the purposes
+ of session announcement, session invitation, and other forms of
+ multimedia session initiation. It is a text format description that
+ provides many details of a multimedia session including: the
+ originator of the session, a URL related to the session, the
+ connection address for the session media(s), and optional attributes
+ for the session media(s). Each of these pieces of information may
+ involve one or more IPv6 addresses. The ABNF for IP addresses in SDP
+ currently leaves the syntax for IPv6 addresses undefined. This
+ document attempts to complete the ABNF to include IPv6 addresses.
+
+ Accordingly, the address type "IP6" indicating an IPv6 address,
+ should be allowed in the connection field, "c=", of the SDP. The
+ ABNF already reflects this, though the "Connection Data" text under
+ section 6 of RFC 2328 currently only defines the "IP4" address type.
+
+
+
+
+Olson, et. al. Standards Track [Page 1]
+
+RFC 3266 Support for IPv6 in Session Description Protocol June 2002
+
+
+2. Terminology
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [5].
+
+3. Syntax
+
+ RFC 2373 [1] gives an ABNF for the text representation of IPv6
+ addresses in Appendix B. RFC 2732 [3] covers the text representation
+ of IPv6 addresses when used within a URL. Using the ABNF described
+ in these documents, the following updated ABNF for SDP is proposed.
+
+ uri = ; defined in RFC1630 and RFC2732
+
+ multicast-address = IP4-multicast / IP6-multicast
+
+ IP4-multicast = m1 3*( "." decimal-uchar )
+ "/" ttl [ "/" integer ]
+ ; IPv4 multicast addresses may be in the
+ ; range 224.0.0.0 to 239.255.255.255
+
+ m1 = ("22" ("4"/"5"/"6"/"7"/"8"/"9")) /
+ ("23" DIGIT ))
+
+ IP6-multicast = hexpart
+ ; IPv6 address starting with FF
+
+ addr = FQDN / unicast-address
+
+ FQDN = 4*(alpha-numeric/"-"/".")
+ ; fully qualified domain name as specified
+ ; in RFC1035
+ unicast-address = IP4-address / IP6-address
+
+ IP4-address = b1 3*("." decimal-uchar) / "0.0.0.0"
+
+ b1 = decimal-uchar
+ ; less than "224"; not "0" or "127"
+
+ ; The following is from RFC2373 Appendix B. It is a direct copy.
+ IP6-address = hexpart [ ":" IP4-address ]
+
+ hexpart = hexseq / hexseq "::" [ hexseq ] /
+ "::" [ hexseq ]
+
+
+
+
+
+
+Olson, et. al. Standards Track [Page 2]
+
+RFC 3266 Support for IPv6 in Session Description Protocol June 2002
+
+
+ hexseq = hex4 *( ":" hex4)
+
+ hex4 = 1*4HEXDIG
+
+4. Example SDP description with IPv6 addresses
+
+ The following is an example SDP description using the above ABNF for
+ IPv6 addresses. In particular, the origin and connection fields
+ contain IPv6 addresses.
+
+ v=0
+ o=nasa1 971731711378798081 0 IN IP6 2201:056D::112E:144A:1E24
+ s=(Almost) live video feed from Mars-II satellite
+ p=+1 713 555 1234
+ c=IN IP6 FF1E:03AD::7F2E:172A:1E24
+ t=3338481189 3370017201
+ m=audio 6000 RTP/AVP 2
+ a=rtpmap:2 G726-32/8000
+ m=video 6024 RTP/AVP 107
+ a=rtpmap:107 H263-1998/90000
+
+5. Note for implementors
+
+ An implementation may receive an SDP session description with an IPv6
+ address whose format [1] is internally that of an IPv4 mapped
+ address. Note that such an address is actually the address of an
+ IPv4-only node, and implementors are warned to interpret IPv4 mapped
+ addresses as equivalent to IP4.
+
+6. IANA Considerations
+
+ This document updates the definition of the IP6 addrtype parameter
+ found in RFC 2327.
+
+7. Security Considerations
+
+ No additional considerations above what is stated in section 7 of RFC
+ 2327.
+
+8. References
+
+ [1] Hinden, R. and S. Deering, "IP Version 6 Addressing
+ Architecture", RFC 2373, July 1998.
+
+ [2] Handley, M. and V. Jacobson, "SDP: Session Description
+ Protocol", RFC 2327, April 1998.
+
+
+
+
+
+Olson, et. al. Standards Track [Page 3]
+
+RFC 3266 Support for IPv6 in Session Description Protocol June 2002
+
+
+ [3] Hinden, R., Carpenter, B. and L. Masinter, "Format for Literal
+ IPv6 Addresses in URL's", RFC 2732, December 1999.
+
+ [4] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [5] Bradner, S., "Key words for Use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+9. Authors' Addresses
+
+ Sean Olson
+ Microsoft
+ One Microsoft Way
+ Redmond, WA 98052
+ USA
+
+
+
+ Gonzalo Camarillo
+ Ericsson
+ Advanced Signalling Research Lab.
+ FIN-02420 Jorvas
+ Finland
+
+ Phone: +358 9 299 3371
+ Fax: +358 9 299 3118
+
+
+ Adam Roach
+ dynamicsoft
+ 5100 Tennyson Parkway
+ Suite 1200
+ Plano, TX 75024
+ USA
+
+ Voice: <sip:[email protected]>
+
+
+
+
+
+
+
+
+
+
+
+Olson, et. al. Standards Track [Page 4]
+
+RFC 3266 Support for IPv6 in Session Description Protocol June 2002
+
+
+10. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Olson, et. al. Standards Track [Page 5]
+
diff --git a/lib/megaco/doc/standard/rfc3525.txt b/lib/megaco/doc/standard/rfc3525.txt
new file mode 100644
index 0000000000..80663cc2cd
--- /dev/null
+++ b/lib/megaco/doc/standard/rfc3525.txt
@@ -0,0 +1,11931 @@
+
+
+
+
+
+
+Network Working Group C. Groves
+Request for Comments: 3525 M. Pantaleo
+Obsoletes: 3015 LM Ericsson
+Category: Standards Track T. Anderson
+ Consultant
+ T. Taylor
+ Nortel Networks
+ Editors
+ June 2003
+
+
+ Gateway Control Protocol Version 1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ This document defines the protocol used between elements of a
+ physically decomposed multimedia gateway, i.e., a Media Gateway and a
+ Media Gateway Controller. The protocol presented in this document
+ meets the requirements for a media gateway control protocol as
+ presented in RFC 2805.
+
+ This document replaces RFC 3015. It is the result of continued
+ cooperation between the IETF Megaco Working Group and ITU-T Study
+ Group 16. It incorporates the original text of RFC 3015, modified by
+ corrections and clarifications discussed on the Megaco
+ E-mail list and incorporated into the Study Group 16 Implementor's
+ Guide for Recommendation H.248. The present version of this document
+ underwent ITU-T Last Call as Recommendation H.248 Amendment 1.
+ Because of ITU-T renumbering, it was published by the ITU-T as
+ Recommendation H.248.1 (03/2002), Gateway Control Protocol Version 1.
+
+ Users of this specification are advised to consult the H.248 Sub-
+ series Implementors' Guide at http://www.itu.int/itudoc/itu-
+ t/com16/implgd for additional corrections and clarifications.
+
+
+
+
+
+Groves, et al. Standards Track [Page 1]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+Conventions used in this document
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+Table of Contents
+
+ 1 Scope.........................................................5
+ 1.1 Changes From RFC 3015.....................................5
+ 1.2 Differences From ITU-T Recommendation H.248.1 (03/2002)...5
+ 2 References....................................................6
+ 2.1 Normative references......................................6
+ 2.2 Informative references....................................9
+ 3 Definitions..................................................10
+ 4 Abbreviations................................................11
+ 5 Conventions..................................................12
+ 6 Connection model.............................................13
+ 6.1 Contexts.................................................16
+ 6.2 Terminations.............................................17
+ 6.2.1 Termination dynamics.................................21
+ 6.2.2 TerminationIDs.......................................21
+ 6.2.3 Packages.............................................22
+ 6.2.4 Termination properties and descriptors...............23
+ 6.2.5 Root Termination.....................................25
+ 7 Commands.....................................................26
+ 7.1 Descriptors..............................................27
+ 7.1.1 Specifying parameters................................27
+ 7.1.2 Modem descriptor.....................................28
+ 7.1.3 Multiplex descriptor.................................28
+ 7.1.4 Media descriptor.....................................29
+ 7.1.5 TerminationState descriptor..........................29
+ 7.1.6 Stream descriptor....................................30
+ 7.1.7 LocalControl descriptor..............................31
+ 7.1.8 Local and Remote descriptors.........................32
+ 7.1.9 Events descriptor....................................35
+ 7.1.10 EventBuffer descriptor..............................38
+ 7.1.11 Signals descriptor..................................38
+ 7.1.12 Audit descriptor....................................40
+ 7.1.13 ServiceChange descriptor............................41
+ 7.1.14 DigitMap descriptor.................................41
+ 7.1.15 Statistics descriptor...............................46
+ 7.1.16 Packages descriptor.................................47
+ 7.1.17 ObservedEvents descriptor...........................47
+ 7.1.18 Topology descriptor.................................47
+ 7.1.19 Error Descriptor....................................50
+ 7.2 Command Application Programming Interface................50
+ 7.2.1 Add..................................................51
+
+
+
+Groves, et al. Standards Track [Page 2]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7.2.2 Modify...............................................52
+ 7.2.3 Subtract.............................................53
+ 7.2.4 Move.................................................55
+ 7.2.5 AuditValue...........................................56
+ 7.2.6 AuditCapabilities....................................59
+ 7.2.7 Notify...............................................60
+ 7.2.8 ServiceChange........................................61
+ 7.2.9 Manipulating and Auditing Context Attributes.........65
+ 7.2.10 Generic Command Syntax..............................66
+ 7.3 Command Error Codes......................................66
+ 8 Transactions.................................................66
+ 8.1 Common parameters........................................68
+ 8.1.1 Transaction Identifiers..............................68
+ 8.1.2 Context Identifiers..................................68
+ 8.2 Transaction Application Programming Interface............69
+ 8.2.1 TransactionRequest...................................69
+ 8.2.2 TransactionReply.....................................69
+ 8.2.3 TransactionPending...................................71
+ 8.3 Messages.................................................72
+ 9 Transport....................................................72
+ 9.1 Ordering of Commands.....................................73
+ 9.2 Protection against Restart Avalanche.....................74
+ 10 Security Considerations.....................................75
+ 10.1 Protection of Protocol Connections......................75
+ 10.2 Interim AH scheme.......................................76
+ 10.3 Protection of Media Connections.........................77
+ 11 MG-MGC Control Interface....................................78
+ 11.1 Multiple Virtual MGs....................................78
+ 11.2 Cold start..............................................79
+ 11.3 Negotiation of protocol version.........................79
+ 11.4 Failure of a MG.........................................80
+ 11.5 Failure of an MGC.......................................81
+ 12 Package definition..........................................82
+ 12.1 Guidelines for defining packages........................82
+ 12.1.1 Package.............................................83
+ 12.1.2 Properties..........................................84
+ 12.1.3 Events..............................................85
+ 12.1.4 Signals.............................................85
+ 12.1.5 Statistics..........................................86
+ 12.1.6 Procedures..........................................86
+ 12.2 Guidelines to defining Parameters to Events and Signals.86
+ 12.3 Lists...................................................87
+ 12.4 Identifiers.............................................87
+ 12.5 Package registration....................................88
+ 13 IANA Considerations.........................................88
+ 13.1 Packages................................................88
+ 13.2 Error codes.............................................89
+ 13.3 ServiceChange reasons...................................89
+
+
+
+Groves, et al. Standards Track [Page 3]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ANNEX A Binary encoding of the protocol.......................90
+ A.1 Coding of wildcards......................................90
+ A.2 ASN.1 syntax specification...............................92
+ A.3 Digit maps and path names...............................111
+ ANNEX B Text encoding of the protocol.........................113
+ B.1 Coding of wildcards.....................................113
+ B.2 ABNF specification......................................113
+ B.3 Hexadecimal octet coding................................127
+ B.4 Hexadecimal octet sequence..............................127
+ ANNEX C Tags for media stream properties......................128
+ C.1 General media attributes................................128
+ C.2 Mux properties..........................................130
+ C.3 General bearer properties...............................130
+ C.4 General ATM properties..................................130
+ C.5 Frame Relay.............................................134
+ C.6 IP......................................................134
+ C.7 ATM AAL2................................................134
+ C.8 ATM AAL1................................................136
+ C.9 Bearer capabilities.....................................137
+ C.10 AAL5 properties........................................147
+ C.11 SDP equivalents........................................148
+ C.12 H.245..................................................149
+ ANNEX D Transport over IP.....................................150
+ D.1 Transport over IP/UDP using Application Level Framing ..150
+ D.1.1 Providing At-Most-Once functionality................150
+ D.1.2 Transaction identifiers and three-way handshake.....151
+ D.1.3 Computing retransmission timers.....................152
+ D.1.4 Provisional responses...............................153
+ D.1.5 Repeating Requests, Responses and Acknowledgements..153
+ D.2 Using TCP...............................................155
+ D.2.1 Providing the At-Most-Once functionality............155
+ D.2.2 Transaction identifiers and three-way handshake.....155
+ D.2.3 Computing retransmission timers.....................156
+ D.2.4 Provisional responses...............................156
+ D.2.5 Ordering of commands................................156
+ ANNEX E Basic packages.......................................157
+ E.1 Generic.................................................157
+ E.2 Base Root Package.......................................159
+ E.3 Tone Generator Package..................................161
+ E.4 Tone Detection Package..................................163
+ E.5 Basic DTMF Generator Package............................166
+ E.6 DTMF detection Package..................................167
+ E.7 Call Progress Tones Generator Package...................169
+ E.8 Call Progress Tones Detection Package...................171
+ E.9 Analog Line Supervision Package.........................172
+ E.10 Basic Continuity Package...............................175
+ E.11 Network Package........................................178
+ E.12 RTP Package............................................180
+
+
+
+Groves, et al. Standards Track [Page 4]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ E.13 TDM Circuit Package....................................182
+ APPENDIX I EXAMPLE CALL FLOWS (INFORMATIVE)...................184
+ A.1 Residential Gateway to Residential Gateway Call.........184
+ A.1.1 Programming Residential GW Analog Line Terminations
+ for Idle Behavior...................................184
+ A.1.2 Collecting Originator Digits and Initiating
+ Termination.........................................186
+ APPENDIX II Changes From RFC 3015............................195
+ Intellectual Property Rights..................................210
+ Acknowledgments...............................................211
+ Authors' Addresses............................................212
+ Full Copyright Statement......................................213
+
+1 Scope
+
+ The present document, which is identical to the published version of
+ ITU-T Recommendation H.248.1 (03/2002) except as noted below, defines
+ the protocols used between elements of a physically decomposed
+ multimedia gateway. There are no functional differences from a
+ system view between a decomposed gateway, with distributed sub-
+ components potentially on more than one physical device, and a
+ monolithic gateway such as described in ITU-T Recommendation H.246.
+ This document does not define how gateways, multipoint control units
+ or interactive voice response units (IVRs) work. Instead it creates
+ a general framework that is suitable for these applications.
+
+ Packet network interfaces may include IP, ATM or possibly others.
+ The interfaces will support a variety of Switched Circuit Network
+ (SCN) signalling systems, including tone signalling, ISDN, ISUP, QSIG
+ and GSM. National variants of these signalling systems will be
+ supported where applicable.
+
+1.1 Changes From RFC 3015
+
+ The differences between this document and RFC 3015 are documented in
+ Appendix II.
+
+1.2 Differences From ITU-T Recommendation H.248.1 (03/2002)
+
+ This document differs from the corresponding ITU-T publication in the
+ following respects:
+
+ - Added IETF front matter in place of the corresponding ITU-T
+ material.
+
+ - The ITU-T summary is too H.323-specific and has been omitted.
+
+
+
+
+
+Groves, et al. Standards Track [Page 5]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - The IETF conventions have been stated as governing this document.
+ As discussed in section 5 below, this gives slightly greater
+ strength to "should" requirements.
+
+ - The Scope section (just above) has been edited slightly to suit
+ its IETF context.
+
+ - Added normative references to RFCs 2026 and 2119.
+
+ - Figures 4, 5, and 6 show the centre of the context for greater
+ clarity. Also added Figure 6a showing an important additional
+ example.
+
+ - Added a paragraph in section 7.1.18 which was approved in the
+ Implementor's Guide but lost inadvertently in the ITU-T approved
+ version.
+
+ - This document incorporates corrections to the informative examples
+ in Appendix I which also appear in H.248.1 version 2, but which
+ were not picked up in H.248.1 (03/2002).
+
+ - This document includes a new Appendix II listing all the changes
+ from RFC 3015.
+
+ - This document includes an Acknowledgements section listing the
+ authors of RFC 3015 but also many other people who contributed to
+ the development of the Megaco/H.248.x protocol.
+
+ - Moved the Intellectual Property declaration to its usual place in
+ an IETF document and added a reference to declarations on the IETF
+ web site.
+
+2 References
+
+ The following ITU-T Recommendations and other references contain
+ provisions which, through reference in this text, constitute
+ provisions of this RFC. At the time of publication, the editions
+ indicated were valid. All Recommendations and other references are
+ subject to revision; all users of this RFC are therefore encouraged
+ to investigate the possibility of applying the most recent edition of
+ the Recommendations and other references listed below. A list of the
+ currently valid ITU-T Recommendations is regularly published.
+
+2.1 Normative references
+
+ - ITU-T Recommendation H.225.0 (1999), Call signalling protocols and
+ media stream packetization for packet-based multimedia
+ communication systems.
+
+
+
+Groves, et al. Standards Track [Page 6]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - ITU-T Recommendation H.235 (1998), Security and encryption for
+ H-Series (H.323 and other H.245-based) multimedia terminals.
+
+ - ITU-T Recommendation H.245 (1998), Control protocol for multimedia
+ communication.
+
+ - ITU-T Recommendation H.246 (1998), Interworking of H-series
+ multimedia terminals with H-series multimedia terminals and
+ voice/voiceband terminals on GSTN and ISDN.
+
+ - ITU-T Recommendation H.248.8 (2002), H.248 Error Codes and Service
+ Change Reasons.
+
+ - ITU-T Recommendation H.323 (1999), Packet-based multimedia
+ communication systems.
+
+ - ITU-T Recommendation I.363.1 (1996), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 1 AAL.
+
+ - ITU-T Recommendation I.363.2 (1997), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 2 AAL.
+
+ - ITU-T Recommendation I.363.5 (1996), B-ISDN ATM adaptation layer
+ (AAL) specification: Type 5 AAL.
+
+ - ITU-T Recommendation I.366.1 (1998), Segmentation and Reassembly
+ Service Specific Convergence Sublayer for the AAL type 2.
+
+ - ITU-T Recommendation I.366.2 (1999), AAL type 2 service specific
+ convergence sublayer for trunking.
+
+ - ITU-T Recommendation I.371 (2000), Traffic control and congestion
+ control in B-ISDN.
+
+ - ITU-T Recommendation Q.763 (1999), Signalling System No. 7 - ISDN
+ user part formats and codes.
+
+ - ITU-T Recommendation Q.765.5 (2001), Application transport
+ mechanism - Bearer independent call control (BICC).
+
+ - ITU-T Recommendation Q.931 (1998), ISDN user-network interface
+ layer 3 specification for basic call control.
+
+ - ITU-T Recommendation Q.2630.1 (1999), AAL type 2 signalling
+ protocol (Capability Set 1).
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 7]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - ITU-T Recommendation Q.2931 (1995), Digital Subscriber Signalling
+ System No. 2 (DSS2) - User-Network Interface (UNI) - Layer 3
+ specification for basic call/connection control.
+
+ - ITU-T Recommendation Q.2941.1 (1997), Digital Subscriber
+ Signalling System No. 2 - Generic identifier transport.
+
+ - ITU-T Recommendation Q.2961.1 (1995), Additional signalling
+ capabilities to support traffic parameters for the tagging option
+ and the sustainable call rate parameter set.
+
+ - ITU-T Recommendation Q.2961.2 (1997), Additional traffic
+ parameters: Support of ATM transfer capability in the broadband
+ bearer capability information element.
+
+ - ITU-T Recommendation Q.2965.1 (1999), Digital subscriber
+ signalling system No. 2 - Support of Quality of Service classes.
+
+ - ITU-T Recommendation Q.2965.2 (1999), Digital subscriber
+ signalling system No. 2 - Signalling of individual Quality of
+ Service parameters.
+
+ - ITU-T Recommendation V.76 (1996), Generic multiplexer using V.42
+ LAPM-based procedures.
+
+ - ITU-T Recommendation X.213 (1995), Information technology - Open
+ Systems Interconnection - Network service definition plus
+ Amendment 1 (1997), Addition of the Internet protocol address
+ format identifier.
+
+ - ITU-T Recommendation X.680 (1997), Information technology -
+ Abstract Syntax Notation One (ASN.1): Specification of basic
+ notation.
+
+ - ITU-T Recommendation X.690 (1997), Information Technology - ASN.1
+ Encoding Rules: Specification of Basic Encoding Rules (BER),
+ Canonical Encoding Rules (CER) and Distinguished Encoding Rules
+ (DER).
+
+ - ATM Forum (1996), ATM User-Network Interface (UNI) Signalling
+ Specification - Version 4.0.
+
+ [RFC 1006] Rose, M. and D. Cass, "ISO Transport Service on top of the
+ TCP, Version 3", STD 35, RFC 1006, May 1987.
+
+ [RFC 2026] Brander, S., "The Internet Standards Process -- Revision
+ 3", BCP 9, RFC 2026, October 1996.
+
+
+
+
+Groves, et al. Standards Track [Page 8]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC 2234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [RFC 2327] Handley, M. and V. Jacobson, "SDP: Session Description
+ Protocol", RFC 2327, April 1998.
+
+ [RFC 2402] Kent, S. and R. Atkinson, "IP Authentication Header", RFC
+ 2402, November 1998.
+
+ [RFC 2406] Kent, S. and R. Atkinson, "IP Encapsulating Security
+ Payload (ESP)", RFC 2406, November 1998.
+
+2.2 Informative references
+
+ - ITU-T Recommendation E.180/Q.35 (1998), Technical characteristics
+ of tones for the telephone service.
+
+ - CCITT Recommendation G.711 (1988), Pulse Code Modulation (PCM) of
+ voice frequencies.
+
+ - ITU-T Recommendation H.221 (1999), Frame structure for a 64 to
+ 1920 kbit/s channel in audiovisual teleservices.
+
+ - ITU T Recommendation H.223 (1996), Multiplexing protocol for low
+ bit rate multimedia communication.
+
+ - ITU-T Recommendation H.226 (1998), Channel aggregation protocol
+ for multilink operation on circuit-switched networks
+
+ - ITU-T Recommendation Q.724 (1998), Signalling procedures.
+
+ - ITU-T Recommendation Q.764 (1999), Signalling system No. 7 - ISDN
+ user part signalling procedures.
+
+ - ITU-T Recommendation Q.1902.4 (2001), Bearer independent call
+ control protocol - Basic call procedures.
+
+ [RFC 768] Postel, J., "User Datagram Protocol", STD 6, RFC 768,
+ August 1980.
+
+ [RFC 791] Postel, J., "Internet Protocol", STD 5, RFC 791, September
+ 1981.
+
+ [RFC 793] Postel, J., "Transmission Control Protocol", STD 7, RFC
+ 793, September 1981.
+
+
+
+Groves, et al. Standards Track [Page 9]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ [RFC 1661] Simpson, W., Ed., "The Point-to-Point Protocol (PPP)", STD
+ 51, RFC 1661, July 1994.
+
+ [RFC 1889] Schulzrinne, H., Casner, S., Frederick, R. and V.
+ Jacobson, "RTP: A Transport Protocol for Real-Time
+ Applications", RFC 1889, January 1996.
+
+ [RFC 1890] Schulzrinne, H. and G. Fokus, "RTP Profile for Audio and
+ Video Conferences with Minimal Control", RFC 1890,
+ January 1996.
+
+ [RFC 2401] Kent, S. and R. Atkinson, "Security Architecture for the
+ Internet Protocol", RFC 2401, November 1998.
+
+ [RFC 2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6
+ (IPv6) Specification", RFC 2460, December 1998.
+
+ [RFC 2543] Handley, M., Schulzrinne, H., Schooler, E. and J.
+ Rosenberg, "SIP: Session Initiation Protocol", RFC 2543,
+ March 1999.
+
+ [RFC 2805] Greene, N., Ramalho, M. and B. Rosen, "Media Gateway
+ Control Protocol Architecture and Requirements", RFC 2805,
+ April 2000.
+
+3 Definitions
+
+ This document defines the following terms:
+
+ Access gateway:
+ A type of gateway that provides a User-Network Interface (UNI) such
+ as ISDN.
+
+ Descriptor:
+ A syntactic element of the protocol that groups related properties.
+ For instance, the properties of a media flow on the MG can be set by
+ the MGC by including the appropriate descriptor in a command.
+
+ Media Gateway (MG):
+ The media gateway converts media provided in one type of network to
+ the format required in another type of network. For example, a MG
+ could terminate bearer channels from a switched circuit network
+ (e.g., DS0s) and media streams from a packet network (e.g., RTP
+ streams in an IP network). This gateway may be capable of processing
+ audio, video and T.120 alone or in any combination, and will be
+ capable of full duplex media translations. The MG may also play
+ audio/video messages and perform other IVR functions, or may perform
+ media conferencing.
+
+
+
+Groves, et al. Standards Track [Page 10]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Media Gateway Controller (MGC):
+ Controls the parts of the call state that pertain to connection
+ control for media channels in a MG.
+
+ Multipoint Control Unit (MCU):
+ An entity that controls the setup and coordination of a multi-user
+ conference that typically includes processing of audio, video and
+ data.
+
+ Residential gateway:
+ A gateway that interworks an analogue line to a packet network. A
+ residential gateway typically contains one or two analogue lines and
+ is located at the customer premises.
+
+ SCN FAS signalling gateway:
+ This function contains the SCN Signalling Interface that terminates
+ SS7, ISDN or other signalling links where the call control channel
+ and bearer channels are collocated in the same physical span.
+
+ SCN NFAS signalling gateway:
+ This function contains the SCN Signalling Interface that terminates
+ SS7 or other signalling links where the call control channels are
+ separated from bearer channels.
+
+ Stream:
+ Bidirectional media or control flow received/sent by a media gateway
+ as part of a call or conference.
+
+ Trunk:
+ A communication channel between two switching systems such as a DS0
+ on a T1 or E1 line.
+
+ Trunking gateway:
+ A gateway between SCN network and packet network that typically
+ terminates a large number of digital circuits.
+
+4 Abbreviations
+
+ This RFC document uses the following abbreviations:
+
+ ALF Application Layer Framing
+
+ ATM Asynchronous Transfer Mode
+
+ CAS Channel Associated Signalling
+
+ DTMF Dual Tone Multi-Frequency
+
+
+
+
+Groves, et al. Standards Track [Page 11]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ FAS Facility Associated Signalling
+
+ GSM Global System for Mobile communications
+
+ GW GateWay
+
+ IANA Internet Assigned Numbers Authority (superseded by Internet
+ Corporation for Assigned Names and Numbers - ICANN)
+
+ IP Internet Protocol
+
+ ISUP ISDN User Part
+
+ IVR Interactive Voice Response
+
+ MG Media Gateway
+
+ MGC Media Gateway Controller
+
+ NFAS Non-Facility Associated Signalling
+
+ PRI Primary Rate Interface
+
+ PSTN Public Switched Telephone Network
+
+ QoS Quality of Service
+
+ RTP Real-time Transport Protocol
+
+ SCN Switched Circuit Network
+
+ SG Signalling Gateway
+
+ SS7 Signalling System No. 7
+
+5 Conventions
+
+ In the H.248.1 Recommendation, "SHALL" refers to a mandatory
+ requirement, while "SHOULD" refers to a suggested but optional
+ feature or procedure. The term "MAY" refers to an optional course of
+ action without expressing a preference. Note that these definition
+ are overridden in the present document by the RFC 2119 conventions
+ stated at the beginning of this document. RFC 2119 has a more
+ precise definition of "should" than is provided by the ITU-T.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 12]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+6 Connection model
+
+ The connection model for the protocol describes the logical entities,
+ or objects, within the Media Gateway that can be controlled by the
+ Media Gateway Controller. The main abstractions used in the
+ connection model are Terminations and Contexts.
+
+ A Termination sources and/or sinks one or more streams. In a
+ multimedia conference, a Termination can be multimedia and sources or
+ sinks multiple media streams. The media stream parameters, as well
+ as modem, and bearer parameters are encapsulated within the
+ Termination.
+
+ A Context is an association between a collection of Terminations.
+ There is a special type of Context, the null Context, which contains
+ all Terminations that are not associated to any other Termination.
+ For instance, in a decomposed access gateway, all idle lines are
+ represented by Terminations in the null Context.
+
+ Following is a graphical depiction of these concepts. The diagram of
+ Figure 1 gives several examples and is not meant to be an
+ all-inclusive illustration. The asterisk box in each of the Contexts
+ represents the logical association of Terminations implied by the
+ Context.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 13]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context +-------------+ | |
+ | | | Termination | | |
+ | | |-------------| | |
+ | | +-------------+ +->| SCN Bearer |<---+->
+ | | | Termination | +-----+ | | Channel | | |
+ | | |-------------| | |---+ +-------------+ | |
+ <-+--->| RTP Stream |---| * | | |
+ | | | | | |---+ +-------------+ | |
+ | | +-------------+ +-----+ | | Termination | | |
+ | | | |-------------| | |
+ | | +->| SCN Bearer |<---+->
+ | | | Channel | | |
+ | | +-------------+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | |
+ | +------------------------------+ |
+ | (NULL Context) |Context | |
+ | +-------------+ | +-------------+ | |
+ | | Termination | | +-----+ | Termination | | |
+ | |-------------| | | | |-------------| | |
+ | | SCN Bearer | | | * |------| SCN Bearer |<---+->
+ | | Channel | | | | | Channel | | |
+ | +-------------+ | +-----+ +-------------+ | |
+ | +------------------------------+ |
+ | |
+ | |
+ | +-------------------------------------------------+ |
+ | |Context | |
+ | | +-------------+ +-------------+ | |
+ | | | Termination | +-----+ | Termination | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| SCN Bearer |---| * |------| SCN Bearer |<---+->
+ | | | Channel | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ | ___________________________________________________ |
+ +------------------------------------------------------+
+
+ Figure 1: Examples of Megaco/H.248 Connection Model
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 14]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The example in Figure 2 shows an example of one way to accomplish a
+ call-waiting scenario in a decomposed access gateway, illustrating
+ the relocation of a Termination between Contexts. Terminations T1
+ and T2 belong to Context C1 in a two-way audio call. A second audio
+ call is waiting for T1 from Termination T3. T3 is alone in Context
+ C2. T1 accepts the call from T3, placing T2 on hold. This action
+ results in T1 moving into Context C2, as shown in Figure 3.
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context C1 | |
+ | | +-------------+ +-------------+ | |
+ | | | Term. T2 | +-----+ | Term. T1 | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| RTP Stream |---| * |------| SCN Bearer |<---+->
+ | | | | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | +-------------------------------------------------+ |
+ | |Context C2 | |
+ | | +-------------+ | |
+ | | +-----+ | Term. T3 | | |
+ | | | | |-------------| | |
+ | | | * |------| SCN Bearer |<---+->
+ | | | | | Channel | | |
+ | | +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ +------------------------------------------------------+
+
+ Figure 2: Example Call Waiting Scenario / Alerting Applied to T1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 15]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +------------------------------------------------------+
+ |Media Gateway |
+ | +-------------------------------------------------+ |
+ | |Context C1 | |
+ | | +-------------+ | |
+ | | | Term. T2 | +-----+ | |
+ | | |-------------| | | | |
+ <-+--->| RTP Stream |---| * | | |
+ | | | | | | | |
+ | | +-------------+ +-----+ | |
+ | +-------------------------------------------------+ |
+ | |
+ | +-------------------------------------------------+ |
+ | |Context C2 | |
+ | | +-------------+ +-------------+ | |
+ | | | Term. T1 | +-----+ | Term. T3 | | |
+ | | |-------------| | | |-------------| | |
+ <-+--->| SCN Bearer |---| * |------| SCN Bearer |<---+->
+ | | | Channel | | | | Channel | | |
+ | | +-------------+ +-----+ +-------------+ | |
+ | +-------------------------------------------------+ |
+ +------------------------------------------------------+
+
+ Figure 3. Example Call Waiting Scenario / Answer by T1
+
+6.1 Contexts
+
+ A Context is an association between a number of Terminations. The
+ Context describes the topology (who hears/sees whom) and the media
+ mixing and/or switching parameters if more than two Terminations are
+ involved in the association.
+
+ There is a special Context called the null Context. It contains
+ Terminations that are not associated to any other Termination.
+ Terminations in the null Context can have their parameters examined
+ or modified, and may have events detected on them.
+
+ In general, an Add command is used to add Terminations to Contexts.
+ If the MGC does not specify an existing Context to which the
+ Termination is to be added, the MG creates a new Context. A
+ Termination may be removed from a Context with a Subtract command,
+ and a Termination may be moved from one Context to another with a
+ Move command. A Termination SHALL exist in only one Context at a
+ time.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 16]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The maximum number of Terminations in a Context is a MG property.
+ Media gateways that offer only point-to-point connectivity might
+ allow at most two Terminations per Context. Media gateways that
+ support multipoint conferences might allow three or more Terminations
+ per Context.
+
+6.1.1 Context attributes and descriptors
+
+ The attributes of Contexts are:
+
+ - ContextID.
+
+ - The topology (who hears/sees whom).
+
+ The topology of a Context describes the flow of media between the
+ Terminations within a Context. In contrast, the mode of a
+ Termination (send/receive/...) describes the flow of the media at
+ the ingress/egress of the media gateway.
+
+ - The priority is used for a Context in order to provide the MG with
+ information about a certain precedence handling for a Context.
+ The MGC can also use the priority to control autonomously the
+ traffic precedence in the MG in a smooth way in certain
+ situations (e.g., restart), when a lot of Contexts must be handled
+ simultaneously. Priority 0 is the lowest priority and a priority
+ of 15 is the highest priority.
+
+ - An indicator for an emergency call is also provided to allow a
+ preference handling in the MG.
+
+6.1.2 Creating, deleting and modifying Contexts
+
+ The protocol can be used to (implicitly) create Contexts and modify
+ the parameter values of existing Contexts. The protocol has commands
+ to add Terminations to Contexts, subtract them from Contexts, and to
+ move Terminations between Contexts. Contexts are deleted implicitly
+ when the last remaining Termination is subtracted or moved out.
+
+6.2 Terminations
+
+ A Termination is a logical entity on a MG that sources and/or sinks
+ media and/or control streams. A Termination is described by a number
+ of characterizing Properties, which are grouped in a set of
+ Descriptors that are included in commands. Terminations have unique
+ identities (TerminationIDs), assigned by the MG at the time of their
+ creation.
+
+
+
+
+
+Groves, et al. Standards Track [Page 17]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Terminations representing physical entities have a semi-permanent
+ existence. For example, a Termination representing a TDM channel
+ might exist for as long as it is provisioned in the gateway.
+ Terminations representing ephemeral information flows, such as RTP
+ flows, would usually exist only for the duration of their use.
+
+ Ephemeral Terminations are created by means of an Add command. They
+ are destroyed by means of a Subtract command. In contrast, when a
+ physical Termination is Added to or Subtracted from a Context, it is
+ taken from or to the null Context, respectively.
+
+ Terminations may have signals applied to them (see 7.1.11).
+ Terminations may be programmed to detect Events, the occurrence of
+ which can trigger notification messages to the MGC, or action by the
+ MG. Statistics may be accumulated on a Termination. Statistics are
+ reported to the MGC upon request (by means of the AuditValue command,
+ see 7.2.5) and when the Termination is taken out of the call it is
+ in.
+
+ Multimedia gateways may process multiplexed media streams. For
+ example, Recommendation H.221 describes a frame structure for
+ multiple media streams multiplexed on a number of digital 64 kbit/s
+ channels. Such a case is handled in the connection model in the
+ following way. For every bearer channel that carries part of the
+ multiplexed streams, there is a physical or ephemeral "bearer
+ Termination". The bearer Terminations that source/sink the digital
+ channels are connected to a separate Termination called the
+ "multiplexing Termination". The multiplexing termination is an
+ ephemeral termination representing a frame-oriented session. The
+ MultiplexDescriptor for this Termination describes the multiplex used
+ (e.g., H.221 for an H.320 session) and indicates the order in which
+ the contained digital channels are assembled into a frame.
+
+ Multiplexing terminations may be cascades (e.g., H.226 multiplex of
+ digital channels feeding into a H.223 multiplex supporting an H.324
+ session).
+
+ The individual media streams carried in the session are described by
+ StreamDescriptors on the multiplexing Termination. These media
+ streams can be associated with streams sourced/sunk by Terminations
+ in the Context other than the bearer Terminations supporting the
+ multiplexing Termination. Each bearer Termination supports only a
+ single data stream. These data streams do not appear explicitly as
+ streams on the multiplexing Termination and they are hidden from the
+ rest of the context.
+
+ Figures 4, 5, 6, and 6a illustrate typical applications of the
+ multiplexing termination and Multiplex Descriptor.
+
+
+
+Groves, et al. Standards Track [Page 18]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +-----------------------------------+
+ | Context +-------+ |
+ +----+ | | |
+ Circuit 1 -|--| TC1|---------+ Tmux | |
+ | +----+ (Str 1) | | Audio +-----+
+ | | | +-----*-----+ |-----
+ | +----+ | H.22x | Stream 1 | |
+ Circuit 2 -|--| TC2|---------+ multi-| | TR1 |
+ | +----+ (Str 1) | plex | |(RTP)|
+ | | | | Video | |
+ | +----+ | +-----*-----+ |-----
+ Circuit 3 -|--| TC3|---------+ | Stream 2 | |
+ / +----+ (Str 1) | | +-----+
+ / | +-------+ |
+ / +-----------------\-----------------+
+ Audio, video, and control \
+ signals are carried in frames Tmux is an ephemeral with two
+ spanning the circuits. explicit Stream Descriptors
+ and a Multiplex Descriptor.
+
+ Figure 4: Multiplexed Termination Scenario - Circuit to Packet
+ (Asterisks * denote the centre of the context)
+
+ Context
+ +--------------------------------------+
+ | +-------+ +-------+ |
+ +----+ | | | | +----+
+ Circuit 1 ----| TC1|---+ Tmux1 | Audio | Tmux2 +---| TC4|---
+ +----+ | +---*----+ | +----+
+ | | | Str 1 | | |
+ +----+ | H.22x | | H.22x | +----+
+ Circuit 2 ----| TC2|---+ multi-| | multi-+---| TC5|---
+ +----+ | plex | | plex | +----+
+ | | | Video | | |
+ +----+ | +---*----+ | +----+
+ Circuit 3 ----| TC3|---+ | Str 2 | +---| TC6|---
+ +----+ | | | | +----+
+ | +-------+ +-------+ |
+ +-----------------\-----/--------------+
+ \ /
+ Tmux1 and Tmux2 are ephemerals each with two
+ explicit Stream Descriptors and a Multiplex Descriptor.
+
+ Figure 5: Multiplexed Termination Scenario - Circuit to Circuit
+ (Asterisks * denote the centre of the context)
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 19]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +-----------------------------------+
+ | Context +-------+ |
+ +----+ | | |
+ Circuit 1 -|--| TC1|---------+ Tmux | |
+ | +----+ (Str 1) | | Audio +-----+
+ | | | +-----*-----+ TR1 |-----
+ | +----+ | H.22x | Stream 1 |(RTP)|
+ Circuit 2 -|--| TC2|---------+ multi-| +-----+
+ | +----+ (Str 1) | plex | |
+ | | | | Video +-----+
+ | +----+ | +-----*-----+ TR2 |-----
+ Circuit 3 -|--| TC3|---------+ | Stream 2 |(RTP)|
+ / +----+ (Str 1) | | +-----+
+ / | +-------+ |
+ / +-----------------\-----------------+
+ Audio, video, and control \ Tmux is an ephemeral with two
+ signals are carried in frames explicit Stream Descriptors and
+ spanning the circuits. and a Multiplex Descriptor.
+
+ Figure 6: Multiplexed Termination Scenario - Single to Multiple
+ Terminations
+ (Asterisks * denote the centre of the context)
+
+ Context
+ +---------------------------------------------+
+ | +-------+ +-------+ |
+ Cct 1 +----+ | | | | Audio +-----+
+ ----| TC1|---+ Tmux1 | | Tmux2 +-----*-----| TR1 |-----
+ +----+ | | | | Stream 1 |(RTP)|
+ | | | Data | | +-----+
+ Cct 2 +----+ | H.226 +-------+ H.223 | |
+ ----| TC2|---+ multi-|(Str 1)| multi-| Control +-----+
+ +----+ | plex | | plex +-----*-----+ Tctl|-----
+ | | | | | Stream 3 +-----+
+ Cct 3 +----+ | | | | |
+ ----| TC3|---+ | | | +-----+
+ +----+ | | | +-----*-----+ TR2 |-----
+ | +-------+ | | Video |(RTP)|
+ | +-------+ Stream 2 +-----+
+ | |
+ +---------------------------------------------+
+ Tmux1 has a Multiplex Descriptor and a single data stream.
+ Tmux2 has a Multiplex Descriptor with a single bearer and
+ three explicit Stream Descriptors.
+
+ Figure 6a: Multiplexed Termination Scenario - Cascaded Multiplexes
+ (Asterisks * denote the centre of the context)
+ Note: this figure does not appear in Rec. H.248.1
+
+
+
+Groves, et al. Standards Track [Page 20]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Terminations may be created which represent multiplexed bearers, such
+ as an ATM AAL Type 2 bearer. When a new multiplexed bearer is to be
+ created, an ephemeral Termination is created in a Context established
+ for this purpose. When the Termination is subtracted, the
+ multiplexed bearer is destroyed.
+
+6.2.1 Termination dynamics
+
+ The protocol can be used to create new Terminations and to modify
+ property values of existing Terminations. These modifications
+ include the possibility of adding or removing events and/or signals.
+ The Termination properties, and events and signals are described in
+ the ensuing subclauses. An MGC can only release/modify Terminations
+ and the resources that the Termination represents which it has
+ previously seized via, e.g., the Add command.
+
+6.2.2 TerminationIDs
+
+ Terminations are referenced by a TerminationID, which is an arbitrary
+ schema chosen by the MG.
+
+ TerminationIDs of physical Terminations are provisioned in the Media
+ Gateway. The TerminationIDs may be chosen to have structure. For
+ instance, a TerminationID may consist of trunk group and a trunk
+ within the group.
+
+ A wildcarding mechanism using two types of wildcards can be used with
+ TerminationIDs. The two wildcards are ALL and CHOOSE. The former is
+ used to address multiple Terminations at once, while the latter is
+ used to indicate to a media gateway that it must select a Termination
+ satisfying the partially specified TerminationID. This allows, for
+ instance, that a MGC instructs a MG to choose a circuit within a
+ trunk group.
+
+ When ALL is used in the TerminationID of a command, the effect is
+ identical to repeating the command with each of the matching
+ TerminationIDs. The use of ALL does not address the ROOT
+ termination. Since each of these commands may generate a response,
+ the size of the entire response may be large. If individual
+ responses are not required, a wildcard response may be requested. In
+ such a case, a single response is generated, which contains the UNION
+ of all of the individual responses which otherwise would have been
+ generated, with duplicate values suppressed. For instance, given a
+ Termination Ta with properties p1=a, p2=b and Termination Tb with
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 21]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ properties p2=c, p3=d, a UNION response would consist of a wildcarded
+ TerminationId and the sequence of properties p1=a, p2=b,c and p3=d.
+ Wildcard response may be particularly useful in the Audit commands.
+
+ The encoding of the wildcarding mechanism is detailed in Annexes A
+ and B.
+
+6.2.3 Packages
+
+ Different types of gateways may implement Terminations that have
+ widely differing characteristics. Variations in Terminations are
+ accommodated in the protocol by allowing Terminations to have
+ optional Properties, Events, Signals and Statistics implemented by
+ MGs.
+
+ In order to achieve MG/MGC interoperability, such options are grouped
+ into Packages, and typically a Termination realizes a set of such
+ Packages. More information on definition of packages can be found in
+ clause 12. An MGC can audit a Termination to determine which
+ Packages it realizes.
+
+ Properties, Events, Signals and Statistics defined in Packages, as
+ well as parameters to them, are referenced by identifiers (Ids).
+ Identifiers are scoped. For each package, PropertyIds, EventIds,
+ SignalIds, StatisticsIds and ParameterIds have unique name spaces and
+ the same identifier may be used in each of them. Two PropertyIds in
+ different packages may also have the same identifier, etc.
+
+ To support a particular package the MG must support all properties,
+ signals, events and statistics defined in a package. It must also
+ support all Signal and Event parameters. The MG may support a subset
+ of the values listed in a package for a particular Property or
+ Parameter.
+
+ When packages are extended, the properties, events, signals and
+ statistics defined in the base package can be referred to using
+ either the extended package name or the base package name. For
+ example, if Package A defines event e1, and Package B extends Package
+ A, then B/e1 is an event for a termination implementing Package B. By
+ definition, the MG MUST also implement the base Package, but it is
+ optional to publish the base package as an allowed interface. If it
+ does publish A, then A would be reported on the Package Descriptor
+ in AuditValue as well as B, and event A/e1 would be available on a
+ termination. If the MG does not publish A, then only B/e1 would be
+ available. If published through AuditValue, A/e1 and B/e1 are the
+ same event.
+
+
+
+
+
+Groves, et al. Standards Track [Page 22]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ For improved interoperability and backward compatibility, an MG MAY
+ publish all Packages supported by its Terminations, including base
+ Packages from which extended Packages are derived. An exception to
+ this is in cases where the base packages are expressly "Designed to
+ be extended only".
+
+6.2.4 Termination properties and descriptors
+
+ Terminations have properties. The properties have unique
+ PropertyIDs. Most properties have default values, which are
+ explicitly defined in this protocol specification or in a package
+ (see clause 12) or set by provisioning. If not provisioned
+ otherwise, the properties in all descriptors except TerminationState
+ and LocalControl default to empty/"no value" when a Termination is
+ first created or returned to the null Context. The default contents
+ of the two exceptions are described in 7.1.5 and 7.1.7.
+
+ The provisioning of a property value in the MG will override any
+ default value, be it supplied in this protocol specification or in a
+ package. Therefore if it is essential for the MGC to have full
+ control over the property values of a Termination, it should supply
+ explicit values when ADDing the Termination to a Context.
+ Alternatively, for a physical Termination the MGC can determine any
+ provisioned property values by auditing the Termination while it is
+ in the NULL Context.
+
+ There are a number of common properties for Terminations and
+ properties specific to media streams. The common properties are also
+ called the Termination state properties. For each media stream,
+ there are local properties and properties of the received and
+ transmitted flows.
+
+ Properties not included in the base protocol are defined in Packages.
+ These properties are referred to by a name consisting of the
+ PackageName and a PropertyId. Most properties have default values
+ described in the Package description. Properties may be read-only or
+ read/write. The possible values of a property may be audited, as can
+ their current values. For properties that are read/write, the MGC
+ can set their values. A property may be declared as "Global" which
+ has a single value shared by all Terminations realizing the package.
+ Related properties are grouped into descriptors for convenience.
+
+ When a Termination is added to a Context, the value of its read/write
+ properties can be set by including the appropriate descriptors as
+ parameters to the Add command. Similarly, a property of a
+ Termination in a Context may have its value changed by the Modify
+ command.
+
+
+
+
+Groves, et al. Standards Track [Page 23]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Properties may also have their values changed when a Termination is
+ moved from one Context to another as a result of a Move command. In
+ some cases, descriptors are returned as output from a command.
+
+ In general, if a Descriptor is completely omitted from one of the
+ aforementioned Commands, the properties in that Descriptor retain
+ their prior values for the Termination(s) upon which the Command
+ acts. On the other hand, if some read/write properties are omitted
+ from a Descriptor in a Command (i.e., the Descriptor is only
+ partially specified), those properties will be reset to their default
+ values for the Termination(s) upon which the Command acts, unless the
+ package specifies other behavior. For more details, see clause 7.1
+ dealing with the individual Descriptors.
+
+ The following table lists all of the possible descriptors and their
+ use. Not all descriptors are legal as input or output parameters to
+ every command.
+
+ Descriptor name Description
+
+ Modem Identifies modem type and properties when
+ applicable
+
+ Mux Describes multiplex type for multimedia
+ Terminations (e.g., H.221, H.223, H.225.0) and
+ Terminations forming the input mux
+
+ Media A list of media stream specifications (see 7.1.4)
+
+ TerminationState Properties of a Termination (which can be defined
+ in Packages) that are not stream specific
+
+ Stream A list of remote/local/localControl descriptors for
+ a single stream
+
+ Local Contains properties that specify the media flows
+ that the MG receives from the remote entity.
+
+ Remote Contains properties that specify the media flows
+ that the MG sends to the remote entity.
+
+ LocalControl Contains properties (which can be defined in
+ packages) that are of interest between the MG and
+ the MGC.
+
+ Events Describes events to be detected by the MG and what
+ to do when an event is detected.
+
+
+
+
+Groves, et al. Standards Track [Page 24]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ EventBuffer Describes events to be detected by the MG when
+ Event Buffering is active.
+
+ Signals Describes signals (see 7.1.11) applied to
+ Terminations.
+
+ Audit In Audit commands, identifies which information is
+ desired.
+
+ Packages In AuditValue, returns a list of Packages realized
+ by Termination.
+
+ DigitMap Defines patterns against which sequences of a
+ specified set of events are to be matched so they
+ can be reported as a group rather than singly.
+
+ ServiceChange In ServiceChange, what, why service change
+ occurred, etc.
+
+ ObservedEvents In Notify or AuditValue, report of events observed.
+
+ Statistics In Subtract and Audit, report of Statistics kept on
+ a Termination.
+
+ Topology Specifies flow directions between Terminations in a
+ Context.
+
+ Error Contains an error code and optionally error text;
+ it may occur in command replies and in Notify
+ requests.
+
+6.2.5 Root Termination
+
+ Occasionally, a command must refer to the entire gateway, rather than
+ a Termination within it. A special TerminationID, "Root" is reserved
+ for this purpose. Packages may be defined on Root. Root thus may
+ have properties, events and statistics (signals are not appropriate
+ for root). Accordingly, the root TerminationID may appear in:
+
+ - a Modify command - to change a property or set an event
+
+ - a Notify command - to report an event
+
+ - an AuditValue return - to examine the values of properties and
+ statistics implemented on root
+
+ - an AuditCapability - to determine what properties of root are
+ implemented
+
+
+
+Groves, et al. Standards Track [Page 25]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - a ServiceChange - to declare the gateway in or out of service.
+
+ Any other use of the root TerminationID is an error. Error code
+ 410 - Incorrect identifier shall be returned in these cases.
+
+7 Commands
+
+ The protocol provides commands for manipulating the logical entities
+ of the protocol connection model, Contexts and Terminations.
+ Commands provide control at the finest level of granularity supported
+ by the protocol. For example, Commands exist to add Terminations to
+ a Context, modify Terminations, subtract Terminations from a Context,
+ and audit properties of Contexts or Terminations. Commands provide
+ for complete control of the properties of Contexts and Terminations.
+ This includes specifying which events a Termination is to report,
+ which signals/actions are to be applied to a Termination and
+ specifying the topology of a Context (who hears/sees whom).
+
+ Most commands are for the specific use of the Media Gateway
+ Controller as command initiator in controlling Media Gateways as
+ command responders. The exceptions are the Notify and ServiceChange
+ commands: Notify is sent from Media Gateway to Media Gateway
+ Controller, and ServiceChange may be sent by either entity. Below is
+ an overview of the commands; they are explained in more detail in
+ 7.2.
+
+ 1) Add - The Add command adds a Termination to a Context. The Add
+ command on the first Termination in a Context is used to create a
+ Context.
+
+ 2) Modify - The Modify command modifies the properties, events and
+ signals of a Termination.
+
+ 3) Subtract - The Subtract command disconnects a Termination from its
+ Context and returns statistics on the Termination's participation
+ in the Context. The Subtract command on the last Termination in a
+ Context deletes the Context.
+
+ 4) Move - The Move command atomically moves a Termination to another
+ Context.
+
+ 5) AuditValue - The AuditValue command returns the current state of
+ properties, events, signals and statistics of Terminations.
+
+ 6) AuditCapabilities - The AuditCapabilities command returns all the
+ possible values for Termination properties, events and signals
+ allowed by the Media Gateway.
+
+
+
+
+Groves, et al. Standards Track [Page 26]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7) Notify - The Notify command allows the Media Gateway to inform the
+ Media Gateway Controller of the occurrence of events in the Media
+ Gateway.
+
+ 8) ServiceChange - The ServiceChange command allows the Media Gateway
+ to notify the Media Gateway Controller that a Termination or group
+ of Terminations is about to be taken out of service or has just
+ been returned to service. ServiceChange is also used by the MG to
+ announce its availability to a MGC (registration), and to notify
+ the MGC of impending or completed restart of the MG. The MGC may
+ announce a handover to the MG by sending it a ServiceChange
+ command. The MGC may also use ServiceChange to instruct the MG to
+ take a Termination or group of Terminations in or out of service.
+
+ These commands are detailed in 7.2.1 through 7.2.8.
+
+7.1 Descriptors
+
+ The parameters to a command are termed Descriptors. A descriptor
+ consists of a name and a list of items. Some items may have values.
+ Many Commands share common descriptors. This subclause enumerates
+ these descriptors. Descriptors may be returned as output from a
+ command. In any such return of descriptor contents, an empty
+ descriptor is represented by its name unaccompanied by any list.
+ Parameters and parameter usage specific to a given Command type are
+ described in the subclause that describes the Command.
+
+7.1.1 Specifying parameters
+
+ Command parameters are structured into a number of descriptors. In
+ general, the text format of descriptors is
+ DescriptorName=<someID>{parm=value, parm=value, ...}.
+
+ Parameters may be fully specified, overspecified or underspecified:
+
+ 1) Fully specified parameters have a single, unambiguous value that
+ the command initiator is instructing the command responder to use
+ for the specified parameter.
+
+ 2) Underspecified parameters, using the CHOOSE value, allow the
+ command responder to choose any value it can support.
+
+ 3) Overspecified parameters have a list of potential values. The
+ list order specifies the command initiator's order of preference
+ of selection. The command responder chooses one value from
+ the offered list and returns that value to the command initiator.
+
+
+
+
+
+Groves, et al. Standards Track [Page 27]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ If a required descriptor other than the Audit descriptor is
+ unspecified (i.e., entirely absent) from a command, the previous
+ values set in that descriptor for that Termination, if any, are
+ retained. In commands other than Subtract, a missing Audit
+ descriptor is equivalent to an empty Audit descriptor. The Behaviour
+ of the MG with respect to unspecified parameters within a descriptor
+ varies with the descriptor concerned, as indicated in succeeding
+ subclauses. Whenever a parameter is underspecified or overspecified,
+ the descriptor containing the value chosen by the responder is
+ included as output from the command.
+
+ Each command specifies the TerminationId the command operates on.
+ This TerminationId may be "wildcarded". When the TerminationId of a
+ command is wildcarded, the effect shall be as if the command was
+ repeated with each of the TerminationIds matched.
+
+7.1.2 Modem descriptor
+
+ The Modem descriptor specifies the modem type and parameters, if any,
+ required for use in e.g., H.324 and text conversation. The
+ descriptor includes the following modem types: V.18, V.22, V.22 bis,
+ V.32, V.32 bis, V.34, V.90, V.91, Synchronous ISDN, and allows for
+ extensions. By default, no Modem descriptor is present in a
+ Termination.
+
+7.1.3 Multiplex descriptor
+
+ In multimedia calls, a number of media streams are carried on a
+ (possibly different) number of bearers. The multiplex descriptor
+ associates the media and the bearers. The descriptor includes the
+ multiplex type:
+
+ - H.221;
+
+ - H.223;
+
+ - H.226;
+
+ - V.76;
+
+ - possible extensions,
+
+ and a set of TerminationIDs representing the multiplexed bearers, in
+ order. For example:
+
+ Mux = H.221{ MyT3/1/2, MyT3/2/13, MyT3/3/6, MyT3/21/22}
+
+
+
+
+
+Groves, et al. Standards Track [Page 28]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+7.1.4 Media descriptor
+
+ The Media descriptor specifies the parameters for all the media
+ streams. These parameters are structured into two descriptors: a
+ TerminationState descriptor, which specifies the properties of a
+ Termination that are not stream dependent, and one or more Stream
+ descriptors each of which describes a single media stream.
+
+ A stream is identified by a StreamID. The StreamID is used to link
+ the streams in a Context that belong together. Multiple streams
+ exiting a Termination shall be synchronized with each other. Within
+ the Stream descriptor, there are up to three subsidiary descriptors:
+ LocalControl, Local, and Remote. The relationship between these
+ descriptors is thus:
+
+ Media descriptor
+ TerminationState Descriptor
+ Stream descriptor
+ LocalControl descriptor
+ Local descriptor
+ Remote descriptor
+
+ As a convenience, LocalControl, Local, or Remote descriptors may be
+ included in the Media descriptor without an enclosing Stream
+ descriptor. In this case, the StreamID is assumed to be 1.
+
+7.1.5 TerminationState descriptor
+
+ The TerminationState descriptor contains the ServiceStates property,
+ the EventBufferControl property and properties of a Termination
+ (defined in Packages) that are not stream specific.
+
+ The ServiceStates property describes the overall state of the
+ Termination (not stream specific). A Termination can be in one of
+ the following states: "test", "out of service", or "in service". The
+ "test" state indicates that the Termination is being tested. The
+ state "out of service" indicates that the Termination cannot be used
+ for traffic. The state "in service" indicates that a Termination can
+ be used or is being used for normal traffic. "in service" is the
+ default state.
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 29]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Values assigned to Properties may be simple values
+ (integer/string/enumeration) or may be underspecified, where more
+ than one value is supplied and the MG may make a choice:
+
+ - Alternative Values - multiple values in a list, one of which must
+ be selected
+
+ - Ranges - minimum and maximum values, any value between min and max
+ must be selected, boundary values included
+
+ - Greater Than/Less Than - value must be greater/less than specified
+ value
+
+ - CHOOSE Wildcard - the MG chooses from the allowed values for the
+ property
+
+ The EventBufferControl property specifies whether events are buffered
+ following detection of an event in the Events descriptor, or
+ processed immediately. See 7.1.9 for details.
+
+7.1.6 Stream descriptor
+
+ A Stream descriptor specifies the parameters of a single
+ bidirectional stream. These parameters are structured into three
+ descriptors: one that contains Termination properties specific to a
+ stream and one each for local and remote flows. The Stream
+ Descriptor includes a StreamID which identifies the stream. Streams
+ are created by specifying a new StreamID on one of the Terminations
+ in a Context. A stream is deleted by setting empty Local and Remote
+ descriptors for the stream with ReserveGroup and ReserveValue in
+ LocalControl set to "false" on all Terminations in the Context that
+ previously supported that stream.
+
+ StreamIDs are of local significance between MGC and MG and they are
+ assigned by the MGC. Within a Context, StreamID is a means by which
+ to indicate which media flows are interconnected: streams with the
+ same StreamID are connected.
+
+ If a Termination is moved from one Context to another, the effect on
+ the Context to which the Termination is moved is the same as in the
+ case that a new Termination were added with the same StreamIDs as the
+ moved Termination.
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 30]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+7.1.7 LocalControl descriptor
+
+ The LocalControl descriptor contains the Mode property, the
+ ReserveGroup and ReserveValue properties and properties of a
+ Termination (defined in Packages) that are stream specific, and are
+ of interest between the MG and the MGC. Values of properties may be
+ underspecified as in 7.1.1.
+
+ The allowed values for the mode property are send-only, receive-only,
+ send/receive, inactive and loop-back. "Send" and "receive" are with
+ respect to the exterior of the Context, so that, for example, a
+ stream set to mode=sendOnly does not pass received media into the
+ Context. The default value for the mode property is "Inactive".
+ Signals and Events are not affected by mode.
+
+ The boolean-valued Reserve properties, ReserveValue and ReserveGroup,
+ of a Termination indicate what the MG is expected to do when it
+ receives a Local and/or Remote descriptor.
+
+ If the value of a Reserve property is True, the MG SHALL reserve
+ resources for all alternatives specified in the Local and/or Remote
+ descriptors for which it currently has resources available. It SHALL
+ respond with the alternatives for which it reserves resources. If it
+ cannot not support any of the alternatives, it SHALL respond with a
+ reply to the MGC that contains empty Local and/or Remote descriptors.
+ If media begins to flow while more than a single alternative is
+ reserved, media packets may be sent/received on any of the
+ alternatives and must be processed, although only a single
+ alternative may be active at any given time.
+
+ If the value of a Reserve property is False, the MG SHALL choose one
+ of the alternatives specified in the Local descriptor (if present)
+ and one of the alternatives specified in the Remote descriptor (if
+ present). If the MG has not yet reserved resources to support the
+ selected alternative, it SHALL reserve the resources. If, on the
+ other hand, it already reserved resources for the Termination
+ addressed (because of a prior exchange with ReserveValue and/or
+ ReserveGroup equal to True), it SHALL release any excess resources it
+ reserved previously. Finally, the MG shall send a reply to the MGC
+ containing the alternatives for the Local and/or Remote descriptor
+ that it selected. If the MG does not have sufficient resources to
+ support any of the alternatives specified, it SHALL respond with
+ error 510 (insufficient resources).
+
+ The default value of ReserveValue and ReserveGroup is False. More
+ information on the use of the two Reserve properties is provided in
+ 7.1.8.
+
+
+
+
+Groves, et al. Standards Track [Page 31]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ A new setting of the LocalControl Descriptor completely replaces the
+ previous setting of that descriptor in the MG. Thus, to retain
+ information from the previous setting, the MGC must include that
+ information in the new setting. If the MGC wishes to delete some
+ information from the existing descriptor, it merely resends the
+ descriptor (in a Modify command) with the unwanted information
+ stripped out.
+
+7.1.8 Local and Remote descriptors
+
+ The MGC uses Local and Remote descriptors to reserve and commit MG
+ resources for media decoding and encoding for the given Stream(s) and
+ Termination to which they apply. The MG includes these descriptors
+ in its response to indicate what it is actually prepared to support.
+ The MG SHALL include additional properties and their values in its
+ response if these properties are mandatory yet not present in the
+ requests made by the MGC (e.g., by specifying detailed video encoding
+ parameters where the MGC only specified the payload type).
+
+ Local refers to the media received by the MG and Remote refers to the
+ media sent by the MG.
+
+ When text encoding the protocol, the descriptors consist of session
+ descriptions as defined in SDP (RFC 2327). In session descriptions
+ sent from the MGC to the MG, the following exceptions to the syntax
+ of RFC 2327 are allowed:
+
+ - the "s=", "t=" and "o=" lines are optional;
+
+ - the use of CHOOSE is allowed in place of a single parameter value;
+ and
+
+ - the use of alternatives is allowed in place of a single parameter
+ value.
+
+ A Stream Descriptor specifies a single bi-directional media stream
+ and so a single session description MUST NOT include more than one
+ media description ("m=" line). A Stream Descriptor may contain
+ additional session descriptions as alternatives. Each media stream
+ for a termination must appear in distinct Stream Descriptors. When
+ multiple session descriptions are provided in one descriptor, the
+ "v=" lines are required as delimiters; otherwise they are optional in
+ session descriptions sent to the MG. Implementations shall accept
+ session descriptions that are fully conformant to RFC 2327. When
+ binary encoding the protocol the descriptor consists of groups of
+ properties (tag-value pairs) as specified in Annex C. Each such
+ group may contain the parameters of a session description.
+
+
+
+
+Groves, et al. Standards Track [Page 32]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Below, the semantics of the Local and Remote descriptors are
+ specified in detail. The specification consists of two parts. The
+ first part specifies the interpretation of the contents of the
+ descriptor. The second part specifies the actions the MG must take
+ upon receiving the Local and Remote descriptors. The actions to be
+ taken by the MG depend on the values of the ReserveValue and
+ ReserveGroup properties of the LocalControl descriptor.
+
+ Either the Local or the Remote descriptor or both may be:
+
+ 1) unspecified (i.e., absent);
+
+ 2) empty;
+
+ 3) underspecified through use of CHOOSE in a property value;
+
+ 4) fully specified; or
+
+ 5) overspecified through presentation of multiple groups of
+ properties and possibly multiple property values in one or more of
+ these groups.
+
+ Where the descriptors have been passed from the MGC to the MG, they
+ are interpreted according to the rules given in 7.1.1, with the
+ following additional comments for clarification:
+
+ a) An unspecified Local or Remote descriptor is considered to be a
+ missing mandatory parameter. It requires the MG to use whatever
+ was last specified for that descriptor. It is possible that there
+ was no previously specified value, in which case the descriptor
+ concerned is ignored in further processing of the command.
+
+ b) An empty Local (Remote) descriptor in a message from the MGC
+ signifies a request to release any resources reserved for the
+ media flow received (sent).
+
+ c) If multiple groups of properties are present in a Local or Remote
+ descriptor or multiple values within a group, the order of
+ preference is descending.
+
+ d) Underspecified or overspecified properties within a group of
+ properties sent by the MGC are requests for the MG to choose one
+ or more values which it can support for each of those properties.
+ In case of an overspecified property, the list of values is in
+ descending order of preference.
+
+ Subject to the above rules, subsequent action depends on the values
+ of the ReserveValue and ReserveGroup properties in LocalControl.
+
+
+
+Groves, et al. Standards Track [Page 33]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ If ReserveGroup is True, the MG reserves the resources required to
+ support any of the requested property group alternatives that it can
+ currently support. If ReserveValue is True, the MG reserves the
+ resources required to support any of the requested property value
+ alternatives that it can currently support.
+
+ NOTE - If a Local or Remote descriptor contains multiple groups of
+ properties, and ReserveGroup is True, then the MG is requested to
+ reserve resources so that it can decode or encode the media stream
+ according to any of the alternatives. For instance, if the Local
+ descriptor contains two groups of properties, one specifying
+ packetized G.711 A-law audio and the other G.723.1 audio, the MG
+ reserves resources so that it can decode one audio stream encoded in
+ either G.711 A-law format or G.723.1 format. The MG does not have to
+ reserve resources to decode two audio streams simultaneously, one
+ encoded in G.711 A-law and one in G.723.1. The intention for the use
+ of ReserveValue is analogous.
+
+ If ReserveGroup is true or ReserveValue is True, then the following
+ rules apply:
+
+ - If the MG has insufficient resources to support all alternatives
+ requested by the MGC and the MGC requested resources in both Local
+ and Remote, the MG should reserve resources to support at least
+ one alternative each within Local and Remote.
+
+ - If the MG has insufficient resources to support at least one
+ alternative within a Local (Remote) descriptor received from the
+ MGC, it shall return an empty Local (Remote) in response.
+
+ - In its response to the MGC, when the MGC included Local and Remote
+ descriptors, the MG SHALL include Local and Remote descriptors for
+ all groups of properties and property values it reserved resources
+ for. If the MG is incapable of supporting at least one of the
+ alternatives within the Local (Remote) descriptor received from
+ the MGC, it SHALL return an empty Local (Remote) descriptor.
+
+ - If the Mode property of the LocalControl descriptor is RecvOnly,
+ SendRecv, or LoopBack, the MG must be prepared to receive media
+ encoded according to any of the alternatives included in its
+ response to the MGC.
+
+ If ReserveGroup is False and ReserveValue is False, then the MG
+ SHOULD apply the following rules to resolve Local and Remote to a
+ single alternative each:
+
+ - The MG chooses the first alternative in Local for which it is able
+ to support at least one alternative in Remote.
+
+
+
+Groves, et al. Standards Track [Page 34]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - If the MG is unable to support at least one Local and one Remote
+ alternative, it returns Error 510 (Insufficient Resources).
+
+ - The MG returns its selected alternative in each of Local and
+ Remote.
+
+ A new setting of a Local or Remote descriptor completely replaces the
+ previous setting of that descriptor in the MG. Thus, to retain
+ information from the previous setting, the MGC must include that
+ information in the new setting. If the MGC wishes to delete some
+ information from the existing descriptor, it merely resends the
+ descriptor (in a Modify command) with the unwanted information
+ stripped out.
+
+7.1.9 Events descriptor
+
+ The EventsDescriptor parameter contains a RequestIdentifier and a
+ list of events that the Media Gateway is requested to detect and
+ report. The RequestIdentifier is used to correlate the request with
+ the notifications that it may trigger. Requested events include, for
+ example, fax tones, continuity test results, and on-hook and off-hook
+ transitions. The RequestIdentifier is omitted if the
+ EventsDescriptor is empty (i.e., no events are specified).
+
+ Each event in the descriptor contains the Event name, an optional
+ streamID, an optional KeepActive flag, and optional parameters. The
+ Event name consists of a Package Name (where the event is defined)
+ and an EventID. The ALL wildcard may be used for the EventID,
+ indicating that all events from the specified package have to be
+ detected. The default streamID is 0, indicating that the event to be
+ detected is not related to a particular media stream. Events can
+ have parameters. This allows a single event description to have some
+ variation in meaning without creating large numbers of individual
+ events. Further event parameters are defined in the package.
+
+ If a digit map completion event is present or implied in the
+ EventsDescriptor, the EventDM parameter is used to carry either the
+ name or the value of the associated digit map. See 7.1.14 for
+ further details.
+
+ When an event is processed against the contents of an active Events
+ Descriptor and found to be present in that descriptor ("recognized"),
+ the default action of the MG is to send a Notify command to the MGC.
+ Notification may be deferred if the event is absorbed into the
+ current dial string of an active digit map (see 7.1.14). Any other
+ action is for further study. Moreover, event recognition may cause
+ currently active signals to stop, or may cause the current Events
+ and/or Signals descriptor to be replaced, as described at the end of
+
+
+
+Groves, et al. Standards Track [Page 35]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ this subclause. Unless the Events Descriptor is replaced by another
+ Events Descriptor, it remains active after an event has been
+ recognized.
+
+ If the value of the EventBufferControl property equals LockStep,
+ following detection of such an event, normal handling of events is
+ suspended. Any event which is subsequently detected and occurs in
+ the EventBuffer descriptor is added to the end of the EventBuffer (a
+ FIFO queue), along with the time that it was detected. The MG SHALL
+ wait for a new EventsDescriptor to be loaded. A new EventsDescriptor
+ can be loaded either as the result of receiving a command with a new
+ EventsDescriptor, or by activating an embedded EventsDescriptor.
+
+ If EventBufferControl equals Off, the MG continues processing based
+ on the active EventsDescriptor.
+
+ In the case of an embedded EventsDescriptor being activated, the MG
+ continues event processing based on the newly activated
+ EventsDescriptor.
+
+ NOTE 1 - For purposes of EventBuffer handling, activation of an
+ embedded EventsDescriptor is equivalent to receipt of a new
+ EventsDescriptor.
+
+ When the MG receives a command with a new EventsDescriptor, one or
+ more events may have been buffered in the EventBuffer in the MG. The
+ value of EventBufferControl then determines how the MG treats such
+ buffered events.
+
+ Case 1
+
+ If EventBufferControl equals LockStep and the MG receives a new
+ EventsDescriptor, it will check the FIFO EventBuffer and take the
+ following actions:
+
+ 1) If the EventBuffer is empty, the MG waits for detection of events
+ based on the new EventsDescriptor.
+
+ 2) If the EventBuffer is non-empty, the MG processes the FIFO queue
+ starting with the first event:
+
+ a) If the event in the queue is in the events listed in the new
+ EventsDescriptor, the MG acts on the event and removes the
+ event from the EventBuffer. The time stamp of the Notify shall
+ be the time the event was actually detected. The MG then waits
+ for a new EventsDescriptor. While waiting for a new
+ EventsDescriptor, any events detected that appear in the
+
+
+
+
+Groves, et al. Standards Track [Page 36]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ EventsBufferDescriptor will be placed in the EventBuffer. When
+ a new EventsDescriptor is received, the event processing will
+ repeat from step 1.
+
+ b) If the event is not in the new EventsDescriptor, the MG SHALL
+ discard the event and repeat from step 1.
+
+ Case 2
+
+ If EventBufferControl equals Off and the MG receives a new
+ EventsDescriptor, it processes new events with the new
+ EventsDescriptor.
+
+ If the MG receives a command instructing it to set the value of
+ EventBufferControl to Off, all events in the EventBuffer SHALL be
+ discarded.
+
+ The MG may report several events in a single Transaction as long as
+ this does not unnecessarily delay the reporting of individual events.
+
+ For procedures regarding transmitting the Notify command, refer to
+ the appropriate annex or Recommendation of the H.248 sub-series for
+ specific transport considerations.
+
+ The default value of EventBufferControl is Off.
+
+ NOTE 2 - Since the EventBufferControl property is in the
+ TerminationStateDescriptor, the MG might receive a command that
+ changes the EventBufferControl property and does not include an
+ EventsDescriptor.
+
+ Normally, recognition of an event shall cause any active signals to
+ stop. When KeepActive is specified in the event, the MG shall not
+ interrupt any signals active on the Termination on which the event is
+ detected.
+
+ An event can include an Embedded Signals descriptor and/or an
+ Embedded Events descriptor which, if present, replaces the current
+ Signals/Events descriptor when the event is recognized. It is
+ possible, for example, to specify that the dial-tone Signal be
+ generated when an off-hook Event is recognized, or that the dial-tone
+ Signal be stopped when a digit is recognized. A media gateway
+ controller shall not send EventsDescriptors with an event both marked
+ KeepActive and containing an embedded SignalsDescriptor.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 37]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Only one level of embedding is permitted. An embedded
+ EventsDescriptor SHALL NOT contain another embedded EventsDescriptor;
+ an embedded EventsDescriptor MAY contain an embedded
+ SignalsDescriptor.
+
+ An EventsDescriptor received by a media gateway replaces any previous
+ Events descriptor. Event notification in process shall complete, and
+ events detected after the command containing the new EventsDescriptor
+ executes, shall be processed according to the new EventsDescriptor.
+
+ An empty Events Descriptor disables all event recognition and
+ reporting. An empty EventBuffer Descriptor clears the EventBuffer
+ and disables all event accumulation in LockStep mode: the only events
+ reported will be those occurring while an Events Descriptor is
+ active. If an empty Events Descriptor is activated while the
+ Termination is operating in LockStep mode, the events buffer is
+ immediately cleared.
+
+7.1.10 EventBuffer descriptor
+
+ The EventBuffer descriptor contains a list of events, with their
+ parameters if any, that the MG is requested to detect and buffer when
+ EventBufferControl equals LockStep (see 7.1.9).
+
+7.1.11 Signals descriptor
+
+ Signals are MG generated media such as tones and announcements as
+ well as bearer-related signals such as hookswitch. More complex
+ signals may include a sequence of such simple signals interspersed
+ with and conditioned upon the receipt and analysis of media or
+ bearer-related signals. Examples include echoing of received data as
+ in Continuity Test package. Signals may also request preparation of
+ media content for future signals.
+
+ A SignalsDescriptor is a parameter that contains the set of signals
+ that the Media Gateway is asked to apply to a Termination. A
+ SignalsDescriptor contains a number of signals and/or sequential
+ signal lists. A SignalsDescriptor may contain zero signals and
+ sequential signal lists. Support of sequential signal lists is
+ optional.
+
+ Signals are defined in packages. Signals shall be named with a
+ Package name (in which the signal is defined) and a SignalID. No
+ wildcard shall be used in the SignalID. Signals that occur in a
+ SignalsDescriptor have an optional StreamID parameter (default is 0,
+ to indicate that the signal is not related to a particular media
+ stream), an optional signal type (see below), an optional duration
+ and possibly parameters defined in the package that defines the
+
+
+
+Groves, et al. Standards Track [Page 38]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ signal. This allows a single signal to have some variation in
+ meaning, obviating the need to create large numbers of individual
+ signals.
+
+ Finally, the optional parameter "notifyCompletion" allows a MGC to
+ indicate that it wishes to be notified when the signal finishes
+ playout. The possible cases are that the signal timed out (or
+ otherwise completed on its own), that it was interrupted by an event,
+ that it was halted when a Signals descriptor was replaced, or that it
+ stopped or never started for other reasons. If the notifyCompletion
+ parameter is not included in a Signals descriptor, notification is
+ generated only if the signal stopped or was never started for other
+ reasons. For reporting to occur, the signal completion event (see
+ E.1.2) must be enabled in the currently active Events descriptor.
+
+ The duration is an integer value that is expressed in hundredths of a
+ second.
+
+ There are three types of signals:
+
+ - on/off - the signal lasts until it is turned off;
+
+ - timeout - the signal lasts until it is turned off or a specific
+ period of time elapses;
+
+ - brief - the signal will stop on its own unless a new Signals
+ descriptor is applied that causes it to stop; no timeout value is
+ needed.
+
+ If a signal of default type other than TO has its type overridden to
+ type TO in the Signals descriptor, the duration parameter must be
+ present.
+
+ If the signal type is specified in a SignalsDescriptor, it overrides
+ the default signal type (see 12.1.4). If duration is specified for
+ an on/off signal, it SHALL be ignored.
+
+ A sequential signal list consists of a signal list identifier and a
+ sequence of signals to be played sequentially. Only the trailing
+ element of the sequence of signals in a sequential signal list may be
+ an on/off signal. The duration of a sequential signal list is the
+ sum of the durations of the signals it contains.
+
+ Multiple signals and sequential signal lists in the same
+ SignalsDescriptor shall be played simultaneously.
+
+ Signals are defined as proceeding from the Termination towards the
+ exterior of the Context unless otherwise specified in a package.
+
+
+
+Groves, et al. Standards Track [Page 39]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ When the same Signal is applied to multiple Terminations within one
+ Transaction, the MG should consider using the same resource to
+ generate these Signals.
+
+ Production of a Signal on a Termination is stopped by application of
+ a new SignalsDescriptor, or detection of an Event on the Termination
+ (see 7.1.9).
+
+ A new SignalsDescriptor replaces any existing SignalsDescriptor. Any
+ signals applied to the Termination not in the replacement descriptor
+ shall be stopped, and new signals are applied, except as follows.
+ Signals present in the replacement descriptor and containing the
+ KeepActive flag shall be continued if they are currently playing and
+ have not already completed. If a replacement signal descriptor
+ contains a signal that is not currently playing and contains the
+ KeepActive flag, that signal SHALL be ignored. If the replacement
+ descriptor contains a sequential signal list with the same identifier
+ as the existing descriptor, then
+
+ - the signal type and sequence of signals in the sequential signal
+ list in the replacement descriptor shall be ignored; and
+
+ - the playing of the signals in the sequential signal list in the
+ existing descriptor shall not be interrupted.
+
+7.1.12 Audit descriptor
+
+ The Audit descriptor specifies what information is to be audited.
+ The Audit descriptor specifies the list of descriptors to be
+ returned. Audit may be used in any command to force the return of
+ any descriptor containing the current values of its properties,
+ events, signals and statistics even if that descriptor was not
+ present in the command, or had no underspecified parameters.
+ Possible items in the Audit descriptor are:
+
+ Modem
+ Mux
+ Events
+ Media
+ Signals
+ ObservedEvents
+ DigitMap
+ Statistics
+ Packages
+ EventBuffer
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 40]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Audit may be empty, in which case, no descriptors are returned. This
+ is useful in Subtract, to inhibit return of statistics, especially
+ when using wildcard.
+
+7.1.13 ServiceChange descriptor
+
+ The ServiceChangeDescriptor contains the following parameters:
+
+ . ServiceChangeMethod
+ . ServiceChangeReason
+ . ServiceChangeAddress
+ . ServiceChangeDelay
+ . ServiceChangeProfile
+ . ServiceChangeVersion
+ . ServiceChangeMGCId
+ . TimeStamp
+ . Extension
+
+ See 7.2.8.
+
+7.1.14 DigitMap descriptor
+
+7.1.14.1 DigitMap definition, creation, modification and deletion
+
+ A DigitMap is a dialing plan resident in the Media Gateway used for
+ detecting and reporting digit events received on a Termination. The
+ DigitMap descriptor contains a DigitMap name and the DigitMap to be
+ assigned. A digit map may be preloaded into the MG by management
+ action and referenced by name in an EventsDescriptor, may be defined
+ dynamically and subsequently referenced by name, or the actual
+ digitmap itself may be specified in the EventsDescriptor. It is
+ permissible for a digit map completion event within an Events
+ descriptor to refer by name to a DigitMap which is defined by a
+ DigitMap descriptor within the same command, regardless of the
+ transmitted order of the respective descriptors.
+
+ DigitMaps defined in a DigitMapDescriptor can occur in any of the
+ standard Termination manipulation Commands of the protocol. A
+ DigitMap, once defined, can be used on all Terminations specified by
+ the (possibly wildcarded) TerminationID in such a command. DigitMaps
+ defined on the root Termination are global and can be used on every
+ Termination in the MG, provided that a DigitMap with the same name
+ has not been defined on the given Termination. When a DigitMap is
+ defined dynamically in a DigitMap descriptor:
+
+ - A new DigitMap is created by specifying a name that is not yet
+ defined. The value shall be present.
+
+
+
+
+Groves, et al. Standards Track [Page 41]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - A DigitMap value is updated by supplying a new value for a name
+ that is already defined. Terminations presently using the
+ digitmap shall continue to use the old definition; subsequent
+ EventsDescriptors specifying the name, including any
+ EventsDescriptor in the command containing the DigitMap
+ descriptor, shall use the new one.
+
+ - A DigitMap is deleted by supplying an empty value for a name that
+ is already defined. Terminations presently using the digitmap
+ shall continue to use the old definition.
+
+7.1.14.2 DigitMap Timers
+
+ The collection of digits according to a DigitMap may be protected by
+ three timers, viz. a start timer (T), short timer (S), and long timer
+ (L).
+
+ 1) The start timer (T) is used prior to any digits having been
+ dialed. If the start timer is overridden with the value set to
+ zero (T=0), then the start timer shall be disabled. This implies
+ that the MG will wait indefinitely for digits.
+
+ 2) If the Media Gateway can determine that at least one more digit is
+ needed for a digit string to match any of the allowed patterns in
+ the digit map, then the interdigit timer value should be set to a
+ long (L) duration (e.g., 16 seconds).
+
+ 3) If the digit string has matched one of the patterns in a digit
+ map, but it is possible that more digits could be received which
+ would cause a match with a different pattern, then instead of
+ reporting the match immediately, the MG must apply the short timer
+ (S) and wait for more digits.
+
+ The timers are configurable parameters to a DigitMap. Default values
+ of these timers should be provisioned on the MG, but can be
+ overridden by values specified within the DigitMap.
+
+7.1.14.3 DigitMap Syntax
+
+ The formal syntax of the digit map is described by the DigitMap rule
+ in the formal syntax description of the protocol (see Annex A and
+ Annex B). A DigitMap, according to this syntax, is defined either by
+ a string or by a list of strings. Each string in the list is an
+ alternative event sequence, specified either as a sequence of digit
+ map symbols or as a regular expression of digit map symbols. These
+ digit map symbols, the digits "0" through "9" and letters "A" through
+ a maximum value depending on the signalling system concerned, but
+ never exceeding "K", correspond to specified events within a package
+
+
+
+Groves, et al. Standards Track [Page 42]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ which has been designated in the Events descriptor on the Termination
+ to which the digit map is being applied. (The mapping between events
+ and digit map symbols is defined in the documentation for packages
+ associated with channel-associated signalling systems such as DTMF,
+ MF, or R2. Digits "0" through "9" MUST be mapped to the
+ corresponding digit events within the signalling system concerned.
+ Letters should be allocated in logical fashion, facilitating the use
+ of range notation for alternative events.)
+
+ The letter "x" is used as a wildcard, designating any event
+ corresponding to symbols in the range "0"-"9". The string may also
+ contain explicit ranges and, more generally, explicit sets of
+ symbols, designating alternative events any one of which satisfies
+ that position of the digit map. Finally, the dot symbol "." stands
+ for zero or more repetitions of the event selector (event, range of
+ events, set of alternative events, or wildcard) that precedes it. As
+ a consequence of the third timing rule above, inter-event timing
+ while matching a terminal dot symbol uses the short timer by default.
+
+ In addition to these event symbols, the string may contain "S" and
+ "L" inter-event timing specifiers and the "Z" duration modifier. "S"
+ and "L" respectively indicate that the MG should use the short (S)
+ timer or the long (L) timer for subsequent events, overriding the
+ timing rules described above. If an explicit timing specifier is in
+ effect in one alternative event sequence, but none is given in any
+ other candidate alternative, the timer value set by the explicit
+ timing specifier must be used. If all sequences with explicit timing
+ controls are dropped from the candidate set, timing reverts to the
+ default rules given above. Finally, if conflicting timing specifiers
+ are in effect in different alternative sequences, the long timer
+ shall be used.
+
+ A "Z" designates a long duration event: placed in front of the
+ symbol(s) designating the event(s) which satisfy a given digit
+ position, it indicates that that position is satisfied only if the
+ duration of the event exceeds the long-duration threshold. The value
+ of this threshold is assumed to be provisioned in the MG.
+
+7.1.14.4 DigitMap Completion Event
+
+ A digit map is active while the Events descriptor which invoked it is
+ active and it has not completed. A digit map completes when:
+
+ - a timer has expired; or
+
+ - an alternative event sequence has been matched and no other
+ alternative event sequence in the digit map could be matched
+ through detection of an additional event (unambiguous match); or
+
+
+
+Groves, et al. Standards Track [Page 43]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - an event has been detected such that a match to a complete
+ alternative event sequence of the digit map will be impossible no
+ matter what additional events are received.
+
+ Upon completion, a digit map completion event as defined in the
+ package providing the events being mapped into the digit map shall be
+ generated. At that point the digit map is deactivated. Subsequent
+ events in the package are processed as per the currently active event
+ processing mechanisms.
+
+7.1.14.5 DigitMap Procedures
+
+ Pending completion, successive events shall be processed according to
+ the following rules:
+
+ 1) The "current dial string", an internal variable, is initially
+ empty. The set of candidate alternative event sequences includes
+ all of the alternatives specified in the digit map.
+
+ 2) At each step, a timer is set to wait for the next event, based
+ either on the default timing rules given above or on explicit
+ timing specified in one or more alternative event sequences. If
+ the timer expires and a member of the candidate set of
+ alternatives is fully satisfied, a timeout completion with full
+ match is reported. If the timer expires and part or none of any
+ candidate alternative is satisfied, a timeout completion with
+ partial match is reported.
+
+ 3) If an event is detected before the timer expires, it is mapped to
+ a digit string symbol and provisionally added to the end of the
+ current dial string. The duration of the event (long or not long)
+ is noted if and only if this is relevant in the current symbol
+ position (because at least one of the candidate alternative event
+ sequences includes the "Z" modifier at this position in the
+ sequence).
+
+ 4) The current dial string is compared to the candidate alternative
+ event sequences. If and only if a sequence expecting a
+ long-duration event at this position is matched (i.e., the event
+ had long duration and met the specification for this position),
+ then any alternative event sequences not specifying a long
+ duration event at this position are discarded, and the current
+ dial string is modified by inserting a "Z" in front of the symbol
+ representing the latest event. Any sequence expecting a long-
+ duration event at this position but not matching the observed
+ event is discarded from the candidate set. If alternative event
+ sequences not specifying a long duration event in the given
+
+
+
+
+Groves, et al. Standards Track [Page 44]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ position remain in the candidate set after application of the
+ above rules, the observed event duration is treated as irrelevant
+ in assessing matches to them.
+
+ 5) If exactly one candidate remains and it has been fully matched, a
+ completion event is generated indicating an unambiguous match. If
+ no candidates remain, the latest event is removed from the current
+ dial string and a completion event is generated indicating full
+ match if one of the candidates from the previous step was fully
+ satisfied before the latest event was detected, or partial match
+ otherwise. The event removed from the current dial string will
+ then be reported as per the currently active event processing
+ mechanisms.
+
+ 6) If no completion event is reported out of step 5, processing
+ returns to step 2.
+
+7.1.14.6 DigitMap Activation
+
+ A digit map is activated whenever a new Event descriptor is applied
+ to the Termination or embedded Event descriptor is activated, and
+ that Event descriptor contains a digit map completion event. The
+ digit map completion event contains an eventDM field in the requested
+ actions field. Each new activation of a digit map begins at step 1
+ of the above procedure, with a clear current dial string. Any
+ previous contents of the current dial string from an earlier
+ activation are lost.
+
+ A digit map completion event that does not contain an eventDM field
+ in its requested actions field is considered an error. Upon receipt
+ of such an event in an EventsDescriptor, a MG shall respond with an
+ error response, including Error 457 - Missing parameter in signal or
+ event.
+
+7.1.14.7 Interaction Of DigitMap and Event Processing
+
+ While the digit map is activated, detection is enabled for all events
+ defined in the package containing the specified digit map completion
+ event. Normal event behaviour (e.g., stopping of signals unless the
+ digit completion event has the KeepActive flag enabled) continues to
+ apply for each such event detected, except that:
+
+ - the events in the package containing the specified digit map
+ completion event other than the completion event itself are not
+ individually notified and have no side-effects unless separately
+ enabled; and
+
+
+
+
+
+Groves, et al. Standards Track [Page 45]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - an event that triggers a partial match completion event is not
+ recognized and therefore has no side effects until reprocessed
+ following the recognition of the digit map completion event.
+
+7.1.14.8 Wildcards
+
+ Note that if a package contains a digit map completion event, then an
+ event specification consisting of the package name with a wildcarded
+ ItemID (Property Name) will activate a digit map; to that end, the
+ event specification must include an eventDM field according to
+ section 7.1.14.6. If the package also contains the digit events
+ themselves, this form of event specification will cause the
+ individual events to be reported to the MGC as they are detected.
+
+7.1.14.9 Example
+
+ As an example, consider the following dial plan:
+
+ 0 Local operator
+
+ 00 Long-distance operator
+
+ xxxx Local extension number (starts with 1-7)
+
+ 8xxxxxxx Local number
+
+ #xxxxxxx Off-site extension
+
+ *xx Star services
+
+ 91xxxxxxxxxx Long-distance number
+
+ 9011 + up to 15 digits International number
+
+
+
+ If the DTMF detection package described in E.6 is used to collect the
+ dialed digits, then the dialing plan shown above results in the
+ following digit map:
+
+ (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)
+
+7.1.15 Statistics descriptor
+
+ The Statistics Descriptor provides information describing the status
+ and usage of a Termination during its existence within a specific
+ Context. There is a set of standard statistics kept for each
+ Termination where appropriate (number of octets sent and received for
+
+
+
+Groves, et al. Standards Track [Page 46]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ example). The particular statistical properties that are reported
+ for a given Termination are determined by the Packages realized by
+ the Termination. By default, statistics are reported when the
+ Termination is Subtracted from the Context. This behaviour can be
+ overridden by including an empty AuditDescriptor in the Subtract
+ command. Statistics may also be returned from the AuditValue
+ command, or any Add/Move/Modify command using the Audit descriptor.
+
+ Statistics are cumulative; reporting Statistics does not reset them.
+ Statistics are reset when a Termination is Subtracted from a Context.
+
+7.1.16 Packages descriptor
+
+ Used only with the AuditValue command, the PackageDescriptor returns
+ a list of Packages realized by the Termination.
+
+7.1.17 ObservedEvents descriptor
+
+ ObservedEvents is supplied with the Notify command to inform the MGC
+ of which event(s) were detected. Used with the AuditValue command,
+ the ObservedEventsDescriptor returns events in the event buffer which
+ have not been Notified. ObservedEvents contains the
+ RequestIdentifier of the EventsDescriptor that triggered the
+ notification, the event(s) detected, optionally the detection time(s)
+ and any parameters of the observed event. Detection times are
+ reported with a precision of hundredths of a second.
+
+7.1.18 Topology descriptor
+
+ A Topology descriptor is used to specify flow directions between
+ Terminations in a Context. Contrary to the descriptors in previous
+ subclauses, the Topology descriptor applies to a Context instead of a
+ Termination. The default topology of a Context is that each
+ Termination's transmission is received by all other Terminations.
+ The Topology descriptor is optional to implement. An MG that does
+ not support Topology descriptors, but receives a command containing
+ one, returns Error 444 Unsupported or unknown descriptor, and
+ optionally includes a string containing the name of the unsupported
+ Descriptor ("Topology") in the error text in the error descriptor.
+
+ The Topology descriptor occurs before the commands in an action. It
+ is possible to have an action containing only a Topology descriptor,
+ provided that the Context to which the action applies already exists.
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 47]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ A Topology descriptor consists of a sequence of triples of the form
+ (T1, T2, association). T1 and T2 specify Terminations within the
+ Context, possibly using the ALL or CHOOSE wildcard. The association
+ specifies how media flows between these two Terminations as follows.
+
+ - (T1, T2, isolate) means that the Terminations matching T2 do not
+ receive media from the Terminations matching T1, nor vice versa.
+
+ - (T1, T2, oneway) means that the Terminations that match T2 receive
+ media from the Terminations matching T1, but not vice versa. In
+ this case use of the ALL wildcard such that there are Terminations
+ that match both T1 and T2 is not allowed.
+
+ - (T1, T2, bothway) means that the Terminations matching T2 receive
+ media from the Terminations matching T1, and vice versa. In this
+ case it is allowed to use wildcards such that there are
+ Terminations that match both T1 and T2. However, if there is a
+ Termination that matches both, no loopback is introduced.
+
+ CHOOSE wildcards may be used in T1 and T2 as well, under the
+ following restrictions:
+
+ - the action (see clause 8) of which the topology descriptor is part
+ contains an Add command in which a CHOOSE wildcard is used;
+
+ - if a CHOOSE wildcard occurs in T1 or T2, then a partial name SHALL
+ NOT be specified.
+
+ The CHOOSE wildcard in a Topology descriptor matches the
+ TerminationID that the MG assigns in the first Add command that uses
+ a CHOOSE wildcard in the same action. An existing Termination that
+ matches T1 or T2 in the Context to which a Termination is added, is
+ connected to the newly added Termination as specified by the Topology
+ descriptor.
+
+ If a termination is not mentioned within a Topology Descriptor, any
+ topology associated with it remains unchanged. If, however, a new
+ termination is added into a context its association with the other
+ terminations within the context defaults to bothway, unless a
+ Topology Descriptor is given to change this (e.g., if T3 is added to
+ a context with T1 and T2 with topology (T3, T1, oneway) it will be
+ connected bothway to T2).
+
+ Figure 7 and the table following it show some examples of the effect
+ of including topology descriptors in actions. In these examples it
+ is assumed that the topology descriptors are applied in sequence.
+
+
+
+
+
+Groves, et al. Standards Track [Page 48]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +------------------+ +------------------+ +------------------+
+ | +----+ | | +----+ | | +----+ |
+ | | T2 | | | | T2 | | | | T2 | |
+ | +----+ | | +----+ | | +----+ |
+ | ^ ^ | | ^ | | ^ |
+ | | | | | | | | | |
+ | +--+ +--+ | | +---+ | | +--+ |
+ | | | | | | | | | |
+ | v v | | v | | | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ | | T1 |<-->| T3 | | | | T1 |<-->| T3 | | | | T1 |<-->| T3 | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ +------------------+ +------------------+ +------------------+
+ 1. No Topology Desc. 2. T1, T2, Isolate 3. T3, T2, Oneway
+
+ +------------------+ +------------------+ +------------------+
+ | +----+ | | +----+ | | +----+ |
+ | | T2 | | | | T2 | | | | T2 | |
+ | +----+ | | +----+ | | +----+ |
+ | | | | ^ | | ^ ^ |
+ | | | | | | | | | |
+ | +--+ | | +---+ | | +--+ +--+ |
+ | | | | | | | | | |
+ | v | | v | | v v |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ | | T1 |<-->| T3 | | | | T1 |<-->| T3 | | | | T1 |<-->| T3 | |
+ | +----+ +----+ | | +----+ +----+ | | +----+ +----+ |
+ +------------------+ +------------------+ +------------------+
+ 4. T2, T3 oneway 5. T2, T3 bothway 6. T1, T2 bothway
+
+ Note: the direction of the arrow indicates the direction of flow.
+
+ Figure 7: Example topologies
+
+ Topology Description
+
+ 1 No topology descriptors When no topology descriptors are
+ included, all Terminations have a
+ bothway connection to all other
+ Terminations.
+
+ 2 T1, T2 Isolate Removes the connection between T1 and
+ T2. T3 has a bothway connection with
+ both T1 and T2. T1 and T2 have bothway
+ connection to T3.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 49]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 3 T3, T2 oneway A oneway connection from T3 to T2 (i.e.,
+ T2 receives media flow from T3). A
+ bothway connection between T1 and T3.
+
+ 4 T2, T3 oneway A oneway connection between T2 to T3.
+ T1 and T3 remain bothway connected.
+
+ 5 T2, T3 bothway T2 is bothway connected to T3. This
+ results in the same as 2.
+
+ 6 T1, T2 bothway (T2, T3 All Terminations have a bothway
+ bothway and T1, T3 connection to all other Terminations.
+ bothway may be implied or
+ explicit).
+
+ A oneway connection must be implemented in such a way that the other
+ Terminations in the Context are not aware of the change in topology.
+
+7.1.19 Error Descriptor
+
+ If a responder encounters an error when processing a transaction
+ request, it must include an error descriptor in its response. A
+ Notify request may contain an error descriptor as well.
+
+ An error descriptor consists of an IANA-registered error code,
+ optionally accompanied by an error text. H.248.8 contains a list of
+ valid error codes and error descriptions.
+
+ An error descriptor shall be specified at the "deepest level" that is
+ semantically appropriate for the error being described and that is
+ possible given any parsing problems with the original request. An
+ error descriptor may refer to a syntactical construct other than
+ where it appears. For example, Error descriptor 422 - Syntax Error
+ in Action, could appear within a command even though it refers to the
+ larger construct - the action - and not the particular command within
+ which it appears.
+
+7.2 Command Application Programming Interface
+
+ Following is an Application Programming Interface (API) describing
+ the Commands of the protocol. This API is shown to illustrate the
+ Commands and their parameters and is not intended to specify
+ implementation (e.g., via use of blocking function calls). It
+ describes the input parameters in parentheses after the command name
+ and the return values in front of the Command. This is only for
+ descriptive purposes; the actual Command syntax and encoding are
+
+
+
+
+
+Groves, et al. Standards Track [Page 50]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ specified in later subclauses. The order of parameters to commands
+ is not fixed. Descriptors may appear as parameters to commands in
+ any order. The descriptors SHALL be processed in the order in which
+ they appear.
+
+ Any reply to a command may contain an error descriptor; the API does
+ not specifically show this.
+
+ All parameters enclosed by square brackets ([. . .]) are considered
+ optional.
+
+7.2.1 Add
+
+ The Add Command adds a Termination to a Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Add( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor]
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ The TerminationID specifies the Termination to be added to the
+ Context. The Termination is either created, or taken from the null
+ Context. If a CHOOSE wildcard is used in the TerminationID, the
+ selected TerminationID will be returned. Wildcards may be used in an
+ Add, but such usage would be unusual. If the wildcard matches more
+ than one TerminationID, all possible matches are attempted, with
+ results reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified.
+
+ The optional MediaDescriptor describes all media streams.
+
+
+
+
+Groves, et al. Standards Track [Page 51]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The optional ModemDescriptor and MuxDescriptor specify a modem and
+ multiplexer if applicable. For convenience, if a Multiplex
+ descriptor is present in an Add command and lists any Terminations
+ that are not currently in the Context, such Terminations are added to
+ the Context as if individual Add commands listing the Terminations
+ were invoked. If an error occurs on such an implied Add, error 471 -
+ Implied Add for Multiplex failure shall be returned and further
+ processing of the command shall cease.
+
+ The EventsDescriptor parameter is optional. If present, it provides
+ the list of events that should be detected on the Termination.
+
+ The EventBufferDescriptor parameter is optional. If present, it
+ provides the list of events that the MG is requested to detect and
+ buffer when EventBufferControl equals LockStep.
+
+ The SignalsDescriptor parameter is optional. If present, it provides
+ the list of signals that should be applied to the Termination.
+
+ The DigitMapDescriptor parameter is optional. If present, it defines
+ a DigitMap definition that may be used in an EventsDescriptor.
+
+ The AuditDescriptor is optional. If present, the command will return
+ descriptors as specified in the AuditDescriptor.
+
+ All descriptors that can be modified could be returned by MG if a
+ parameter was underspecified or overspecified. ObservedEvents,
+ Statistics, and Packages, and the EventBuffer descriptors are
+ returned only if requested in the AuditDescriptor.
+
+ Add SHALL NOT be used on a Termination with a serviceState of
+ "OutofService".
+
+7.2.2 Modify
+
+ The Modify Command modifies the properties of a Termination.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+
+
+
+Groves, et al. Standards Track [Page 52]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Modify( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor]
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ The TerminationID may be specific if a single Termination in the
+ Context is to be modified. Use of wildcards in the TerminationID may
+ be appropriate for some operations. If the wildcard matches more
+ than one TerminationID, all possible matches are attempted, with
+ results reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified. The CHOOSE option is an
+ error, as the Modify command may only be used on existing
+ Terminations.
+
+ For convenience, if a Multiplex Descriptor is present in a Modify
+ command, then:
+
+ - if the new Multiplex Descriptor lists any Terminations that are
+ not currently in the Context, such Terminations are added to the
+ context as if individual commands listing the Terminations were
+ invoked.
+
+ - if any Terminations listed previously in the Multiplex Descriptor
+ are no longer present in the new Multiplex Descriptor, they are
+ subtracted from the context as if individual Subtract commands
+ listing the Terminations were invoked.
+
+ The remaining parameters to Modify are the same as those to Add.
+ Possible return values are the same as those to Add.
+
+7.2.3 Subtract
+
+ The Subtract Command disconnects a Termination from its Context and
+ returns statistics on the Termination's participation in the Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+
+
+
+Groves, et al. Standards Track [Page 53]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Subtract(TerminationID
+ [, AuditDescriptor]
+ )
+
+ TerminationID in the input parameters represents the Termination that
+ is being subtracted. The TerminationID may be specific or may be a
+ wildcard value indicating that all (or a set of related) Terminations
+ in the Context of the Subtract Command are to be subtracted. If the
+ wildcard matches more than one TerminationID, all possible matches
+ are attempted, with results reported for each one. The order of
+ attempts when multiple TerminationIDs match is not specified.
+
+ The use of CHOOSE in the TerminationID is an error, as the Subtract
+ command may only be used on existing Terminations.
+
+ ALL may be used as the ContextID as well as the TerminationId in a
+ Subtract, which would have the effect of deleting all Contexts,
+ deleting all ephemeral Terminations, and returning all physical
+ Terminations to Null Context. Subtract of a termination from the
+ Null Context is not allowed.
+
+ For convenience, if a multiplexing Termination is the object of a
+ Subtract command, then any bearer Terminations listed in its
+ Multiplex Descriptor are subtracted from the context as if individual
+ Subtract commands listing the Terminations were invoked.
+
+ By default, the Statistics parameter is returned to report
+ information collected on the Termination or Terminations specified in
+ the Command. The information reported applies to the Termination's
+ or Terminations' existence in the Context from which it or they are
+ being subtracted.
+
+ The AuditDescriptor is optional. If present, the command will return
+ only those descriptors as specified in the AuditDescriptor, which may
+ be empty. If omitted, the Statistics descriptor is returned, by
+ default. Possible return values are the same as those to Add.
+
+ When a provisioned Termination is Subtracted from a Context, its
+ property values shall revert to:
+
+ - the default value, if specified for the property and not
+ overridden by provisioning;
+
+ - otherwise, the provisioned value.
+
+
+
+Groves, et al. Standards Track [Page 54]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+7.2.4 Move
+
+ The Move Command moves a Termination to another Context from its
+ current Context in one atomic operation. The Move command is the
+ only command that refers to a Termination in a Context different from
+ that to which the command is applied. The Move command shall not be
+ used to move Terminations to or from the null Context.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ Move( TerminationID
+ [, MediaDescriptor]
+ [, ModemDescriptor]
+ [, MuxDescriptor]
+ [, EventsDescriptor]
+ [, EventBufferDescriptor]
+ [, SignalsDescriptor]
+ [, DigitMapDescriptor]
+ [, AuditDescriptor]
+ )
+
+ The TerminationID specifies the Termination to be moved. It may be
+ wildcarded, but CHOOSE shall not be used in the TerminationID. If
+ the wildcard matches more than one TerminationID, all possible
+ matches are attempted, with results reported for each one. The order
+ of attempts when multiple TerminationIDs match is not specified. The
+ Context to which the Termination is moved is indicated by the target
+ ContextId in the Action. If the last remaining Termination is moved
+ out of a Context, the Context is deleted.
+
+ The Move command does not affect the properties of the Termination on
+ which it operates, except those properties explicitly modified by
+ descriptors included in the Move command. The AuditDescriptor with
+ the Statistics option, for example, would return statistics on the
+ Termination just prior to the Move. Possible descriptors returned
+ from Move are the same as for Add.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 55]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ For convenience, if a multiplexing Termination is the object of a
+ Move command, then any bearer Terminations listed in its Multiplex
+ Descriptor are also moved as if individual Move commands listing the
+ Terminations were invoked.
+
+ Move SHALL NOT be used on a Termination with a serviceState of
+ "OutofService".
+
+7.2.5 AuditValue
+
+ The AuditValue Command returns the current values of properties,
+ events, signals and statistics associated with Terminations.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,DigitMapDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ [,PackagesDescriptor]
+ AuditValue(TerminationID,
+ AuditDescriptor
+ )
+
+ TerminationID may be specific or wildcarded. If the wildcard matches
+ more than one TerminationID, all possible matches are attempted, with
+ results reported for each one. The order of attempts when multiple
+ TerminationIDs match is not specified. If a wildcarded response is
+ requested, only one command return is generated, with the contents
+ containing the union of the values of all Terminations matching the
+ wildcard. This convention may reduce the volume of data required to
+ audit a group of Terminations. Use of CHOOSE is an error.
+
+ The appropriate descriptors, with the current values for the
+ Termination, are returned from AuditValue. Values appearing in
+ multiple instances of a descriptor are defined to be alternate values
+ supported, with each parameter in a descriptor considered
+ independent.
+
+ ObservedEvents returns a list of events in the EventBuffer. If the
+ ObservedEventsDescriptor is audited while a DigitMap is active, the
+ returned ObservedEvents descriptor also includes a digit map
+ completion event that shows the current dial string but does not show
+ a Termination method.
+
+
+
+Groves, et al. Standards Track [Page 56]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ EventBuffer returns the set of events and associated parameter values
+ currently enabled in the EventBufferDescriptor. PackagesDescriptor
+ returns a list of packages realized by the Termination.
+ DigitMapDescriptor returns the name or value of the current DigitMap
+ for the Termination. DigitMap requested in an AuditValue command
+ with TerminationID ALL returns all DigitMaps in the gateway.
+ Statistics returns the current values of all statistics being kept on
+ the Termination. Specifying an empty Audit descriptor results in
+ only the TerminationID being returned. This may be useful to get a
+ list of TerminationIDs when used with wildcard. Annexes A and B
+ provide a special syntax for presenting such a list in condensed
+ form, such that the AuditValue command tag does not have to be
+ repeated for each TerminationID.
+
+ AuditValue results depend on the Context, viz. specific, null, or
+ wildcarded. (Note that ContextID ALL does not include the null
+ Context.) The TerminationID may be specific, or wildcarded.
+
+ The following are examples of what is returned in case the context
+ and/or the termination is wildcarded and a wildcarded response has
+ been specified.
+
+ Assume that the gateway has 4 terminations: t1/1, t1/2, t2/1 and
+ t2/2. Assume that terminations t1/* have implemented packages aaa
+ and bbb and that terminations t2/* have implemented packages ccc and
+ ddd. Assume that Context 1 has t1/1 and t2/1 in it and that Context
+ 2 has t1/2 and t2/2 in it.
+
+ The command:
+
+ Context=1{AuditValue=t1/1{Audit{Packages}}}
+
+ Returns:
+
+ Context=1{AuditValue=t1/1{Packages{aaa,bbb}}}
+
+ The command:
+
+ Context=*{AuditValue=t2/*{Audit{Packages}}}
+
+ Returns:
+
+ Context=1{AuditValue=t2/1{Packages{ccc,ddd}}},
+ Context=2{AuditValue=t2/2{Packages{ccc,ddd}}}
+
+ The command:
+
+ Context=*{W-AuditValue=t1/*{Audit{Packages}}}
+
+
+
+Groves, et al. Standards Track [Page 57]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Returns:
+
+ Context=*{W-AuditValue=t1/*{Packages{aaa,bbb}}}
+
+ Note: A wildcard response may also be used for other commands such as
+ Subtract.
+
+ The following illustrates other information that can be obtained with
+ the AuditValue Command:
+
+ ContextID TerminationID Information Obtained
+
+ Specific wildcard Audit of matching Terminations in a Context
+
+ Specific specific Audit of a single Termination in a Context
+
+ Null Root Audit of Media Gateway state and events
+
+ Null wildcard Audit of all matching Terminations in the
+ null Context
+
+ Null specific Audit of a single Termination outside of any
+ Context
+
+ All wildcard Audit of all matching Terminations and the
+ Context to which they are associated
+
+ All Root List of all ContextIds (the ContextID list
+ should be returned by using multiple action
+ replies, each containing a ContextID from
+ the list)
+
+ All Specific (Non-null) ContextID in which the
+ Termination currently exists
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 58]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+7.2.6 AuditCapabilities
+
+ The AuditCapabilities Command returns the possible values of
+ properties, events, signals and statistics associated with
+ Terminations.
+
+ TerminationID
+ [,MediaDescriptor]
+ [,ModemDescriptor]
+ [,MuxDescriptor]
+ [,EventsDescriptor]
+ [,SignalsDescriptor]
+ [,ObservedEventsDescriptor]
+ [,EventBufferDescriptor]
+ [,StatisticsDescriptor]
+ AuditCapabilities(TerminationID,
+ AuditDescriptor
+ )
+
+ The appropriate descriptors, with the possible values for the
+ Termination are returned from AuditCapabilities. Descriptors may be
+ repeated where there are multiple possible values. If a wildcarded
+ response is requested, only one command return is generated, with the
+ contents containing the union of the values of all Terminations
+ matching the wildcard. This convention may reduce the volume of data
+ required to audit a group of Terminations.
+
+ Interpretation of what capabilities are requested for various values
+ of ContextID and TerminationID is the same as in AuditValue.
+
+ The EventsDescriptor returns the list of possible events on the
+ Termination together with the list of all possible values for the
+ EventsDescriptor Parameters. EventBufferDescriptor returns the same
+ information as EventsDescriptor. The SignalsDescriptor returns the
+ list of possible signals that could be applied to the Termination
+ together with the list of all possible values for the Signals
+ Parameters. StatisticsDescriptor returns the names of the statistics
+ being kept on the termination. ObservedEventsDescriptor returns the
+ names of active events on the Termination. DigitMap and Packages are
+ not legal in AuditCapability.
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 59]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The following illustrates other information that can be obtained with
+ the AuditCapabilties Command:
+
+ ContextID TerminationID Information Obtained
+
+ Specific wildcard Audit of matching Terminations in a Context
+
+ Specific specific Audit of a single Termination in a Context
+
+ Null Root Audit of MG state and events
+
+ Null wildcard Audit of all matching Terminations in the
+ Null Context
+
+ Null specific Audit of a single Termination outside of any
+ Context
+
+ All wildcard Audit of all matching Terminations and the
+ Context to which they are associated
+
+ All Root Same as for AuditValue
+
+ All Specific Same as for AuditValue
+
+7.2.7 Notify
+
+ The Notify Command allows the Media Gateway to notify the Media
+ Gateway Controller of events occurring within the Media Gateway.
+
+ TerminationID
+ Notify(TerminationID,
+ ObservedEventsDescriptor,
+ [ErrorDescriptor]
+ )
+
+ The TerminationID parameter specifies the Termination issuing the
+ Notify Command. The TerminationID shall be a fully qualified name.
+
+ The ObservedEventsDescriptor contains the RequestID and a list of
+ events that the Media Gateway detected in the order that they were
+ detected. Each event in the list is accompanied by parameters
+ associated with the event and optionally an indication of the time
+ that the event was detected. Procedures for sending Notify commands
+ with RequestID equal to 0 are for further study.
+
+ Notify Commands with RequestID not equal to 0 shall occur only as the
+ result of detection of an event specified by an Events descriptor
+ which is active on the Termination concerned.
+
+
+
+Groves, et al. Standards Track [Page 60]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The RequestID returns the RequestID parameter of the EventsDescriptor
+ that triggered the Notify Command. It is used to correlate the
+ notification with the request that triggered it. The events in the
+ list must have been requested via the triggering EventsDescriptor or
+ embedded events descriptor unless the RequestID is 0 (which is for
+ further study).
+
+ The ErrorDescriptor may be sent in the Notify Command as a result of
+ Error 518 - Event buffer full.
+
+7.2.8 ServiceChange
+
+ The ServiceChange Command allows the Media Gateway to notify the
+ Media Gateway Controller that a Termination or group of Terminations
+ is about to be taken out of service or has just been returned to
+ service. The Media Gateway Controller may indicate that
+ Termination(s) shall be taken out of or returned to service. The
+ Media Gateway may notify the MGC that the capability of a Termination
+ has changed. It also allows a MGC to hand over control of a MG to
+ another MGC.
+
+ TerminationID,
+
+ [ServiceChangeDescriptor]
+ ServiceChange ( TerminationID,
+ ServiceChangeDescriptor
+ )
+
+ The TerminationID parameter specifies the Termination(s) that are
+ taken out of or returned to service. Wildcarding of Termination
+ names is permitted, with the exception that the CHOOSE mechanism
+ shall not be used. Use of the "Root" TerminationID indicates a
+ ServiceChange affecting the entire Media Gateway.
+
+ The ServiceChangeDescriptor contains the following parameters as
+ required:
+
+ - ServiceChangeMethod
+ - ServiceChangeReason
+ - ServiceChangeDelay
+ - ServiceChangeAddress
+ - ServiceChangeProfile
+ - ServiceChangeVersion
+ - ServiceChangeMgcId
+ - TimeStamp
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 61]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The ServiceChangeMethod parameter specifies the type of ServiceChange
+ that will or has occurred:
+
+ 1) Graceful - indicates that the specified Terminations will be taken
+ out of service after the specified ServiceChangeDelay; established
+ connections are not yet affected, but the Media Gateway Controller
+ should refrain from establishing new connections and should
+ attempt to gracefully tear down existing connections on the
+ Termination(s) affected by the serviceChange command. The MG
+ should set Termination serviceState at the expiry of
+ ServiceChangeDelay or the removal of the Termination from an
+ active Context (whichever is first), to "out of service".
+
+ 2) Forced - indicates that the specified Terminations were taken
+ abruptly out of service and any established connections associated
+ with them may be lost. For non-Root terminations, the MGC is
+ responsible for cleaning up the Context (if any) with which the
+ failed Termination is associated. At a minimum the Termination
+ shall be subtracted from the Context. The Termination
+ serviceState should be "out of service". For the root
+ termination, the MGC can assume that all connections are lost on
+ the MG and thus can consider that all the terminations have been
+ subtracted.
+
+ 3) Restart - indicates that service will be restored on the specified
+ Terminations after expiration of the ServiceChangeDelay. The
+ serviceState should be set to "inService" upon expiry of
+ ServiceChangeDelay.
+
+ 4) Disconnected - always applied with the Root TerminationID,
+ indicates that the MG lost communication with the MGC, but it was
+ subsequently restored to the same MGC (possibly after trying other
+ MGCs on a pre-provisioned list). Since MG state may have changed,
+ the MGC may wish to use the Audit command to resynchronize its
+ state with the MG's.
+
+ 5) Handoff - sent from the MGC to the MG, this reason indicates that
+ the MGC is going out of service and a new MGC association must be
+ established. Sent from the MG to the MGC, this indicates that the
+ MG is attempting to establish a new association in accordance with
+ a Handoff received from the MGC with which it was previously
+ associated.
+
+ 6) Failover - sent from MG to MGC to indicate the primary MG is out
+ of service and a secondary MG is taking over. This serviceChange
+ method is also sent from the MG to the MGC when the MG detects
+ that MGC has failed.
+
+
+
+
+Groves, et al. Standards Track [Page 62]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7) Another value whose meaning is mutually understood between the MG
+ and the MGC.
+
+ The ServiceChangeReason parameter specifies the reason why the
+ ServiceChange has or will occur. It consists of an alphanumeric
+ token (IANA registered) and, optionally, an explanatory string.
+
+ The optional ServiceChangeAddress parameter specifies the address
+ (e.g., IP port number for IP networks) to be used for subsequent
+ communications. It can be specified in the input parameter
+ descriptor or the returned result descriptor. ServiceChangeAddress
+ and ServiceChangeMgcId parameters must not both be present in the
+ ServiceChangeDescriptor or the ServiceChangeResultDescriptor. The
+ ServiceChangeAddress provides an address to be used within the
+ Context of the association currently being negotiated, while the
+ ServiceChangeMgcId provides an alternate address where the MG should
+ seek to establish another association. Note that the use of
+ ServiceChangeAddress is not encouraged. MGCs and MGs must be able to
+ cope with the ServiceChangeAddress being either a full address or
+ just a port number in the case of TCP transports.
+
+ The optional ServiceChangeDelay parameter is expressed in seconds.
+ If the delay is absent or set to zero, the delay value should be
+ considered to be null. In the case of a "graceful"
+ ServiceChangeMethod, a null delay indicates that the Media Gateway
+ Controller should wait for the natural removal of existing
+ connections and should not establish new connections. For "graceful"
+ only, a null delay means the MG must not set serviceState "out of
+ service" until the Termination is in the null Context.
+
+ The optional ServiceChangeProfile parameter specifies the Profile (if
+ any) of the protocol supported. The ServiceChangeProfile includes
+ the version of the profile supported.
+
+ The optional ServiceChangeVersion parameter contains the protocol
+ version and is used if protocol version negotiation occurs (see
+ 11.3).
+
+ The optional TimeStamp parameter specifies the actual time as kept by
+ the sender. As such, it is not necessarily absolute time according
+ to, for example, a local time zone - it merely establishes an
+ arbitrary starting time against which all future timestamps
+ transmitted by a sender during this association shall be compared.
+ It can be used by the responder to determine how its notion of time
+ differs from that of its correspondent. TimeStamp is sent with a
+ precision of hundredths of a second.
+
+
+
+
+
+Groves, et al. Standards Track [Page 63]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The optional Extension parameter may contain any value whose meaning
+ is mutually understood by the MG and MGC.
+
+ A ServiceChange Command specifying the "Root" for the TerminationID
+ and ServiceChangeMethod equal to Restart is a registration command by
+ which a Media Gateway announces its existence to the Media Gateway
+ Controller. The Media Gateway may also announce a registration
+ command by specifying the "Root" for the TerminationID and
+ ServiceChangeMethod equal to Failover when the MG detects MGC
+ failures. The Media Gateway is expected to be provisioned with the
+ name of one primary and optionally some number of alternate Media
+ Gateway Controllers. Acknowledgement of the ServiceChange Command
+ completes the registration process, except when the MGC has returned
+ an alternative ServiceChangeMgcId as described in the following
+ paragraph. The MG may specify the transport ServiceChangeAddress to
+ be used by the MGC for sending messages in the ServiceChangeAddress
+ parameter in the input ServiceChangeDescriptor. The MG may specify
+ an address in the ServiceChangeAddress parameter of the ServiceChange
+ request, and the MGC may also do so in the ServiceChange reply. In
+ either case, the recipient must use the supplied address as the
+ destination for all subsequent transaction requests within the
+ association. At the same time, as indicated in clause 9, transaction
+ replies and pending indications must be sent to the address from
+ which the corresponding requests originated. This must be done even
+ if it implies extra messaging because commands and responses cannot
+ be packed together. The TimeStamp parameter shall be sent with a
+ registration command and its response.
+
+ The Media Gateway Controller may return a ServiceChangeMgcId
+ parameter that describes the Media Gateway Controller that should
+ preferably be contacted for further service by the Media Gateway. In
+ this case the Media Gateway shall reissue the ServiceChange command
+ to the new Media Gateway Controller. The MGC specified in a
+ ServiceChangeMgcId, if provided, shall be contacted before any
+ further alternate MGCs. On a HandOff message from MGC to MG, the
+ ServiceChangeMgcId is the new MGC that will take over from the
+ current MGC.
+
+ The return from ServiceChange is empty except when the Root
+ terminationID is used. In that case it includes the following
+ parameters as required:
+
+ - ServiceChangeAddress, if the responding MGC wishes to specify a
+ new destination for messages from the MG for the remainder of the
+ association;
+
+ - ServiceChangeMgcId, if the responding MGC does not wish to sustain
+ an association with the MG;
+
+
+
+Groves, et al. Standards Track [Page 64]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ - ServiceChangeProfile, if the responder wishes to negotiate the
+ profile to be used for the association;
+
+ - ServiceChangeVersion, if the responder wishes to negotiate the
+ version of the protocol to be used for the association.
+
+ The following ServiceChangeReasons are defined. This list may be
+ extended by an IANA registration as outlined in 13.3.
+
+ 900 Service Restored
+ 901 Cold Boot
+ 902 Warm Boot
+ 903 MGC Directed Change
+ 904 Termination malfunctioning
+ 905 Termination taken out of service
+ 906 Loss of lower layer connectivity (e.g., downstream sync)
+ 907 Transmission Failure
+ 908 MG Impending Failure
+ 909 MGC Impending Failure
+ 910 Media Capability Failure
+ 911 Modem Capability Failure
+ 912 Mux Capability Failure
+ 913 Signal Capability Failure
+ 914 Event Capability Failure
+ 915 State Loss
+
+7.2.9 Manipulating and Auditing Context Attributes
+
+ The commands of the protocol as discussed in the preceding subclauses
+ apply to Terminations. This subclause specifies how Contexts are
+ manipulated and audited.
+
+ Commands are grouped into actions (see clause 8). An action applies
+ to one Context. In addition to commands, an action may contain
+ Context manipulation and auditing instructions.
+
+ An action request sent to a MG may include a request to audit
+ attributes of a Context. An action may also include a request to
+ change the attributes of a Context.
+
+ The Context properties that may be included in an action reply are
+ used to return information to a MGC. This can be information
+ requested by an audit of Context attributes or details of the effect
+ of manipulation of a Context.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 65]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ If a MG receives an action which contains both a request to audit
+ context attributes and a request to manipulate those attributes, the
+ response SHALL include the values of the attributes after processing
+ the manipulation request.
+
+7.2.10 Generic Command Syntax
+
+ The protocol can be encoded in a binary format or in a text format.
+ MGCs should support both encoding formats. MGs may support both
+ formats.
+
+ The protocol syntax for the binary format of the protocol is defined
+ in Annex A. Annex C specifies the encoding of the Local and Remote
+ descriptors for use with the binary format.
+
+ A complete ABNF of the text encoding of the protocol per RFC 2234 is
+ given in Annex B. SDP is used as the encoding of the Local and
+ Remote descriptors for use with the text encoding as modified in
+ 7.1.8.
+
+7.3 Command Error Codes
+
+ Errors consist of an IANA registered error code and an explanatory
+ string. Sending the explanatory string is optional. Implementations
+ are encouraged to append diagnostic information to the end of the
+ string.
+
+ When a MG reports an error to a MGC, it does so in an error
+ descriptor. An error descriptor consists of an error code and
+ optionally the associated explanatory string.
+
+ H.248.8 contains the error codes supported by Recommendations in the
+ H.248 sub-series.
+
+8 Transactions
+
+ Commands between the Media Gateway Controller and the Media Gateway
+ are grouped into Transactions, each of which is identified by a
+ TransactionID. Transactions consist of one or more Actions. An
+ Action consists of a non-empty series of Commands, Context property
+ modifications, or Context property audits that are limited to
+ operating within a single Context. Consequently, each Action
+ typically specifies a ContextID. However, there are two
+ circumstances where a specific ContextID is not provided with an
+ Action. One is the case of modification of a Termination outside of
+ a Context. The other is where the controller requests the gateway to
+ create a new Context. Figure 8 is a graphic representation of the
+ Transaction, Action and Command relationships.
+
+
+
+Groves, et al. Standards Track [Page 66]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ +----------------------------------------------------------+
+ | Transaction x |
+ | +----------------------------------------------------+ |
+ | | Action 1 | |
+ | | +---------+ +---------+ +---------+ +---------+ | |
+ | | | Command | | Command | | Command | | Command | | |
+ | | | 1 | | 2 | | 3 | | 4 | | |
+ | | +---------+ +---------+ +---------+ +---------+ | |
+ | +----------------------------------------------------+ |
+ | |
+ | +----------------------------------------------------+ |
+ | | Action 2 | |
+ | | +---------+ | |
+ | | | Command | | |
+ | | | 1 | | |
+ | | +---------+ | |
+ | +----------------------------------------------------+ |
+ | |
+ | +----------------------------------------------------+ |
+ | | Action 3 | |
+ | | +---------+ +---------+ +---------+ | |
+ | | | Command | | Command | | Command | | |
+ | | | 1 | | 2 | | 3 | | |
+ | | +---------+ +---------+ +---------+ | |
+ | +----------------------------------------------------+ |
+ +----------------------------------------------------------+
+
+ Figure 8: Transactions, Actions and Commands
+
+ Transactions are presented as TransactionRequests. Corresponding
+ responses to a TransactionRequest are received in a single reply,
+ possibly preceded by a number of TransactionPending messages (see
+ 8.2.3).
+
+ Transactions guarantee ordered Command processing. That is, Commands
+ within a Transaction are executed sequentially. Ordering of
+ Transactions is NOT guaranteed - transactions may be executed in any
+ order, or simultaneously.
+
+ At the first failing Command in a Transaction, processing of the
+ remaining Commands in that Transaction stops. If a command contains
+ a wildcarded TerminationID, the command is attempted with each of the
+ actual TerminationIDs matching the wildcard. A response within the
+ TransactionReply is included for each matching TerminationID, even if
+ one or more instances generated an error. If any TerminationID
+ matching a wildcard results in an error when executed, any commands
+ following the wildcarded command are not attempted.
+
+
+
+
+Groves, et al. Standards Track [Page 67]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Commands may be marked as "Optional" which can override this
+ behaviour - if a command marked as Optional results in an error,
+ subsequent commands in the Transaction will be executed. If a
+ command fails, the MG shall as far as possible restore the state that
+ existed prior to the attempted execution of the command before
+ continuing with command processing.
+
+ A TransactionReply includes the results for all of the Commands in
+ the corresponding TransactionRequest. The TransactionReply includes
+ the return values for the Commands that were executed successfully,
+ and the Command and error descriptor for any Command that failed.
+
+ TransactionPending is used to periodically notify the receiver that a
+ Transaction has not completed yet, but is actively being processed.
+
+ Applications SHOULD implement an application level timer per
+ transaction. Expiration of the timer should cause a retransmission
+ of the request. Receipt of a Reply should cancel the timer. Receipt
+ of Pending should restart the timer.
+
+8.1 Common parameters
+
+8.1.1 Transaction Identifiers
+
+ Transactions are identified by a TransactionID, which is assigned by
+ sender and is unique within the scope of the sender. A response
+ containing an error descriptor to indicate that the TransactionID is
+ missing in a request shall use TransactionID 0 in the corresponding
+ TransactionReply.
+
+8.1.2 Context Identifiers
+
+ Contexts are identified by a ContextID, which is assigned by the
+ Media Gateway and is unique within the scope of the Media Gateway.
+ The Media Gateway Controller shall use the ContextID supplied by the
+ Media Gateway in all subsequent Transactions relating to that
+ Context. The protocol makes reference to a distinguished value that
+ may be used by the Media Gateway Controller when referring to a
+ Termination that is currently not associated with a Context, namely
+ the null ContextID.
+
+ The CHOOSE wildcard is used to request that the Media Gateway create
+ a new Context.
+
+ The MGC may use the ALL wildcard to address all Contexts on the MG.
+ The null Context is not included when the ALL wildcard is used.
+
+
+
+
+
+Groves, et al. Standards Track [Page 68]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The MGC shall not use partially specified ContextIDs containing the
+ CHOOSE or ALL wildcards.
+
+8.2 Transaction Application Programming Interface
+
+ Following is an Application Programming Interface (API) describing
+ the Transactions of the protocol. This API is shown to illustrate
+ the Transactions and their parameters and is not intended to specify
+ implementation (e.g., via use of blocking function calls). It will
+ describe the input parameters and return values expected to be used
+ by the various Transactions of the protocol from a very high level.
+ Transaction syntax and encodings are specified in later subclauses.
+
+8.2.1 TransactionRequest
+
+ The TransactionRequest is invoked by the sender. There is one
+ Transaction per request invocation. A request contains one or more
+ Actions, each of which specifies its target Context and one or more
+ Commands per Context.
+
+ TransactionRequest(TransactionId {
+ ContextID {Command ... Command},
+ . . .
+ ContextID {Command ... Command } })
+
+ The TransactionID parameter must specify a value for later
+ correlation with the TransactionReply or TransactionPending response
+ from the receiver.
+
+ The ContextID parameter must specify a value to pertain to all
+ Commands that follow up to either the next specification of a
+ ContextID parameter or the end of the TransactionRequest, whichever
+ comes first.
+
+ The Command parameter represents one of the Commands mentioned in 7.2
+ (Command Application Programming Interface).
+
+8.2.2 TransactionReply
+
+ The TransactionReply is invoked by the receiver. There is one reply
+ invocation per transaction. A reply contains one or more Actions,
+ each of which must specify its target Context and one or more
+ Responses per Context. The TransactionReply is invoked by the
+ responder when it has processed the TransactionRequest.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 69]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ A TransactionRequest has been processed:
+
+ - when all actions in that TransactionRequest have been processed;
+ or
+
+ - when an error is encountered in processing that
+ TransactionRequest, except when the error is in an optional
+ command.
+
+ A command has been processed when all descriptors in that command
+ have been processed.
+
+ A SignalsDescriptor is considered to have been processed when it has
+ been established that the descriptor is syntactically valid, the
+ requested signals are supported and they have been queued to be
+ applied.
+
+ An EventsDescriptor or EventBufferDescriptor is considered to have
+ been processed when it has been established that the descriptor is
+ syntactically valid, the requested events can be observed, any
+ embedded signals can be generated, any embedded events can be
+ detected, and the MG has been brought into a state in which the
+ events will be detected.
+
+ TransactionReply(TransactionID {
+ ContextID { Response ... Response },
+ . . .
+ ContextID { Response ... Response } })
+
+ The TransactionID parameter must be the same as that of the
+ corresponding TransactionRequest.
+
+ The ContextID parameter must specify a value to pertain to all
+ Responses for the action. The ContextID may be specific, all or
+ null.
+
+ Each of the Response parameters represents a return value as
+ mentioned in 7.2, or an error descriptor if the command execution
+ encountered an error. Commands after the point of failure are not
+ processed and, therefore, Responses are not issued for them.
+
+ An exception to this occurs if a command has been marked as optional
+ in the Transaction request. If the optional command generates an
+ error, the transaction still continues to execute, so the Reply
+ would, in this case, have Responses after an Error.
+
+ Section 7.1.19 Error Descriptor specifies the generation of error
+ descriptors. The text below discusses several individual cases.
+
+
+
+Groves, et al. Standards Track [Page 70]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ If the receiver encounters an error in processing a ContextID, the
+ requested Action response will consist of the Context ID and a single
+ error descriptor, 422 - Syntax Error in Action.
+
+ If the receiver encounters an error such that it cannot determine a
+ legal Action, it will return a TransactionReply consisting of the
+ TransactionID and a single error descriptor, 422 - Syntax Error in
+ Action. If the end of an action cannot be reliably determined but
+ one or more commands can be parsed, it will process them and then
+ send 422 - Syntax Error in Action as the last action for the
+ transaction. If the receiver encounters an error such that is cannot
+ determine a legal Transaction, it will return a TransactionReply with
+ a null TransactionID and a single error descriptor (403 - Syntax
+ Error in TransactionRequest).
+
+ If the end of a transaction cannot be reliably determined and one or
+ more Actions can be parsed, it will process them and then return 403
+ - Syntax Error in Transaction as the last action reply for the
+ transaction. If no Actions can be parsed, it will return 403 -
+ Syntax Error in TransactionRequest as the only reply.
+
+ If the terminationID cannot be reliably determined, it will send 442
+ - Syntax Error in Command as the action reply.
+
+ If the end of a command cannot be reliably determined, it will return
+ 442 - Syntax Error in Command as the reply to the last action it can
+ parse.
+
+8.2.3 TransactionPending
+
+ The receiver invokes the TransactionPending. A TransactionPending
+ indicates that the Transaction is actively being processed, but has
+ not been completed. It is used to prevent the sender from assuming
+ the TransactionRequest was lost where the Transaction will take some
+ time to complete.
+
+ TransactionPending(TransactionID { } )
+
+ The TransactionID parameter must be the same as that of the
+ corresponding TransactionRequest. A property of root
+ (normalMGExecutionTime) is settable by the MGC to indicate the
+ interval within which the MGC expects a response to any transaction
+ from the MG. Another property (normalMGCExecutionTime) is settable
+ by the MGC to indicate the interval within which the MG should expect
+ a response to any transaction from the MGC. Senders may receive more
+ than one TransactionPending for a command. If a duplicate request is
+
+
+
+
+
+Groves, et al. Standards Track [Page 71]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ received when pending, the responder may send a duplicate pending
+ immediately, or continue waiting for its timer to trigger another
+ TransactionPending.
+
+8.3 Messages
+
+ Multiple Transactions can be concatenated into a Message. Messages
+ have a header, which includes the identity of the sender. The
+ Message Identifier (MID) of a message is set to a provisioned name
+ (e.g., domain address/domain name/device name) of the entity
+ transmitting the message. Domain name is a suggested default. An
+ H.248.1 entity (MG/MGC) must consistently use the same MID in all
+ messages it originates for the duration of control association with
+ the peer (MGC/MG).
+
+ Every Message contains a Version Number identifying the version of
+ the protocol the message conforms to. Versions consist of one or two
+ digits, beginning with version 1 for the present version of the
+ protocol.
+
+ The transactions in a message are treated independently. There is no
+ order implied; there is no application or protocol acknowledgement of
+ a message. A message is essentially a transport mechanism. For
+ example, message X containing transaction requests A, B, and C may be
+ responded to with message Y containing replies to A and C and message
+ Z containing the reply to B. Likewise, message L containing request
+ D and message M containing request E may be responded to with message
+ N containing replies to both D and E.
+
+9 Transport
+
+ The transport mechanism for the protocol should allow the reliable
+ transport of transactions between a MGC and MG. The transport shall
+ remain independent of what particular commands are being sent and
+ shall be applicable to all application states. There are several
+ transports defined for the protocol, which are defined in Annexes to
+ this RFC and other Recommendations of the H.248
+ sub-series. Additional Transports may be defined as additional
+
+ Recommendations of the H.248 sub-series. For transport of the
+ protocol over IP, MGCs shall implement both TCP and UDP/ALF, a MG
+ shall implement TCP or UDP/ALF or both.
+
+ The MG is provisioned with a name or address (such as DNS name or IP
+ address) of a primary and zero or more secondary MGCs (see 7.2.8)
+ that is the address the MG uses to send messages to the MGC. If TCP
+ or UDP is used as the protocol transport and the port to which the
+ initial ServiceChange request is to be sent is not otherwise known,
+
+
+
+Groves, et al. Standards Track [Page 72]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ that request should be sent to the default port number for the
+ protocol. This port number is 2944 for text-encoded operation or
+ 2945 for binary-encoded operation, for either UDP or TCP. The MGC
+ receives the message containing the ServiceChange request from the MG
+ and can determine the MG's address from it. As described in 7.2.8,
+ either the MG or the MGC may supply an address in the
+ ServiceChangeAddress parameter to which subsequent transaction
+ requests must be addressed, but responses (including the response to
+ the initial ServiceChange request) must always be sent back to the
+ address which was the source of the corresponding request. For
+ example, in IP networks, this is the source address in the IP header
+ and the source port number in the TCP/UDP/SCTP header.
+
+9.1 Ordering of Commands
+
+ This RFC does not mandate that the underlying transport protocol
+ guarantees the sequencing of transactions sent to an entity. This
+ property tends to maximize the timeliness of actions, but it has a
+ few drawbacks. For example:
+
+ - Notify commands may be delayed and arrive at the MGC after the
+ transmission of a new command changing the EventsDescriptor.
+
+ - If a new command is transmitted before a previous one is
+ acknowledged, there is no guarantee that prior command will be
+ executed before the new one.
+
+ Media Gateway Controllers that want to guarantee consistent operation
+ of the Media Gateway may use the following rules. These rules are
+ with respect to commands that are in different transactions.
+ Commands that are in the same transaction are executed in order (see
+ clause 8).
+
+ 1) When a Media Gateway handles several Terminations, commands
+ pertaining to the different Terminations may be sent in parallel,
+ for example following a model where each Termination (or group of
+ Terminations) is controlled by its own process or its own thread.
+
+ 2) On a Termination, there should normally be at most one outstanding
+ command (Add or Modify or Move), unless the outstanding commands
+ are in the same transaction. However, a Subtract command may be
+ issued at any time. In consequence, a Media Gateway may sometimes
+ receive a Modify command that applies to a previously subtracted
+ Termination. Such commands should be ignored, and an error code
+ should be returned.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 73]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 3) For transports that do not guarantee in-sequence delivery of
+ messages (i.e., UDP), there should normally be on a given
+ Termination at most one outstanding Notify command at any time.
+
+ 4) In some cases, an implicitly or explicitly wildcarded Subtract
+ command that applies to a group of Terminations may step in front
+ of a pending Add command. The Media Gateway Controller should
+ individually delete all Terminations for which an Add command was
+ pending at the time of the global Subtract command. Also, new Add
+ commands for Terminations named by the wildcarding (or implied in
+ a Multiplex descriptor) should not be sent until the wildcarded
+ Subtract command is acknowledged.
+
+ 5) AuditValue and AuditCapability are not subject to any sequencing.
+
+ 6) ServiceChange shall always be the first command sent by a MG as
+ defined by the restart procedure. Any other command or response
+ must be delivered after this ServiceChange command.
+
+ These rules do not affect the command responder, which should always
+ respond to commands.
+
+9.2 Protection against Restart Avalanche
+
+ In the event that a large number of Media Gateways are powered on
+ simultaneously and they were to all initiate a ServiceChange
+ transaction, the Media Gateway Controller would very likely be
+ swamped, leading to message losses and network congestion during the
+ critical period of service restoration. In order to prevent such
+ avalanches, the following behaviour is suggested:
+
+ 1) When a Media Gateway is powered on, it should initiate a restart
+ timer to a random value, uniformly distributed between 0 and a
+ maximum waiting delay (MWD). Care should be taken to avoid
+ synchronicity of the random number generation between multiple
+ Media Gateways that would use the same algorithm.
+
+ 2) The Media Gateway should then wait for either the end of this
+ timer or the detection of a local user activity, such as for
+ example an off-hook transition on a residential Media Gateway.
+
+ 3) When the timer elapses, or when an activity is detected, the Media
+ Gateway should initiate the restart procedure.
+
+ The restart procedure simply requires the MG to guarantee that the
+ first message that the Media Gateway Controller sees from this MG is
+ a ServiceChange message informing the Media Gateway Controller about
+ the restart.
+
+
+
+Groves, et al. Standards Track [Page 74]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ NOTE - The value of MWD is a configuration parameter that depends
+ on the type of the Media Gateway. The following reasoning may be
+ used to determine the value of this delay on residential gateways.
+
+ Media Gateway Controllers are typically dimensioned to handle the
+ peak hour traffic load, during which, in average, 10% of the lines
+ will be busy, placing calls whose average duration is typically 3
+ minutes. The processing of a call typically involves 5 to 6 Media
+ Gateway Controller transactions between each Media Gateway and the
+ Media Gateway Controller. This simple calculation shows that the
+ Media Gateway Controller is expected to handle 5 to 6 transactions
+ for each Termination, every 30 minutes on average, or, to put it
+ otherwise, about one transaction per Termination every 5 to 6 minutes
+ on average. This suggests that a reasonable value of MWD for a
+ residential gateway would be 10 to 12 minutes. In the absence of
+ explicit configuration, residential gateways should adopt a value of
+ 600 seconds for MWD.
+
+ The same reasoning suggests that the value of MWD should be much
+ shorter for trunking gateways or for business gateways, because they
+ handle a large number of Terminations, and also because the usage
+ rate of these Terminations is much higher than 10% during the peak
+ busy hour, a typical value being 60%. These Terminations, during the
+ peak hour, are this expected to contribute about one transaction per
+ minute to the Media Gateway Controller load. A reasonable algorithm
+ is to make the value of MWD per "trunk" Termination six times shorter
+ than the MWD per residential gateway, and also inversely proportional
+ to the number of Terminations that are being restarted. For example
+ MWD should be set to 2.5 seconds for a gateway that handles a T1
+ line, or to 60 milliseconds for a gateway that handles a T3 line.
+
+10 Security Considerations
+
+ This clause covers security when using the protocol in an IP
+ environment.
+
+10.1 Protection of Protocol Connections
+
+ A security mechanism is clearly needed to prevent unauthorized
+ entities from using the protocol defined in this RFC for setting up
+ unauthorized calls or interfering with authorized calls. The
+ security mechanism for the protocol when transported over IP networks
+ is IPsec [RFC 2401 to RFC 2411].
+
+ The AH header [RFC 2402] affords data origin authentication,
+ connectionless integrity and optional anti-replay protection of
+ messages passed between the MG and the MGC. The ESP header [RFC
+ 2406] provides confidentiality of messages, if desired. For
+
+
+
+Groves, et al. Standards Track [Page 75]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ instance, the ESP encryption service should be requested if the
+ session descriptions are used to carry session keys, as defined in
+ SDP.
+
+ Implementations of the protocol defined in this RFC employing the ESP
+ header SHALL comply with section 5 of [RFC 2406], which defines a
+ minimum set of algorithms for integrity checking and encryption.
+ Similarly, implementations employing the AH header SHALL comply with
+ section 5 of [RFC 2402], which defines a minimum set of algorithms
+ for integrity checking using manual keys.
+
+ Implementations SHOULD use IKE [RFC 2409] to permit more robust
+ keying options. Implementations employing IKE SHOULD support
+ authentication with RSA signatures and RSA public key encryption.
+
+10.2 Interim AH scheme
+
+ Implementation of IPsec requires that the AH or ESP header be
+ inserted immediately after the IP header. This cannot be easily done
+ at the application level. Therefore, this presents a deployment
+ problem for the protocol defined in this RFC where the underlying
+ network implementation does not support IPsec.
+
+ As an interim solution, an optional AH header is defined within the
+ H.248.1 protocol header. The header fields are exactly those of the
+ SPI, SEQUENCE NUMBER and DATA fields as defined in [RFC 2402]. The
+ semantics of the header fields are the same as the "transport mode"
+ of [RFC 2402], except for the calculation of the Integrity Check
+ Value (ICV). In IPsec, the ICV is calculated over the entire IP
+ packet including the IP header. This prevents spoofing of the IP
+ addresses. To retain the same functionality, the ICV calculation
+ should be performed across all the transactions (concatenated) in the
+ message prepended by a synthesized IP header consisting of a 32-bit
+ source IP address, a 32-bit destination address and a 16-bit UDP
+ destination port encoded as 20 hex digits. When the interim AH
+ mechanism is employed when TCP is the transport Layer, the UDP Port
+ above becomes the TCP port, and all other operations are the same.
+
+ Implementations of the H.248.1 protocol SHALL implement IPsec where
+ the underlying operating system and the transport network supports
+ IPsec. Implementations of the protocol using IPv4 SHALL implement
+ the interim AH scheme. However, this interim scheme SHALL NOT be
+ used when the underlying network layer supports IPsec. IPv6
+ implementations are assumed to support IPsec and SHALL NOT use the
+ interim AH scheme.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 76]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ All implementations of the interim AH mechanism SHALL comply with
+ section 5 of RFC 2402 which defines a minimum set of algorithms for
+ integrity checking using manual keys.
+
+ The interim AH interim scheme does not provide protection against
+ eavesdropping, thus forbidding third parties from monitoring the
+ connections set up by a given Termination. Also, it does not provide
+ protection against replay attacks. These procedures do not
+ necessarily protect against denial of service attacks by misbehaving
+ MGs or misbehaving MGCs. However, they will provide an
+ identification of these misbehaving entities, which should then be
+ deprived of their authorization through maintenance procedures.
+
+10.3 Protection of Media Connections
+
+ The protocol allows the MGC to provide MGs with "session keys" that
+ can be used to encrypt the audio messages, protecting against
+ eavesdropping.
+
+ A specific problem of packet networks is "uncontrolled barge-in".
+ This attack can be performed by directing media packets to the IP
+ address and UDP port used by a connection. If no protection is
+ implemented, the packets must be decompressed and the signals must be
+ played on the "line side".
+
+ A basic protection against this attack is to only accept packets from
+ known sources, checking for example that the IP source address and
+ UDP source port match the values announced in the Remote descriptor.
+ This has two inconveniences: it slows down connection establishment
+ and it can be fooled by source spoofing:
+
+ - To enable the address-based protection, the MGC must obtain the
+ remote session description of the egress MG and pass it to the
+ ingress MG. This requires at least one network round trip, and
+ leaves us with a dilemma: either allow the call to proceed without
+ waiting for the round trip to complete, and risk for example,
+ "clipping" a remote announcement, or wait for the full round trip
+ and settle for slower call-set up procedures.
+
+ - Source spoofing is only effective if the attacker can obtain valid
+ pairs of source destination addresses and ports, for example by
+ listening to a fraction of the traffic. To fight source spoofing,
+ one could try to control all access points to the network. But
+ this is in practice very hard to achieve.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 77]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ An alternative to checking the source address is to encrypt and
+ authenticate the packets, using a secret key that is conveyed during
+ the call set-up procedure. This will not slow down the call set-up,
+ and provides strong protection against address spoofing.
+
+11 MG-MGC Control Interface
+
+ The control association between MG and MGC is initiated at MG cold
+ start, and announced by a ServiceChange message, but can be changed
+ by subsequent events, such as failures or manual service events.
+ While the protocol does not have an explicit mechanism to support
+ multiple MGCs controlling a physical MG, it has been designed to
+ support the multiple logical MG (within a single physical MG) that
+ can be associated with different MGCs.
+
+11.1 Multiple Virtual MGs
+
+ A physical Media Gateway may be partitioned into one or more Virtual
+ MGs. A virtual MG consists of a set of statically partitioned
+ physical Terminations and/or sets of ephemeral Terminations. A
+ physical Termination is controlled by one MGC. The model does not
+ require that other resources be statically allocated, just
+ Terminations. The mechanism for allocating Terminations to virtual
+ MGs is a management method outside the scope of the protocol. Each
+ of the virtual MGs appears to the MGC as a complete MG client.
+
+ A physical MG may have only one network interface, which must be
+ shared across virtual MGs. In such a case, the packet/cell side
+ Termination is shared. It should be noted however, that in use, such
+ interfaces require an ephemeral instance of the Termination to be
+ created per flow, and thus sharing the Termination is
+ straightforward. This mechanism does lead to a complication, namely
+ that the MG must always know which of its controlling MGCs should be
+ notified if an event occurs on the interface.
+
+ In normal operation, the Virtual MG will be instructed by the MGC to
+ create network flows (if it is the originating side), or to expect
+ flow requests (if it is the terminating side), and no confusion will
+ arise. However, if an unexpected event occurs, the Virtual MG must
+ know what to do with respect to the physical resources it is
+ controlling.
+
+ If recovering from the event requires manipulation of a physical
+ interface's state, only one MGC should do so. These issues are
+ resolved by allowing any of the MGCs to create EventsDescriptors to
+ be notified of such events, but only one MGC can have read/write
+
+
+
+
+
+Groves, et al. Standards Track [Page 78]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ access to the physical interface properties; all other MGCs have
+ read-only access. The management mechanism is used to designate
+ which MGC has read/write capability, and is designated the Master
+ MGC.
+
+ Each virtual MG has its own Root Termination. In most cases the
+ values for the properties of the Root Termination are independently
+ settable by each MGC. Where there can only be one value, the
+ parameter is read-only to all but the Master MGC.
+
+ ServiceChange may only be applied to a Termination or set of
+ Terminations partitioned to the Virtual MG or created (in the case of
+ ephemeral Terminations) by that Virtual MG.
+
+11.2 Cold start
+
+ A MG is pre-provisioned by a management mechanism outside the scope
+ of this protocol with a primary and (optionally) an ordered list of
+ secondary MGCs. Upon a cold start of the MG, it will issue a
+ ServiceChange command with a "Restart" method, on the Root
+ Termination to its primary MGC. If the MGC accepts the MG, it sends
+ a Transaction Reply not including a ServiceChangeMgcId parameter. If
+ the MGC does not accept the MG's registration, it sends a Transaction
+ Reply, providing the address of an alternate MGC to be contacted by
+ including a ServiceChangeMgcId parameter.
+
+ If the MG receives a Transaction Reply that includes a
+ ServiceChangeMgcId parameter, it sends a ServiceChange to the MGC
+ specified in the ServiceChangeMgcId. It continues this process until
+ it gets a controlling MGC to accept its registration, or it fails to
+ get a reply. Upon failure to obtain a reply, either from the primary
+ MGC, or a designated successor, the MG tries its pre-provisioned
+ secondary MGCs, in order. If the MG is unable to establish a control
+ relationship with any MGC, it shall wait a random amount of time as
+ described in 9.2 and then start contacting its primary, and if
+ necessary, its secondary MGCs again.
+
+ It is possible that the reply to a ServiceChange with Restart will be
+ lost, and a command will be received by the MG prior to the receipt
+ of the ServiceChange response. The MG shall issue Error 505 -
+ Command Received before a ServiceChange Reply has been received.
+
+11.3 Negotiation of protocol version
+
+ The first ServiceChange command from a MG shall contain the version
+ number of the protocol supported by the MG in the
+ ServiceChangeVersion parameter. Upon receiving such a message, if
+ the MGC supports only a lower version, then the MGC shall send a
+
+
+
+Groves, et al. Standards Track [Page 79]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ServiceChangeReply with the lower version and thereafter all the
+ messages between MG and MGC shall conform to the lower version of the
+ protocol. If the MG is unable to comply and it has established a
+ transport connection to the MGC, it should close that connection. In
+ any event, it should reject all subsequent requests from the MGC with
+ error 406 - Version Not Supported.
+
+ If the MGC supports a higher version than the MG but is able to
+ support the lower version proposed by the MG, it shall send a
+ ServiceChangeReply with the lower version and thereafter all the
+ messages between MG and MGC shall conform to the lower version of the
+ protocol. If the MGC is unable to comply, it shall reject the
+ association, with error 406 - Version Not Supported.
+
+ Protocol version negotiation may also occur at "handoff" and
+ "failover" ServiceChanges.
+
+ When extending the protocol with new versions, the following rules
+ should be followed:
+
+ 1) Existing protocol elements, i.e., procedures, parameters,
+ descriptor, property, values, should not be changed unless a
+ protocol error needs to be corrected or it becomes necessary to
+ change the operation of the service that is being supported by the
+ protocol.
+
+ 2) The semantics of a command, a parameter, a descriptor, a property,
+ or a value should not be changed.
+
+ 3) Established rules for formatting and encoding messages and
+ parameters should not be modified.
+
+ 4) When information elements are found to be obsolete they can be
+ marked as not used. However, the identifier for that information
+ element will be marked as reserved. In that way it can not be
+ used in future versions.
+
+11.4 Failure of a MG
+
+ If a MG fails, but is capable of sending a message to the MGC, it
+ sends a ServiceChange with an appropriate method (graceful or forced)
+ and specifies the Root TerminationID. When it returns to service, it
+ sends a ServiceChange with a "Restart" method.
+
+ Allowing the MGC to send duplicate messages to both MGs accommodates
+ pairs of MGs that are capable of redundant failover of one of the
+ MGs. Only the Working MG shall accept or reject transactions. Upon
+ failover, the primary MG sends a ServiceChange command with a
+
+
+
+Groves, et al. Standards Track [Page 80]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ "Failover" method and a "MG Impending Failure" reason. The MGC then
+ uses the secondary MG as the active MG. When the error condition is
+ repaired, the Working MG can send a "ServiceChange" with a "Restart"
+ method.
+
+ Note: Redundant failover MGs require a reliable transport, because
+ the protocol provides no means for a secondary MG running ALF to
+ acknowledge messages sent from the MGC.
+
+11.5 Failure of an MGC
+
+ If the MG detects a failure of its controlling MGC, it attempts to
+ contact the next MGC on its pre-provisioned list. It starts its
+ attempts at the beginning (primary MGC), unless that was the MGC that
+ failed, in which case it starts at its first secondary MGC. It sends
+ a ServiceChange message with a "Failover" method and a "MGC Impending
+ Failure" reason. If the MG is unable to establish a control
+ relationship with any MGC, it shall wait a random amount of time as
+ described in section 9.2 and then start again contacting its primary,
+ and (if necessary) its secondary MGCs. When contacting its
+ previously controlling MGC, the MG sends the ServiceChange message
+ with "Disconnected" method.
+
+ In partial failure, or for manual maintenance reasons, an MGC may
+ wish to direct its controlled MGs to use a different MGC. To do so,
+ it sends a ServiceChange method to the MG with a "HandOff" method,
+ and its designated replacement in ServiceChangeMgcId. If "HandOff"
+ is supported, the MG shall send a ServiceChange message with a
+ "Handoff" method and a "MGC directed change" reason to the designated
+ MGC. If it fails to get a reply from the designated MGC, the MG
+ shall behave as if its MGC failed, and start contacting secondary
+ MGCs as specified in the previous paragraph. If the MG is unable to
+ establish a control relationship with any MGC, it shall wait a random
+ amount of time as described in 9.2 and then start contacting its
+ primary, and if necessary, its secondary MGCs again.
+
+ No recommendation is made on how the MGCs involved in the Handoff
+ maintain state information; this is considered to be out of scope of
+ this RFC. The MGC and MG may take the following steps when Handoff
+ occurs. When the MGC initiates a HandOff, the handover should be
+ transparent to Operations on the Media Gateway. Transactions can be
+ executed in any order, and could be in progress when the
+ ServiceChange is executed. Accordingly, commands in progress
+ continue and replies to all commands from the original MGC must be
+ sent to the transport address from which they were sent. If the
+ service relationship with the sending MGC has ended, the replies
+ should be discarded. The MG may receive outstanding transaction
+ replies from the new MGC. No new messages shall be sent to the new
+
+
+
+Groves, et al. Standards Track [Page 81]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ MGC until the control association is established. Repeated
+ transaction requests shall be directed to the new MGC. The MG shall
+ maintain state on all Terminations and Contexts.
+
+ It is possible that the MGC could be implemented in such a way that a
+ failed MGC is replaced by a working MGC where the identity of the new
+ MGC is the same as the failed one. In such a case,
+ ServiceChangeMgcId would be specified with the previous value and the
+ MG shall behave as if the value was changed, and send a ServiceChange
+ message, as above.
+
+ Pairs of MGCs that are capable of redundant failover can notify the
+ controlled MGs of the failover by the above mechanism.
+
+12 Package definition
+
+ The primary mechanism for extension is by means of Packages.
+ Packages define additional Properties, Events, Signals and Statistics
+ that may occur on Terminations.
+
+ Packages defined by IETF will appear in separate RFCs.
+
+ Packages defined by ITU-T may appear in the relevant Recommendations
+ (e.g., as Recommendations of the H.248 sub-series).
+
+ 1) A public document or a standard forum document, which can be
+ referenced as the document that describes the package following
+ the guideline above, should be specified.
+
+ 2) The document shall specify the version of the Package that it
+ describes.
+
+ 3) The document should be available on a public web server and should
+ have a stable URL. The site should provide a mechanism to provide
+ comments and appropriate responses should be returned.
+
+12.1 Guidelines for defining packages
+
+ Packages define Properties, Events, Signals, and Statistics.
+
+ Packages may also define new error codes according to the guidelines
+ given in 13.2. This is a matter of documentary convenience: the
+ package documentation is submitted to IANA in support of the error
+ code registration. If a package is modified, it is unnecessary to
+ provide IANA with a new document reference in support of the error
+ code unless the description of the error code itself is modified.
+
+
+
+
+
+Groves, et al. Standards Track [Page 82]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Names of all such defined constructs shall consist of the PackageID
+ (which uniquely identifies the package) and the ID of the item (which
+ uniquely identifies the item in that package). In the text encoding
+ the two shall be separated by a forward slash ("/") character.
+ Example: togen/playtone is the text encoding to refer to the play
+ tone signal in the tone generation package.
+
+ A Package will contain the following sections:
+
+12.1.1 Package
+
+ Overall description of the package, specifying:
+
+ Package Name: only descriptive
+
+ PackageID: is an identifier
+
+ Description:
+
+ Version:
+
+ A new version of a package can only add additional Properties,
+ Events, Signals, Statistics and new possible values for an
+ existing parameter described in the original package. No
+ deletions or modifications shall be allowed. A version is an
+ integer in the range from 1 to 99.
+
+ Designed to be extended only (Optional):
+
+ This indicates that the package has been expressly designed to
+ be extended by others, not to be directly referenced. For
+ example, the package may not have any function on its own or be
+ nonsensical on its own. The MG SHOULD NOT publish this
+ PackageID when reporting packages.
+
+ Extends (Optional): existing package Descriptor
+
+ A package may extend an existing package. The version of the
+ original package must be specified. When a package extends
+ another package it shall only add additional Properties,
+ Events, Signals, Statistics and new possible values for an
+ existing parameter described in the original package. An
+ extended package shall not redefine or overload an identifier
+ defined in the original package and packages it may have
+ extended (multiple levels of extension). Hence, if package B
+ version 1 extends package A version 1, version 2 of B will not
+ be able to extend the A version 2 if A version 2 defines a name
+ already in B version 1.
+
+
+
+Groves, et al. Standards Track [Page 83]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+12.1.2 Properties
+
+ Properties defined by the package, specifying:
+
+ Property Name: only descriptive
+
+ PropertyID: is an identifier
+
+ Description:
+
+ Type: One of:
+
+ Boolean
+
+ String: UTF-8 string
+
+ Octet String: A number of octets. See Annex A and Annex B.3
+ for encoding
+
+ Integer: 4 byte signed integer
+
+ Double: 8 byte signed integer
+
+ Character: unicode UTF-8 encoding of a single letter. Could be
+ more than one octet.
+
+ Enumeration: one of a list of possible unique values (see 12.3)
+
+ Sub-list: a list of several values from a list. The type of
+ sub-list SHALL also be specified. The type shall be chosen
+ from the types specified in this section (with the exception of
+ sub-list). For example, Type: sub-list of enumeration. The
+ encoding of sub-lists is specified in Annexes A and B.3.
+
+ Possible values:
+
+ A package MUST specify either a specific set of values or a
+ description of how values are determined. A package MUST also
+ specify a default value or the default behaviour when the value
+ is omitted from its descriptor. For example, a package may
+ specify that procedures related to the property are suspended
+ when its value is omitted. A default value (but not
+ procedures)
+ may be specified as provisionable.
+
+ Defined in:
+
+ Which H.248.1 descriptor the property is defined in.
+
+
+
+Groves, et al. Standards Track [Page 84]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ LocalControl is for stream dependent properties.
+ TerminationState is for stream independent properties. These
+ are expected to be the most common cases, but it is possible
+ for properties to be defined in other descriptors.
+
+ Characteristics: Read/Write or both, and (optionally), global:
+
+ Indicates whether a property is read-only, or read-write, and
+ if it is global. If Global is omitted, the property is not
+ global. If a property is declared as global, the value of the
+ property is shared by all Terminations realizing the package.
+
+12.1.3 Events
+
+ Events defined by the package, specifying:
+
+ Event name: only descriptive
+
+ EventID: is an identifier
+
+ Description:
+
+ EventsDescriptor Parameters:
+
+ Parameters used by the MGC to configure the event, and found in
+ the EventsDescriptor. See 12.2.
+
+ ObservedEventsDescriptor Parameters:
+
+ Parameters returned to the MGC in Notify requests and in
+ replies to command requests from the MGC that audit
+ ObservedEventsDescriptor, and found in the
+ ObservedEventsDescriptor. See 12.2.
+
+12.1.4 Signals
+
+ Signals defined by the package, specifying:
+
+ Signal Name: only descriptive
+
+ SignalID: is an identifier. SignalID is used in a
+ SignalsDescriptor
+
+ Description
+
+ SignalType: one of:
+
+ OO (On/Off)
+
+
+
+Groves, et al. Standards Track [Page 85]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ TO (TimeOut)
+
+ BR (Brief)
+
+ NOTE - SignalType may be defined such that it is dependent on the
+ value of one or more parameters. The package MUST specify a
+ default signal type. If the default type is TO, the package MUST
+ specify a default duration which may be provisioned. A default
+ duration is meaningless for BR.
+
+ Duration: in hundredths of seconds
+
+ Additional Parameters: see 12.2
+
+12.1.5 Statistics
+
+ Statistics defined by the package, specifying:
+
+ Statistic name: only descriptive
+
+ StatisticID: is an identifier
+
+ StatisticID is used in a StatisticsDescriptor
+
+ Description:
+
+ Units: unit of measure, e.g., milliseconds, packets
+
+12.1.6 Procedures
+
+ Additional guidance on the use of the package.
+
+12.2 Guidelines to defining Parameters to Events and Signals
+
+ Parameter Name: only descriptive
+
+ ParameterID: is an identifier. The textual ParameterID of parameters
+ to Events and Signals shall not start with "EPA" and "SPA",
+ respectively. The textual ParameterID shall also not be "ST",
+ "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+ "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+ "DigitMap".
+
+ Type: One of:
+
+ Boolean
+
+ String: UTF-8 octet string
+
+
+
+Groves, et al. Standards Track [Page 86]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Octet String: A number of octets. See Annex A and Annex B.3 for
+ encoding
+
+ Integer: 4-octet signed integer
+
+ Double: 8-octet signed integer
+
+ Character: unicode UTF-8 encoding of a single letter. Could be
+ more than one octet.
+
+ Enumeration: one of a list of possible unique values (see 12.3)
+
+ Sub-list: a list of several values from a list (not supported for
+ statistics). The type of sub-list SHALL also be specified. The
+ type shall be chosen from the types specified in this section
+ (with the exception of sub-list). For example, Type: sub-list of
+ enumeration. The encoding of sub-lists is specified in Annexes A
+ and B.3.
+
+ Possible values:
+
+ A package MUST specify either a specific set of values or a
+ description of how values are determined. A package MUST also
+ specify a default value or the default behavior when the value is
+ omitted from its descriptor. For example, a package may specify
+ that procedures related to the parameter are suspended when it
+ value is omitted. A default value (but not procedures) may be
+ specified as provisionable.
+
+ Description:
+
+12.3 Lists
+
+ Possible values for parameters include enumerations. Enumerations
+ may be defined in a list. It is recommended that the list be IANA
+ registered so that packages that extend the list can be defined
+ without concern for conflicting names.
+
+12.4 Identifiers
+
+ Identifiers in text encoding shall be strings of up to 64 characters,
+ containing no spaces, starting with an alphabetic character and
+ consisting of alphanumeric characters and/or digits, and possibly
+ including the special character underscore ("_").
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 87]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Identifiers in binary encoding are 2 octets long.
+
+ Both text and binary values shall be specified for each identifier,
+ including identifiers used as values in enumerated types.
+
+12.5 Package registration
+
+ A package can be registered with IANA for interoperability reasons.
+ See clause 13 for IANA Considerations.
+
+13 IANA Considerations
+
+13.1 Packages
+
+ The following considerations SHALL be met to register a package with
+ IANA:
+
+ 1) A unique string name, unique serial number and version number is
+ registered for each package. The string name is used with text
+ encoding. The serial number shall be used with binary encoding.
+ Serial Numbers 0x8000 to 0xFFFF are reserved for private use.
+ Serial number 0 is reserved.
+
+ 2) A contact name, email and postal addresses for that contact shall
+ be specified. The contact information shall be updated by the
+ defining organization as necessary.
+
+ 3) A reference to a document that describes the package, which should
+ be public:
+
+ The document shall specify the version of the Package that it
+ describes.
+
+ If the document is public, it should be located on a public web
+ server and should have a stable URL. The site should provide a
+ mechanism to provide comments and appropriate responses should be
+ returned.
+
+ 4) Packages registered by other than recognized standards bodies
+ shall have a minimum package name length of 8 characters.
+
+ 5) All other package names are first come-first served if all other
+ conditions are met.
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 88]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+13.2 Error codes
+
+ The following considerations SHALL be met to register an error code
+ with IANA:
+
+ 1) An error number and a one-line (80-character maximum) string is
+ registered for each error.
+
+ 2) A complete description of the conditions under which the error is
+ detected shall be included in a publicly available document. The
+ description shall be sufficiently clear to differentiate the error
+ from all other existing error codes.
+
+ 3) The document should be available on a public web server and should
+ have a stable URL.
+
+ 4) Error numbers registered by recognized standards bodies shall have
+ 3- or 4-character error numbers.
+
+ 5) Error numbers registered by all other organizations or individuals
+ shall have 4-character error numbers.
+
+ 6) An error number shall not be redefined nor modified except by the
+ organization or individual that originally defined it, or their
+ successors or assigns.
+
+13.3 ServiceChange reasons
+
+ The following considerations SHALL be met to register service change
+ reason with IANA:
+
+ 1) A one-phrase, 80-character maximum, unique reason code is
+ registered for each reason.
+
+ 2) A complete description of the conditions under which the reason is
+ used is detected shall be included in a publicly available
+ document. The description shall be sufficiently clear to
+ differentiate the reason from all other existing reasons.
+
+ 3) The document should be available on a public web server and should
+ have a stable URL.
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 89]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ANNEX A - Binary encoding of the protocol
+
+ This annex specifies the syntax of messages using the notation
+ defined in Recommendation X.680; Information technology - Abstract
+ Syntax Notation One (ASN.1): Specification of basic notation.
+ Messages shall be encoded for transmission by applying the basic
+ encoding rules specified in Recommendation X.690, Information
+ Technology - ASN.1 Encoding Rules: Specification of Basic Encoding
+ Rules (BER), Canonical Encoding Rules (CER) and Distinguished
+ Encoding Rules.
+
+A.1 Coding of wildcards
+
+ The use of wildcards ALL and CHOOSE is allowed in the protocol. This
+ allows a MGC to partially specify Termination IDs and to let the MG
+ choose from the values that conform to the partial specification.
+ Termination IDs may encode a hierarchy of names. This hierarchy is
+ provisioned. For instance, a TerminationID may consist of a trunk
+ group, a trunk within the group and a circuit. Wildcarding must be
+ possible at all levels. The following paragraphs explain how this is
+ achieved.
+
+ The ASN.1 description uses octet strings of up to 8 octets in length
+ for Termination IDs. This means that Termination IDs consist of at
+ most 64 bits. A fully specified Termination ID may be preceded by a
+ sequence of wildcarding fields. A wildcarding field is one octet in
+ length. Bit 7 (the most significant bit) of this octet specifies
+ what type of wildcarding is invoked: if the bit value equals 1, then
+ the ALL wildcard is used; if the bit value if 0, then the CHOOSE
+ wildcard is used. Bit 6 of the wildcarding field specifies whether
+ the wildcarding pertains to one level in the hierarchical naming
+ scheme (bit value 0) or to the level of the hierarchy specified in
+ the wildcarding field plus all lower levels (bit value 1). Bits 0
+ through 5 of the wildcarding field specify the bit position in the
+ Termination ID at which the wildcarding starts.
+
+ We illustrate this scheme with some examples. In these examples, the
+ most significant bit in a string of bits appears on the left hand
+ side.
+
+ Assume that Termination IDs are three octets long and that each octet
+ represents a level in a hierarchical naming scheme. A valid
+ Termination ID is:
+
+ 00000001 00011110 01010101.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 90]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Addressing ALL names with prefix 00000001 00011110 is done as
+ follows:
+
+ wildcarding field: 10000111
+
+ Termination ID: 00000001 00011110 xxxxxxxx.
+
+ The values of the bits labeled "x" is irrelevant and shall be ignored
+ by the receiver.
+
+ Indicating to the receiver that it must choose a name with 00011110
+ as the second octet is done as follows:
+
+ wildcarding fields: 00010111 followed by 00000111
+
+ Termination ID: xxxxxxxx 00011110 xxxxxxxx.
+
+ The first wildcard field indicates a CHOOSE wildcard for the level in
+ the naming hierarchy starting at bit 23, the highest level in our
+ assumed naming scheme. The second wildcard field indicates a CHOOSE
+ wildcard for the level in the naming hierarchy starting at bit 7, the
+ lowest level in our assumed naming scheme.
+
+ Finally, a CHOOSE-wildcarded name with the highest level of the name
+ equal to 00000001 is specified as follows:
+
+ wildcard field: 01001111
+
+ Termination ID: 0000001 xxxxxxxx xxxxxxxx .
+
+ Bit value 1 at bit position 6 of the first octet of the wildcard
+ field indicates that the wildcarding pertains to the specified level
+ in the naming hierarchy and all lower levels.
+
+ Context IDs may also be wildcarded. In the case of Context IDs,
+ however, specifying partial names is not allowed. Context ID 0x0
+ SHALL be used to indicate the NULL Context, Context ID 0xFFFFFFFE
+ SHALL be used to indicate a CHOOSE wildcard, and Context ID
+ 0xFFFFFFFF SHALL be used to indicate an ALL wildcard.
+
+ TerminationID 0xFFFFFFFFFFFFFFFF SHALL be used to indicate the ROOT
+ Termination.
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 91]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+A.2 ASN.1 syntax specification
+
+ This subclause contains the ASN.1 specification of the H.248.1
+ protocol syntax.
+
+ NOTE 1 - In case a transport mechanism is used that employs
+ application level framing, the definition of Transaction below
+ changes. Refer to the annex or to the Recommendation of the H.248
+ sub-series defining the transport mechanism for the definition that
+ applies in that case.
+
+ NOTE 2 - The ASN.1 specification below contains a clause defining
+ TerminationIDList as a sequence of TerminationIDs. The length of
+ this sequence SHALL be one, except possibly when used in
+ contextAuditResult.
+
+ NOTE 3 - This syntax specification does not enforce all
+ restrictions on element inclusions and values. Some additional
+ restrictions are stated in comments and other restrictions appear
+ in the text of this RFC. These additional restrictions
+ are part of the protocol even though not enforced by this
+ specification.
+
+ NOTE 4 - The ASN.1 module in this Annex uses octet string types to
+ encode values for property parameter, signal parameter and event
+ parameter values and statistics. The actual types of these values
+ vary and are specified in Annex C or the relevant package
+ definition.
+
+ A value is first BER-encoded based on its type using the table below.
+ The result of this BER-encoding is then encoded as an ASN.1 octet
+ string, "double wrapping" the value. The format specified in Annex C
+ or the package relates to BER encoding according to the following
+ table:
+
+ Type Specified in Package ASN.1 BER Type
+
+ String IA5String or UTF8String (Note 4)
+
+ Integer (4 Octet) INTEGER
+
+ Double (8 octet signed int) INTEGER (Note 3)
+
+ Character (UTF-8, Note 1) IA5String
+
+ Enumeration ENUMERATED
+
+ Boolean BOOLEAN
+
+
+
+Groves, et al. Standards Track [Page 92]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Unsigned Integer (Note 2) INTEGER (Note 3)
+
+ Octet (String) OCTET STRING
+
+ Note 1: Can be more than one byte
+
+ Note 2: Unsigned integer is referenced in Annex C
+
+ Note 3: The BER encoding of INTEGER does not imply the use of 4
+ bytes.
+
+ Note 4: String should be encoded as IA5String when the contents
+ are all ASCII characters, but as UTF8String if it contains any
+ Non-ASCII characters.
+
+ See ITU-T Rec. X.690, 8.7, for the definition of the encoding of an
+ octet string value.
+
+ MEDIA-GATEWAY-CONTROL DEFINITIONS AUTOMATIC TAGS::=
+ BEGIN
+
+ MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+ AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+ SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+ SequenceNum ::= OCTET STRING(SIZE(4))
+
+ AuthData ::= OCTET STRING (SIZE (12..32))
+
+ Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 1.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+
+
+
+Groves, et al. Standards Track [Page 93]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+ MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+ DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+ PathName ::= IA5String(SIZE (1..64))
+ -- See A.3
+
+ Transaction ::= CHOICE
+
+
+
+Groves, et al. Standards Track [Page 94]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+ TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+ TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+ TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+ }
+
+ TransactionResponseAck ::= SEQUENCE OF TransactionAck
+ TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+
+
+Groves, et al. Standards Track [Page 95]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ ErrorCode ::= INTEGER(0..65535)
+ -- See clause 13 for IANA Considerations with respect to error codes
+
+ ErrorText ::= IA5String
+
+ ContextID ::= INTEGER(0..4294967295)
+
+ -- Context NULL Value: 0
+ -- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+ -- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+ }
+
+ ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+ }
+
+ CommandRequest ::= SEQUENCE
+ {
+ command Command,
+
+
+
+Groves, et al. Standards Track [Page 96]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+ Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+ CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+ TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...
+ }
+
+ AmmRequest ::= SEQUENCE
+ {
+
+
+
+Groves, et al. Standards Track [Page 97]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+ AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+ AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+ SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+ AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+ AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+
+
+Groves, et al. Standards Track [Page 98]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+ TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+ AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+ AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...
+ }
+
+ NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+
+
+
+Groves, et al. Standards Track [Page 99]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+ EventName ::= PkgdName
+
+ EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+ ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+
+
+
+Groves, et al. Standards Track [Page 100]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+ -- For ServiceChangeResult, no parameters are mandatory. Hence the
+ -- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+ WildcardField ::= OCTET STRING(SIZE(1))
+
+ TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+ -- See A.1 for explanation of wildcarding mechanism.
+ -- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+ TerminationIDList ::= SEQUENCE OF TerminationID
+
+ MediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+ StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+ StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+
+
+
+Groves, et al. Standards Track [Page 101]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+ LocalControlDescriptor ::= SEQUENCE
+ {
+
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+ StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+ -- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+ -- by an MGC the interpretation is as follows:
+ -- empty sequence means CHOOSE
+ -- one element sequence specifies value
+ -- If the sublist field is not selected, a longer sequence means
+ -- "choose one of the values" (i.e., value1 OR value2 OR ...)
+ -- If the sublist field is selected,
+ -- a sequence with more than one element encodes the value of a
+ -- list-valued property (i.e., value1 AND value2 AND ...).
+ -- The relation field may only be selected if the value sequence
+ -- has length 1. It indicates that the MG has to choose a value
+ -- for the property. E.g., x > 3 (using the greaterThan
+ -- value for relation) instructs the MG to choose any value larger
+ -- than 3 for property x.
+ -- The range field may only be selected if the value sequence
+ -- has length 2. It indicates that the MG has to choose a value
+ -- in the range between the first octet in the value sequence and
+ -- the trailing octet in the value sequence, including the
+ -- boundary values.
+ -- When sent by the MG, only responses to an AuditCapability request
+ -- may contain multiple values, a range, or a relation field.
+
+ PropertyParm ::= SEQUENCE
+ {
+
+
+
+Groves, et al. Standards Track [Page 102]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+ Name ::= OCTET STRING(SIZE(2))
+
+ PkgdName ::= OCTET STRING(SIZE(4))
+ -- represents Package Name (2 octets) plus Property, Event,
+ -- Signal Names or Statistics ID. (2 octets)
+ -- To wildcard a package use 0xFFFF for first two octets, choose
+ -- is not allowed. To reference native property tag specified in
+ -- Annex C, use 0x0000 as first two octets.
+ -- To wildcard a Property, Event, Signal, or Statistics ID, use
+ -- 0xFFFF for last two octets, choose is not allowed.
+ -- Wildcarding of Package Name is permitted only if Property,
+ -- Event, Signal, or Statistics ID are
+ -- also wildcarded.
+
+ Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+ LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+ PropertyGroup ::= SEQUENCE OF PropertyParm
+
+ TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+
+
+Groves, et al. Standards Track [Page 103]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ ServiceState ::= ENUMERATED
+
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+ MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+ MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...
+ }
+
+ StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+ EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+ RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+
+
+
+Groves, et al. Standards Track [Page 104]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+ RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+ EventDM ::= CHOICE
+ { digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+ SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+ SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+ SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+ EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+ EventSpec ::= SEQUENCE
+ {
+
+
+
+Groves, et al. Standards Track [Page 105]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+ SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+ SignalRequest ::=CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+ SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+ Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+ }
+
+ SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+ SignalName ::= PkgdName
+
+ NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+
+
+Groves, et al. Standards Track [Page 106]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+
+ } OPTIONAL,
+ ...
+ }
+
+ -- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+ -- ALL is represented by 0xffffffff.
+
+ RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+ DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+
+
+
+Groves, et al. Standards Track [Page 107]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ DigitMapName ::= Name
+
+ DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...
+ }
+
+ ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+ ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+
+
+
+Groves, et al. Standards Track [Page 108]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ...
+ }
+
+ ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ ServiceChangeMethod ::= ENUMERATED
+
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+ PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+ PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+ StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+ StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+
+
+
+Groves, et al. Standards Track [Page 109]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+ NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters should be "X-" or "X+"
+ ...
+ }
+
+ H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+ TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+ Value ::= SEQUENCE OF OCTET STRING
+
+ END
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 110]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+A.3 Digit maps and path names
+
+ From a syntactic viewpoint, digit maps are strings with syntactic
+ restrictions imposed upon them. The syntax of valid digit maps is
+ specified in ABNF [RFC 2234]. The syntax for digit maps presented in
+ this subclause is for illustrative purposes only. The definition of
+ digitMap in Annex B takes precedence in the case of differences
+ between the two.
+
+ digitMap = (digitString / LWSP "(" LWSP digitStringList LWSP ")"
+ LWSP)
+
+ digitStringList = digitString *( LWSP "|" LWSP digitString )
+ digitString = 1*(digitStringElement)
+ digitStringElement = digitPosition [DOT]
+ digitPosition = digitMapLetter / digitMapRange
+ digitMapRange = ("x" / (LWSP "[" LWSP digitLetter LWSP "]" LWSP))
+ digitLetter = *((DIGIT "-" DIGIT) /digitMapLetter)
+ digitMapLetter = DIGIT ;digits 0-9
+ / %x41-4B / %x61-6B ;a-k and A-K
+ / "L"/ "S" ;Inter-event timers
+ ;(long, short)
+ / "Z" ;Long duration event
+ DOT = %x2E ; "."
+ LWSP = *(WSP / COMMENT / EOL)
+ WSP = SP / HTAB
+ COMMENT = ";" *(SafeChar / RestChar / WSP) EOL
+ EOL = (CR [LF]) / LF
+ SP = %x20
+ HTAB = %x09
+ CR = %x0D
+ LF = %x0A
+ SafeChar = DIGIT / ALPHA / "+" / "-" / "&" / "!" / "_" / "/" /
+ "'" / "?" / "@" / "^" / "`" / "~" / "*" / "$" / "\" /
+ "(" / ")" / "%" / "."
+ RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+ "<" / ">" / "=" / %x22
+ DIGIT = %x30-39 ; digits 0 through 9
+ ALPHA = %x41-5A / %x61-7A; A-Z, a-z
+
+ A path name is also a string with syntactic restrictions imposed upon
+ it. The ABNF production defining it is copied from Annex B.
+
+ ; Total length of pathNAME must not exceed 64 chars.
+ pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ ["@" pathDomainName ]
+
+
+
+
+
+Groves, et al. Standards Track [Page 111]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ; ABNF allows two or more consecutive "." although it is
+ ; meaningless in a path domain name.
+ pathDomainName = (ALPHA / DIGIT / "*" )
+ *63(ALPHA / DIGIT / "-"
+ NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 112]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ANNEX B - Text encoding of the protocol
+
+B.1 Coding of wildcards
+
+ In a text encoding of the protocol, while TerminationIDs are
+ arbitrary, by judicious choice of names, the wildcard character, "*"
+ may be made more useful. When the wildcard character is encountered,
+ it will "match" all TerminationIDs having the same previous and
+ following characters (if appropriate). For example, if there were
+ TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+ R13/3/* would match all of them. There are some circumstances where
+ ALL Terminations must be referred to. The TerminationID "*"
+ suffices, and is referred to as ALL. The CHOOSE TerminationID "$"
+ may be used to signal to the MG that it has to create an ephemeral
+ Termination or select an idle physical Termination.
+
+B.2 ABNF specification
+
+ The protocol syntax is presented in ABNF according to RFC 2234.
+
+ Note 1 - This syntax specification does not enforce all
+ restrictions on element inclusions and values. Some additional
+ restrictions are stated in comments and other restrictions appear
+ in the text of this RFC. These additional restrictions are part
+ of the protocol even though not enforced by this specification.
+
+ Note 2 - The syntax is context-dependent. For example, "Add" can
+ be the AddToken or a NAME depending on the context in which it
+ occurs.
+
+ Everything in the ABNF and text encoding is case insensitive. This
+ includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+ per RFC 2327.
+
+ ; NOTE -- The ABNF in this section uses the VALUE construct (or lists
+ ; of VALUE constructs) to encode various package element values
+ ; (properties, signal parameters, etc.). The types of these values
+ ; vary and are specified the relevant package definition. Several
+ ; such types are described in section 12.2.
+ ;
+ ; The ABNF specification for VALUE allows a quotedString form or a
+ ; collection of SafeChars. The encoding of package element values
+ ; into ABNF VALUES is specified below. If a type's encoding allows
+ ; characters other than SafeChars, the quotedString form MUST be used
+ ; for all values of that type, even for specific values that consist
+ ; only of SafeChars.
+ ;
+
+
+
+
+Groves, et al. Standards Track [Page 113]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ; String: A string MUST use the quotedString form of VALUE and can
+ ; contain anything allowable in the quotedString form.
+ ;
+ ; Integer, Double, and Unsigned Integer: Decimal values can be
+ ; encoded using characters 0-9. Hexadecimal values must be prefixed
+ ; with '0x' and can use characters 0-9,a-f,A-F. An octal format is
+ ; not supported. Negative integers start with '-' and MUST be
+ ; Decimal. The SafeChar form of VALUE MUST be used.
+ ;
+ ; Character: A UTF-8 encoding of a single letter surrounded by
+ ; double quotes.
+ ;
+ ; Enumeration: An enumeration MUST use the SafeChar form of VALUE
+ ; and can contain anything allowable in the SafeChar form.
+ ;
+ ; Boolean: Boolean values are encoded as "on" and "off" and are
+ ; case insensitive. The SafeChar form of VALUE MUST be used.
+ ;
+ ; Future types: Any defined types MUST fit within
+ ; the ABNF specification of VALUE. Specifically, if a type's
+ ; encoding allows characters other than SafeChars, the quotedString
+ ; form MUST be used for all values of that type, even for specific
+ ; values that consist only of SafeChars.
+ ;
+ ; Note that there is no way to use the double quote character within
+ ; a value.
+ ;
+ ; Note that SDP disallows whitespace at the beginning of a line,
+ ; Megaco ABNF allows whitespace before the beginning of the SDP in
+ ; the Local/Remote descriptor. Parsers should accept whitespace
+ ; between the LBRKT following the Local/Remote token and the
+ ; beginning of the SDP.
+
+ megacoMessage = LWSP [authenticationHeader SEP ] message
+
+ authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+ SequenceNum COLON AuthData
+
+ SecurityParmIndex = "0x" 8(HEXDIG)
+ SequenceNum = "0x" 8(HEXDIG)
+ AuthData = "0x" 24*64(HEXDIG)
+
+ message = MegacopToken SLASH Version SEP mId SEP
+ messageBody
+ ; The version of the protocol defined here is equal to 1.
+
+ messageBody = ( errorDescriptor / transactionList )
+
+
+
+
+Groves, et al. Standards Track [Page 114]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ transactionList = 1*( transactionRequest / transactionReply /
+ transactionPending / transactionResponseAck )
+ ;Use of response acks is dependent on underlying transport
+
+
+ transactionPending = PendingToken EQUAL TransactionID LBRKT
+ RBRKT
+
+ transactionResponseAck = ResponseAckToken LBRKT transactionAck
+ *(COMMA transactionAck) RBRKT
+ transactionAck = transactionID / (transactionID "-" transactionID)
+
+ transactionRequest = TransToken EQUAL TransactionID LBRKT
+ actionRequest *(COMMA actionRequest) RBRKT
+
+ actionRequest = CtxToken EQUAL ContextID LBRKT ((
+ contextRequest [COMMA commandRequestList])
+ / commandRequestList) RBRKT
+
+ contextRequest = ((contextProperties [COMMA contextAudit])
+ / contextAudit)
+
+ contextProperties = contextProperty *(COMMA contextProperty)
+
+ ; at-most-once
+ contextProperty = (topologyDescriptor / priority / EmergencyToken)
+
+ contextAudit = ContextAuditToken LBRKT contextAuditProperties
+ *(COMMA contextAuditProperties) RBRKT
+
+ ; at-most-once
+ contextAuditProperties = ( TopologyToken / EmergencyToken /
+ PriorityToken )
+
+ ; "O-" indicates an optional command
+ ; "W-" indicates a wildcarded response to a command
+ commandRequestList = ["O-"] ["W-"] commandRequest
+ *(COMMA ["O-"] ["W-"]commandRequest)
+
+ commandRequest = ( ammRequest / subtractRequest / auditRequest /
+ notifyRequest / serviceChangeRequest)
+
+ transactionReply = ReplyToken EQUAL TransactionID LBRKT
+ [ ImmAckRequiredToken COMMA]
+ ( errorDescriptor / actionReplyList ) RBRKT
+
+ actionReplyList = actionReply *(COMMA actionReply )
+
+
+
+
+Groves, et al. Standards Track [Page 115]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ actionReply = CtxToken EQUAL ContextID LBRKT
+ ( errorDescriptor / commandReply ) /
+ (commandReply COMMA errorDescriptor) ) RBRKT
+
+ commandReply = (( contextProperties [COMMA commandReplyList] ) /
+ commandReplyList )
+
+
+ commandReplyList = commandReplys *(COMMA commandReplys )
+
+ commandReplys = (serviceChangeReply / auditReply / ammsReply /
+ notifyReply )
+
+ ;Add Move and Modify have the same request parameters
+ ammRequest = (AddToken / MoveToken / ModifyToken ) EQUAL
+ TerminationID [LBRKT ammParameter *(COMMA
+ ammParameter) RBRKT]
+
+ ;at-most-once
+ ammParameter = (mediaDescriptor / modemDescriptor /
+ muxDescriptor / eventsDescriptor /
+ signalsDescriptor / digitMapDescriptor /
+ eventBufferDescriptor / auditDescriptor)
+
+ ammsReply = (AddToken / MoveToken / ModifyToken /
+ SubtractToken ) EQUAL TerminationID [ LBRKT
+ terminationAudit RBRKT ]
+
+ subtractRequest = SubtractToken EQUAL TerminationID
+ [ LBRKT auditDescriptor RBRKT]
+
+ auditRequest = (AuditValueToken / AuditCapToken ) EQUAL
+ TerminationID LBRKT auditDescriptor RBRKT
+
+ auditReply = (AuditValueToken / AuditCapToken )
+ ( contextTerminationAudit / auditOther)
+
+ auditOther = EQUAL TerminationID [LBRKT
+ terminationAudit RBRKT]
+
+ terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+
+ contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+ LBRKT errorDescriptor RBRKT )
+
+ auditReturnParameter = (mediaDescriptor / modemDescriptor /
+ muxDescriptor / eventsDescriptor /
+ signalsDescriptor / digitMapDescriptor /
+
+
+
+Groves, et al. Standards Track [Page 116]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ observedEventsDescriptor / eventBufferDescriptor /
+ statisticsDescriptor / packagesDescriptor /
+ errorDescriptor / auditItem)
+
+ auditDescriptor = AuditToken LBRKT [ auditItem
+ *(COMMA auditItem) ] RBRKT
+
+ notifyRequest = NotifyToken EQUAL TerminationID
+ LBRKT ( observedEventsDescriptor
+ [ COMMA errorDescriptor ] ) RBRKT
+
+ notifyReply = NotifyToken EQUAL TerminationID
+ [ LBRKT errorDescriptor RBRKT ]
+
+ serviceChangeRequest = ServiceChangeToken EQUAL TerminationID
+ LBRKT serviceChangeDescriptor RBRKT
+
+ serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+ [LBRKT (errorDescriptor /
+ serviceChangeReplyDescriptor) RBRKT]
+
+ errorDescriptor = ErrorToken EQUAL ErrorCode
+ LBRKT [quotedString] RBRKT
+
+ ErrorCode = 1*4(DIGIT) ; could be extended
+
+ TransactionID = UINT32
+
+ mId = (( domainAddress / domainName )
+ [":" portNumber]) / mtpAddress / deviceName
+
+ ; ABNF allows two or more consecutive "." although it is meaningless
+ ; in a domain name.
+ domainName = "<" (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" /
+ ".") ">"
+ deviceName = pathNAME
+
+ ;The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+ ContextID = (UINT32 / "*" / "-" / "$")
+
+ domainAddress = "[" (IPv4address / IPv6address) "]"
+ ;RFC2373 contains the definition of IP6Addresses.
+ IPv6address = hexpart [ ":" IPv4address ]
+ IPv4address = V4hex DOT V4hex DOT V4hex DOT V4hex
+ V4hex = 1*3(DIGIT) ; "0".."255"
+ ; this production, while occurring in RFC2373, is not referenced
+ ; IPv6prefix = hexpart SLASH 1*2DIGIT
+ hexpart = hexseq "::" [ hexseq ] / "::" [ hexseq ] / hexseq
+
+
+
+Groves, et al. Standards Track [Page 117]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ hexseq = hex4 *( ":" hex4)
+ hex4 = 1*4HEXDIG
+
+ portNumber = UINT16
+
+ ; Addressing structure of mtpAddress:
+ ; 25 - 15 0
+ ; | PC | NI |
+ ; 24 - 14 bits 2 bits
+ ; Note: 14 bits are defined for international use.
+ ; Two national options exist where the point code is 16 or 24 bits.
+ ; To octet align the mtpAddress the MSBs shall be encoded as 0s.
+ ; An octet shall be represented by 2 hex digits.
+ mtpAddress = MTPToken LBRKT 4*8 (HEXDIG) RBRKT
+
+ terminationIDList = LBRKT TerminationID *(COMMA TerminationID) RBRKT
+
+ ; Total length of pathNAME must not exceed 64 chars.
+ pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ ["@" pathDomainName ]
+
+ ; ABNF allows two or more consecutive "." although it is meaningless
+ ; in a path domain name.
+ pathDomainName = (ALPHA / DIGIT / "*" )
+ *63(ALPHA / DIGIT / "-" / "*" / ".")
+
+ TerminationID = "ROOT" / pathNAME / "$" / "*"
+
+ mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+
+ ; at-most one terminationStateDescriptor
+ ; and either streamParm(s) or streamDescriptor(s) but not both
+ mediaParm = (streamParm / streamDescriptor /
+ terminationStateDescriptor)
+
+ ; at-most-once per item
+ streamParm = ( localDescriptor / remoteDescriptor /
+ localControlDescriptor )
+
+ streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+ *(COMMA streamParm) RBRKT
+
+ localControlDescriptor = LocalControlToken LBRKT localParm
+ *(COMMA localParm) RBRKT
+
+ ; at-most-once per item except for propertyParm
+ localParm = ( streamMode / propertyParm / reservedValueMode
+ / reservedGroupMode )
+
+
+
+Groves, et al. Standards Track [Page 118]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+ reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+
+ streamMode = ModeToken EQUAL streamModes
+
+ streamModes = (SendonlyToken / RecvonlyToken / SendrecvToken /
+ InactiveToken / LoopbackToken )
+
+ propertyParm = pkgdName parmValue
+ parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+ alternativeValue = ( VALUE
+ / LSBRKT VALUE *(COMMA VALUE) RSBRKT
+ ; sublist (i.e., A AND B AND ...)
+ / LBRKT VALUE *(COMMA VALUE) RBRKT
+ ; alternatives (i.e., A OR B OR ...)
+ / LSBRKT VALUE COLON VALUE RSBRKT )
+ ; range
+
+ INEQUAL = LWSP (">" / "<" / "#" ) LWSP
+ LSBRKT = LWSP "[" LWSP
+ RSBRKT = LWSP "]" LWSP
+
+ ; Note - The octet zero is not among the permitted characters in
+ ; octet string. As the current definition is limited to SDP, and a
+ ; zero octet would not be a legal character in SDP, this is not a
+ ; concern.
+
+ localDescriptor = LocalToken LBRKT octetString RBRKT
+
+ remoteDescriptor = RemoteToken LBRKT octetString RBRKT
+
+ eventBufferDescriptor= EventBufferToken [ LBRKT eventSpec
+ *( COMMA eventSpec) RBRKT ]
+
+ eventSpec = pkgdName [ LBRKT eventSpecParameter
+ *(COMMA eventSpecParameter) RBRKT ]
+ eventSpecParameter = (eventStream / eventOther)
+
+ eventBufferControl = BufferToken EQUAL ( "OFF" / LockStepToken )
+
+ terminationStateDescriptor = TerminationStateToken LBRKT
+ terminationStateParm *( COMMA terminationStateParm ) RBRKT
+
+ ; at-most-once per item except for propertyParm
+ terminationStateParm = (propertyParm / serviceStates /
+ eventBufferControl )
+
+
+
+
+Groves, et al. Standards Track [Page 119]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ serviceStates = ServiceStatesToken EQUAL ( TestToken /
+ OutOfSvcToken / InSvcToken )
+
+ muxDescriptor = MuxToken EQUAL MuxType terminationIDList
+
+ MuxType = ( H221Token / H223Token / H226Token / V76Token
+ / extensionParameter )
+
+ StreamID = UINT16
+ pkgdName = (PackageName SLASH ItemID) ;specific item
+ / (PackageName SLASH "*") ;all items in package
+ / ("*" SLASH "*") ; all items supported by the MG
+ PackageName = NAME
+ ItemID = NAME
+
+ eventsDescriptor = EventsToken [ EQUAL RequestID LBRKT
+ requestedEvent *( COMMA requestedEvent ) RBRKT ]
+
+ requestedEvent = pkgdName [ LBRKT eventParameter
+ *( COMMA eventParameter ) RBRKT ]
+
+ ; at-most-once each of KeepActiveToken , eventDM and eventStream
+ ;at most one of either embedWithSig or embedNoSig but not both
+ ;KeepActiveToken and embedWithSig must not both be present
+ eventParameter = ( embedWithSig / embedNoSig / KeepActiveToken
+ /eventDM / eventStream / eventOther )
+
+ embedWithSig = EmbedToken LBRKT signalsDescriptor
+ [COMMA embedFirst ] RBRKT
+ embedNoSig = EmbedToken LBRKT embedFirst RBRKT
+
+ ; at-most-once of each
+ embedFirst = EventsToken [ EQUAL RequestID LBRKT
+ secondRequestedEvent *(COMMA secondRequestedEvent) RBRKT ]
+
+ secondRequestedEvent = pkgdName [ LBRKT secondEventParameter
+ *( COMMA secondEventParameter ) RBRKT ]
+
+ ; at-most-once each of embedSig , KeepActiveToken, eventDM or
+ ; eventStream
+ ; KeepActiveToken and embedSig must not both be present
+ secondEventParameter = ( embedSig / KeepActiveToken / eventDM /
+ eventStream / eventOther )
+
+ embedSig = EmbedToken LBRKT signalsDescriptor RBRKT
+
+ eventStream = StreamToken EQUAL StreamID
+
+
+
+
+Groves, et al. Standards Track [Page 120]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ eventOther = eventParameterName parmValue
+
+ eventParameterName = NAME
+
+ eventDM = DigitMapToken EQUAL(( digitMapName ) /
+ (LBRKT digitMapValue RBRKT ))
+
+ signalsDescriptor = SignalsToken LBRKT [ signalParm
+ *(COMMA signalParm)] RBRKT
+
+ signalParm = signalList / signalRequest
+
+ signalRequest = signalName [ LBRKT sigParameter
+ *(COMMA sigParameter) RBRKT ]
+
+ signalList = SignalListToken EQUAL signalListId LBRKT
+ signalListParm *(COMMA signalListParm) RBRKT
+
+ signalListId = UINT16
+
+ ;exactly once signalType, at most once duration and every signal
+ ;parameter
+ signalListParm = signalRequest
+
+ signalName = pkgdName
+ ;at-most-once sigStream, at-most-once sigSignalType,
+ ;at-most-once sigDuration, every signalParameterName at most once
+ sigParameter = sigStream / sigSignalType / sigDuration / sigOther
+ / notifyCompletion / KeepActiveToken
+ sigStream = StreamToken EQUAL StreamID
+ sigOther = sigParameterName parmValue
+ sigParameterName = NAME
+ sigSignalType = SignalTypeToken EQUAL signalType
+ signalType = (OnOffToken / TimeOutToken / BriefToken)
+ sigDuration = DurationToken EQUAL UINT16
+ notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+ notificationReason *(COMMA notificationReason) RBRKT)
+
+ notificationReason = ( TimeOutToken / InterruptByEventToken
+ / InterruptByNewSignalsDescrToken
+ / OtherReasonToken )
+ observedEventsDescriptor = ObservedEventsToken EQUAL RequestID
+ LBRKT observedEvent *(COMMA observedEvent) RBRKT
+
+ ;time per event, because it might be buffered
+ observedEvent = [ TimeStamp LWSP COLON] LWSP
+ pkgdName [ LBRKT observedEventParameter
+ *(COMMA observedEventParameter) RBRKT ]
+
+
+
+Groves, et al. Standards Track [Page 121]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ ;at-most-once eventStream, every eventParameterName at most once
+ observedEventParameter = eventStream / eventOther
+
+ ; For an AuditCapReply with all events, the RequestID should be ALL.
+ RequestID = ( UINT32 / "*" )
+
+ modemDescriptor = ModemToken (( EQUAL modemType) /
+ (LSBRKT modemType *(COMMA modemType) RSBRKT))
+ [ LBRKT propertyParm *(COMMA propertyParm) RBRKT ]
+
+
+ ; at-most-once except for extensionParameter
+ modemType = (V32bisToken / V22bisToken / V18Token /
+ V22Token / V32Token / V34Token / V90Token /
+ V91Token / SynchISDNToken / extensionParameter)
+
+ digitMapDescriptor = DigitMapToken EQUAL
+ ( ( LBRKT digitMapValue RBRKT ) /
+ (digitMapName [ LBRKT digitMapValue RBRKT ]) )
+ digitMapName = NAME
+ digitMapValue = ["T" COLON Timer COMMA] ["S" COLON Timer COMMA]
+ ["L" COLON Timer COMMA] digitMap
+ Timer = 1*2DIGIT
+ ; Units are seconds for T, S, and L timers, and hundreds of
+ ; milliseconds for Z timer. Thus T, S, and L range from 1 to 99
+ ; seconds and Z from 100 ms to 9.9 s
+ digitMap = (digitString /
+ LWSP "(" LWSP digitStringList LWSP ")" LWSP)
+ digitStringList = digitString *( LWSP "|" LWSP digitString )
+ digitString = 1*(digitStringElement)
+ digitStringElement = digitPosition [DOT]
+ digitPosition = digitMapLetter / digitMapRange
+ digitMapRange = ("x" / (LWSP "[" LWSP digitLetter LWSP "]" LWSP))
+ digitLetter = *((DIGIT "-" DIGIT ) / digitMapLetter)
+ digitMapLetter = DIGIT ;Basic event symbols
+ / %x41-4B / %x61-6B ; a-k, A-K
+ / "L" / "S" ;Inter-event timers (long, short)
+ / "Z" ;Long duration modifier
+
+ ;at-most-once, and DigitMapToken and PackagesToken are not allowed
+ ;in AuditCapabilities command
+ auditItem = ( MuxToken / ModemToken / MediaToken /
+ SignalsToken / EventBufferToken /
+ DigitMapToken / StatsToken / EventsToken /
+ ObservedEventsToken / PackagesToken )
+
+
+
+
+
+Groves, et al. Standards Track [Page 122]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ serviceChangeDescriptor = ServicesToken LBRKT serviceChangeParm
+ *(COMMA serviceChangeParm) RBRKT
+
+ ; each parameter at-most-once
+ ; at most one of either serviceChangeAddress or serviceChangeMgcId
+ ; but not both
+ ; serviceChangeMethod and serviceChangeReason are REQUIRED
+ serviceChangeParm = (serviceChangeMethod / serviceChangeReason /
+ serviceChangeDelay / serviceChangeAddress /
+ serviceChangeProfile / extension / TimeStamp /
+ serviceChangeMgcId / serviceChangeVersion )
+
+ serviceChangeReplyDescriptor = ServicesToken LBRKT
+ servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+
+ ; at-most-once. Version is REQUIRED on first ServiceChange response
+ ; at most one of either serviceChangeAddress or serviceChangeMgcId
+ ; but not both
+ servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+ serviceChangeProfile / serviceChangeVersion /
+ TimeStamp)
+ serviceChangeMethod = MethodToken EQUAL (FailoverToken /
+ ForcedToken / GracefulToken / RestartToken /
+ DisconnectedToken / HandOffToken /
+ extensionParameter)
+ ; A serviceChangeReason consists of a numeric reason code
+ ; and an optional text description.
+ ; A serviceChangeReason MUST be encoded using the quotedString
+ ; form of VALUE.
+ ; The quotedString SHALL contain a decimal reason code,
+ ; optionally followed by a single space character and a
+ ; textual description string.
+
+
+ serviceChangeReason = ReasonToken EQUAL VALUE
+ serviceChangeDelay = DelayToken EQUAL UINT32
+ serviceChangeAddress = ServiceChangeAddressToken EQUAL ( mId /
+ portNumber )
+ serviceChangeMgcId = MgcIdToken EQUAL mId
+ serviceChangeProfile = ProfileToken EQUAL NAME SLASH Version
+ serviceChangeVersion = VersionToken EQUAL Version
+ extension = extensionParameter parmValue
+
+ packagesDescriptor = PackagesToken LBRKT packagesItem
+ *(COMMA packagesItem) RBRKT
+
+ Version = 1*2(DIGIT)
+ packagesItem = NAME "-" UINT16
+
+
+
+Groves, et al. Standards Track [Page 123]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ TimeStamp = Date "T" Time ; per ISO 8601:1988
+ ; Date = yyyymmdd
+ Date = 8(DIGIT)
+ ; Time = hhmmssss
+ Time = 8(DIGIT)
+ statisticsDescriptor = StatsToken LBRKT statisticsParameter
+ *(COMMA statisticsParameter ) RBRKT
+
+ ;at-most-once per item
+ statisticsParameter = pkgdName [EQUAL VALUE]
+
+ topologyDescriptor = TopologyToken LBRKT topologyTriple
+ *(COMMA topologyTriple) RBRKT
+ topologyTriple = terminationA COMMA
+ terminationB COMMA topologyDirection
+ terminationA = TerminationID
+ terminationB = TerminationID
+ topologyDirection = BothwayToken / IsolateToken / OnewayToken
+
+ priority = PriorityToken EQUAL UINT16
+
+ extensionParameter = "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+
+ ; octetString is used to describe SDP defined in RFC2327.
+ ; Caution should be taken if CRLF in RFC2327 is used.
+ ; To be safe, use EOL in this ABNF.
+ ; Whenever "}" appears in SDP, it is escaped by "\", e.g., "\}"
+ octetString = *(nonEscapeChar)
+ nonEscapeChar = ( "\}" / %x01-7C / %x7E-FF )
+ ; Note - The double-quote character is not allowed in quotedString.
+ quotedString = DQUOTE *(SafeChar / RestChar/ WSP) DQUOTE
+
+ UINT16 = 1*5(DIGIT) ; %x0-FFFF
+ UINT32 = 1*10(DIGIT) ; %x0-FFFFFFFF
+
+ NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ VALUE = quotedString / 1*(SafeChar)
+ SafeChar = DIGIT / ALPHA / "+" / "-" / "&" /
+ "!" / "_" / "/" / "\'" / "?" / "@" /
+ "^" / "`" / "~" / "*" / "$" / "\" /
+ "(" / ")" / "%" / "|" / "."
+
+ EQUAL = LWSP %x3D LWSP ; "="
+ COLON = %x3A ; ":"
+ LBRKT = LWSP %x7B LWSP ; "{"
+ RBRKT = LWSP %x7D LWSP ; "}"
+ COMMA = LWSP %x2C LWSP ; ","
+
+
+
+Groves, et al. Standards Track [Page 124]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ DOT = %x2E ; "."
+ SLASH = %x2F ; "/"
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ DIGIT = %x30-39 ; 0-9
+ DQUOTE = %x22 ; " (Double Quote)
+ HEXDIG = ( DIGIT / "A" / "B" / "C" / "D" / "E" / "F" )
+ SP = %x20 ; space
+ HTAB = %x09 ; horizontal tab
+ CR = %x0D ; Carriage return
+ LF = %x0A ; linefeed
+ LWSP = *( WSP / COMMENT / EOL )
+ EOL = (CR [LF] / LF )
+ WSP = SP / HTAB ; white space
+ SEP = ( WSP / EOL / COMMENT) LWSP
+ COMMENT = ";" *(SafeChar/ RestChar / WSP / %x22) EOL
+ RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+ "<" / ">" / "="
+
+ ; New Tokens added to sigParameter must take the format of SPA*
+ ; * may be of any form i.e., SPAM
+ ; New Tokens added to eventParameter must take the form of EPA*
+ ; * may be of any form i.e., EPAD
+
+ AddToken = ("Add" / "A")
+ AuditToken = ("Audit" / "AT")
+ AuditCapToken = ("AuditCapability" / "AC")
+ AuditValueToken = ("AuditValue" / "AV")
+ AuthToken = ("Authentication" / "AU")
+ BothwayToken = ("Bothway" / "BW")
+ BriefToken = ("Brief" / "BR")
+ BufferToken = ("Buffer" / "BF")
+ CtxToken = ("Context" / "C")
+ ContextAuditToken = ("ContextAudit" / "CA")
+ DigitMapToken = ("DigitMap" / "DM")
+ DisconnectedToken = ("Disconnected" / "DC")
+ DelayToken = ("Delay" / "DL")
+ DurationToken = ("Duration" / "DR")
+ EmbedToken = ("Embed" / "EM")
+ EmergencyToken = ("Emergency" / "EG")
+ ErrorToken = ("Error" / "ER")
+ EventBufferToken = ("EventBuffer" / "EB")
+ EventsToken = ("Events" / "E")
+ FailoverToken = ("Failover" / "FL")
+ ForcedToken = ("Forced" / "FO")
+ GracefulToken = ("Graceful" / "GR")
+ H221Token = ("H221" )
+ H223Token = ("H223" )
+ H226Token = ("H226" )
+
+
+
+Groves, et al. Standards Track [Page 125]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ HandOffToken = ("HandOff" / "HO")
+ ImmAckRequiredToken = ("ImmAckRequired" / "IA")
+ InactiveToken = ("Inactive" / "IN")
+ IsolateToken = ("Isolate" / "IS")
+ InSvcToken = ("InService" / "IV")
+ InterruptByEventToken = ("IntByEvent" / "IBE")
+ InterruptByNewSignalsDescrToken
+ = ("IntBySigDescr" / "IBS")
+ KeepActiveToken = ("KeepActive" / "KA")
+ LocalToken = ("Local" / "L")
+ LocalControlToken = ("LocalControl" / "O")
+ LockStepToken = ("LockStep" / "SP")
+ LoopbackToken = ("Loopback" / "LB")
+ MediaToken = ("Media" / "M")
+ MegacopToken = ("MEGACO" / "!")
+ MethodToken = ("Method" / "MT")
+ MgcIdToken = ("MgcIdToTry" / "MG")
+ ModeToken = ("Mode" / "MO")
+ ModifyToken = ("Modify" / "MF")
+ ModemToken = ("Modem" / "MD")
+ MoveToken = ("Move" / "MV")
+ MTPToken = ("MTP")
+ MuxToken = ("Mux" / "MX")
+ NotifyToken = ("Notify" / "N")
+ NotifyCompletionToken = ("NotifyCompletion" / "NC")
+ ObservedEventsToken = ("ObservedEvents" / "OE")
+ OnewayToken = ("Oneway" / "OW")
+ OnOffToken = ("OnOff" / "OO")
+ OtherReasonToken = ("OtherReason" / "OR")
+ OutOfSvcToken = ("OutOfService" / "OS")
+ PackagesToken = ("Packages" / "PG")
+ PendingToken = ("Pending" / "PN")
+ PriorityToken = ("Priority" / "PR")
+ ProfileToken = ("Profile" / "PF")
+ ReasonToken = ("Reason" / "RE")
+ RecvonlyToken = ("ReceiveOnly" / "RC")
+ ReplyToken = ("Reply" / "P")
+ RestartToken = ("Restart" / "RS")
+ RemoteToken = ("Remote" / "R")
+ ReservedGroupToken = ("ReservedGroup" / "RG")
+ ReservedValueToken = ("ReservedValue" / "RV")
+ SendonlyToken = ("SendOnly" / "SO")
+ SendrecvToken = ("SendReceive" / "SR")
+ ServicesToken = ("Services" / "SV")
+ ServiceStatesToken = ("ServiceStates" / "SI")
+ ServiceChangeToken = ("ServiceChange" / "SC")
+ ServiceChangeAddressToken = ("ServiceChangeAddress" / "AD")
+ SignalListToken = ("SignalList" / "SL")
+
+
+
+Groves, et al. Standards Track [Page 126]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ SignalsToken = ("Signals" / "SG")
+ SignalTypeToken = ("SignalType" / "SY")
+ StatsToken = ("Statistics" / "SA")
+ StreamToken = ("Stream" / "ST")
+ SubtractToken = ("Subtract" / "S")
+ SynchISDNToken = ("SynchISDN" / "SN")
+ TerminationStateToken = ("TerminationState" / "TS")
+ TestToken = ("Test" / "TE")
+ TimeOutToken = ("TimeOut" / "TO")
+ TopologyToken = ("Topology" / "TP")
+ TransToken = ("Transaction" / "T")
+ ResponseAckToken = ("TransactionResponseAck" / "K")
+ V18Token = ("V18")
+ V22Token = ("V22")
+ V22bisToken = ("V22b")
+ V32Token = ("V32")
+ V32bisToken = ("V32b")
+ V34Token = ("V34")
+ V76Token = ("V76")
+ V90Token = ("V90")
+ V91Token = ("V91")
+ VersionToken = ("Version" / "V")
+
+B.3 Hexadecimal octet coding
+
+ Hexadecimal octet coding is a means for representing a string of
+ octets as a string of hexadecimal digits, with two digits
+ representing each octet. This octet encoding should be used when
+ encoding octet strings in the text version of the protocol. For each
+ octet, the 8-bit sequence is encoded as two hexadecimal digits. Bit
+ 0 is the first transmitted; bit 7 is the last. Bits 7-4 are encoded
+ as the first hexadecimal digit, with Bit 7 as MSB and Bit 4 as LSB.
+ Bits 3-0 are encoded as the second hexadecimal digit, with Bit 3 as
+ MSB and Bit 0 as LSB. Examples:
+
+ Octet bit pattern Hexadecimal coding
+ 00011011 D8
+ 11100100 27
+ 10000011 10100010 11001000 00001001 C1451390
+
+B.4 Hexadecimal octet sequence
+
+ A hexadecimal octet sequence is an even number of hexadecimal digits,
+ terminated by a <CR> character.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 127]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ANNEX C - Tags for media stream properties
+
+ Parameters for Local, Remote and LocalControl descriptors are
+ specified as tag-value pairs if binary encoding is used for the
+ protocol. This annex contains the property names (PropertyID), the
+ tags (Property tag), type of the property (Type) and the values
+ (Value). Values presented in the Value field when the field contains
+ references shall be regarded as "information". The reference
+ contains the normative values. If a value field does not contain a
+ reference, then the values in that field can be considered as
+ "normative".
+
+ Tags are given as hexadecimal numbers in this annex. When setting
+ the value of a property, a MGC may underspecify the value according
+ to one of the mechanisms specified in 7.1.1.
+
+ It is optional to support the properties in this Annex or any of its
+ sub-sections. For example, only three properties from C.3 and only
+ five properties from C.8 might be implemented.
+
+ For type "enumeration" the value is represented by the value in
+ brackets, e.g., Send(0), Receive(1). Annex C properties with the
+ types "N bits" or "M Octets" should be treated as octet strings when
+ encoding the protocol. Properties with "N bit integer" shall be
+ treated as an integers. "String" shall be treated as an IA5String
+ when encoding the protocol.
+
+ When a type is smaller than one octet, the value shall be stored in
+ the low-order bits of an octet string of size 1.
+
+C.1 General media attributes
+
+ PropertyID Property Type Value
+ tag
+
+ Media 1001 Enumeration Audio(0), Video(1), Data(2)
+
+ Transmission 1002 Enumeration Send(0), Receive(1),
+ mode Send&Receive(2)
+
+ Number of 1003 Unsigned 0-255
+ Channels integer
+
+ Sampling 1004 Unsigned 0-2^32
+ rate integer
+
+ Bitrate 1005 Integer (0..4294967295)NOTE - Units of
+ 100 bit/s.
+
+
+
+Groves, et al. Standards Track [Page 128]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ACodec 1006 Octet string Audio Codec Type:
+ Ref.: ITU-T Q.765
+ Non-ITU-T codecs are defined
+ with the appropriate standards
+ organization under a defined
+ Organizational Identifier.
+
+ Samplepp 1007 Unsigned Maximum samples or frames per
+ integer packet: 0..65535
+
+ Silencesupp 1008 Boolean Silence Suppression: True/False
+
+ Encrypttype 1009 Octet string Ref.: ITU-T H.245
+
+ Encryptkey 100A Octet string Encryption key
+ size Ref.: ITU-T H.235
+ (0..65535)
+
+ Echocanc 100B Not Used. See H.248.1 E.13 for
+ an example of possible Echo
+ Control properties.
+
+ Gain 100C Unsigned Gain in dB: 0..65535
+ integer
+
+ Jitterbuff 100D Unsigned Jitter buffer size in ms:
+ integer 0..65535
+
+ PropDelay 100E Unsigned Propagation Delay: 0..65535
+ integer Maximum propagation delay in
+ milliseconds for the bearer
+ connection between two media
+ gateways. The maximum delay
+ will be dependent on the bearer
+ technology.
+
+ RTPpayload 100F Integer Payload type in RTP Profile for
+ Audio and Video Conferences
+ with Minimal Control
+ Ref.: RFC 1890
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 129]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+C.2 Mux properties
+
+ PropertyID Property tag Type Value
+
+ H222 2001 Octet string H222LogicalChannelParameters
+ Ref.: ITU-T H.245
+
+ H223 2002 Octet string H223LogicalChannelParameters
+ Ref.: ITU-T H.245
+
+ V76 2003 Octet string V76LogicalChannelParameters
+ Ref.: ITU-T H.245
+
+ H2250 2004 Octet string H2250LogicalChannelParameters
+ Ref.: ITU-T H.245
+
+C.3 General bearer properties
+
+ PropertyID Property Type Value
+ tag
+
+ Mediatx 3001 Enumeration Media Transport TypeTDM
+ Circuit(0), ATM(1), FR(2),
+ Ipv4(3), Ipv6(4), ...
+
+ BIR 3002 4 octets Value depends on transport
+ technology
+
+ NSAP 3003 1-20 octets See NSAP.
+ Ref.: Annex A/X.213
+
+C.4 General ATM properties
+
+ PropertyID Property Type Value
+ tag
+
+ AESA 4001 20 octets ATM End System Address
+
+ VPVC 4002 4 octets: VPCI VPCI/VCI
+ in first two
+ least Ref.: ITU-T Q.2931
+ significant
+ octets, VCI in
+ second two
+ octets
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 130]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ SC 4003 Enumeration Service Category: CBR(0),
+ nrt-VBR1(1), nrt VBR2(2),
+ nrt-VBR3(3), rt-VBR1(4),
+ rt VBR2(5), rt-VBR3(6),
+ UBR1(7), UBR2(8), ABR(9).
+ Ref.: ATM Forum UNI 4.0
+
+ BCOB 4004 5-bit integer Broadband Bearer Class
+ Ref.: ITU-T Q.2961.2
+
+ BBTC 4005 7-bit integer Broadband Transfer Capability
+ Ref.: ITU-T Q.2961.1
+
+ ATC 4006 Enumeration I.371 ATM Traffic
+ CapabilityDBR(0), SBR1(1),
+ SBR2(2), SBR3(3), ABT/IT(4),
+ ABT/DT(5), ABR(6)
+ Ref.: ITU-T I.371
+
+ STC 4007 2 bits Susceptibility to clipping:
+ Bits
+ 2 1
+ ---
+ 0 0 not susceptible to
+ clipping
+ 0 1 susceptible to
+ clipping
+ Ref.: ITU-T Q.2931
+
+ UPCC 4008 2 bits User Plane Connection
+ configuration:
+ Bits
+ 2 1
+ ---
+ 0 0 point-to-point
+ 0 1 point-to-multipoint
+ Ref.: ITU-T Q.2931
+
+ PCR0 4009 24-bit integer Peak Cell Rate (For CLP = 0)
+ Ref.: ITU-T Q.2931
+
+ SCR0 400A 24-bit integer Sustainable Cell Rate (For
+ CLP = 0)
+ Ref.: ITU-T Q.2961.1
+
+ MBS0 400B 24-bit integer Maximum Burst Size (For CLP =
+ 0)
+ Ref.: ITU-T Q.2961.1
+
+
+
+Groves, et al. Standards Track [Page 131]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ PCR1 400C 24-bit integer Peak Cell Rate (For CLP = 0 +
+ 1)
+ Ref.: ITU-T Q.2931
+
+ SCR1 400D 24-bit integer Sustainable Cell Rate (For
+ CLP = 0 + 1)
+ Ref.: ITU-T Q.2961.1
+
+ MBS1 400E 24-bit integer Maximum Burst Size (For CLP =
+ 0 + 1)
+ Ref.: ITU-T Q.2961.1
+
+ BEI 400F Boolean Best Effort Indicator
+ Value 1 indicates that BEI is
+ to be included in the ATM
+ signaling; value 0 indicates
+ that BEI is not to be
+ included in the ATM
+ signaling.
+ Ref.: ATM Forum UNI 4.0
+
+ TI 4010 Boolean Tagging Indicator
+ Value 0 indicates that
+ tagging is not allowed; value
+ 1 indicates that tagging is
+ requested.
+ Ref.: ITU-T Q.2961.1
+
+ FD 4011 Boolean Frame Discard
+ Value 0 indicates that no
+ frame discard is allowed;
+ value 1 indicates that frame
+ discard is allowed.
+ Ref.: ATM Forum UNI 4.0
+
+ A2PCDV 4012 24-bit integer Acceptable 2-point CDV
+ Ref.: ITU-T Q.2965.2
+
+ C2PCDV 4013 24-bit integer Cumulative 2-point CDV
+ Ref.: ITU-T Q.2965.2
+
+ APPCDV 4014 24-bit integer Acceptable P-P CDV
+ Ref.: ATM Forum UNI 4.0
+
+ CPPCDV 4015 24-bit integer Cumulative P-P CDV
+ Ref.: ATM Forum UNI 4.0
+
+
+
+
+
+Groves, et al. Standards Track [Page 132]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ACLR 4016 8-bit integer Acceptable Cell Loss Ratio
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ MEETD 4017 16-bit integer Maximum End-to-end transit
+ delay
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ CEETD 4018 16-bit integer Cumulative End-to-end transit
+ delay
+ Ref.: ITU-T Q.2965.2, ATM
+ Forum UNI 4.0
+
+ QosClass 4019 Integer 0-5 QoS Class
+
+ QoS Class Meaning
+
+ 0 Default QoS
+ associated
+ with the ATC
+ as defined
+ in ITU-T
+ Q.2961.2
+
+ 1 Stringent
+
+ 2 Tolerant
+
+ 3 Bi-level
+
+ 4 Unbounded
+
+ 5 Stringent
+ Bi-level
+ Ref.: ITU-T Q.2965.1
+
+ AALtype 401A 1 octet AAL Type
+ Bits
+ 8 7 6 5 4 3 2 1
+ ---------------
+ 0 0 0 0 0 0 0 0 AAL for
+ voice
+ 0 0 0 0 0 0 0 1 AAL type 1
+ 0 0 0 0 0 0 1 0 AAL type 2
+ 0 0 0 0 0 0 1 1 AAL type
+ 3/4
+ 0 0 0 0 0 1 0 1 AAL type 5
+
+
+
+Groves, et al. Standards Track [Page 133]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 0 0 0 1 0 0 0 0 user-
+ defined AAL
+ Ref.: ITU-T Q.2931
+
+C.5 Frame Relay
+
+ PropertyID Property Type Value
+ tag
+
+ DLCI 5001 Unsigned Data link connection
+ integer id
+
+ CID 5002 Unsigned sub-channel id
+ integer
+
+ SID/Noiselevel 5003 Unsigned silence insertion
+ integer descriptor
+
+ Primary Payload 5004 Unsigned Primary Payload Type
+ type integer Covers FAX and codecs
+
+C.6 IP
+
+ PropertyID Property tag Type Value
+
+ IPv4 6001 32 bits Ipv4Address Ipv4Address
+ Ref.: IETF RFC 791
+
+ IPv6 6002 128 bits IPv6 Address
+ Ref.: IETF RFC 2460
+
+ Port 6003 Unsigned integer 0..65535
+
+ Porttype 6004 Enumerated TCP(0), UDP(1), SCTP(2)
+
+
+C.7 ATM AAL2
+
+ PropertyID Property Type Value
+ tag
+
+ AESA 7001 20 octets AAL2 service endpoint
+ address as defined in
+ the referenced
+ Recommendation.
+ ESEANSEA
+ Ref.: ITU-T Q.2630.1
+
+
+
+
+Groves, et al. Standards Track [Page 134]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ BIR See C.3 4 octets Served user generated
+ reference as defined in
+ the referenced
+ Recommendation.
+ SUGR
+ Ref.: ITU-T Q.2630.1
+
+ ALC 7002 12 octets AAL2 link
+ characteristics as
+ defined in the
+ referenced
+ Recommendation.
+ Maximum/Average CPS-SDU
+ bit rate;
+ Maximum/Average CPS-SDU
+ size
+ Ref.: ITU-T Q.2630.1
+
+ SSCS 7003 I.366.2: Audio (8 Service specific
+ octets); Multirate (3 convergence sublayer
+ octets), or I.366.1: information as defined
+ SAR-assured (14 in:
+ octets);SAR-unassured - ITU-T Q.2630.1,and
+ (7 octets). used in:
+ - ITU-T I.366.2:
+ Audio/Multirate;
+ - ITU-T I.366.1: SAR-
+ assured/unassured.
+ Ref.: ITU-T Q.2630.1,
+ I.366.1 and I.366.2
+
+ SUT 7004 1..254 octets Served user transport
+ parameter as defined in
+ the referenced
+ Recommendation.
+ Ref.: ITU-T Q.2630.1
+
+ TCI 7005 Boolean Test connection
+ indicator as defined in
+ the referenced
+ Recommendation.
+ Ref.: ITU-T Q.2630.1
+
+ Timer_CU 7006 32-bit integer Timer-CU
+ Milliseconds to hold
+ partially filled cell
+ before sending.
+
+
+
+
+Groves, et al. Standards Track [Page 135]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ MaxCPSSDU 7007 8-bit integer Maximum Common Part
+ Sublayer Service Data
+ Unit
+ Ref.: ITU-T Q.2630.1
+
+ CID 7008 8 bits subchannel id: 0-255
+ Ref.: ITU-T I.363.2
+C.8 ATM AAL1
+
+ PropertyID Property Type Value
+ tag
+
+ BIR See table 4-29 octets GIT (Generic Identifier
+ in C.3 Transport)
+ Ref.: ITU-T Q.2941.1
+
+ AAL1ST 8001 1 octet AAL1 Subtype
+ Bits
+ 8 7 6 5 4 3 2 1
+ ---------------
+ 0 0 0 0 0 0 0 0 null
+ 0 0 0 0 0 0 0 1 voiceband
+ signal transport on 64 kbit/s
+ 0 0 0 0 0 0 1 0 circuit
+ transport
+ 0 0 0 0 0 1 0 0 high-quality
+ audio signal transport
+ 0 0 0 0 0 1 0 1 video signal
+ transport
+ Ref.: ITU-T Q.2931
+
+ CBRR 8002 1 octet CBR Rate
+ Bits
+ 8 7 6 5 4 3 2 1
+ ---------------
+ 0 0 0 0 0 0 0 1 64 kbit/s
+ 0 0 0 0 0 1 0 0 1544 kbit/s
+ 0 0 0 0 0 1 0 1 6312 kbit/s
+ 0 0 0 0 0 1 1 0 32 064 kbit/s
+ 0 0 0 0 0 1 1 1 44 736 kbit/s
+ 0 0 0 0 1 0 0 0 97 728 kbit/s
+ 0 0 0 1 0 0 0 0 2048 kbit/s
+ 0 0 0 1 0 0 0 1 8448 kbit/s
+ 0 0 0 1 0 0 1 0 34 368 kbit/s
+ 0 0 0 1 0 0 1 1 139 264 kbit/s
+ 0 1 0 0 0 0 0 0 n x 64 kbit/s
+ 0 1 0 0 0 0 0 1 n x 8 kbit/s
+ Ref.: ITU-T Q.2931
+
+
+
+Groves, et al. Standards Track [Page 136]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ MULT See table Multiplier, or n x 64k/8k/300
+ in C.9 Ref.: ITU-T Q.2931
+
+ SCRI 8003 1 octet Source Clock Frequency Recovery
+ Method
+ Bits
+ 8 7 6 5 4 3 2 1
+ ---------------
+ 0 0 0 0 0 0 0 0 null
+ 0 0 0 0 0 0 0 1 SRTS
+ 0 0 0 0 0 0 1 0 ACM
+ Ref.: ITU-T Q.2931
+
+ ECM 8004 1 octet Error Correction Method
+ Bits
+ 8 7 6 5 4 3 2 1
+ ---------------
+ 0 0 0 0 0 0 0 0 null
+ 0 0 0 0 0 0 0 1 FEC - Loss
+ 0 0 0 0 0 0 1 0 FEC - Delay
+ Ref.: ITU-T Q.2931
+
+ SDTB 8005 16-bit Structured Data Transfer
+ integer Blocksize
+ Block size of SDT CBR service
+ Ref.: ITU-T I.363.1
+
+ PFCI 8006 8-bit Partially filled cells identifier
+ integer 1-47
+ Ref.: ITU-T I.363.1
+
+C.9 Bearer capabilities
+
+ The table entries referencing Recommendation Q.931 refer to the
+ encoding in the bearer capability information element of Q.931, not
+ to the low layer information element.
+
+ PropertyID Tag Type Value
+
+ TMR 9001 1 octet Transmission Medium
+ Requirement (Q.763)
+ Bits
+ 87654321
+ --------
+ 00000000 speech
+ 00000001 spare
+ 00000010 64 kbit/s
+ unrestricted
+
+
+
+Groves, et al. Standards Track [Page 137]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 00000011 3.1 kHz audio
+ 00000100 reserved for
+ alternate speech (service
+ 2)/64 kbit/s unrestricted
+ (service 1)
+ 00000101 reserved for
+ alternate 64 kbit/s
+ unrestricted (service
+ 1)/speech (service 2)
+ 00000110 64 kbit/s preferred
+
+ The assigned codepoints
+ listed below are all for
+ unrestricted service.
+ 00000111 2 x 64 kbit/s
+ 00001000 384 kbit/s
+ 00001001 1536 kbit/s
+ 00001010 1920 kbit/s
+ 00001011
+ through
+ 00001111 spare
+ 00010000
+ through
+ 00101010:
+ 3 x 64 kbit/s through
+ 29 x 64 kbit/s
+ except
+ 00010011 spare
+ 00100101 spare
+
+ 00101011
+ through
+ 11111111 spare
+ Ref.: ITU-T Q.763
+
+ TMRSR 9002 1 octet Transmission Medium
+ Requirement Subrate
+ 0 unspecified
+ 1 8 kbit/s
+ 2 16 kbit/s
+ 3 32 kbit/s
+
+ Contcheck 9003 Boolean Continuity Check
+ 0 continuity check not
+ required on this circuit
+ 1 continuity check
+ required on this circuit
+ Ref.: ITU-T Q.763
+
+
+
+Groves, et al. Standards Track [Page 138]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ ITC 9004 5 bits Information Transfer
+ Capability
+ Bits
+ 5 4 3 2 1
+ ---------
+ 0 0 0 0 0 Speech
+ 0 1 0 0 0 Unrestricted
+ digital information
+ 0 1 0 0 1 Restricted
+ digital information
+ 1 0 0 0 0 3.1 kHz audio
+ 1 0 0 0 1 Unrestricted
+ digital information with
+ tones/announcements
+ 1 1 0 0 0 Video
+ All other values are
+ reserved.
+ Ref.: ITU-T Q.763
+
+ TransMode 9005 2 bits Transfer Mode
+ Bits
+ 2 1
+ ---
+ 0 0 Circuit mode
+ 1 0 Packet mode
+ Ref.: ITU-T Q.931
+
+ TransRate 9006 5 bits Transfer Rate
+ Bits
+ 5 4 3 2 1
+ ---------
+ 0 0 0 0 0 This code shall
+ be used for packet mode calls
+ 1 0 0 0 0 64 kbit/s
+ 1 0 0 0 1 2 x 64 kbit/s
+ 1 0 0 1 1 384 kbit/s
+ 1 0 1 0 1 1536 kbit/s
+ 1 0 1 1 1 1920 kbit/s
+ 1 1 0 0 0 Multirate (64
+ kbit/s base rate)
+ Ref.: ITU-T Q.931
+
+ MULT 9007 7 bits Rate Multiplier
+ Any value from 2 to n
+ (maximum number of B-
+ channels)
+ Ref.: ITU-T Q.931
+
+
+
+Groves, et al. Standards Track [Page 139]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ layer1prot 9008 5 bits User Information Layer 1
+ Protocol
+ Bits
+ 5 4 3 2 1
+ ---------
+ 0 0 0 0 1 ITU-T
+ standardized rate adaption
+ V.110 and X.30.
+ 0 0 0 1 0 Recommendation
+ G.711 m-law
+ 0 0 0 1 1 Recommendation
+ G.711 A-law
+ 0 0 1 0 0 Recommendation
+ G.721 32 kbit/s ADPCM and
+ Recommendation I.460
+ 0 0 1 0 1 Recommendations
+ H.221 and H.242
+ 0 0 1 1 0 Recommendations
+ H.223 and H.245
+ 0 0 1 1 1 Non-ITU-T
+ standardized rate adaption.
+ 0 1 0 0 0 ITU-T
+ standardized rate adaption
+ V.120.
+ 0 1 0 0 1 ITU-T
+ standardized rate adaption
+ X.31 HDLC flag stuffing
+ All other values are
+ reserved.
+ Ref.: ITU Recommendation
+ Q.931
+
+ syncasync 9009 Boolean Synchronous/Asynchronous
+ 0 Synchronous data
+ 1 Asynchronous data
+ Ref.: ITU-T Q.931
+
+ negotiation 900A Boolean Negotiation
+ 0 In-band negotiation
+ possible
+ 1 In-band negotiation not
+ possible
+ Ref.: ITU-T Q.931
+
+ Userrate 900B 5 bits User Rate
+ Bits
+ 5 4 3 2 1
+
+
+
+Groves, et al. Standards Track [Page 140]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ---------
+ 0 0 0 0 0 Rate is
+ indicated by E-bits specified
+ in Recommendation I.460 or
+ may be negotiated in-band
+ 0 0 0 0 1 0.6 kbit/s
+ Recommendations V.6 and X.1
+ 0 0 0 1 0 1.2 kbit/s
+ Recommendation V.6
+ 0 0 0 1 1 2.4 kbit/s
+ Recommendations V.6 and X.1
+ 0 0 1 0 0 3.6 kbit/s
+ Recommendation V.6
+ 0 0 1 0 1 4.8 kbit/s
+ Recommendations V.6 and X.1
+ 0 0 1 1 0 7.2 kbit/s
+ Recommendation V.6
+ 0 0 1 1 1 8 kbit/s
+ Recommendation I.460
+ 0 1 0 0 0 9.6 kbit/s
+ Recommendations V.6 and X.1
+ 0 1 0 0 1 14.4 kbit/s
+ Recommendation V.6
+ 0 1 0 1 0 16 kbit/s
+ Recommendation I.460
+ 0 1 0 1 1 19.2 kbit/s
+ Recommendation V.6
+ 0 1 1 0 0 32 kbit/s
+ Recommendation I.460
+ 0 1 1 0 1 38.4 kbit/s
+ Recommendation V.110
+ 0 1 1 1 0 48 kbit/s
+ Recommendations V.6 and X.1
+ 0 1 1 1 1 56 kbit/s
+ Recommendation V.6
+ 1 0 0 1 0 57.6 kbit/s
+ Recommendation V.14 extended
+ 1 0 0 1 1 28.8 kbit/s
+ Recommendation V.110
+ 1 0 1 0 0 24 kbit/s
+ Recommendation V.110
+ 1 0 1 0 1 0.1345 kbit/s
+ Recommendation X.1
+ 1 0 1 1 0 0.100 kbit/s
+ Recommendation X.1
+ 1 0 1 1 1 0.075/1.2
+ kbit/s Recommendations V.6
+ and X.1
+
+
+
+Groves, et al. Standards Track [Page 141]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 1 1 0 0 0 1.2/0.075
+ kbit/s Recommendations V.6
+ and X.1
+ 1 1 0 0 1 0.050 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 0 1 0 0.075 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 0 1 1 0.110 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 1 0 0 0.150 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 1 0 1 0.200 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 1 1 0 0.300 kbit/s
+ Recommendations V.6 and X.1
+ 1 1 1 1 1 12 kbit/s
+ Recommendation V.6
+ All other values are
+ reserved.
+ Ref.: ITU-T Q.931
+ INTRATE 900C 2 bits Intermediate Rate
+ Bits
+ 2 1
+ ---
+ 0 0 Not used
+ 0 1 8 kbit/s
+ 1 0 16 kbit/s
+ 1 1 32 kbit/s
+ Ref.: ITU-T Q.931
+
+ nictx 900D Boolean Network Independent Clock
+ (NIC) on transmission
+ 0 Not required to send
+ data with network independent
+ clock
+ 1 Required to send data
+ with network independent
+ clock
+ Ref.: ITU-T Q.931
+
+ nicrx 900E Boolean Network independent clock
+ (NIC) on reception
+ 0 Cannot accept data with
+ network independent clock
+ (i.e., sender does not support
+ this optional procedure)
+ 1 Can accept data with
+ network independent clock
+
+
+
+Groves, et al. Standards Track [Page 142]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ (i.e., sender does support
+ this optional procedure)
+ Ref.: ITU-T Q.931
+
+ flowconttx 900F Boolean Flow Control on transmission
+ (Tx)
+ 0 Not required to send
+ data with flow control
+ mechanism
+ 1 Required to send data
+ with flow control mechanism
+ Ref.: ITU-T Q.931
+
+ flowcontrx 9010 Boolean Flow control on reception
+ (Rx)
+ 0 Cannot accept data with
+ flow control mechanism (i.e.,
+ sender does not support this
+ optional procedure)
+ 1 Can accept data with
+ flow control mechanism (i.e.,
+ sender does support this
+ optional procedure)
+ Ref.: ITU-T Q.931
+
+ rateadapthdr 9011 Boolean Rate adaption header/no
+ header
+ 0 Rate adaption header
+ not included
+ 1 Rate adaption header
+ included
+ Ref.: ITU-T Q.931
+
+ multiframe 9012 Boolean Multiple frame establishment
+ support in data link
+ 0 Multiple frame
+ establishment not supported.
+ Only UI frames allowed
+ 1 Multiple frame
+ establishment supported
+ Ref.: ITU-T Q.931
+
+ OPMODE 9013 Boolean Mode of operation
+ 0 Bit transparent mode of
+ operation
+ 1 Protocol sensitive mode
+ of operation
+ Ref.: ITU-T Q.931
+
+
+
+Groves, et al. Standards Track [Page 143]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ llidnegot 9014 Boolean Logical link identifier
+ negotiation
+ 0 Default, LLI = 256 only
+ 1 Full protocol
+ negotiation
+ Ref.: ITU-T Q.931
+
+ assign 9015 Boolean Assignor/assignee
+ 0 Message originator is
+ "default assignee"
+ 1 Message originator is
+ "assignor only"
+ Ref.: ITU-T Q.931
+
+ inbandneg 9016 Boolean In-band/out-band negotiation
+ 0 Negotiation is done
+ with USER INFORMATION
+ messages on a temporary
+ signalling connection
+ 1 Negotiation is done in-
+ band using logical link zero
+ Ref.: ITU-T Q.931
+
+ stopbits 9017 2 bits Number of stop bits
+ Bits
+ 2 1
+ ---
+ 0 0 Not used
+ 0 1 1 bit
+ 1 0 1.5 bits
+ 1 1 2 bits
+ Ref.: ITU-T Q.931
+
+ databits 9018 2 bits Number of data bits excluding
+ parity bit if present
+ Bits
+ 2 1
+ ---
+ 0 0 Not used
+ 0 1 5 bits
+ 1 0 7 bits
+ 1 1 8 bits
+ Ref.: ITU-T Q.931
+
+ parity 9019 3 bits Parity information
+ Bits
+ 3 2 1
+
+
+
+Groves, et al. Standards Track [Page 144]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ------
+ 0 0 0 Odd
+ 0 1 0 Even
+ 0 1 1 None
+ 1 0 0 Forced to 0
+ 1 0 1 Forced to 1
+ All other values are
+ reserved.
+ Ref.: ITU-T Q.931
+
+ duplexmode 901A Boolean Mode duplex
+ 0 Half duplex
+ 1 Full duplex
+ Ref.: ITU-T Q.931
+
+ modem 901B 6 bits Modem Type
+ Bits
+ 6 5 4 3 2 1
+ -----------
+ 0 0 0 0 0 0 through
+ 0 0 0 1 0 1 National use
+ 0 1 0 0 0 1 Rec. V.21
+ 0 1 0 0 1 0 Rec. V.22
+ 0 1 0 0 1 1 Rec. V.22 bis
+ 0 1 0 1 0 0 Rec. V.23
+ 0 1 0 1 0 1 Rec. V.26
+ 0 1 1 0 0 1 Rec. V.26 bis
+ 0 1 0 1 1 1 Rec. V.26 ter
+ 0 1 1 0 0 0 Rec. V.27
+ 0 1 1 0 0 1 Rec. V.27 bis
+ 0 1 1 0 1 0 Rec. V.27 ter
+ 0 1 1 0 1 1 Rec. V.29
+ 0 1 1 1 0 1 Rec. V.32
+ 0 1 1 1 1 0 Rec. V.34
+ 1 0 0 0 0 0 through
+ 1 0 1 1 1 1 National use
+ 1 1 0 0 0 0 through
+ 1 1 1 1 1 1 User specified
+ Ref.: ITU-T Q.931
+
+ layer2prot 901C 5 bits User information layer 2
+ protocol
+ Bits
+ 5 4 3 2 1
+ ---------
+ 0 0 0 1 0 Rec. Q.921/I.441
+ 0 0 1 1 0 Rec. X.25, link
+ layer
+
+
+
+Groves, et al. Standards Track [Page 145]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 0 1 1 0 0 LAN logical link
+ control (ISO/IEC 8802 2)
+ All other values are
+ reserved.
+ Ref.: ITU-T Q.931
+
+ layer3prot 901D 5 bits User information layer 3
+ protocol
+ Bits
+ 5 4 3 2 1
+ ---------
+ 0 0 0 1 0 ITU-T Q.931
+ 0 0 1 1 0 ITU-T X.25,
+ packet layer
+ 0 1 0 1 1 ISO/IEC TR 9577
+ (Protocol identification in
+ the network layer)
+ All other values are
+ reserved.
+ Ref.: ITU-T Q.931
+
+ addlayer3prot 901E Octet Additional User Information
+ layer 3 protocol
+ Bits Bits
+ 4 3 2 1 4 3 2 1
+ ------- -------
+ 1 1 0 0 1 1 0 0
+ Internet Protocol (RFC 791)
+ (ISO/IEC TR 9577)
+ 1 1 0 0 1 1 1 1
+ Point-to-point Protocol (RFC
+ 1661)
+ Ref.: ITU-T Q.931
+
+ DialledN 901F 30 Dialled Number
+ octets
+
+ DiallingN 9020 30 Dialling Number
+ octets
+
+ ECHOCI 9021 Not Used. See H.248.1 E.13
+ for an example of possible
+ Echo Control properties.
+
+ NCI 9022 1 octet Nature of Connection
+ Indicators
+ Bits
+ 2 1 Satellite Indicator
+
+
+
+Groves, et al. Standards Track [Page 146]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ---
+ 0 0 no satellite circuit
+ in the connection
+ 0 1 one satellite circuit
+ in the connection
+ 1 0 two satellite
+ circuits in the connection
+ 1 1 spare
+
+ Bits
+ 4 3 Continuity check
+ --- indicator
+ 0 0 continuity check not
+ required
+ 0 1 continuity check
+ required on this circuit
+ 1 0 continuity check
+ performed on a previous
+ circuit
+ 1 1 spare
+
+ Bit
+ 5 Echo control device
+ - indicator
+ 0 outgoing echo control
+ device not included
+ 1 outgoing echo control
+ device included
+
+ Bits
+ 8 7 6 Spare
+ Ref.: ITU-T Q.763
+
+ USI 9023 Octet User Service Information
+ string Ref.: ITU-T Q.763 Clause 3.57
+
+C.10 AAL5 properties
+
+ PropertyID Property Type Value
+ tag
+
+ FMSDU A001 32-bit Forward Maximum CPCS-SDU Size:
+ integer Maximum CPCS-SDU size sent in the
+ direction from the calling user to
+ the called user.
+ Ref.: ITU-T Q.2931
+
+
+
+
+
+Groves, et al. Standards Track [Page 147]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ BMSDU A002 32-bit Backwards Maximum CPCS-SDU Size:
+ integer Maximum CPCS-SDU size sent in the
+ direction from the called user to
+ the calling user.
+ Ref.: ITU-T Q.2931
+
+ SSCS See table See table See table in C.7
+ in C.7 in C.7 Additional values:
+ VPI/VCI
+
+C.11 SDP equivalents
+
+ PropertyID Property Type Value
+ tag
+
+ SDP_V B001 String Protocol Version
+ Ref.: RFC 2327
+
+ SDP_O B002 String Owner/creator and session ID
+ Ref.: RFC 2327
+
+ SDP_S B003 String Session name
+ Ref.: RFC 2327
+
+ SDP_I B004 String Session identifier
+ Ref.: RFC 2327
+
+ SDP_U B005 String URI of descriptor
+ Ref.: RFC 2327
+
+ SDC_E B006 String email address
+ Ref.: RFC 2327
+
+ SDP_P B007 String phone number
+ Ref.: RFC 2327
+
+ SDP_C B008 String Connection information
+ Ref.: RFC 2327
+
+ SDP_B B009 String Bandwidth Information
+ Ref.: RFC 2327
+
+ SDP_Z B00A String Time zone adjustment
+ Ref.: RFC 2327
+
+ SDP_K B00B String Encryption Key
+ Ref.: RFC 2327
+
+
+
+
+Groves, et al. Standards Track [Page 148]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ SDP_A B00C String Zero or more session attributes
+ Ref.: RFC 2327
+
+ SDP_T B00D String Active Session Time
+ Ref.: RFC 2327
+
+ SDP_R B00E String Zero or more repeat times
+ Reference: RFC 2327
+
+ SDP_M B00F String Media type, port, transport and format
+ Ref.: RFC 2327
+
+C.12 H.245
+
+ PropertyID Property Type Value
+ tag
+
+ OLC C001 Octet The value of H.245
+ OpenLogicalChannel structure.
+ string Ref.: ITU-T H.245
+
+ OLCack C002 Octet The value of H.245
+ string OpenLogicalChannelAck structure.
+ Ref.: ITU-T H.245
+
+ OLCcnf C003 Octet The value of H.245
+ string OpenLogicalChannelConfirm structure.
+ Ref.: ITU-T H.245
+
+ OLCrej C004 Octet The value of H.245
+ string OpenLogicalChannelReject structure.
+ Ref.: ITU-T H.245
+
+ CLC C005 Octet The value of H.245
+ string CloseLogicalChannel structure.
+ Ref.: ITU-T H.245
+
+ CLCack C006 Octet The value of H.245
+ string CloseLogicalChannelAck structure.
+ Ref.: ITU-T H.245
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 149]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ANNEX D - Transport over IP
+
+D.1 Transport over IP/UDP using Application Level Framing (ALF)
+
+ Protocol messages defined in this RFC may be transmitted over UDP.
+ When no port is provided by the peer (see 7.2.8), commands should be
+ sent to the default port number: 2944 for text-encoded operation, or
+ 2945 for binary-encoded operation. Responses must be sent to the
+ address and port from which the corresponding commands were sent.
+
+ ALF is a set of techniques that allows an application, as opposed to
+ a stack, to affect how messages are sent to the other side. A
+ typical ALF technique is to allow an application to change the order
+ of messages sent when there is a queue after it has queued them.
+ There is no formal specification for ALF. The procedures in Annex
+ D.1 contain a minimum suggested set of ALF behaviours
+
+ Implementors using IP/UDP with ALF should be aware of the
+ restrictions of the MTU on the maximum message size.
+
+D.1.1 Providing At-Most-Once functionality
+
+ Messages, being carried over UDP, may be subject to losses. In the
+ absence of a timely response, commands are repeated. Most commands
+ are not idempotent. The state of the MG would become unpredictable
+ if, for example, Add commands were executed several times. The
+ transmission procedures shall thus provide an "At-Most-Once"
+ functionality.
+
+ Peer protocol entities are expected to keep in memory a list of the
+ responses that they sent to recent transactions and a list of the
+ transactions that are currently outstanding. The transaction
+ identifier of each incoming message is compared to the transaction
+ identifiers of the recent responses sent to the same MId. If a match
+ is found, the entity does not execute the transaction, but simply
+ repeats the response. If no match is found, the message will be
+ compared to the list of currently outstanding transactions. If a
+ match is found in that list, indicating a duplicate transaction, the
+ entity does not execute the transaction (see D.1.4 for procedures on
+ sending TransactionPending).
+
+ The procedure uses a long timer value, noted LONG-TIMER in the
+ following. The timer should be set larger than the maximum duration
+ of a transaction, which should take into account the maximum number
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 150]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ of repetitions, the maximum value of the repetition timer and the
+ maximum propagation delay of a packet in the network. A suggested
+ value is 30 seconds.
+
+ The copy of the responses may be destroyed either LONG-TIMER seconds
+ after the response is issued, or when the entity receives a
+ confirmation that the response has been received, through the
+ "Response Acknowledgement parameter". For transactions that are
+ acknowledged through this parameter, the entity shall keep a copy of
+ the transaction-id for LONG-TIMER seconds after the response is
+ issued, in order to detect and ignore duplicate copies of the
+ transaction request that could be produced by the network.
+
+D.1.2 Transaction identifiers and three-way handshake
+
+D.1.2.1 Transaction identifiers
+
+ Transaction identifiers are 32-bit integer numbers. A Media Gateway
+ Controller may decide to use a specific number space for each of the
+ MGs that they manage, or to use the same number space for all MGs
+ that belong to some arbitrary group. MGCs may decide to share the
+ load of managing a large MG between several independent processes.
+ These processes will share the same transaction number space. There
+ are multiple possible implementations of this sharing, such as having
+ a centralized allocation of transaction identifiers, or
+ pre-allocating non-overlapping ranges of identifiers to different
+ processes. The implementations shall guarantee that unique
+ transaction identifiers are allocated to all transactions that
+ originate from a logical MGC (identical mId). MGs can simply detect
+ duplicate transactions by looking at the transaction identifier and
+ mId only.
+
+D.1.2.2 Three-way handshake
+
+ The TransactionResponse Acknowledgement parameter can be found in any
+ message. It carries a set of "confirmed transaction-id ranges".
+ Entities may choose to delete the copies of the responses to
+ transactions whose id is included in "confirmed transaction-id
+ ranges" received in the transaction response messages. They should
+ silently discard further commands when the transaction-id falls
+ within these ranges.
+
+ The "confirmed transaction-id ranges" values shall not be used if
+ more than LONG-TIMER seconds have elapsed since the MG issued its
+ last response to that MGC, or when a MG resumes operation. In this
+ situation, transactions should be accepted and processed, without any
+ test on the transaction-id.
+
+
+
+
+Groves, et al. Standards Track [Page 151]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Messages that carry the "Transaction Response Acknowledgement"
+ parameter may be transmitted in any order. The entity shall retain
+ the "confirmed transaction-id ranges" received for LONG-TIMER
+ seconds.
+
+ In the binary encoding, if only the firstAck is present in a response
+ acknowledgement (see A.2), only one transaction is acknowledged. If
+ both firstAck and lastAck are present, then the range of transactions
+ from firstAck to lastAck is acknowledged. In the text encoding, a
+ horizontal dash is used to indicate a range of transactions being
+ acknowledged (see B.2).
+
+D.1.3 Computing retransmission timers
+
+ It is the responsibility of the requesting entity to provide suitable
+ timeouts for all outstanding transactions, and to retry transactions
+ when timeouts have been exceeded. Furthermore, when repeated
+ transactions fail to be acknowledged, it is the responsibility of the
+ requesting entity to seek redundant services and/or clear existing or
+ pending connections.
+
+ The specification purposely avoids specifying any value for the
+ retransmission timers. These values are typically network dependent.
+ The retransmission timers should normally estimate the timer value by
+ measuring the time spent between the sending of a command and the
+ return of a response. Implementations SHALL ensure that the
+ algorithm used to calculate retransmission timing performs an
+ exponentially increasing backoff of the retransmission timeout for
+ each retransmission or repetition after the first one.
+
+ NOTE - One possibility is to use the algorithm implemented in
+ TCP-IP, which uses two variables:
+
+ - The average acknowledgement delay (AAD), estimated through an
+ exponentially smoothed average of the observed delays.
+
+ - The average deviation (ADEV), estimated through an exponentially
+ smoothed average of the absolute value of the difference between
+ the observed delay and the current average. The retransmission
+ timer, in TCP, is set to the sum of the average delay plus N times
+ the average deviation. The maximum value of the timer should
+ however be bounded for the protocol defined in this
+ RFC, in order to guarantee that no repeated packet
+ would be received by the gateways after LONG-TIMER seconds. A
+ suggested maximum value is 4 seconds.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 152]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ After any retransmission, the entity SHOULD do the following:
+
+ - It should double the estimated value of the average delay, AAD.
+
+ - It should compute a random value, uniformly distributed between
+ 0.5 AAD and AAD.
+
+ - It should set the retransmission timer to the sum of that random
+ value and N times the average deviation.
+
+ This procedure has two effects. Because it includes an exponentially
+ increasing component, it will automatically slow down the stream of
+ messages in case of congestion. Because it includes a random
+ component, it will break the potential synchronization between
+ notifications triggered by the same external event.
+
+D.1.4 Provisional responses
+
+ Executing some transactions may require a long time. Long execution
+ times may interact with the timer-based retransmission procedure.
+ This may result either in an inordinate number of retransmissions, or
+ in timer values that become too long to be efficient. Entities that
+ can predict that a transaction will require a long execution time may
+ send a provisional response, "Transaction Pending". They SHOULD send
+ this response if they receive a repetition of a transaction that is
+ still being executed.
+
+ Entities that receive a Transaction Pending shall switch to a
+ different repetition timer for repeating requests. The root
+ Termination has a property (ProvisionalResponseTimerValue), which can
+ be set to the requested maximum number of milliseconds between
+ receipt of a command and transmission of the TransactionPending
+ response. Upon receipt of a final response following receipt of
+ provisional responses, an immediate confirmation shall be sent, and
+ normal repetition timers shall be used thereafter. An entity that
+ sends a provisional response, SHALL include the immAckRequired field
+ in the ensuing final response, indicating that an immediate
+ confirmation is expected. Receipt of a Transaction Pending after
+ receipt of a reply shall be ignored.
+
+D.1.5 Repeating Requests, Responses and Acknowledgements
+
+ The protocol is organized as a set of transactions, each of which is
+ composed of a request and a response, commonly referred to as an
+ acknowledgement. The protocol messages, being carried over UDP, may
+ be subject to losses. In the absence of a timely response,
+ transactions are repeated. Entities are expected to keep in memory a
+
+
+
+
+Groves, et al. Standards Track [Page 153]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ list of the responses that they sent to recent transactions, i.e., a
+ list of all the responses they sent over the last LONG-TIMER seconds,
+ and a list of the transactions that are currently being executed.
+
+ The repetition mechanism is used to guard against three types of
+ possible errors:
+
+ - transmission errors, when for example a packet is lost due to
+ noise on a line or congestion in a queue;
+
+ - component failure, when for example an interface to a entity
+ becomes unavailable;
+
+ - entity failure, when for example an entire entity becomes
+ unavailable.
+
+ The entities should be able to derive from the past history an
+ estimate of the packet loss rate due to transmission errors. In a
+ properly configured system, this loss rate should be kept very low,
+ typically less than 1%. If a Media Gateway Controller or a Media
+ Gateway has to repeat a message more than a few times, it is very
+ legitimate to assume that something else than a transmission error is
+ occurring. For example, given a loss rate of 1%, the probability
+ that five consecutive transmission attempts fail is 1 in 100 billion,
+ an event that should occur less than once every 10 days for a Media
+ Gateway Controller that processes 1000 transactions per second.
+ (Indeed, the number of repetition that is considered excessive should
+ be a function of the prevailing packet loss rate.) We should note
+ that the "suspicion threshold", which we will call "Max1", is
+ normally lower than the "disconnection threshold", which should be
+ set to a larger value.
+
+ A classic retransmission algorithm would simply count the number of
+ successive repetitions, and conclude that the association is broken
+ after retransmitting the packet an excessive number of times
+ (typically between 7 and 11 times.) In order to account for the
+ possibility of an undetected or in progress "failover", we modify
+ the classic algorithm so that if the Media Gateway receives a valid
+ ServiceChange message announcing a failover, it will start
+ transmitting outstanding commands to that new MGC. Responses to
+ commands are still transmitted to the source address of the command.
+
+ In order to automatically adapt to network load, this RFC specifies
+ exponentially increasing timers. If the initial timer is set to 200
+ milliseconds, the loss of a fifth retransmission will be detected
+ after about 6 seconds. This is probably an acceptable waiting delay
+ to detect a failover. The repetitions should continue after that
+ delay not only in order to perhaps overcome a transient connectivity
+
+
+
+Groves, et al. Standards Track [Page 154]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ problem, but also in order to allow some more time for the execution
+ of a failover (waiting a total delay of 30 seconds is probably
+ acceptable).
+
+ It is, however, important that the maximum delay of retransmissions
+ be bounded. Prior to any retransmission, it is checked that the time
+ elapsed since the sending of the initial datagram is no greater than
+ T-MAX. If more than T-MAX time has elapsed, the MG concludes that
+ the MGC has failed, and it begins its recovery process as described
+ in section 11.5. If the MG retries to connect to the current MGC it
+ shall use a ServiceChange with ServiceChangeMethod set to
+ Disconnected so that the new MGC will be aware that the MG lost one
+ or more transactions. The value T-MAX is related to the LONG-TIMER
+ value: the LONG-TIMER value is obtained by adding to T MAX the
+ maximum propagation delay in the network.
+
+D.2 Using TCP
+
+ Protocol messages as defined in this RFC may be transmitted over TCP.
+ When no port is specified by the other side (see 7.2.8), the commands
+ should be sent to the default port. The defined protocol has
+ messages as the unit of transfer, while TCP is a stream-oriented
+ protocol. TPKT, according to RFC 1006, SHALL be used to delineate
+ messages within the TCP stream.
+
+ In a transaction-oriented protocol, there are still ways for
+ transaction requests or responses to be lost. As such, it is
+ recommended that entities using TCP transport implement application
+ level timers for each request and each response, similar to those
+ specified for application level framing over UDP.
+
+D.2.1 Providing the At-Most-Once functionality
+
+ Messages, being carried over TCP, are not subject to transport
+ losses, but loss of a transaction request or its reply may
+ nonetheless be noted in real implementations. In the absence of a
+ timely response, commands are repeated. Most commands are not
+ idempotent. The state of the MG would become unpredictable if, for
+ example, Add commands were executed several times.
+
+ To guard against such losses, it is recommended that entities follow
+ the procedures in D.1.1.
+
+D.2.2 Transaction identifiers and three-way handshake
+
+ For the same reasons, it is possible that transaction replies may be
+ lost even with a reliable delivery protocol such as TCP. It is
+ recommended that entities follow the procedures in D.1.2.2.
+
+
+
+Groves, et al. Standards Track [Page 155]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+D.2.3 Computing retransmission timers
+
+ With reliable delivery, the incidence of loss of a transaction
+ request or reply is expected to be very low. Therefore, only simple
+ timer mechanisms are required. Exponential back-off algorithms
+ should not be necessary, although they could be employed where, as in
+ an MGC, the code to do so is already required, since MGCs must
+ implement ALF/UDP as well as TCP.
+
+D.2.4 Provisional responses
+
+ As with UDP, executing some transactions may require a long time.
+ Entities that can predict that a transaction will require a long
+ execution time may send a provisional response, "Transaction
+ Pending". They should send this response if they receive a
+ repetition of a transaction that is still being executed.
+
+ Entities that receive a Transaction Pending shall switch to a longer
+ repetition timer for that transaction.
+
+ Entities shall retain Transactions and replies until they are
+ confirmed. The basic procedure of D.1.4 should be followed, but
+ simple timer values should be sufficient. There is no need to send
+ an immediate confirmation upon receipt of a final response.
+
+D.2.5 Ordering of commands
+
+ TCP provides ordered delivery of transactions. No special procedures
+ are required. It should be noted that ALF/UDP allows sending entity
+ to modify its behaviour under congestion, and in particular, could
+ reorder transactions when congestion is encountered. TCP could not
+ achieve the same results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 156]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ANNEX E - Basic packages
+
+ This annex contains definitions of some packages for use with
+ Recommendation H.248.1.
+
+E.1 Generic
+
+ PackageID: g (0x0001)
+ Version: 1
+ Extends: None
+
+ Description:
+ Generic package for commonly encountered items.
+
+E.1.1 Properties
+
+ None.
+
+E.1.2 Events
+
+ Cause
+
+ EventID: cause (0x0001)
+ Generic error event
+
+ EventsDescriptor parameters: None
+
+ ObservedEvents Descriptor Parameters:
+
+ General Cause
+ ParameterID: Generalcause (0x0001)
+
+ This parameter groups the failures into six groups, which
+ the MGC may act upon.
+
+ Type: enumeration
+
+ Possible values:
+ "NR" Normal Release (0x0001)
+ "UR" Unavailable Resources (0x0002)
+ "FT" Failure, Temporary (0x0003)
+ "FP" Failure, Permanent (0x0004)
+ "IW" Interworking Error (0x0005)
+ "UN" Unsupported (0x0006)
+
+ Failure Cause
+ ParameterID: Failurecause (0x0002)
+
+
+
+
+Groves, et al. Standards Track [Page 157]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Possible values: OCTET STRING
+
+ Description: The Failure Cause is the value generated by the
+ Released equipment, i.e., a released network connection.
+ The concerned value is defined in the appropriate bearer
+ control protocol.
+
+ Signal Completion
+
+ EventID: sc (0x0002)
+
+ Indicates the termination of a signal for which the
+ notifyCompletion parameter was set to enable reporting of a
+ completion event. For further procedural description, see 7.1.1,
+ 7.1.17 and 7.2.7.
+
+ EventsDescriptor parameters: None
+
+ ObservedEvents Descriptor parameters:
+
+ Signal Identity
+ ParameterID: SigID (0x0001)
+
+ This parameter identifies the signal which has terminated.
+ For a signal that is contained in a signal list, the signal
+ list identity parameter should also be returned indicating
+ the appropriate list.
+
+ Type: Binary: octet (string), Text: string
+
+ Possible values: a signal which has terminated. A signal
+ shall be identified using the pkgdName syntax without
+ wildcarding.
+
+ Termination Method
+ ParameterID: Meth (0x0002)
+
+ Indicates the means by which the signal terminated.
+
+ Type: enumeration
+
+ Possible values:
+ "TO" (0x0001) Signal timed out or otherwise completed on
+ its own
+ "EV" (0x0002) Interrupted by event
+ "SD" (0x0003) Halted by new Signals descriptor
+ "NC" (0x0004) Not completed, other cause
+
+
+
+
+Groves, et al. Standards Track [Page 158]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Signal List ID
+ ParameterID: SLID (0x0003)
+
+ Indicates to which signal list a signal belongs. The
+ SignalList ID is only returned in cases where the signal
+ resides in a signal list.
+
+ Type: integer
+
+ Possible values: any integer
+
+E.1.3 Signals
+
+ None.
+
+E.1.4 Statistics
+
+ None.
+
+E.2 Base Root Package
+
+ PackageID: root (0x0002)
+ Version: 1
+ Extends: None
+
+ Description:
+ This package defines Gateway wide properties.
+
+E.2.1 Properties
+
+ MaxNrOfContexts
+ PropertyID: maxNumberOfContexts (0x0001)
+
+ The value of this property gives the maximum number of contexts
+ that can exist at any time. The NULL context is not included in
+ this number.
+
+ Type: double
+
+ Possible values: 1 and up
+
+ Defined in: TerminationState
+
+ Characteristics: read only
+
+ MaxTerminationsPerContext
+ PropertyID: maxTerminationsPerContext (0x0002)
+
+
+
+
+Groves, et al. Standards Track [Page 159]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The maximum number of allowed terminations in a context, see 6.1
+
+ Type: integer
+
+ Possible values: any integer
+
+ Defined in: TerminationState
+
+ Characteristics: read only
+
+ normalMGExecutionTime
+ PropertyId: normalMGExecutionTime (0x0003)
+
+ Settable by the MGC to indicate the interval within which the MGC
+ expects a response to any transaction from the MG (exclusive of
+ network delay)
+
+ Type: integer
+
+ Possible values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+ normalMGCExecutionTime
+ PropertyId: normalMGCExecutionTime (0x0004)
+
+ Settable by the MGC to indicate the interval within which the MG
+ should expects a response to any transaction from the MGC
+ (exclusive of network delay)
+
+ Type: integer
+
+ Possible values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+ MGProvisionalResponseTimerValue
+ PropertyId: MGProvisionalResponseTimerValue (0x0005)
+
+ Indicates the time within which the MGC should expect a Pending
+ Response from the MG if a Transaction cannot be completed.
+
+ Initially set to normalMGExecutionTime plus network delay, but may
+ be lowered.
+
+
+
+Groves, et al. Standards Track [Page 160]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Type: Integer
+
+ Possible Values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+ MGCProvisionalResponseTimerValue
+ PropertyId: MGCProvisionalResponseTimerValue (0x0006)
+
+ Indicates the time within which the MG should expect a Pending
+ Response from the MGC if a Transaction cannot be completed.
+ Initially set to normalMGCExecutionTime plus network delay, but
+ may be lowered.
+
+ Type: Integer
+
+ Possible Values: any integer, represents milliseconds
+
+ Defined in: TerminationState
+
+ Characteristics: read / write
+
+E.2.2 Events
+
+ None.
+
+E.2.3 Signals
+
+ None.
+
+E.2.4 Statistics
+
+ None.
+
+E.2.5 Procedures
+
+ None.
+
+E.3 Tone Generator Package
+
+ PackageID: tonegen (0x0003)
+ Version: 1
+ Extends: None
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 161]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Description:
+
+ This package defines signals to generate audio tones. This
+ package does not specify parameter values. It is intended to be
+ extendable. Generally, tones are defined as an individual signal
+ with a parameter, ind, representing "interdigit" time delay, and a
+ tone id to be used with playtones. A tone id should be kept
+ consistent with any tone generation for the same tone. MGs are
+ expected to be provisioned with the characteristics of appropriate
+ tones for the country in which the MG is located.
+
+ Designed to be extended only.
+
+E.3.1 Properties
+
+ None.
+
+E.3.2 Events
+
+ None.
+
+E.3.3 Signals
+
+ Play tone
+ SignalID: pt (0x0001)
+
+ Plays audio tone over an audio channel
+
+ Signal Type: Brief
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ Tone id list
+ ParameterID: tl (0x0001)
+
+ Type: list of tone ids
+
+ List of tones to be played in sequence. The list SHALL
+ contain one or more tone ids.
+
+ Inter signal duration
+ ParameterID: ind (0x0002)
+
+ Type: integer
+
+ Timeout between two consecutive tones in milliseconds
+
+
+
+Groves, et al. Standards Track [Page 162]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ No tone ids are specified in this package. Packages that extend this
+ package can add possible values for tone id as well as adding
+ individual tone signals.
+
+E.3.4 Statistics
+
+ None.
+
+E.3.5 Procedures
+
+ None.
+
+E.4 Tone Detection Package
+
+ PackageID: tonedet (0x0004)
+ Version: 1
+ Extends: None
+
+ This Package defines events for audio tone detection. Tones are
+ selected by name (tone id). MGs are expected to be provisioned with
+ the characteristics of appropriate tones for the country in which the
+ MG is located.
+
+ Designed to be extended only:
+ This package does not specify parameter values. It is intended to
+ be extendable.
+
+E.4.1 Properties
+
+ None.
+
+E.4.2 Events
+
+ Start tone detected
+ EventID: std, 0x0001
+
+ Detects the start of a tone. The characteristics of positive tone
+ detection are implementation dependent.
+
+ EventsDescriptor parameters:
+
+ Tone id list
+ ParameterID: tl (0x0001)
+
+ Type: list of tone ids
+
+
+
+
+
+Groves, et al. Standards Track [Page 163]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Possible values: The only tone id defined in this package is
+ "wild card" which is "*" in text encoding and 0x0000 in
+ binary. Extensions to this package would add possible
+ values for tone id. If tl is "wild card", any tone id is
+ detected.
+
+ ObservedEventsDescriptor parameters:
+
+ Tone id
+ ParameterID: tid (0x0003)
+
+ Type: enumeration
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this package
+ would add additional possible values for tone id.
+
+ End tone detected
+ EventID: etd, 0x0002
+
+ Detects the end of a tone.
+
+ EventDescriptor parameters:
+
+ Tone id list
+ ParameterID: tl (0x0001)
+
+ Type: enumeration or list of enumerated types
+
+ Possible values: No possible values are specified in this
+ package. Extensions to this package would add possible
+ values for tone id.
+
+ ObservedEventsDescriptor parameters:
+
+ Tone id
+ ParameterID: tid (0x0003)
+
+ Type: enumeration
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this
+ package would add possible values for tone id.
+
+ Duration
+ ParameterId: dur (0x0002)
+
+ Type: integer, in milliseconds
+
+
+
+Groves, et al. Standards Track [Page 164]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+
+ This parameter contains the duration of the tone from
+ first detection until it stopped.
+
+ Long tone detected
+ EventID: ltd, 0x0003
+
+ Detects that a tone has been playing for at least a certain amount
+ of time.
+
+ EventDescriptor parameters:
+
+ Tone id list
+ ParameterID: tl (0x0001)
+
+ Type: enumeration or list
+
+ Possible values: "wildcard" as defined above is the only
+ value defined in this package. Extensions to this package
+ would add possible values for tone id.
+
+ Duration
+ ParameterID: dur (0x0002)
+
+ Type: integer, duration to test against
+
+ Possible values: any legal integer, expressed in
+ milliseconds
+
+ ObservedEventsDescriptor parameters:
+
+ Tone id
+ ParameterID: tid (0x0003)
+
+ Type: Enumeration
+
+ Possible values: No possible values are specified in this
+ package. Extensions to this package would add possible
+ values for tone id.
+
+E.4.3 Signals
+
+ None.
+
+E.4.4 Statistics
+
+ None.
+
+
+
+
+Groves, et al. Standards Track [Page 165]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+E.4.5 Procedures
+
+ None.
+
+E.5 Basic DTMF Generator Package
+
+ PackageID: dg (0x0005)
+ Version: 1
+ Extends: tonegen version 1
+
+ This package defines the basic DTMF tones as signals and extends the
+ allowed values of parameter tl of playtone in tonegen.
+
+E.5.1 Properties
+
+ None.
+
+E.5.2 Events
+
+ None.
+
+E.5.3 Signals
+
+ DTMF character 0
+ SignalID: d0 (0x0010)
+
+ Generate DTMF 0 tone. The physical characteristic of DTMF 0 is
+ defined in the gateway.
+
+ Signal Type: Brief
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ None.
+
+ Additional values:
+
+ d0 (0x0010) is defined as a tone id for playtone
+
+ The other DTMF characters are specified in exactly the same way. A
+ table with all signal names and signal IDs is included. Note that
+ each DTMF character is defined as both a signal and a tone id, thus
+ extending the basic tone generation package. Also note that DTMF
+ SignalIds are different from the names used in a digit map.
+
+
+
+
+
+Groves, et al. Standards Track [Page 166]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Signal name Signal ID/Tone id
+
+ DTMF character 0 d0 (0x0010)
+ DTMF character 1 d1 (0x0011)
+ DTMF character 2 d2 (0x0012)
+ DTMF character 3 d3 (0x0013)
+ DTMF character 4 d4 (0x0014)
+ DTMF character 5 d5 (0x0015)
+ DTMF character 6 d6 (0x0016)
+ DTMF character 7 d7 (0x0017)
+ DTMF character 8 d8 (0x0018)
+ DTMF character 9 d9 (0x0019)
+ DTMF character * ds (0x0020)
+ DTMF character # do (0x0021)
+ DTMF character A da (0x001a)
+ DTMF character B db (0x001b)
+ DTMF character C dc (0x001c)
+ DTMF character D dd (0x001d)
+
+E.5.4 Statistics
+
+ None.
+
+E.5.5 Procedures
+
+ None.
+
+E.6 DTMF detection Package
+
+ PackageID: dd (0x0006)
+ Version: 1
+ Extends: tonedet version 1
+
+ This package defines the basic DTMF tones detection. This Package
+ extends the possible values of tone id in the "start tone detected"
+ "end tone detected" and "long tone detected" events.
+
+ Additional tone id values are all tone ids described in package dg
+ (basic DTMF generator package).
+
+ The following table maps DTMF events to digit map symbols as
+ described in 7.1.14.
+
+ DTMF Event Symbol
+
+ d0 "0"
+ d1 "1"
+ d2 "2"
+
+
+
+Groves, et al. Standards Track [Page 167]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ d3 "3"
+ d4 "4"
+ d5 "5"
+ d6 "6"
+ d7 "7"
+ d8 "8"
+ d9 "9"
+ da "A" or "a"
+ db "B" or "b"
+ dc "C" or "c"
+ dd "D" or "d"
+ ds "E" or "e"
+ do "F" or "f"
+
+E.6.1 Properties
+
+ None.
+
+E.6.2 Events
+
+ DTMF digits
+
+ EventIds are defined with the same names as the SignalIds defined
+ in the table found in E.5.3.
+
+ DigitMap Completion Event
+ EventID: ce, 0x0004
+
+ Generated when a digit map completes as described in 7.1.14.
+
+ EventsDescriptor parameters: None.
+
+ ObservedEventsDescriptor parameters:
+
+ DigitString
+ ParameterID: ds (0x0001)
+
+ Type: string of digit map symbols (possibly empty) returned
+ as a quotedString
+
+ Possible values: a sequence of the characters "0" through
+ "9", "A" through "F", and the long duration modifier "Z".
+
+ Description: the portion of the current dial string as
+ described in 7.1.14 which matched part or all of an
+ alternative event sequence specified in the digit map.
+
+
+
+
+
+Groves, et al. Standards Track [Page 168]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Termination Method
+ ParameterID: Meth (0x0003)
+
+ Type: enumeration
+
+ Possible values:
+
+ "UM" (0x0001) Unambiguous match
+
+ "PM" (0x0002) Partial match, completion by timer expiry
+ or unmatched event
+
+ "FM" (0x0003) Full match, completion by timer expiry or
+ unmatched event
+
+ Description: indicates the reason for generation of the
+ event. See the procedures in 7.1.14.
+
+E.6.3 Signals
+
+ None.
+
+E.6.4 Statistics
+
+ None.
+
+E.6.5 Procedures
+
+ Digit map processing is activated only if an events descriptor is
+ activated that contains a digit map completion event as defined in
+ Section E.6.2 and that digit map completion event contains an eventDM
+ field in the requested actions as defined in Section 7.1.9. Other
+ parameters such as KeepActive or embedded events of signals
+ descriptors may also be present in the events descriptor and do not
+ affect the activation of digit map processing.
+
+E.7 Call Progress Tones Generator Package
+
+ PackageID: cg, 0x0007
+ Version: 1
+ Extends: tonegen version 1
+
+ This package defines the basic call progress tones as signals and
+ extends the allowed values of the tl parameter of playtone in
+ tonegen.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 169]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+E.7.1 Properties
+
+ None.
+
+E.7.2 Events
+
+ None.
+
+E.7.3 Signals
+
+ Dial Tone
+ SignalID: dt (0x0030)
+
+ Generate dial tone. The physical characteristic of dial tone is
+ available in the gateway.
+
+ Signal Type: TimeOut
+
+ Duration: Provisioned
+
+ Additional parameters:
+
+ None.
+
+ Additional values:
+
+ dt (0x0030) is defined as a tone id for playtone
+
+ The other tones of this package are defined in exactly the same way.
+ A table with all signal names and signal IDs is included. Note that
+ each tone is defined as both a signal and a tone id, thus extending
+ the basic tone generation package.
+
+ Signal Name Signal ID/tone id
+
+ Dial Tone dt (0x0030)
+ Ringing Tone rt (0x0031)
+ Busy Tone bt (0x0032)
+ Congestion Tone ct (0x0033)
+ Special Information Tone sit(0x0034)
+ Warning Tone wt (0x0035)
+ Payphone Recognition Tone prt (0x0036)
+ Call Waiting Tone cw (0x0037)
+ Caller Waiting Tone cr (0x0038)
+
+E.7.4 Statistics
+
+ None.
+
+
+
+Groves, et al. Standards Track [Page 170]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+E.7.5 Procedures
+
+ NOTE - The required set of tone ids corresponds to those defined
+ in Recommendation E.180/Q.35. See Recommendation E.180/Q.35 for
+ definition of the meanings of these tones.
+
+
+E.8 Call Progress Tones Detection Package
+
+ PackageID: cd (0x0008)
+ Version: 1
+ Extends: tonedet version 1
+
+ This package defines the basic call progress detection tones. This
+ package extends the possible values of tone id in the "start tone
+ detected", "end tone detected" and "long tone detected" events.
+
+ Additional values
+
+ toneID values are defined for start tone detected, end tone
+ detected and long tone detected with the same values as those in
+ package cg (call progress tones generation package).
+
+ The required set of tone ids corresponds to Recommendation
+ E.180/Q.35. See Recommendation E.180/Q.35 for definition of the
+ meanings of these tones.
+
+E.8.1 Properties
+
+ None.
+
+E.8.2 Events
+
+ Events are defined as in the call progress tones generator package
+ (cg) for the tones listed in the table of E.7.3.
+
+E.8.3 Signals
+
+ None.
+
+E.8.4 Statistics
+
+ None.
+
+E.8.5 Procedures
+
+ None.
+
+
+
+
+Groves, et al. Standards Track [Page 171]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+E.9 Analog Line Supervision Package
+
+ PackageID: al, 0x0009
+ Version: 1
+ Extends: None
+
+ This package defines events and signals for an analog line.
+
+ E.9.1 Properties
+
+ None.
+
+E.9.2 Events
+
+ onhook
+ EventID: on (0x0004)
+
+ Detects handset going on hook. Whenever an events descriptor is
+ activated that requests monitoring for an on-hook event and the
+ line is already on-hook, then the MG shall behave according to the
+ setting of the "strict" parameter.
+
+ EventDescriptor parameters:
+
+ Strict Transition
+ ParameterID: strict (0x0001)
+
+ Type: enumeration
+
+ Possible values: "exact" (0x00), "state" (0x01), "failWrong"
+ (0x02)
+
+ "exact" means that only an actual hook state transition to
+ on-hook is to be recognized;
+
+ "state" means that the event is to be recognized either if
+ the hook state transition is detected or if the hook state
+ is already on-hook;
+
+ "failWrong" means that if the hook state is already
+ on-hook, the command fails and an error is reported.
+
+ ObservedEventsDescriptor parameters:
+
+ Initial State
+ ParameterID: init (0x0002)
+
+ Type: Boolean
+
+
+
+Groves, et al. Standards Track [Page 172]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Possible values:
+
+ "True" means that the event was reported because the line
+ was already on-hook when the events descriptor containing
+ this event was activated;
+
+ "False" means that the event represents an actual state
+ transition to on-hook.
+
+ offhook
+ EventID: of (0x0005)
+
+ Detects handset going off hook. Whenever an events descriptor is
+ activated that requests monitoring for an off-hook event and the
+ line is already off-hook, then the MG shall behave according to
+ the setting of the "strict" parameter.
+
+ EventDescriptor parameters:
+
+ Strict Transition
+ ParameterID: strict (0x0001)
+
+ Type: enumeration
+
+ Possible values: "exact" (0x00), "state" (0x01), "failWrong"
+ (0x02)
+
+ "exact" means that only an actual hook state transition
+ to off-hook is to be recognized;
+
+ "state" means that the event is to be recognized either
+ if the hook state transition is detected or if the hook
+ state is already off-hook;
+
+ "failWrong" means that if the hook state is already off-
+ hook, the command fails and an error is reported.
+
+ ObservedEventsDescriptor parameters
+
+ Initial State
+ ParameterID: init (0x0002)
+
+ Type: Boolean
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 173]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Possible values:
+
+ "True" means that the event was reported because the line
+ was already off-hook when the events descriptor
+ containing this event was activated;
+
+ "False" means that the event represents an actual state
+ transition to off-hook.
+
+ flashhook
+ EventID: fl, 0x0006
+
+ Detects handset flash. A flash occurs when an onhook is followed
+ by an offhook between a minimum and maximum duration.
+
+ EventDescriptor parameters:
+
+ Minimum duration
+ ParameterID: mindur (0x0004)
+
+ Type: integer in milliseconds
+
+ Default value is provisioned.
+
+ Maximum duration
+ ParameterID: maxdur (0x0005)
+
+ Type: integer in milliseconds
+
+ Default value is provisioned.
+
+ ObservedEventsDescriptor parameters:
+
+ None
+
+E.9.3 Signals
+
+ ring
+ SignalID: ri, 0x0002
+
+ Applies ringing on the line
+
+ Signal Type: TimeOut
+
+ Duration: Provisioned
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 174]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Additional parameters:
+
+ Cadence
+ ParameterID: cad (0x0006)
+
+ Type: list of integers representing durations of alternating
+ on and off segments, constituting a complete ringing cycle
+ starting with an on. Units in milliseconds
+
+ Default is fixed or provisioned. Restricted function MGs
+ may ignore cadence values they are incapable of generating.
+
+ Frequency
+ ParameterID: freq (0x0007)
+
+ Type: integer in Hz
+
+ Default is fixed or provisioned. Restricted function MGs
+ may ignore frequency values they are incapable of
+ generating.
+
+E.9.4 Statistics
+
+ None.
+
+E.9.5 Procedures
+
+ If the MGC sets an EventsDescriptor containing a hook state
+ transition event (on-hook or off-hook) with the "strict" (0x0001)
+ parameter set to "failWrong", and the hook state is already what the
+ transition implies, the execution of the command containing that
+ EventsDescriptor fails. The MG SHALL include error code 540
+ "Unexpected initial hook state" in its reponse.
+
+E.9.6 Error code
+
+ This package defines a new error code:
+
+ 540 - Unexpected initial hook state
+
+ The procedure for use of this code is given in E.9.5.
+
+E.10 Basic Continuity Package
+
+ PackageID: ct (0x000a)
+ Version: 1
+ Extends: None
+
+
+
+
+Groves, et al. Standards Track [Page 175]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ This package defines events and signals for continuity test. The
+ continuity test includes provision of either a loopback or
+ transceiver functionality.
+
+E.10.1 Properties
+
+ None.
+
+E.10.2 Events
+
+ Completion
+ EventID: cmp, 0x0005
+
+ This event detects test completion of continuity test.
+
+ EventDescriptor parameters
+
+ None.
+
+ ObservedEventsDescriptor parameters
+
+ Result
+ ParameterID: res (0x0008)
+
+ Type: enumeration
+
+ Possible values: success (0x0001), failure (0x0000)
+
+E.10.3 Signals
+
+ Continuity test
+ SignalID: ct (0x0003)
+
+ Initiates sending of continuity test tone on the termination to
+ which it is applied.
+
+ Signal Type: TimeOut
+
+ Default value is provisioned
+
+ Additional parameters:
+
+ None.
+
+ Respond
+ SignalID: rsp (0x0004)
+
+
+
+
+
+Groves, et al. Standards Track [Page 176]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The signal is used to respond to a continuity test. See E.10.5
+ for further explanation.
+
+ Signal Type: On/Off
+
+ Default duration is provisioned
+
+ Additional parameters:
+
+ None.
+
+E.10.4 Statistics
+
+ None.
+
+E.10.5 Procedures
+
+ When a MGC wants to initiate a continuity test, it sends a command to
+ the MG containing:
+
+ - a signals descriptor with the ct signal; and
+
+ - an events descriptor containing the cmp event.
+
+ Upon reception of a command containing the ct signal and cmp event,
+ the MG initiates the continuity test tone for the specified
+ Termination. If the return tone is detected and any other required
+ conditions are satisfied before the signal times out, the cmp event
+ shall be generated with the value of the result parameter equal to
+ success. In all other cases, the cmp event shall be generated with
+ the value of the result parameter equal to failure.
+
+ When a MGC wants the MG to respond to a continuity test, it sends a
+ command to the MG containing a signals descriptor with the rsp
+ signal. Upon reception of a command with the rsp signal, the MG
+ either applies a loopback or (for 2-wire circuits) awaits reception
+ of a continuity test tone. In the loopback case, any incoming
+ information shall be reflected back as outgoing information. In the
+ 2-wire case, any time the appropriate test tone is received, the
+ appropriate response tone should be sent. The MGC determines when to
+ remove the rsp signal.
+
+ When a continuity test is performed on a Termination, no echo devices
+ or codecs shall be active on that Termination.
+
+ Performing voice path assurance as part of continuity testing is
+ provisioned by bilateral agreement between network operators.
+
+
+
+
+Groves, et al. Standards Track [Page 177]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ (Informative Note) Example tones and test procedure details are
+ given in Q.724 sections 7 and 8, Q.764 section 2.1.8 and Q.1902.4.
+
+E.11 Network Package
+
+ PackageID: nt (0x000b)
+ Version: 1
+ Extends: None
+
+ This package defines properties of network terminations independent
+ of network type.
+
+E.11.1 Properties
+
+ Maximum Jitter Buffer
+ PropertyID: jit (0x0007)
+
+ This property puts a maximum size on the jitter buffer.
+
+ Type: integer in milliseconds
+
+ Possible values: This property is specified in milliseconds.
+
+ Defined in: LocalControlDescriptor
+
+ Characteristics: read/write
+
+E.11.2 Events
+
+ network failure
+ EventID: netfail, 0x0005
+
+ The termination generates this event upon detection of a failure
+ due to external or internal network reasons.
+
+ EventDescriptor parameters
+
+ None.
+
+ ObservedEventsDescriptor parameters
+
+ cause
+ ParameterID: cs (0x0001)
+
+ Type: string
+
+ Possible values: any text string
+
+
+
+
+Groves, et al. Standards Track [Page 178]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ This parameter may be included with the failure event to
+ provide diagnostic information on the reason of failure.
+
+ quality alert
+ EventID: qualert, 0x0006
+
+ This property allows the MG to indicate a loss of quality of the
+ network connection. The MG may do this by measuring packet loss,
+ interarrival jitter, propagation delay and then indicating this
+ using a percentage of quality loss.
+
+ EventDescriptor parameters
+
+ Threshold
+ ParameterId: th (0x0001)
+
+ Type: integer
+
+ Possible values: 0 to 99
+
+ Description: threshold for percent of quality loss measured,
+ calculated based on a provisioned method, that could take
+ into consideration packet loss, jitter, and delay for
+ example. Event is triggered when calculation exceeds the
+ threshold.
+
+ ObservedEventsDescriptor parameters
+
+ Threshold
+ ParameterId: th (0x0001)
+
+ Type: integer
+
+ Possible values: 0 to 99
+
+ Description: percent of quality loss measured, calculated
+ based on a provisioned method, that could take into
+ consideration packet loss, jitter, and delay for example.
+
+E.11.3 Signals
+
+ None.
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 179]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+E.11.4 Statistics
+
+ Duration
+ StatisticsID: dur (0x0001)
+
+ Description: provides duration of time the termination has been in
+ the Context.
+
+ Type: double, in milliseconds
+
+ Octets Sent
+ StatisticID: os (0x0002)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Octets Received
+ StatisticID: or (0x0003)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+E.11.5 Procedures
+
+ None.
+
+E.12 RTP Package
+
+ PackageID: rtp (0x000c)
+ Version: 1
+ Extends: Network Package version 1
+
+ This package is used to support packet-based multimedia data transfer
+ by means of the Real-time Transport Protocol (RTP) [RFC 1889].
+
+E.12.1 Properties
+
+ None.
+
+E.12.2 Events
+
+ Payload Transition
+ EventID: pltrans, 0x0001
+
+ This event detects and notifies when there is a transition of the
+ RTP payload format from one format to another.
+
+
+
+Groves, et al. Standards Track [Page 180]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ EventDescriptor parameters
+
+ None.
+
+ ObservedEventsDescriptor parameters
+
+ ParameterName: rtppayload
+ ParameterID: rtppltype, 0x01
+
+ Type: list of enumerated types.
+
+ Possible values: The encoding method shall be specified by
+ using one or several valid encoding names, as defined in the
+ RTP AV Profile or registered with IANA.
+
+E.12.3 Signals
+
+ None.
+
+E.12.4 Statistics
+
+ Packets Sent
+ StatisticID: ps (0x0004)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Packets Received
+ StatisticID: pr (0x0005)
+
+ Type: double
+
+ Possible values: any 64-bit integer
+
+ Packet Loss
+ StatisticID: pl (0x0006)
+
+ Describes the current rate of packet loss on an RTP stream, as
+ defined in IETF RFC 1889. Packet loss is expressed as percentage
+ value: number of packets lost in the interval between two
+ reception reports, divided by the number of packets expected
+ during that interval.
+
+ Type: double
+
+ Possible values: a 32-bit whole number and a 32-bit fraction.
+
+
+
+
+Groves, et al. Standards Track [Page 181]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Jitter
+ StatisticID: jit (0x0007)
+
+ Requests the current value of the interarrival jitter on an RTP
+ stream as defined in IETF RFC 1889. Jitter measures the variation
+ in interarrival time for RTP data packets.
+
+ Delay
+ StatisticID:delay (0x0008)
+
+ Requests the current value of packet propagation delay expressed
+ in timestamp units. Same as average latency.
+
+E.12.5 Procedures
+
+ None.
+
+E.13 TDM Circuit Package
+
+ PackageID: tdmc (0x000d)
+ Version: 1
+ Extends: Network Package version 1
+
+ This package may be used by any termination that supports gain and
+ echo control. It was originally intended for use on TDM circuits
+ but may be more widely used.
+
+
+ New versions or extensions of this package should take non-TDM use
+ into account.
+
+E.13.1 Properties
+
+ Echo Cancellation
+ PropertyID: ec (0x0008)
+
+ Type: boolean
+
+ Possible values:
+
+ "on" (when the echo cancellation is requested) and
+
+ "off" (when it is turned off.)
+
+ The default is provisioned.
+
+ Defined in: LocalControlDescriptor
+
+
+
+
+Groves, et al. Standards Track [Page 182]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Characteristics: read/write
+
+ Gain Control
+ PropertyID: gain (0x000a)
+
+ Gain control, or usage of of signal level adaptation and
+ noise level reduction is used to adapt the level of the signal.
+ However, it is necessary, for example for modem calls, to turn
+ off this function.
+
+ Type: integer
+
+ Possible values:
+
+ The gain control parameter may either be specified as
+ "automatic" (0xffffffff), or as an explicit number of decibels
+ of gain (any other integer value). The default is provisioned
+ in the MG.
+
+ Defined in: LocalControlDescriptor
+
+ Characteristics: read/write
+
+E.13.2 Events
+
+ None.
+
+E.13.3 Signals
+
+ None.
+
+E.13.4 Statistics
+
+ None.
+
+E.13.5 Procedures
+
+ None.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 183]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+APPENDIX I EXAMPLE CALL FLOWS (INFORMATIVE)
+
+ All H.248.1 implementors must read the normative part of this RFC
+ carefully before implementing from it. The examples in this appendix
+ should not be used as stand-alone explanations of how to create
+ protocol messages.
+
+ The examples in this appendix use SDP for encoding of the Local and
+ and Remote stream descriptors. SDP is defined in RFC 2327. If there
+ is is any discrepancy between the SDP in the examples, and RFC 2327,
+ the the RFC should be consulted for correctness. Audio profiles used
+ are are those defined in IETF RFC 1890, and others registered with
+ IANA. For example, G.711 A-law is called PCMA in SDP, and is
+ assigned profile 0. G.723.1 is called G723 and is profile 4; H.263 is
+ called H263 and is profile 34. See also
+ http://www.iana.org/assignments/rtp-parameters.
+
+A.1 Residential Gateway to Residential Gateway Call
+
+ This example scenario illustrates the use of the elements of the
+ protocol to set up a Residential Gateway to Residential Gateway call
+ over an IP-based network. For simplicity, this example assumes that
+ both Residential Gateways involved in the call are controlled by the
+ same Media Gateway Controller.
+
+A.1.1 Programming Residential GW Analog Line Terminations for Idle
+ Behavior
+
+ The following illustrates the API invocations from the Media Gateway
+ Controller and Media Gateways to get the Terminations in this
+ scenario programmed for idle behavior. Both the originating and
+ terminating Media Gateways have idle AnalogLine Terminations
+ programmed to look for call initiation events (i.e., -offhook) by
+ using the Modify Command with the appropriate parameters. The null
+ Context is used to indicate that the Terminations are not yet
+ involved in a Context. The ROOT termination is used to indicate the
+ entire MG instead of a termination within the MG.
+
+ In this example, MG1 has the IP address 124.124.124.222, MG2 is
+ 125.125.125.111, and the MGC is 123.123.123.4. The default Megaco
+ port is 55555 for all three.
+
+ 1. An MG registers with an MGC using the ServiceChange command:
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222] Transaction = 9998 {
+ Context = - {
+
+
+
+Groves, et al. Standards Track [Page 184]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ ServiceChange = ROOT {Services {
+ Method=Restart,
+ ServiceChangeAddress=55555, Profile=ResGW/1}
+ }
+ } }
+
+ 2. The MGC sends a reply:
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {ServiceChange = ROOT {
+ Services {ServiceChangeAddress=55555, Profile=ResGW/1} } } }
+
+ 3. The MGC programs a Termination in the NULL context. The
+ terminationId is A4444, the streamId is 1, the requestId in the
+ Events descriptor is 2222. The mId is the identifier of the sender
+ of this message, in this case, it is the IP address and port
+ [123.123.123.4]:55555. Mode for this stream is set to SendReceive.
+ "al" is the analog line supervision package. Local and Remote are
+ assumed to be provisioned.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media { Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ },
+
+ }
+ },
+ Events = 2222 {al/of(strict=state)}
+ }
+ } }
+
+
+ The dialplan script could have been loaded into the MG previously.
+ Its function would be to wait for the OffHook, turn on dialtone and
+ start collecting DTMF digits. However in this example, we use the
+ digit map, which is put into place after the offhook is detected
+ (step 5 below).
+
+
+
+
+
+Groves, et al. Standards Track [Page 185]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Note that the embedded EventsDescriptor could have been used to
+ combine steps 3 and 4 with steps 8 and 9, eliminating steps 6 and 7.
+
+ 4. The MG1 accepts the Modify with this reply:
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555
+
+ Reply = 9999 {
+ Context = - {Modify = A4444} }
+
+ 5. A similar exchange happens between MG2 and the MGC, resulting in
+ an idle Termination called A5555.
+
+A.1.2 Collecting Originator Digits and Initiating Termination
+
+ The following builds upon the previously shown conditions. It
+ illustrates the transactions from the Media Gateway Controller and
+ originating Media Gateway (MG1) to get the originating Termination
+ (A4444) through the stages of digit collection required to initiate a
+ connection to the terminating Media Gateway (MG2).
+
+ 6. MG1 detects an offhook event from User 1 and reports it to the
+ Media Gateway Controller via the Notify Command.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {ObservedEvents =2222 {
+ 19990729T22000000:al/of(init=false)}}
+ } }
+
+ 7. And the Notify is acknowledged.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Reply = 10000 {
+
+ Context = - {Notify = A4444} }
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 186]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 8. The MGC Modifies the termination to play dial tone, to look for
+ digits according to Dialplan0 and to look for the on-hook event now.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on(strict=state), dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap= Dialplan0{ (0| 00|[1-
+ 7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)}
+ }
+ } }
+
+ 9. And the Modify is acknowledged.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {Modify = A4444} }
+
+ 10. Next, digits are accumulated by MG1 as they are dialed by User
+ 1. Dialtone is stopped upon detection of the first digit. When an
+ appropriate match is made of collected digits against the currently
+ programmed Dialplan for A4444, another Notify is sent to the Media
+ Gateway Controller.
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {ObservedEvents =2223 {
+ 19990729T22010001:dd/ce{ds="916135551212",Meth=UM}}}
+ } }
+
+ 11. And the Notify is acknowledged.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {Notify = A4444} }
+
+
+ 12. The controller then analyses the digits and determines that a
+ connection needs to be made from MG1 to MG2. Both the TDM
+
+
+
+Groves, et al. Standards Track [Page 187]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ termination A4444, and an RTP termination are added to a new context
+ in MG1. Mode is ReceiveOnly since Remote descriptor values are not
+ yet specified. Preferred codecs are in the MGC's preferred order of
+ choice.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+
+ nt/jit=40 ; in ms
+ },
+ Local { v=0 c=IN IP4 $ m=audio $ RTP/AVP 4
+ a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ } }
+
+
+ NOTE - The MGC states its preferred parameter values as a series
+ of SDP blocks in Local. The MG fills in the Local Descriptor in
+ the Reply.
+
+ 13. MG1 acknowledges the new Termination and fills in the Local IP
+ address and UDP port. It also makes a choice for the codec based on
+ the MGC preferences in Local. MG1 sets the RTP port to 2222.
+
+ MG1 -> MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add=A4445{
+ Media {
+ Stream = 1 {
+ Local { v=0 o=- 2890844526 2890842807 IN IP4
+ 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222
+ RTP/AVP 4 a=ptime:30 a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+
+
+
+Groves, et al. Standards Track [Page 188]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ }
+ }
+ } }
+
+ 14. The MGC will now associate A5555 with a new Context on MG2, and
+ establish an RTP Stream (i.e., A5556 will be assigned), SendReceive
+ connection through to the originating user, User 1. The MGC also
+ sets ring on A5555.
+
+ MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 { Media {
+ Stream = 1 {
+ LocalControl {Mode = SendReceive} }},
+ Events=1234{al/of(strict=state)},
+ Signals {al/ri}
+
+ },
+ Add = $ {Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local { v=0 c=IN IP4 $ m=audio $ RTP/AVP 4
+ a=ptime:30
+ },
+ Remote { v=0 c=IN IP4 124.124.124.222 m=audio 2222
+ RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ } }
+
+ 15. This is acknowledged. The stream port number is different from
+ the control port number. In this case it is 1111 (in the SDP).
+
+ MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556{
+ Media {
+ Stream = 1 {
+
+
+
+Groves, et al. Standards Track [Page 189]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ Local { v=0 o=- 7736844526 7736842807 IN IP4
+ 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111
+ RTP/AVP 4 }
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+
+ } }
+
+ 16. The above IPAddr and UDPport need to be given to MG1 now.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote { v=0 o=- 7736844526 7736842807 IN IP4
+ 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111
+ RTP/AVP 4
+ }
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ } }
+
+
+ MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {Modify = A4444, Modify = A4445} }
+
+ 17. The two gateways are now connected and User 1 hears the
+ RingBack. The MG2 now waits until User2 picks up the receiver and
+ then the two-way call is established.
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 190]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+
+ Notify = A5555 {ObservedEvents =1234 {
+ 19990729T22020002:al/of(init=false)}}
+ } }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {Notify = A5555} }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {al/on(strict=state)},
+ Signals { } ; to turn off ringing
+ }
+ } }
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {Modify = A4445} }
+
+ 18. Change mode on MG1 to SendReceive, and stop the ringback.
+
+ MGC to MG1:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode=SendReceive
+
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals { }
+ }
+
+
+
+Groves, et al. Standards Track [Page 191]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ } }
+
+ from MG1 to MGC:
+
+ MEGACO/1 [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {Modify = A4445, Modify = A4444}}
+
+ 19. The MGC decides to Audit the RTP termination on MG2.
+
+ MGC -> MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {AuditValue = A5556{
+ Audit{Media, DigitMap, Events, Signals, Packages, Statistics }}
+ } }
+
+ 20. The MG2 replies.
+
+ MG2 -> MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Reply = 50007 {
+ Context = - { AuditValue = A5556 {
+ Media {
+ TerminationState { ServiceStates = InService,
+ Buffer = OFF },
+ Stream = 1 {
+ LocalControl { Mode = SendReceive,
+ nt/jit=40 },
+ Local { v=0 o=- 7736844526 7736842807 IN IP4
+ 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111
+ RTP/AVP 4 a=ptime:30
+ },
+ Remote { v=0 o=- 2890844526 2890842807 IN IP4
+ 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222
+ RTP/AVP 4 a=ptime:30
+ } } },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics { rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 } ; avg latency
+ }
+
+
+
+Groves, et al. Standards Track [Page 192]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ } }
+
+ 21. When the MGC receives an onhook signal from one of the MGs, it
+ brings down the call. In this example, the user at MG2 hangs up
+ first.
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {ObservedEvents =1235 {
+ 19990729T24020002:al/on(init=false)}
+ }
+ } }
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Reply = 50008 {
+
+ Context = - {Notify = A5555} }
+
+ 22. The MGC now sends both MGs a Subtract to take down the call.
+ Only the subtracts to MG2 are shown here. Each termination has its
+ own set of statistics that it gathers. An MGC may not need to
+ request both to be returned. A5555 is a physical termination, and
+ A5556 is an RTP termination.
+
+ From MGC to MG2:
+
+ MEGACO/1 [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {Audit{Statistics}},
+ Subtract = A5556 {Audit{Statistics}}
+ } }
+
+ From MG2 to MGC:
+
+ MEGACO/1 [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+
+
+
+Groves, et al. Standards Track [Page 193]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ } }
+
+ 23. The MGC now sets up both MG1 and MG2 to be ready to detect the
+ next off-hook event. See step 1. Note that this could be the
+ default state of a termination in the null context, and if this were
+ the case, no message need be sent from the MGC to the MG. Once a
+ termination returns to the null context, it goes back to the default
+ termination values for that termination.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 194]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+APPENDIX II Changes From RFC 3015
+
+ In the following table, "source" indicates when the change was first
+ approved. It has the following values:
+
+ IG1100: H.248 Implementor's Guide approved in November, 2000 (as TD
+ Plen-39, Christian Groves, editor).
+
+ IG0601: H.248 Implementor's Guide approved in June, 2001 (as TD
+ Plen-15, Christian Groves, editor).
+
+ IGDUB: Draft H.248 Implementor's Guide approved at the Q.3
+ Rapporteur's meeting held near Dublin, October 2001 (as TD-28, Terry
+ Anderson, editor).
+
+ GEN0202: added at the Geneva meeting, February 2002, which consented
+ to H.248 v1 Amendment 1 (as TD Plen-36r1, Marcello Pantaleo, editor).
+
+ ITUPOST: added in post-Geneva editing by the ITU-T.
+
+ TTPOST: added in post-approval editing by the Megaco Chair, Tom
+ Taylor, who assembled this document for submission.
+
+ Section Source Change
+
+ 1 ITUPOST Reference changed from H.248 to H.248.1.
+
+ 2.1 ITUPOST Reference added for error codes, changed from
+ H.248 Annex L to H.248.8 (2002).
+
+ 2.1 IG1100 Corrected Q.765 reference to Q.765.5.
+
+ 2.1 GEN0202 Added reference to X.690.
+
+ 2.2 GEN0202 Added reference to H.226.
+
+ 2.2 IGDUB Added informative references to Q.724, Q.764,
+ and Q.1902.4.
+
+ 4 IG0601 Added expansion of ALF.
+
+ 5 TTPOST Gave priority to IETF conventions (added at
+ start of document).
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 195]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 6.1.1 IG0601 Added text regarding use of wildcards for
+ context identifiers. (This information
+ already appeared in section 8.1.2. The IG
+ change subsequently disappeared.)
+
+ 6.1.1 IG1100 Added ranking of priority values.
+
+ 6.2 IGDUB Deleted definition of signals.
+
+ 6.2 GEN0202 Expanded text and diagrams describing
+ multiplexing terminations.
+
+ 6.2 TTPOST Added asterisks to multiplexing diagrams to
+ indicate centre of context. Added Figure 6a
+ showing cascading of multiplexes.
+
+ 6.2.2 IG0601 Added text indicating that ALL does not
+ include ROOT.
+
+ 6.2.3 IG1100 Added text clarifying what must be supported
+ to claim support of a package.
+
+ 6.2.3 IG1100 Added text indicating what packages a peer can
+ indicate support for, when some of them are
+ extensions of others.
+
+ 6.2.4 IG0601 Added text on ability of provisioning to
+ override default values, and need for MGC to
+ audit to learn the provisioned defaults.
+
+ 6.2.4 IG0601 Added text indicating effect of omitting
+ specific properties from Descriptors in
+ commands modifying a termination.
+ Contradicted original text saying that omitted
+ properties retain their prior values (still
+ true for entirely-omitted Descriptors).
+
+ 6.2.4 GEN0202 Modified above text to restrict it to
+ read/write properties, allow for default
+ behaviour in place of default values if so
+ specified in the property definition.
+
+ 6.2.4 IGDUB Trimmed definition of signals Descriptor in
+ table and inserted cross-reference to section
+ 7.1.11.
+
+ 6.2.4 IG1100 Added Topology and Error Descriptors to table.
+
+
+
+
+Groves, et al. Standards Track [Page 196]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 6.2.5 IGDUB Specified error code to return if ROOT used
+ inappropriately.
+
+ 7.1.1 IG1100 Added qualification to explanation of effect
+ of missing Audit Descriptor, excepting
+ Subtract.
+
+ 7.1.3 GEN0202 Changed "inputs" to "bearers" to be consistent
+ with terminology in 6.2.
+
+ 7.1.4 IG0601 Small change to make clear that more than one
+ of Local, Remote, and LocalControl can be
+ included in the default streamId.
+
+ 7.1.7 IG0601 Default value for Mode specified to be
+ Inactive.
+
+ 7.1.7 GEN0202 Added text requiring processing of media in
+ any of the reserved formats, where more than
+ one has been reserved in a given stream.
+
+ 7.1.8 IGDUB Added restriction to at most one m= line per
+ session description.
+
+ 7.1.9 IG0601 Text added to omit request identifier if the
+ EventsDescriptor is empty. Further text added
+ at end to indicate the effects of an empty
+ EventsDescriptor and an empty
+ EventBufferDescriptor.
+
+ 7.1.9 IG0601 Fixed typo for destination of a Notify.
+
+ 7.1.9 IG1100 Added note to say event remains active after
+ it has been notified, so long as it is still
+ present in the active Events Descriptor.
+
+ 7.1.11 IGDUB Added definition of signals.
+
+ 7.1.11 GEN0202 Modified definition to include example of more
+ complex signal, and added role of signal in
+ media preparation for future signals.
+
+ 7.1.11 IGDUB The timeout completion reason was broadened to
+ include other circumstances where the signal
+ completed on its own. Text added to indicate
+ that if default signal type changed to TO,
+ duration parameter must be provided.
+
+
+
+
+Groves, et al. Standards Track [Page 197]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7.1.11 GEN0202 Removed reference to BR signal being "so
+ short" it will stop on its own. Added text
+ indicating that if the type of a signal is
+ changed to TO, the Duration parameter must be
+ supplied.
+
+ 7.1.11 IG1100 Deleted text discussing type of Signals List.
+
+ 7.1.12 GEN0202 Improved wording of introductory paragraph and
+ added text making content of returned
+ Descriptor clear.
+
+ 7.1.14.2 GEN0202 Added text indicating that when the start
+ timer is set to 0, initial digit timing is
+ disabled and the MG waits indefinitely for
+ digits.
+
+ 7.1.14.2 GEN0202 Added text pointing out that default digit
+ timer values should be provisioned, but can be
+ overridden in the digit map.
+
+ 7.1.14.3 GEN0202 Changed result of long-short digit timer
+ conflict from undefined to long.
+
+ 7.1.14.6 IG1100 Clarified that the digit map is provided by
+ the eventDM parameter, which must be present.
+
+ 7.1.14.7 GEN0202 Added text clarifying that events covered by
+ the digit map completion event have no side-
+ effects unless separately enabled.
+
+ 7.1.14.8 IG0601 Added requirement that the event specification
+ include the eventDM parameter.
+
+ 7.1.17 IGDUB Added text to indicate timestamp is optional
+ and to include observed event parameters in
+ reported content.
+
+ 7.1.17 GEN0202 Deleted provision that time is expressed in
+ UTC (since intention was to use format, not
+ time zone).
+
+ 7.1.18 IGDUB Added text indicating error to return if
+ topology option not supported.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 198]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7.1.18 IG1100 Added text clarifying effect of not mentioning
+ TTPOST a termination in a topology Descriptor, and
+ default topology for a new termination. (This
+ text got lost between the Dublin meeting and
+ the production of H.248 Amendment 1 out of the
+ Geneva 02/02 meeting. It has been added back
+ to the present document.)
+
+ 7.1.19 IG1100 New section to describe Error Descriptor.
+ GEN0202 Slightly edited in Geneva 02/02 meeting.
+ ITUPOST Reference for error code documentation updated
+ to H.248.8.
+
+ 7.1.19 IG0601 Added paragraph giving guidance on level at
+ which errors should be reported.
+
+ 7.2 IG1100 Noted possibility of Error Descriptor in reply
+ to any command.
+
+ 7.2.1 IG1100 Added EventBufferDescriptor as Add parameter.
+
+ 7.2.1 IG1100 Removed restriction on use of CHOOSE wildcard.
+
+ 7.2.2 IG1100 Added EventBufferDescriptor as Modify
+ parameter.
+
+ 7.2.2 GEN0202 Added text on side-effects of Modify of a
+ multiplexing termination.
+
+ 7.2.3 IG1100 Added prohibition against subtracting from the
+ NULL context.
+
+ 7.2.3 GEN0202 Added text on side-effects of Subtract of a
+ multiplexing termination.
+
+ 7.2.3 IGDUB Added text clarifying effect of empty
+ AuditDescriptor in Subtract.
+
+ 7.2.4 IG1100 Added EventBufferDescriptor as Move parameter.
+
+ 7.2.4 GEN0202 Removed misleading statement that Move acts as
+ subtract from original context.
+
+ 7.2.4 IG1100 Clarified effect of Move on properties of the
+ moved termination.
+
+ 7.2.4 GEN0202 Added text on side-effects of Move of a
+ multiplexing termination.
+
+
+
+Groves, et al. Standards Track [Page 199]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 7.2.5 IG1100 Added examples showing W- wildcard usage.
+
+ 7.2.5 IG1100 Noted that returning a list of all contextIDs
+ requires that they be returned one per
+ ActionReply.
+
+ 7.2.5 IG1100 Added table entry (ALL, specific) to determine
+ context in which termination currently
+ resides.
+
+ 7.2.6 GEN0202 Added table similar to that in 7.2.5.
+
+ 7.2.7 IG0601 Added TerminationID to API.
+
+ 7.2.7 IGDUB Indicated timestamp was optional in Notify, to
+ accord with syntax.
+
+ 7.2.7 IG1100 Noted possibility of sending Error Descriptor
+ in Notify.
+
+ 7.2.8 IG0601 Added text to description of Forced method to
+ indicate that Forced on ROOT indicates a cold
+ restart (all context state lost).
+
+ 7.2.8 IGDUB Amplified explanation of Disconnected method
+ to emphasize return to the previously
+ controlling MGC.
+
+ 7.2.8 IG0601 Added text for MG use of Failover method when
+ it detects MGC failure.
+
+ 7.2.8 IG1100 Added notes discouraging use of
+ ServiceChangeAddress and warning that it could
+ be either a full address or just a port
+ number.
+
+ 7.2.8 IG0601 Added text indicating that timestamp does not
+ necessarily represent absolute time, only
+ local clock reading.
+
+ 7.2.8 IGDUB Corrected "gateway" to "MGC" in discussion of
+ returned ServiceChangeMgcId parameter.
+
+ 7.3 IG0601 Removed error code documentation to Annex L
+ ITUPOST (now H.248.8).
+
+ 8 IG1100 Added requirement that an Action be non-empty.
+
+
+
+
+Groves, et al. Standards Track [Page 200]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 8 GEN0202 Added context properties and context property
+ audit requests to commands as potential
+ contents of actions.
+
+ 8.1.2 GEN0202 Added prohibition on using partial contextIDs
+ with ALL wildcards.
+
+ 8.2.2 IG1100 Added text clarifying when in transaction
+ processing the requested actions have been
+ completed and a reply can be sent.
+
+ 8.2.2 IG1100 Added ALL as allowed contextID in
+ TransactionReply.
+
+ 8.2.2 GEN0202 Provided general reference to section 7.1.19
+ for generation of error Descriptors.
+
+ 8.2.2 IG0601 Corrected Actions to Commands when discussing
+ partially-understood action.
+
+ 8.3 IG0601 Added text specifying that the same MId value
+ must be used by a given entity throughout the
+ life of a control association.
+
+ 8.3 IG0601 Added text expanding on independence of
+ transactions from messages.
+
+ 9 ITUPOST Indicated that additional transports may be
+ defined in separate Recommendations as well as
+ annexes to the primary specification.
+
+ 9 IG0601 Gave specific example of "request source
+ address" for IP.
+
+ 9.1 IG1100 Deleted restriction to one outstanding Notify
+ command on a termination at one time, since
+ this is transport-specific.
+
+ 9.1 IG0601 Restored restriction, but noted that it
+ applied only to transport not guaranteeing
+ ordered delivery.
+
+ 10.2 IG1100 Corrected length of synthesized address field
+ from 10 to 20 hex digits and indicated that
+ calculation should be over entire message, not
+ just one transaction.
+
+
+
+
+
+Groves, et al. Standards Track [Page 201]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 11.2 IG1100 Corrected text in first two paragraphs
+ describing use of ServiceChangeMgcId
+ parameter.
+
+ 11.2 IG1100 Corrected "Transaction Accept" to "Transaction
+ Reply".
+
+ 11.4 IG0601 Noted that support of redundant MGs requires
+ GEN0202 use of a reliable transport and support in the
+ MGC. Added more explanation in Geneva.
+
+ 11.5 IG0601 Added text clarifying procedure if MG unable
+ to establish a control relationship with any
+ of its eligible MGCs.
+
+ 11.5 IGDUB Added text indicating that when trying to
+ reestablish contact with the previously
+ controlling MGC the MG uses the Disconnected
+ method.
+
+ 11.5 IG1100 Clarified handoff procedure.
+
+ 11.5 GEN0202 Changed text on replies to transactions in
+ progress during handoff. Replies now
+ discarded when the service relationship with
+ the old MGC has ended, rather than sent to the
+ new MGC. The new MGC could still send replies
+ to requests sent to the old MGC.
+
+ 12.1.1 GEN0202 Added optional package designation as
+ "designed to be extended only".
+
+ 12.1.1 IG1100 Made prohibition on overloading of identifiers
+ in extended packages transitive through all
+ ancestors of the extended package.
+
+ 12.1.2 IGDUB Clarified the set of types allowed for
+ properties.
+
+ 12.1.2 GEN0202 Added requirement to specify the base type of
+ a sub-list.
+
+ 12.1.2 GEN0202 Provided requirements for content of the
+ "Possible Values" template item, including
+ specification of default values or behaviour.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 202]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ 12.1.4 GEN0202 Added requirement to specify the default
+ signal type, and specify a default duration
+ for TO signals. Also noted that duration is
+ meaningless for BR, and that the signal type
+ might be dependent on the values of other
+ signal parameters.
+
+ 12.2 GEN0202 Fixed section title (covers only event and
+ signal parameters, not properties or
+ statistics).
+
+ 12.2 IG1100 Reserved SPA and EPA prefixes, so they are not
+ to be used for signal and event parameter
+ tokens.
+
+ 12.2 IG0601 Expanded list of reserved prefixes.
+
+ 12.2 IGDUB Clarified the set of types allowed for signal
+ and event parameters.
+
+ 12.2 GEN0202 Added requirement to specify the base type of
+ a sub-list.
+
+ 12.2 GEN0202 Provided requirements for content of the
+ "Possible Values" template item, including
+ specification of default values or behaviour.
+
+ 12.4 IGDUB Corrected to indicate identifiers must start
+ with alphabetic rather than alphanumeric
+ character.
+
+ 13.1 IG0601 Changed private range of binary package
+ identifiers to convenient hex values.
+
+ A GEN0202 Removed versions from X.680 and X.690
+ references.
+
+ A.2 IGDUB Added note warning that the syntax alone does
+ not provide a complete description of the
+ constraints, but must be supplemented by a
+ reading of the text and comments.
+
+ A.2 IG0601 Added description of double wrapping of
+ parameters declared as OCTET STRING.
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 203]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ A.2 GEN0202 Some editing of double wrapping description to
+ use ASN.1, BER in their proper places. Added
+ possibility of encoding strings as UTF8String,
+ but only if they contain non-ASCII characters.
+
+ A.2 IGDUB Added line in table on double wrapping of true
+ octet strings.
+
+ A.2 IG1100 Corrected and expanded comments describing
+ mtpAddress form of MId. Fixed maximum length
+ of mtpAddress both here and in
+ ServiceChangeAddress.
+
+ A.2 IG0601 Inserted missing lines in IP4Address
+ production.
+
+ A.2 IG0601 Modified TransactionResponseAck to allow
+ acknowledgement of multiple ranges of
+ transactionIds.
+
+ A.2 IG0601 Corrected numerical value of CHOOSE as a
+ context identifier.
+
+ A.2 IGDUB Added missing extension marker in
+ TopologyRequest.
+
+ A.2 IG1100 AuditReply and AuditResult modified to bring
+ binary functionality into line with text
+ functionality.
+
+ A.2 IG0601 Removed OPTIONAL tag from terminationID in
+ NotifyReply.
+
+ A.2 IG0601 Added extraInfo substructure to EventParameter
+ and SigParameter.
+
+ A.2 IG0601 Modified MediaDescriptor to make it optional
+ to specify a stream.
+
+ A.2 IG0601 Added OPTIONAL tags to reserveValue and
+ reserveGroup.
+
+ A.2 IGDUB Added to comments for pkgdName to indicate
+ applicability to event names, signal names,
+ and statisticIds as well as property.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 204]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ A.2 IG0601 RequestID made optional in EventsDescriptor
+ and SecondEventsDescriptor and comment added
+ saying it must be present if events are
+ present.
+
+ A.2 IG1100 Added OPTIONAL tags on RequestActions and
+ SecondRequestedActions keepActive BOOLEANs.
+
+ A.2 IG1100 Added comment to indicate requestID value to
+ use in an AuditCapReply.
+
+ A.2 GEN0202 Added comment to DigitMapValue indicating time
+ units for timers.
+
+ A.2 IG0601 Added comment indicating coding of Value for
+ GEN0202 ServiceChangeReason. Cleaned up in Geneva to
+ use ASN.1 and BER in their proper places.
+
+ A.2 IG0601 Inserted missing extension marker in
+ ServiceChangeParm production.
+
+ A.2 IG0601 Aligned definition of mtpAddress in
+ ServiceChangeAddress with that in MId.
+
+ A.2 IG0601 Added timestamp to ServiceChangeResParm.
+
+ A.2 IGDUB Changed type of profileName in
+ ServiceChangeProfile to IA5String.
+
+ A.2 IG0601 Made returned value optional in
+ statisticsParameter, to support
+ auditCapability result.
+
+ A.2 GEN0202 Added reference to ISO 8601:1988 for
+ TimeNotation.
+
+ A.2 IG1100 Value production modified to support the
+ sublist parameter type.
+
+ A.3 IG1100 Corrected ABNF for digitStringlisT, replacing
+ "/" with "|".
+
+ A.3 IG1100 Added parentheses to digitMapRange production.
+
+ A.3 IG1100 Replaced more abbreviated syntax for pathName
+ with fuller definition and constraints copied
+ from B.2.
+
+
+
+
+Groves, et al. Standards Track [Page 205]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ B.2 IGDUB Added note warning that the syntax alone does
+ not provide a complete description of the
+ constraints, but must be supplemented by a
+ reading of the text and comments.
+
+ B.2 IG0601 Added note warning that the interpretation of
+ symbols is context-dependent.
+
+ B.2 IG1100 Added comment to indicate case insensitivity
+ of protocol (excepting SDP) and ABNF.
+
+ B.2 IG0601 Expanded upon and capitalized this comment.
+
+ B.2 IG0601 Lengthy note added on the coding of the VALUE
+ construct.
+
+ B.2 IGDUB Deleted sentence in note suggesting that
+ packages could add new types for properties,
+ parameters, or statistics.
+
+ B.2 IG0601 Added note indicating that parsers should
+ allow for white space preceding the first line
+ of SDP in Local or Remote.
+
+ B.2 IGDUB Added comments identifying the O- and W- tags.
+
+ B.2 IG1100 Moved wildcard tag up from individual commands
+ to commandRequestList.
+
+ B.2 GEN0202 Added additional error case to actionReply.
+
+ B.2 IG0601 Modified syntax of auditOther to allow return
+ of terminationID only.
+
+ B.2 IGDUB Corrected upper limit for V4hex.
+
+ B.2 IG1100 Corrected and expanded comments describing
+ mtpAddress form of MId.
+
+ B.2 IG0601 Modified comment to mediaParm to make
+ streamParms and StreamDescriptor mutually
+ exclusive.
+
+ B.2 GEN0202 Modified comment further to indicate at most
+ one instance of terminationStateDescriptor.
+
+ B.2 GEN0202 Expanded comment for streamParm to indicate
+ the restriction on repetition is per item.
+
+
+
+Groves, et al. Standards Track [Page 206]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ B.2 IG0601 Modified "at most once" comments to localParm,
+ terminationStateParm, and modemType, to allow
+ multiple instances of propertyParm in the
+ first two cases and extensionParameter in the
+ last one.
+
+ B.2 IG0601 Added note before description of Local and
+ Remote, pointing out that the octet value x00
+ is not allowed in octetString.
+
+ B.2 IG0601 Syntax for eventsDescriptor, embedFirst, and
+ eventBufferDescriptor modified to make
+ contents beyond token optional.
+
+ B.2 IGDUB Replaced "event" by "item" in comment to
+ pkgdName because pkgdName applies to
+ properties, signals, and statistics as well.
+
+ B.2 IG0601 Corrected placement of EQUAL in eventDM
+ production.
+
+ B.2 IG1100 Added comment and syntax to indicate requestID
+ value to use in an AuditCapReply.
+
+ B.2 IG1100 Corrected Modem Descriptor to allow package
+ items as properties.
+
+ B.2 IG0601 Comment to modemType changed to allow multiple
+ instances of extensionParameter.
+
+ B.2 GEN0202 Comment added to indicate units for Timer.
+
+ B.2 IG1100 Added parentheses to digitMapRange production.
+
+ B.2 IG1100 Added comment to serviceChangeParm,
+ restricting each parameter to one appearance.
+
+ B.2 IG0601 Added comments making serviceChangeMgcId and
+ serviceChangeAddress mutually exclusive in
+ ServiceChangeParm and servChgReplyParm.
+
+ B.2 IGDUB Added comment to serviceChangeParm indicating
+ that ServiceChangeMethod and
+ ServiceChangeReason are required.
+
+ B.2 IG0601 Added Timestamp to servChgReplyParm.
+
+
+
+
+
+Groves, et al. Standards Track [Page 207]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ B.2 IG0601 Added comment indicating coding of Value for
+ ServiceChangeReason.
+
+ B.2 IG0601 Modified ServiceChangeAddress to use MId
+ definition for full address.
+
+ B.2 IG1100 Made returned value optional in
+ statisticsParameter, to support
+ auditCapability result.
+
+ B.2 IG1100 Changed topologyDescriptor to allow multiple
+ triples.
+
+ B.2 IG0601 Added comment forbidding use of a double quote
+ within a quotedString value.
+
+ B.2 IG1100 Reserved prefixes for new tokens added to
+ signalParameter and eventParameter, to avoid
+ collision with package names.
+
+ B.2 IG1100 EmbedToken and EmergencyToken changed to
+ remove clash with EventBufferToken.
+
+ B.3 IG1100 New section describing hexadecimal octet
+ encoding.
+
+ B.4 IG1100 New section describing hex octet sequence.
+
+ C IG1100 Added permission to use Annex C properties in
+ LocalControl as well as in Local and Remote.
+
+ C IG0601 Added text making support of all properties of
+ Annex C optional.
+
+ C IGDUB Added directions to reconcile tabulated
+ formats with allowed types for properties.
+
+ C.1 IG1100 Corrected Q.765 reference to Q.765.5 for
+ ACodec.
+
+ C.1 IG1100 Deprecated Echocanc codepoint in favour of
+ package-defined property.
+
+ C.4 ITUPOST Updated references from Q.2961 to Q.2961.1.
+
+ C.4 IGDUB Added details on format of VPVC.
+
+ C.9 IG1100 Renamed USI to layer1prot.
+
+
+
+Groves, et al. Standards Track [Page 208]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ C.9 IG1100 Deprecated ECHOCI codepoint in favour of
+ package-defined property.
+
+ C.9 IG1100 Added new USI property.
+
+ C.11 IG1100 Added m= line tag.
+
+ D.1 IG0601 Added explanation of ALF.
+
+ D.1.5 IGDUB Expanded text indicating that when trying to
+ reestablish contact with the previously
+ controlling MGC the MG uses the Disconnected
+ method.
+
+ E.1.2 GEN0202 Added missing EventsDescriptor parameters
+ lines.
+
+ E.1.2 GEN0202 For the Signal Completion event:
+ - corrected the description of how it is
+ enabled
+ - heavily edited the description of the Signal
+ Identity observed event parameter and added a
+ type.
+
+ E.1.2 IGDUB The timeout completion reason for the Signal
+ Completion event was broadened to include
+ other circumstances where the signal completed
+ on its own.
+
+ E.1.2 IG1100 Added signal list ID observed event parameter
+ to the Signal Completion event.
+
+ E.2.1 IG0601 Added missing read only, read-write
+ specifications.
+
+ E.2.1 IG0601 Split ProvisionalResponseTimer properties into
+ one for MG, one for MGC.
+
+ E.3 GEN0202 Added "Designed to be extended only" to
+ tonegen package description.
+
+ E.4 GEN0202 Added "Designed to be extended only" to
+ tonedet package description.
+
+ E.4.2 GEN0202 Added type for tone ID observed parameter for
+ Long Tone Detected event.
+
+
+
+
+
+Groves, et al. Standards Track [Page 209]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ E.6.2 IG1100 Corrected binary identifier for digit map
+ completion event to avoid clash with base
+ package.
+
+ E.6.2 IG1100 Removed procedural text.
+
+ E.6.5 IG1100 Added procedural text indicating where to find
+ the applicable digit map and indicating the
+ error to return if the parameter is missing.
+
+ E.6.5 IG0601 Further modified procedural text.
+
+ E.7.3 IG1100 Corrected text identifier for payphone
+ recognition tone to avoid clash with base
+ package.
+
+ E.10.5 IGDUB Provided informative references for tones and
+ procedures for continuity check.
+
+ E.13 GEN0202 Added note that TDM package could also apply
+ to other transports.
+
+ E.13.1 IG1100 Changed default for echo cancellation from
+ "on" to provisioned.
+
+ E.13.1 IG0601 Corrected type for gain property.
+
+ Appendix TTPOST Included a number of corrections which were
+ I not picked up in H.248.1 Amendment 1 but which
+ do appear in H.248.1 v2.
+
+Intellectual Property Rights
+
+ The ITU draws attention to the possibility that the practice or
+ implementation of this RFC may involve the use of a claimed
+ Intellectual Property Right. The ITU takes no position concerning
+ the evidence, validity or applicability of claimed Intellectual
+ Property Rights, whether asserted by ITU members or others outside of
+ the Recommendation development process.
+
+ As of the date of approval of this RFC, the ITU had received notice
+ of intellectual property, protected by patents, which may be required
+ to implement this RFC. However, implementors are cautioned that this
+ may not represent the latest information and are therefore strongly
+ urged to consult the TSB patent database.
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 210]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ The IETF has also received notice of intellectual property claims
+ relating to Megaco/H.248.1. Please consult the IETF IPR
+ announcements at http://www.ietf.org/ipr.html.
+
+Acknowledgments
+
+ Megaco/H.248.1 is the result of hard work by many people in both the
+ IETF and in ITU-T Study Group 16. This section records those who
+ played a prominent role in ITU-T meetings, on the Megaco list, or
+ both.
+
+ Megaco/H.248 owes a large initial debt to the MGCP protocol (RFC
+ 2705), and thus to its authors, Mauricio Arango, Andrew Dugan, Ike
+ Elliott, Christian Huitema, and Scott Pickett. Flemming Andreasen
+ does not appear on this list of authors, but was a major contributor
+ to the development of both MGCP and Megaco/H.248.1. RFC 3435 has an
+ extensive acknowledgement of many other people who worked on media
+ gateway control before Megaco got started.
+
+ The authors of the first Megaco RFCs (2805, then 3015) were Fernando
+ Cuervo, Nancy Greene, Abdallah Rayhan, Christian Huitema, Brian
+ Rosen, and John Segers. Christian Groves conceived and was editor of
+ Annex C. The people most active on the Megaco list in the period
+ leading up to the completion of RFC 2885 were Brian Rosen, Tom
+ Taylor, Nancy Greene, Christian Huitema, Matt Holdrege, Chip Sharp,
+ John Segers, Michael Thomas, Henry Sinnreich, and Paul Sijben. The
+ people who sacrificed sleep and meals to complete the massive amount
+ of work required in the decisive Study Group 16 meeting of February,
+ 2000, were Michael Brown, Ranga Dendi, Larry Forni, Glen Freundlich,
+ Christian Groves, Alf Heidemark, Steve Magnell, Selvam Rengasami,
+ Rich Rubin, Klaus Sambor, John Segers, Chip Sharp, Tom Taylor, and
+ Stephen Terrill.
+
+ The most active people on the Megaco list in the period since the
+ February 2000 have been Tom Taylor, Brian Rosen, Christian Groves,
+ Madhu Babu Brahmanapally, Troy Cauble, Terry Anderson, Chuong Nguyen,
+ and Kevin Boyle, but many other people have been regular
+ contributors. Brian Rosen did tremendous service in putting together
+ the Megaco interoperability tests. On the Study Group 16 side, the
+ editorial team for the final revised document in February, 2002
+ included Christian Groves, Marcello Pantaleo, Terry Anderson, Peter
+ Leis, Kevin Boyle, and Tom Taylor.
+
+ Tom Taylor as Megaco Chair managed the day to day operation of the
+ Megaco list, with Brian Rosen taking an equal share of the burden for
+ most of the last three years. Glen Freundlich as the Study Group 16
+ Rapporteur ran the ITU-T meetings and ensured that all of the work at
+ hand was completed. Without Glen's determination the Megaco/H.248
+
+
+
+Groves, et al. Standards Track [Page 211]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+ standard would have taken at least half a year longer to produce.
+ Christian Groves filled in ably as Rapporteur when Glen could no
+ longer take part.
+
+Authors' Addresses
+
+ Terry L. Anderson
+ 24 Hill St
+ Bernardsville, NJ 07924
+ USA
+
+
+
+ Christian Groves
+ Ericsson AsiaPacificLab Australia
+ 37/360 Elizabeth St
+ Melbourne, Victoria 3000
+ Australia
+
+
+
+ Marcello Pantaleo
+ Ericsson Eurolab Deuschland
+ Ericsson Allee 1
+ 52134 Herzogenrath, Germany
+
+
+
+ Tom Taylor
+ Nortel Networks
+ 1852 Lorraine Ave,
+ Ottawa, Ontario
+ Canada K1H 6Z8
+
+ Phone: +1 613 736 0961
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 212]
+
+RFC 3525 Gateway Control Protocol June 2003
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groves, et al. Standards Track [Page 213]
+
diff --git a/lib/megaco/doc/standard/rfc4234.txt b/lib/megaco/doc/standard/rfc4234.txt
new file mode 100644
index 0000000000..74d4c44f43
--- /dev/null
+++ b/lib/megaco/doc/standard/rfc4234.txt
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+Network Working Group D. Crocker, Ed.
+Request for Comments: 4234 Brandenburg InternetWorking
+Obsoletes: 2234 P. Overell
+Category: Standards Track THUS plc.
+ October 2005
+
+
+ Augmented BNF for Syntax Specifications: ABNF
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ Internet technical specifications often need to define a formal
+ syntax. Over the years, a modified version of Backus-Naur Form
+ (BNF), called Augmented BNF (ABNF), has been popular among many
+ Internet specifications. The current specification documents ABNF.
+ It balances compactness and simplicity, with reasonable
+ representational power. The differences between standard BNF and
+ ABNF involve naming rules, repetition, alternatives, order-
+ independence, and value ranges. This specification also supplies
+ additional rule definitions and encoding for a core lexical analyzer
+ of the type common to several Internet specifications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 1]
+
+RFC 4234 ABNF October 2005
+
+
+Table of Contents
+
+ 1. INTRODUCTION ....................................................2
+ 2. RULE DEFINITION .................................................3
+ 2.1. Rule Naming ................................................3
+ 2.2. Rule Form ..................................................3
+ 2.3. Terminal Values ............................................4
+ 2.4. External Encodings .........................................5
+ 3. OPERATORS .......................................................6
+ 3.1. Concatenation: Rule1 Rule2 ................................6
+ 3.2. Alternatives: Rule1 / Rule2 ...............................6
+ 3.3. Incremental Alternatives: Rule1 =/ Rule2 ...................7
+ 3.4. Value Range Alternatives: %c##-## .........................7
+ 3.5. Sequence Group: (Rule1 Rule2) .............................8
+ 3.6. Variable Repetition: *Rule ................................8
+ 3.7. Specific Repetition: nRule ................................9
+ 3.8. Optional Sequence: [RULE] .................................9
+ 3.9. Comment: ; Comment ........................................9
+ 3.10. Operator Precedence .......................................9
+ 4. ABNF DEFINITION OF ABNF ........................................10
+ 5. SECURITY CONSIDERATIONS ........................................11
+ 6. References .....................................................11
+ 6.1. Normative References ......................................11
+ 6.2. Informative References ....................................11
+ Appendix A. ACKNOWLEDGEMENTS .....................................13
+ Appendix B. APPENDIX - CORE ABNF OF ABNF .........................13
+ B.1. Core Rules ...............................................13
+ B.2. Common Encoding ..........................................14
+
+1. INTRODUCTION
+
+ Internet technical specifications often need to define a formal
+ syntax and are free to employ whatever notation their authors deem
+ useful. Over the years, a modified version of Backus-Naur Form
+ (BNF), called Augmented BNF (ABNF), has been popular among many
+ Internet specifications. It balances compactness and simplicity,
+ with reasonable representational power. In the early days of the
+ Arpanet, each specification contained its own definition of ABNF.
+ This included the email specifications, [RFC733] and then [RFC822],
+ which came to be the common citations for defining ABNF. The current
+ document separates those definitions to permit selective reference.
+ Predictably, it also provides some modifications and enhancements.
+
+ The differences between standard BNF and ABNF involve naming rules,
+ repetition, alternatives, order-independence, and value ranges.
+ Appendix B supplies rule definitions and encoding for a core lexical
+ analyzer of the type common to several Internet specifications. It
+ is provided as a convenience and is otherwise separate from the meta
+
+
+
+Crocker & Overell Standards Track [Page 2]
+
+RFC 4234 ABNF October 2005
+
+
+ language defined in the body of this document, and separate from its
+ formal status.
+
+ Changes since [RFC2234]:
+
+ In Section 3.7, the phrase: "That is, exactly <N> occurrences of
+ <element>." was corrected to: "That is, exactly <n> occurrences of
+ <element>."
+
+ Some continuation comment lines needed to be corrected to begin
+ with comment character (";").
+
+2. RULE DEFINITION
+
+2.1. Rule Naming
+
+ The name of a rule is simply the name itself; that is, a sequence of
+ characters, beginning with an alphabetic character, and followed by a
+ combination of alphabetics, digits, and hyphens (dashes).
+
+ NOTE:
+
+ Rule names are case-insensitive
+
+ The names <rulename>, <Rulename>, <RULENAME>, and <rUlENamE> all
+ refer to the same rule.
+
+ Unlike original BNF, angle brackets ("<", ">") are not required.
+ However, angle brackets may be used around a rule name whenever their
+ presence facilitates in discerning the use of a rule name. This is
+ typically restricted to rule name references in free-form prose, or
+ to distinguish partial rules that combine into a string not separated
+ by white space, such as shown in the discussion about repetition,
+ below.
+
+2.2. Rule Form
+
+ A rule is defined by the following sequence:
+
+ name = elements crlf
+
+ where <name> is the name of the rule, <elements> is one or more rule
+ names or terminal specifications, and <crlf> is the end-of-line
+ indicator (carriage return followed by line feed). The equal sign
+ separates the name from the definition of the rule. The elements
+ form a sequence of one or more rule names and/or value definitions,
+ combined according to the various operators defined in this document,
+ such as alternative and repetition.
+
+
+
+Crocker & Overell Standards Track [Page 3]
+
+RFC 4234 ABNF October 2005
+
+
+ For visual ease, rule definitions are left aligned. When a rule
+ requires multiple lines, the continuation lines are indented. The
+ left alignment and indentation are relative to the first lines of the
+ ABNF rules and need not match the left margin of the document.
+
+2.3. Terminal Values
+
+ Rules resolve into a string of terminal values, sometimes called
+ characters. In ABNF, a character is merely a non-negative integer.
+ In certain contexts, a specific mapping (encoding) of values into a
+ character set (such as ASCII) will be specified.
+
+ Terminals are specified by one or more numeric characters, with the
+ base interpretation of those characters indicated explicitly. The
+ following bases are currently defined:
+
+ b = binary
+
+ d = decimal
+
+ x = hexadecimal
+
+ Hence:
+
+ CR = %d13
+
+ CR = %x0D
+
+ respectively specify the decimal and hexadecimal representation of
+ [US-ASCII] for carriage return.
+
+ A concatenated string of such values is specified compactly, using a
+ period (".") to indicate a separation of characters within that
+ value. Hence:
+
+ CRLF = %d13.10
+
+ ABNF permits the specification of literal text strings directly,
+ enclosed in quotation-marks. Hence:
+
+ command = "command string"
+
+ Literal text strings are interpreted as a concatenated set of
+ printable characters.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 4]
+
+RFC 4234 ABNF October 2005
+
+
+ NOTE:
+
+ ABNF strings are case-insensitive and the character set for these
+ strings is us-ascii.
+
+ Hence:
+
+ rulename = "abc"
+
+ and:
+
+ rulename = "aBc"
+
+ will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC", and
+ "ABC".
+
+ To specify a rule that IS case SENSITIVE, specify the characters
+ individually.
+
+ For example:
+
+ rulename = %d97 %d98 %d99
+
+ or
+
+ rulename = %d97.98.99
+
+ will match only the string that comprises only the lowercased
+ characters, abc.
+
+2.4. External Encodings
+
+ External representations of terminal value characters will vary
+ according to constraints in the storage or transmission environment.
+ Hence, the same ABNF-based grammar may have multiple external
+ encodings, such as one for a 7-bit US-ASCII environment, another for
+ a binary octet environment, and still a different one when 16-bit
+ Unicode is used. Encoding details are beyond the scope of ABNF,
+ although Appendix A (Core) provides definitions for a 7-bit US-ASCII
+ environment as has been common to much of the Internet.
+
+ By separating external encoding from the syntax, it is intended that
+ alternate encoding environments can be used for the same syntax.
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 5]
+
+RFC 4234 ABNF October 2005
+
+
+3. OPERATORS
+
+3.1. Concatenation: Rule1 Rule2
+
+ A rule can define a simple, ordered string of values (i.e., a
+ concatenation of contiguous characters) by listing a sequence of rule
+ names. For example:
+
+ foo = %x61 ; a
+
+ bar = %x62 ; b
+
+ mumble = foo bar foo
+
+ So that the rule <mumble> matches the lowercase string "aba".
+
+ LINEAR WHITE SPACE: Concatenation is at the core of the ABNF parsing
+ model. A string of contiguous characters (values) is parsed
+ according to the rules defined in ABNF. For Internet specifications,
+ there is some history of permitting linear white space (space and
+ horizontal tab) to be freely and implicitly interspersed around major
+ constructs, such as delimiting special characters or atomic strings.
+
+ NOTE:
+
+ This specification for ABNF does not provide for implicit
+ specification of linear white space.
+
+ Any grammar that wishes to permit linear white space around
+ delimiters or string segments must specify it explicitly. It is
+ often useful to provide for such white space in "core" rules that are
+ then used variously among higher-level rules. The "core" rules might
+ be formed into a lexical analyzer or simply be part of the main
+ ruleset.
+
+3.2. Alternatives: Rule1 / Rule2
+
+ Elements separated by a forward slash ("/") are alternatives.
+ Therefore,
+
+ foo / bar
+
+ will accept <foo> or <bar>.
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 6]
+
+RFC 4234 ABNF October 2005
+
+
+ NOTE:
+
+ A quoted string containing alphabetic characters is a special form
+ for specifying alternative characters and is interpreted as a
+ non-terminal representing the set of combinatorial strings with
+ the contained characters, in the specified order but with any
+ mixture of upper and lower case.
+
+3.3. Incremental Alternatives: Rule1 =/ Rule2
+
+ It is sometimes convenient to specify a list of alternatives in
+ fragments. That is, an initial rule may match one or more
+ alternatives, with later rule definitions adding to the set of
+ alternatives. This is particularly useful for otherwise, independent
+ specifications that derive from the same parent rule set, such as
+ often occurs with parameter lists. ABNF permits this incremental
+ definition through the construct:
+
+ oldrule =/ additional-alternatives
+
+ So that the rule set
+
+ ruleset = alt1 / alt2
+
+ ruleset =/ alt3
+
+ ruleset =/ alt4 / alt5
+
+ is the same as specifying
+
+ ruleset = alt1 / alt2 / alt3 / alt4 / alt5
+
+3.4. Value Range Alternatives: %c##-##
+
+ A range of alternative numeric values can be specified compactly,
+ using dash ("-") to indicate the range of alternative values. Hence:
+
+ DIGIT = %x30-39
+
+ is equivalent to:
+
+ DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" /
+
+ "7" / "8" / "9"
+
+ Concatenated numeric values and numeric value ranges cannot be
+ specified in the same string. A numeric value may use the dotted
+ notation for concatenation or it may use the dash notation to specify
+
+
+
+Crocker & Overell Standards Track [Page 7]
+
+RFC 4234 ABNF October 2005
+
+
+ one value range. Hence, to specify one printable character between
+ end of line sequences, the specification could be:
+
+ char-line = %x0D.0A %x20-7E %x0D.0A
+
+3.5. Sequence Group: (Rule1 Rule2)
+
+ Elements enclosed in parentheses are treated as a single element,
+ whose contents are STRICTLY ORDERED. Thus,
+
+ elem (foo / bar) blat
+
+ matches (elem foo blat) or (elem bar blat), and
+
+ elem foo / bar blat
+
+ matches (elem foo) or (bar blat).
+
+ NOTE:
+
+ It is strongly advised that grouping notation be used, rather than
+ relying on the proper reading of "bare" alternations, when
+ alternatives consist of multiple rule names or literals.
+
+ Hence, it is recommended that the following form be used:
+
+ (elem foo) / (bar blat)
+
+ It will avoid misinterpretation by casual readers.
+
+ The sequence group notation is also used within free text to set off
+ an element sequence from the prose.
+
+3.6. Variable Repetition: *Rule
+
+ The operator "*" preceding an element indicates repetition. The full
+ form is:
+
+ <a>*<b>element
+
+ where <a> and <b> are optional decimal values, indicating at least
+ <a> and at most <b> occurrences of the element.
+
+ Default values are 0 and infinity so that *<element> allows any
+ number, including zero; 1*<element> requires at least one;
+ 3*3<element> allows exactly 3 and 1*2<element> allows one or two.
+
+
+
+
+
+Crocker & Overell Standards Track [Page 8]
+
+RFC 4234 ABNF October 2005
+
+
+3.7. Specific Repetition: nRule
+
+ A rule of the form:
+
+ <n>element
+
+ is equivalent to
+
+ <n>*<n>element
+
+ That is, exactly <n> occurrences of <element>. Thus, 2DIGIT is a 2-
+ digit number, and 3ALPHA is a string of three alphabetic characters.
+
+3.8. Optional Sequence: [RULE]
+
+ Square brackets enclose an optional element sequence:
+
+ [foo bar]
+
+ is equivalent to
+
+ *1(foo bar).
+
+3.9. Comment: ; Comment
+
+ A semi-colon starts a comment that continues to the end of line.
+ This is a simple way of including useful notes in parallel with the
+ specifications.
+
+3.10. Operator Precedence
+
+ The various mechanisms described above have the following precedence,
+ from highest (binding tightest) at the top, to lowest (loosest) at
+ the bottom:
+
+ Strings, Names formation
+
+ Comment
+
+ Value range
+
+ Repetition
+
+ Grouping, Optional
+
+ Concatenation
+
+ Alternative
+
+
+
+Crocker & Overell Standards Track [Page 9]
+
+RFC 4234 ABNF October 2005
+
+
+ Use of the alternative operator, freely mixed with concatenations,
+ can be confusing.
+
+ Again, it is recommended that the grouping operator be used to
+ make explicit concatenation groups.
+
+4. ABNF DEFINITION OF ABNF
+
+ NOTES:
+
+ 1. This syntax requires a formatting of rules that is relatively
+ strict. Hence, the version of a ruleset included in a
+ specification might need preprocessing to ensure that it can be
+ interpreted by an ABNF parser.
+
+ 2. This syntax uses the rules provided in Appendix B (Core).
+
+ rulelist = 1*( rule / (*c-wsp c-nl) )
+
+ rule = rulename defined-as elements c-nl
+ ; continues if next line starts
+ ; with white space
+
+ rulename = ALPHA *(ALPHA / DIGIT / "-")
+
+ defined-as = *c-wsp ("=" / "=/") *c-wsp
+ ; basic rules definition and
+ ; incremental alternatives
+
+ elements = alternation *c-wsp
+
+ c-wsp = WSP / (c-nl WSP)
+
+ c-nl = comment / CRLF
+ ; comment or newline
+
+ comment = ";" *(WSP / VCHAR) CRLF
+
+ alternation = concatenation
+ *(*c-wsp "/" *c-wsp concatenation)
+
+ concatenation = repetition *(1*c-wsp repetition)
+
+ repetition = [repeat] element
+
+ repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)
+
+
+
+
+
+Crocker & Overell Standards Track [Page 10]
+
+RFC 4234 ABNF October 2005
+
+
+ element = rulename / group / option /
+ char-val / num-val / prose-val
+
+ group = "(" *c-wsp alternation *c-wsp ")"
+
+ option = "[" *c-wsp alternation *c-wsp "]"
+
+ char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
+ ; quoted string of SP and VCHAR
+ ; without DQUOTE
+
+ num-val = "%" (bin-val / dec-val / hex-val)
+
+ bin-val = "b" 1*BIT
+ [ 1*("." 1*BIT) / ("-" 1*BIT) ]
+ ; series of concatenated bit values
+ ; or single ONEOF range
+
+ dec-val = "d" 1*DIGIT
+ [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
+
+ hex-val = "x" 1*HEXDIG
+ [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
+
+ prose-val = "<" *(%x20-3D / %x3F-7E) ">"
+ ; bracketed string of SP and VCHAR
+ ; without angles
+ ; prose description, to be used as
+ ; last resort
+
+5. SECURITY CONSIDERATIONS
+
+ Security is truly believed to be irrelevant to this document.
+
+6. References
+
+6.1. Normative References
+
+ [US-ASCII] American National Standards Institute, "Coded Character
+ Set -- 7-bit American Standard Code for Information
+ Interchange", ANSI X3.4, 1986.
+
+6.2. Informative References
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+
+
+
+
+Crocker & Overell Standards Track [Page 11]
+
+RFC 4234 ABNF October 2005
+
+
+ [RFC733] Crocker, D., Vittal, J., Pogran, K., and D. Henderson,
+ "Standard for the format of ARPA network text messages",
+ RFC 733, November 1977.
+
+ [RFC822] Crocker, D., "Standard for the format of ARPA Internet
+ text messages", STD 11, RFC 822, August 1982.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 12]
+
+RFC 4234 ABNF October 2005
+
+
+Appendix A. ACKNOWLEDGEMENTS
+
+ The syntax for ABNF was originally specified in RFC 733. Ken L.
+ Harrenstien, of SRI International, was responsible for re-coding the
+ BNF into an augmented BNF that makes the representation smaller and
+ easier to understand.
+
+ This recent project began as a simple effort to cull out the portion
+ of RFC 822 that has been repeatedly cited by non-email specification
+ writers, namely the description of augmented BNF. Rather than simply
+ and blindly converting the existing text into a separate document,
+ the working group chose to give careful consideration to the
+ deficiencies, as well as benefits, of the existing specification and
+ related specifications made available over the last 15 years, and
+ therefore to pursue enhancement. This turned the project into
+ something rather more ambitious than was first intended.
+ Interestingly, the result is not massively different from that
+ original, although decisions, such as removing the list notation,
+ came as a surprise.
+
+ This "separated" version of the specification was part of the DRUMS
+ working group, with significant contributions from Jerome Abela,
+ Harald Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom
+ Harsch, Dan Kohn, Bill McQuillan, Keith Moore, Chris Newman, Pete
+ Resnick, and Henning Schulzrinne.
+
+ Julian Reschke warrants a special thanks for converting the Draft
+ Standard version to XML source form.
+
+Appendix B. APPENDIX - CORE ABNF OF ABNF
+
+ This Appendix is provided as a convenient core for specific grammars.
+ The definitions may be used as a core set of rules.
+
+B.1. Core Rules
+
+ Certain basic rules are in uppercase, such as SP, HTAB, CRLF, DIGIT,
+ ALPHA, etc.
+
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+
+ BIT = "0" / "1"
+
+ CHAR = %x01-7F
+ ; any 7-bit US-ASCII character,
+ ; excluding NUL
+
+
+
+
+
+Crocker & Overell Standards Track [Page 13]
+
+RFC 4234 ABNF October 2005
+
+
+ CR = %x0D
+ ; carriage return
+
+ CRLF = CR LF
+ ; Internet standard newline
+
+ CTL = %x00-1F / %x7F
+ ; controls
+
+ DIGIT = %x30-39
+ ; 0-9
+
+ DQUOTE = %x22
+ ; " (Double Quote)
+
+ HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+
+ HTAB = %x09
+ ; horizontal tab
+
+ LF = %x0A
+ ; linefeed
+
+ LWSP = *(WSP / CRLF WSP)
+ ; linear white space (past newline)
+
+ OCTET = %x00-FF
+ ; 8 bits of data
+
+ SP = %x20
+
+ VCHAR = %x21-7E
+ ; visible (printing) characters
+
+ WSP = SP / HTAB
+ ; white space
+
+B.2. Common Encoding
+
+ Externally, data are represented as "network virtual ASCII" (namely,
+ 7-bit US-ASCII in an 8-bit field), with the high (8th) bit set to
+ zero. A string of values is in "network byte order", in which the
+ higher-valued bytes are represented on the left-hand side and are
+ sent over the network first.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 14]
+
+RFC 4234 ABNF October 2005
+
+
+Authors' Addresses
+
+ Dave Crocker (editor)
+ Brandenburg InternetWorking
+ 675 Spruce Dr.
+ Sunnyvale, CA 94086
+ US
+
+ Phone: +1.408.246.8253
+
+
+ Paul Overell
+ THUS plc.
+ 1/2 Berkeley Square
+ 99 Berkeley Street
+ Glasgow
+ G3 7HR
+ UK
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 15]
+
+RFC 4234 ABNF October 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Crocker & Overell Standards Track [Page 16]
+
diff --git a/lib/megaco/doc/standard/rfc4566.txt b/lib/megaco/doc/standard/rfc4566.txt
new file mode 100644
index 0000000000..776e62200b
--- /dev/null
+++ b/lib/megaco/doc/standard/rfc4566.txt
@@ -0,0 +1,2747 @@
+
+
+
+
+
+
+Network Working Group M. Handley
+Request for Comments: 4566 UCL
+Obsoletes: 2327, 3266 V. Jacobson
+Category: Standards Track Packet Design
+ C. Perkins
+ University of Glasgow
+ July 2006
+
+
+ SDP: Session Description Protocol
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2006).
+
+Abstract
+
+ This memo defines the Session Description Protocol (SDP). SDP is
+ intended for describing multimedia sessions for the purposes of
+ session announcement, session invitation, and other forms of
+ multimedia session initiation.
+
+Table of Contents
+
+ 1. Introduction ....................................................3
+ 2. Glossary of Terms ...............................................3
+ 3. Examples of SDP Usage ...........................................4
+ 3.1. Session Initiation .........................................4
+ 3.2. Streaming Media ............................................4
+ 3.3. Email and the World Wide Web ...............................4
+ 3.4. Multicast Session Announcement .............................4
+ 4. Requirements and Recommendations ................................5
+ 4.1. Media and Transport Information ............................6
+ 4.2. Timing Information .........................................6
+ 4.3. Private Sessions ...........................................7
+ 4.4. Obtaining Further Information about a Session ..............7
+ 4.5. Categorisation .............................................7
+ 4.6. Internationalisation .......................................7
+
+
+
+
+
+Handley, et al. Standards Track [Page 1]
+
+RFC 4566 SDP July 2006
+
+
+ 5. SDP Specification ...............................................7
+ 5.1. Protocol Version ("v=") ...................................10
+ 5.2. Origin ("o=") .............................................11
+ 5.3. Session Name ("s=") .......................................12
+ 5.4. Session Information ("i=") ................................12
+ 5.5. URI ("u=") ................................................13
+ 5.6. Email Address and Phone Number ("e=" and "p=") ............13
+ 5.7. Connection Data ("c=") ....................................14
+ 5.8. Bandwidth ("b=") ..........................................16
+ 5.9. Timing ("t=") .............................................17
+ 5.10. Repeat Times ("r=") ......................................18
+ 5.11. Time Zones ("z=") ........................................19
+ 5.12. Encryption Keys ("k=") ...................................19
+ 5.13. Attributes ("a=") ........................................21
+ 5.14. Media Descriptions ("m=") ................................22
+ 6. SDP Attributes .................................................24
+ 7. Security Considerations ........................................31
+ 8. IANA Considerations ............................................33
+ 8.1. The "application/sdp" Media Type ..........................33
+ 8.2. Registration of Parameters ................................34
+ 8.2.1. Media Types ("media") ..............................34
+ 8.2.2. Transport Protocols ("proto") ......................34
+ 8.2.3. Media Formats ("fmt") ..............................35
+ 8.2.4. Attribute Names ("att-field") ......................36
+ 8.2.5. Bandwidth Specifiers ("bwtype") ....................37
+ 8.2.6. Network Types ("nettype") ..........................37
+ 8.2.7. Address Types ("addrtype") .........................38
+ 8.2.8. Registration Procedure .............................38
+ 8.3. Encryption Key Access Methods .............................39
+ 9. SDP Grammar ....................................................39
+ 10. Summary of Changes from RFC 2327 ..............................44
+ 11. Acknowledgements ..............................................45
+ 12. References ....................................................45
+ 12.1. Normative References .....................................45
+ 12.2. Informative References ...................................46
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 2]
+
+RFC 4566 SDP July 2006
+
+
+1. Introduction
+
+ When initiating multimedia teleconferences, voice-over-IP calls,
+ streaming video, or other sessions, there is a requirement to convey
+ media details, transport addresses, and other session description
+ metadata to the participants.
+
+ SDP provides a standard representation for such information,
+ irrespective of how that information is transported. SDP is purely a
+ format for session description -- it does not incorporate a transport
+ protocol, and it is intended to use different transport protocols as
+ appropriate, including the Session Announcement Protocol [14],
+ Session Initiation Protocol [15], Real Time Streaming Protocol [16],
+ electronic mail using the MIME extensions, and the Hypertext
+ Transport Protocol.
+
+ SDP is intended to be general purpose so that it can be used in a
+ wide range of network environments and applications. However, it is
+ not intended to support negotiation of session content or media
+ encodings: this is viewed as outside the scope of session
+ description.
+
+ This memo obsoletes RFC 2327 [6] and RFC 3266 [10]. Section 10
+ outlines the changes introduced in this memo.
+
+2. Glossary of Terms
+
+ The following terms are used in this document and have specific
+ meaning within the context of this document.
+
+ Conference: A multimedia conference is a set of two or more
+ communicating users along with the software they are using to
+ communicate.
+
+ Session: A multimedia session is a set of multimedia senders and
+ receivers and the data streams flowing from senders to receivers.
+ A multimedia conference is an example of a multimedia session.
+
+ Session Description: A well-defined format for conveying sufficient
+ information to discover and participate in a multimedia session.
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [3].
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 3]
+
+RFC 4566 SDP July 2006
+
+
+3. Examples of SDP Usage
+
+3.1. Session Initiation
+
+ The Session Initiation Protocol (SIP) [15] is an application-layer
+ control protocol for creating, modifying, and terminating sessions
+ such as Internet multimedia conferences, Internet telephone calls,
+ and multimedia distribution. The SIP messages used to create
+ sessions carry session descriptions that allow participants to agree
+ on a set of compatible media types. These session descriptions are
+ commonly formatted using SDP. When used with SIP, the offer/answer
+ model [17] provides a limited framework for negotiation using SDP.
+
+3.2. Streaming Media
+
+ The Real Time Streaming Protocol (RTSP) [16], is an application-level
+ protocol for control over the delivery of data with real-time
+ properties. RTSP provides an extensible framework to enable
+ controlled, on-demand delivery of real-time data, such as audio and
+ video. An RTSP client and server negotiate an appropriate set of
+ parameters for media delivery, partially using SDP syntax to describe
+ those parameters.
+
+3.3. Email and the World Wide Web
+
+ Alternative means of conveying session descriptions include
+ electronic mail and the World Wide Web (WWW). For both email and WWW
+ distribution, the media type "application/sdp" is used. This enables
+ the automatic launching of applications for participation in the
+ session from the WWW client or mail reader in a standard manner.
+
+ Note that announcements of multicast sessions made only via email or
+ the WWW do not have the property that the receiver of a session
+ announcement can necessarily receive the session because the
+ multicast sessions may be restricted in scope, and access to the WWW
+ server or reception of email is possible outside this scope.
+
+3.4. Multicast Session Announcement
+
+ In order to assist the advertisement of multicast multimedia
+ conferences and other multicast sessions, and to communicate the
+ relevant session setup information to prospective participants, a
+ distributed session directory may be used. An instance of such a
+ session directory periodically sends packets containing a description
+ of the session to a well-known multicast group. These advertisements
+ are received by other session directories such that potential remote
+ participants can use the session description to start the tools
+ required to participate in the session.
+
+
+
+Handley, et al. Standards Track [Page 4]
+
+RFC 4566 SDP July 2006
+
+
+ One protocol used to implement such a distributed directory is the
+ Session Announcement Protocol (SAP) [14]. SDP provides the
+ recommended session description format for such session
+ announcements.
+
+4. Requirements and Recommendations
+
+ The purpose of SDP is to convey information about media streams in
+ multimedia sessions to allow the recipients of a session description
+ to participate in the session. SDP is primarily intended for use in
+ an internetwork, although it is sufficiently general that it can
+ describe conferences in other network environments. Media streams
+ can be many-to-many. Sessions need not be continually active.
+
+ Thus far, multicast-based sessions on the Internet have differed from
+ many other forms of conferencing in that anyone receiving the traffic
+ can join the session (unless the session traffic is encrypted). In
+ such an environment, SDP serves two primary purposes. It is a means
+ to communicate the existence of a session, and it is a means to
+ convey sufficient information to enable joining and participating in
+ the session. In a unicast environment, only the latter purpose is
+ likely to be relevant.
+
+ An SDP session description includes the following:
+
+ o Session name and purpose
+
+ o Time(s) the session is active
+
+ o The media comprising the session
+
+ o Information needed to receive those media (addresses, ports,
+ formats, etc.)
+
+ As resources necessary to participate in a session may be limited,
+ some additional information may also be desirable:
+
+ o Information about the bandwidth to be used by the session
+
+ o Contact information for the person responsible for the session
+
+ In general, SDP must convey sufficient information to enable
+ applications to join a session (with the possible exception of
+ encryption keys) and to announce the resources to be used to any
+ non-participants that may need to know. (This latter feature is
+ primarily useful when SDP is used with a multicast session
+ announcement protocol.)
+
+
+
+
+Handley, et al. Standards Track [Page 5]
+
+RFC 4566 SDP July 2006
+
+
+4.1. Media and Transport Information
+
+ An SDP session description includes the following media information:
+
+ o The type of media (video, audio, etc.)
+
+ o The transport protocol (RTP/UDP/IP, H.320, etc.)
+
+ o The format of the media (H.261 video, MPEG video, etc.)
+
+ In addition to media format and transport protocol, SDP conveys
+ address and port details. For an IP multicast session, these
+ comprise:
+
+ o The multicast group address for media
+
+ o The transport port for media
+
+ This address and port are the destination address and destination
+ port of the multicast stream, whether being sent, received, or both.
+
+ For unicast IP sessions, the following are conveyed:
+
+ o The remote address for media
+
+ o The remote transport port for media
+
+ The semantics of this address and port depend on the media and
+ transport protocol defined. By default, this SHOULD be the remote
+ address and remote port to which data is sent. Some media types may
+ redefine this behaviour, but this is NOT RECOMMENDED since it
+ complicates implementations (including middleboxes that must parse
+ the addresses to open Network Address Translation (NAT) or firewall
+ pinholes).
+
+4.2. Timing Information
+
+ Sessions may be either bounded or unbounded in time. Whether or not
+ they are bounded, they may be only active at specific times. SDP can
+ convey:
+
+ o An arbitrary list of start and stop times bounding the session
+
+ o For each bound, repeat times such as "every Wednesday at 10am for
+ one hour"
+
+ This timing information is globally consistent, irrespective of local
+ time zone or daylight saving time (see Section 5.9).
+
+
+
+Handley, et al. Standards Track [Page 6]
+
+RFC 4566 SDP July 2006
+
+
+4.3. Private Sessions
+
+ It is possible to create both public sessions and private sessions.
+ SDP itself does not distinguish between these; private sessions are
+ typically conveyed by encrypting the session description during
+ distribution. The details of how encryption is performed are
+ dependent on the mechanism used to convey SDP; mechanisms are
+ currently defined for SDP transported using SAP [14] and SIP [15],
+ and others may be defined in the future.
+
+ If a session announcement is private, it is possible to use that
+ private announcement to convey encryption keys necessary to decode
+ each of the media in a conference, including enough information to
+ know which encryption scheme is used for each media.
+
+4.4. Obtaining Further Information about a Session
+
+ A session description should convey enough information to decide
+ whether or not to participate in a session. SDP may include
+ additional pointers in the form of Uniform Resource Identifiers
+ (URIs) for more information about the session.
+
+4.5. Categorisation
+
+ When many session descriptions are being distributed by SAP, or any
+ other advertisement mechanism, it may be desirable to filter session
+ announcements that are of interest from those that are not. SDP
+ supports a categorisation mechanism for sessions that is capable of
+ being automated (the "a=cat:" attribute; see Section 6).
+
+4.6. Internationalisation
+
+ The SDP specification recommends the use of the ISO 10646 character
+ sets in the UTF-8 encoding [5] to allow many different languages to
+ be represented. However, to assist in compact representations, SDP
+ also allows other character sets such as ISO 8859-1 to be used when
+ desired. Internationalisation only applies to free-text fields
+ (session name and background information), and not to SDP as a whole.
+
+5. SDP Specification
+
+ An SDP session description is denoted by the media type
+ "application/sdp" (See Section 8).
+
+ An SDP session description is entirely textual using the ISO 10646
+ character set in UTF-8 encoding. SDP field names and attribute names
+ use only the US-ASCII subset of UTF-8, but textual fields and
+ attribute values MAY use the full ISO 10646 character set. Field and
+
+
+
+Handley, et al. Standards Track [Page 7]
+
+RFC 4566 SDP July 2006
+
+
+ attribute values that use the full UTF-8 character set are never
+ directly compared, hence there is no requirement for UTF-8
+ normalisation. The textual form, as opposed to a binary encoding
+ such as ASN.1 or XDR, was chosen to enhance portability, to enable a
+ variety of transports to be used, and to allow flexible, text-based
+ toolkits to be used to generate and process session descriptions.
+ However, since SDP may be used in environments where the maximum
+ permissible size of a session description is limited, the encoding is
+ deliberately compact. Also, since announcements may be transported
+ via very unreliable means or damaged by an intermediate caching
+ server, the encoding was designed with strict order and formatting
+ rules so that most errors would result in malformed session
+ announcements that could be detected easily and discarded. This also
+ allows rapid discarding of encrypted session announcements for which
+ a receiver does not have the correct key.
+
+ An SDP session description consists of a number of lines of text of
+ the form:
+
+ <type>=<value>
+
+ where <type> MUST be exactly one case-significant character and
+ <value> is structured text whose format depends on <type>. In
+ general, <value> is either a number of fields delimited by a single
+ space character or a free format string, and is case-significant
+ unless a specific field defines otherwise. Whitespace MUST NOT be
+ used on either side of the "=" sign.
+
+ An SDP session description consists of a session-level section
+ followed by zero or more media-level sections. The session-level
+ part starts with a "v=" line and continues to the first media-level
+ section. Each media-level section starts with an "m=" line and
+ continues to the next media-level section or end of the whole session
+ description. In general, session-level values are the default for
+ all media unless overridden by an equivalent media-level value.
+
+ Some lines in each description are REQUIRED and some are OPTIONAL,
+ but all MUST appear in exactly the order given here (the fixed order
+ greatly enhances error detection and allows for a simple parser).
+ OPTIONAL items are marked with a "*".
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 8]
+
+RFC 4566 SDP July 2006
+
+
+ Session description
+ v= (protocol version)
+ o= (originator and session identifier)
+ s= (session name)
+ i=* (session information)
+ u=* (URI of description)
+ e=* (email address)
+ p=* (phone number)
+ c=* (connection information -- not required if included in
+ all media)
+ b=* (zero or more bandwidth information lines)
+ One or more time descriptions ("t=" and "r=" lines; see below)
+ z=* (time zone adjustments)
+ k=* (encryption key)
+ a=* (zero or more session attribute lines)
+ Zero or more media descriptions
+
+ Time description
+ t= (time the session is active)
+ r=* (zero or more repeat times)
+
+ Media description, if present
+ m= (media name and transport address)
+ i=* (media title)
+ c=* (connection information -- optional if included at
+ session level)
+ b=* (zero or more bandwidth information lines)
+ k=* (encryption key)
+ a=* (zero or more media attribute lines)
+
+ The set of type letters is deliberately small and not intended to be
+ extensible -- an SDP parser MUST completely ignore any session
+ description that contains a type letter that it does not understand.
+ The attribute mechanism ("a=" described below) is the primary means
+ for extending SDP and tailoring it to particular applications or
+ media. Some attributes (the ones listed in Section 6 of this memo)
+ have a defined meaning, but others may be added on an application-,
+ media-, or session-specific basis. An SDP parser MUST ignore any
+ attribute it doesn't understand.
+
+ An SDP session description may contain URIs that reference external
+ content in the "u=", "k=", and "a=" lines. These URIs may be
+ dereferenced in some cases, making the session description non-self-
+ contained.
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 9]
+
+RFC 4566 SDP July 2006
+
+
+ The connection ("c=") and attribute ("a=") information in the
+ session-level section applies to all the media of that session unless
+ overridden by connection information or an attribute of the same name
+ in the media description. For instance, in the example below, each
+ media behaves as if it were given a "recvonly" attribute.
+
+ An example SDP description is:
+
+ v=0
+ o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
+ s=SDP Seminar
+ i=A Seminar on the session description protocol
+ u=http://www.example.com/seminars/sdp.pdf
+ [email protected] (Jane Doe)
+ c=IN IP4 224.2.17.12/127
+ t=2873397496 2873404696
+ a=recvonly
+ m=audio 49170 RTP/AVP 0
+ m=video 51372 RTP/AVP 99
+ a=rtpmap:99 h263-1998/90000
+
+ Text fields such as the session name and information are octet
+ strings that may contain any octet with the exceptions of 0x00 (Nul),
+ 0x0a (ASCII newline), and 0x0d (ASCII carriage return). The sequence
+ CRLF (0x0d0a) is used to end a record, although parsers SHOULD be
+ tolerant and also accept records terminated with a single newline
+ character. If the "a=charset" attribute is not present, these octet
+ strings MUST be interpreted as containing ISO-10646 characters in
+ UTF-8 encoding (the presence of the "a=charset" attribute may force
+ some fields to be interpreted differently).
+
+ A session description can contain domain names in the "o=", "u=",
+ "e=", "c=", and "a=" lines. Any domain name used in SDP MUST comply
+ with [1], [2]. Internationalised domain names (IDNs) MUST be
+ represented using the ASCII Compatible Encoding (ACE) form defined in
+ [11] and MUST NOT be directly represented in UTF-8 or any other
+ encoding (this requirement is for compatibility with RFC 2327 and
+ other SDP-related standards, which predate the development of
+ internationalised domain names).
+
+5.1. Protocol Version ("v=")
+
+ v=0
+
+ The "v=" field gives the version of the Session Description Protocol.
+ This memo defines version 0. There is no minor version number.
+
+
+
+
+
+Handley, et al. Standards Track [Page 10]
+
+RFC 4566 SDP July 2006
+
+
+5.2. Origin ("o=")
+
+ o=<username> <sess-id> <sess-version> <nettype> <addrtype>
+ <unicast-address>
+
+ The "o=" field gives the originator of the session (her username and
+ the address of the user's host) plus a session identifier and version
+ number:
+
+ <username> is the user's login on the originating host, or it is "-"
+ if the originating host does not support the concept of user IDs.
+ The <username> MUST NOT contain spaces.
+
+ <sess-id> is a numeric string such that the tuple of <username>,
+ <sess-id>, <nettype>, <addrtype>, and <unicast-address> forms a
+ globally unique identifier for the session. The method of
+ <sess-id> allocation is up to the creating tool, but it has been
+ suggested that a Network Time Protocol (NTP) format timestamp be
+ used to ensure uniqueness [13].
+
+ <sess-version> is a version number for this session description. Its
+ usage is up to the creating tool, so long as <sess-version> is
+ increased when a modification is made to the session data. Again,
+ it is RECOMMENDED that an NTP format timestamp is used.
+
+ <nettype> is a text string giving the type of network. Initially
+ "IN" is defined to have the meaning "Internet", but other values
+ MAY be registered in the future (see Section 8).
+
+ <addrtype> is a text string giving the type of the address that
+ follows. Initially "IP4" and "IP6" are defined, but other values
+ MAY be registered in the future (see Section 8).
+
+ <unicast-address> is the address of the machine from which the
+ session was created. For an address type of IP4, this is either
+ the fully qualified domain name of the machine or the dotted-
+ decimal representation of the IP version 4 address of the machine.
+ For an address type of IP6, this is either the fully qualified
+ domain name of the machine or the compressed textual
+ representation of the IP version 6 address of the machine. For
+ both IP4 and IP6, the fully qualified domain name is the form that
+ SHOULD be given unless this is unavailable, in which case the
+ globally unique address MAY be substituted. A local IP address
+ MUST NOT be used in any context where the SDP description might
+ leave the scope in which the address is meaningful (for example, a
+ local address MUST NOT be included in an application-level
+ referral that might leave the scope).
+
+
+
+
+Handley, et al. Standards Track [Page 11]
+
+RFC 4566 SDP July 2006
+
+
+ In general, the "o=" field serves as a globally unique identifier for
+ this version of this session description, and the subfields excepting
+ the version taken together identify the session irrespective of any
+ modifications.
+
+ For privacy reasons, it is sometimes desirable to obfuscate the
+ username and IP address of the session originator. If this is a
+ concern, an arbitrary <username> and private <unicast-address> MAY be
+ chosen to populate the "o=" field, provided that these are selected
+ in a manner that does not affect the global uniqueness of the field.
+
+5.3. Session Name ("s=")
+
+ s=<session name>
+
+ The "s=" field is the textual session name. There MUST be one and
+ only one "s=" field per session description. The "s=" field MUST NOT
+ be empty and SHOULD contain ISO 10646 characters (but see also the
+ "a=charset" attribute). If a session has no meaningful name, the
+ value "s= " SHOULD be used (i.e., a single space as the session
+ name).
+
+5.4. Session Information ("i=")
+
+ i=<session description>
+
+ The "i=" field provides textual information about the session. There
+ MUST be at most one session-level "i=" field per session description,
+ and at most one "i=" field per media. If the "a=charset" attribute
+ is present, it specifies the character set used in the "i=" field.
+ If the "a=charset" attribute is not present, the "i=" field MUST
+ contain ISO 10646 characters in UTF-8 encoding.
+
+ A single "i=" field MAY also be used for each media definition. In
+ media definitions, "i=" fields are primarily intended for labelling
+ media streams. As such, they are most likely to be useful when a
+ single session has more than one distinct media stream of the same
+ media type. An example would be two different whiteboards, one for
+ slides and one for feedback and questions.
+
+ The "i=" field is intended to provide a free-form human-readable
+ description of the session or the purpose of a media stream. It is
+ not suitable for parsing by automata.
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 12]
+
+RFC 4566 SDP July 2006
+
+
+5.5. URI ("u=")
+
+ u=<uri>
+
+ A URI is a Uniform Resource Identifier as used by WWW clients [7].
+ The URI should be a pointer to additional information about the
+ session. This field is OPTIONAL, but if it is present it MUST be
+ specified before the first media field. No more than one URI field
+ is allowed per session description.
+
+5.6. Email Address and Phone Number ("e=" and "p=")
+
+ e=<email-address>
+ p=<phone-number>
+
+ The "e=" and "p=" lines specify contact information for the person
+ responsible for the conference. This is not necessarily the same
+ person that created the conference announcement.
+
+ Inclusion of an email address or phone number is OPTIONAL. Note that
+ the previous version of SDP specified that either an email field or a
+ phone field MUST be specified, but this was widely ignored. The
+ change brings the specification into line with common usage.
+
+ If an email address or phone number is present, it MUST be specified
+ before the first media field. More than one email or phone field can
+ be given for a session description.
+
+ Phone numbers SHOULD be given in the form of an international public
+ telecommunication number (see ITU-T Recommendation E.164) preceded by
+ a "+". Spaces and hyphens may be used to split up a phone field to
+ aid readability if desired. For example:
+
+ p=+1 617 555-6011
+
+ Both email addresses and phone numbers can have an OPTIONAL free text
+ string associated with them, normally giving the name of the person
+ who may be contacted. This MUST be enclosed in parentheses if it is
+ present. For example:
+
+ [email protected] (Jane Doe)
+
+ The alternative RFC 2822 [29] name quoting convention is also allowed
+ for both email addresses and phone numbers. For example:
+
+ e=Jane Doe <[email protected]>
+
+
+
+
+
+Handley, et al. Standards Track [Page 13]
+
+RFC 4566 SDP July 2006
+
+
+ The free text string SHOULD be in the ISO-10646 character set with
+ UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings if
+ the appropriate session-level "a=charset" attribute is set.
+
+5.7. Connection Data ("c=")
+
+ c=<nettype> <addrtype> <connection-address>
+
+ The "c=" field contains connection data.
+
+ A session description MUST contain either at least one "c=" field in
+ each media description or a single "c=" field at the session level.
+ It MAY contain a single session-level "c=" field and additional "c="
+ field(s) per media description, in which case the per-media values
+ override the session-level settings for the respective media.
+
+ The first sub-field ("<nettype>") is the network type, which is a
+ text string giving the type of network. Initially, "IN" is defined
+ to have the meaning "Internet", but other values MAY be registered in
+ the future (see Section 8).
+
+ The second sub-field ("<addrtype>") is the address type. This allows
+ SDP to be used for sessions that are not IP based. This memo only
+ defines IP4 and IP6, but other values MAY be registered in the future
+ (see Section 8).
+
+ The third sub-field ("<connection-address>") is the connection
+ address. OPTIONAL sub-fields MAY be added after the connection
+ address depending on the value of the <addrtype> field.
+
+ When the <addrtype> is IP4 and IP6, the connection address is defined
+ as follows:
+
+ o If the session is multicast, the connection address will be an IP
+ multicast group address. If the session is not multicast, then
+ the connection address contains the unicast IP address of the
+ expected data source or data relay or data sink as determined by
+ additional attribute fields. It is not expected that unicast
+ addresses will be given in a session description that is
+ communicated by a multicast announcement, though this is not
+ prohibited.
+
+ o Sessions using an IPv4 multicast connection address MUST also have
+ a time to live (TTL) value present in addition to the multicast
+ address. The TTL and the address together define the scope with
+ which multicast packets sent in this conference will be sent. TTL
+ values MUST be in the range 0-255. Although the TTL MUST be
+ specified, its use to scope multicast traffic is deprecated;
+
+
+
+Handley, et al. Standards Track [Page 14]
+
+RFC 4566 SDP July 2006
+
+
+ applications SHOULD use an administratively scoped address
+ instead.
+
+ The TTL for the session is appended to the address using a slash as a
+ separator. An example is:
+
+ c=IN IP4 224.2.36.42/127
+
+ IPv6 multicast does not use TTL scoping, and hence the TTL value MUST
+ NOT be present for IPv6 multicast. It is expected that IPv6 scoped
+ addresses will be used to limit the scope of conferences.
+
+ Hierarchical or layered encoding schemes are data streams where the
+ encoding from a single media source is split into a number of layers.
+ The receiver can choose the desired quality (and hence bandwidth) by
+ only subscribing to a subset of these layers. Such layered encodings
+ are normally transmitted in multiple multicast groups to allow
+ multicast pruning. This technique keeps unwanted traffic from sites
+ only requiring certain levels of the hierarchy. For applications
+ requiring multiple multicast groups, we allow the following notation
+ to be used for the connection address:
+
+ <base multicast address>[/<ttl>]/<number of addresses>
+
+ If the number of addresses is not given, it is assumed to be one.
+ Multicast addresses so assigned are contiguously allocated above the
+ base address, so that, for example:
+
+ c=IN IP4 224.2.1.1/127/3
+
+ would state that addresses 224.2.1.1, 224.2.1.2, and 224.2.1.3 are to
+ be used at a TTL of 127. This is semantically identical to including
+ multiple "c=" lines in a media description:
+
+ c=IN IP4 224.2.1.1/127
+ c=IN IP4 224.2.1.2/127
+ c=IN IP4 224.2.1.3/127
+
+ Similarly, an IPv6 example would be:
+
+ c=IN IP6 FF15::101/3
+
+ which is semantically equivalent to:
+
+ c=IN IP6 FF15::101
+ c=IN IP6 FF15::102
+ c=IN IP6 FF15::103
+
+
+
+
+Handley, et al. Standards Track [Page 15]
+
+RFC 4566 SDP July 2006
+
+
+ (remembering that the TTL field is not present in IPv6 multicast).
+
+ Multiple addresses or "c=" lines MAY be specified on a per-media
+ basis only if they provide multicast addresses for different layers
+ in a hierarchical or layered encoding scheme. They MUST NOT be
+ specified for a session-level "c=" field.
+
+ The slash notation for multiple addresses described above MUST NOT be
+ used for IP unicast addresses.
+
+5.8. Bandwidth ("b=")
+
+ b=<bwtype>:<bandwidth>
+
+ This OPTIONAL field denotes the proposed bandwidth to be used by the
+ session or media. The <bwtype> is an alphanumeric modifier giving
+ the meaning of the <bandwidth> figure. Two values are defined in
+ this specification, but other values MAY be registered in the future
+ (see Section 8 and [21], [25]):
+
+ CT If the bandwidth of a session or media in a session is different
+ from the bandwidth implicit from the scope, a "b=CT:..." line
+ SHOULD be supplied for the session giving the proposed upper limit
+ to the bandwidth used (the "conference total" bandwidth). The
+ primary purpose of this is to give an approximate idea as to
+ whether two or more sessions can coexist simultaneously. When
+ using the CT modifier with RTP, if several RTP sessions are part
+ of the conference, the conference total refers to total bandwidth
+ of all RTP sessions.
+
+ AS The bandwidth is interpreted to be application specific (it will
+ be the application's concept of maximum bandwidth). Normally,
+ this will coincide with what is set on the application's "maximum
+ bandwidth" control if applicable. For RTP-based applications, AS
+ gives the RTP "session bandwidth" as defined in Section 6.2 of
+ [19].
+
+ Note that CT gives a total bandwidth figure for all the media at all
+ sites. AS gives a bandwidth figure for a single media at a single
+ site, although there may be many sites sending simultaneously.
+
+ A prefix "X-" is defined for <bwtype> names. This is intended for
+ experimental purposes only. For example:
+
+ b=X-YZ:128
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 16]
+
+RFC 4566 SDP July 2006
+
+
+ Use of the "X-" prefix is NOT RECOMMENDED: instead new modifiers
+ SHOULD be registered with IANA in the standard namespace. SDP
+ parsers MUST ignore bandwidth fields with unknown modifiers.
+ Modifiers MUST be alphanumeric and, although no length limit is
+ given, it is recommended that they be short.
+
+ The <bandwidth> is interpreted as kilobits per second by default.
+ The definition of a new <bwtype> modifier MAY specify that the
+ bandwidth is to be interpreted in some alternative unit (the "CT" and
+ "AS" modifiers defined in this memo use the default units).
+
+5.9. Timing ("t=")
+
+ t=<start-time> <stop-time>
+
+ The "t=" lines specify the start and stop times for a session.
+ Multiple "t=" lines MAY be used if a session is active at multiple
+ irregularly spaced times; each additional "t=" line specifies an
+ additional period of time for which the session will be active. If
+ the session is active at regular times, an "r=" line (see below)
+ should be used in addition to, and following, a "t=" line -- in which
+ case the "t=" line specifies the start and stop times of the repeat
+ sequence.
+
+ The first and second sub-fields give the start and stop times,
+ respectively, for the session. These values are the decimal
+ representation of Network Time Protocol (NTP) time values in seconds
+ since 1900 [13]. To convert these values to UNIX time, subtract
+ decimal 2208988800.
+
+ NTP timestamps are elsewhere represented by 64-bit values, which wrap
+ sometime in the year 2036. Since SDP uses an arbitrary length
+ decimal representation, this should not cause an issue (SDP
+ timestamps MUST continue counting seconds since 1900, NTP will use
+ the value modulo the 64-bit limit).
+
+ If the <stop-time> is set to zero, then the session is not bounded,
+ though it will not become active until after the <start-time>. If
+ the <start-time> is also zero, the session is regarded as permanent.
+
+ User interfaces SHOULD strongly discourage the creation of unbounded
+ and permanent sessions as they give no information about when the
+ session is actually going to terminate, and so make scheduling
+ difficult.
+
+ The general assumption may be made, when displaying unbounded
+ sessions that have not timed out to the user, that an unbounded
+ session will only be active until half an hour from the current time
+
+
+
+Handley, et al. Standards Track [Page 17]
+
+RFC 4566 SDP July 2006
+
+
+ or the session start time, whichever is the later. If behaviour
+ other than this is required, an end-time SHOULD be given and modified
+ as appropriate when new information becomes available about when the
+ session should really end.
+
+ Permanent sessions may be shown to the user as never being active
+ unless there are associated repeat times that state precisely when
+ the session will be active.
+
+5.10. Repeat Times ("r=")
+
+ r=<repeat interval> <active duration> <offsets from start-time>
+
+ "r=" fields specify repeat times for a session. For example, if a
+ session is active at 10am on Monday and 11am on Tuesday for one hour
+ each week for three months, then the <start-time> in the
+ corresponding "t=" field would be the NTP representation of 10am on
+ the first Monday, the <repeat interval> would be 1 week, the <active
+ duration> would be 1 hour, and the offsets would be zero and 25
+ hours. The corresponding "t=" field stop time would be the NTP
+ representation of the end of the last session three months later. By
+ default, all fields are in seconds, so the "r=" and "t=" fields might
+ be the following:
+
+ t=3034423619 3042462419
+ r=604800 3600 0 90000
+
+ To make description more compact, times may also be given in units of
+ days, hours, or minutes. The syntax for these is a number
+ immediately followed by a single case-sensitive character.
+ Fractional units are not allowed -- a smaller unit should be used
+ instead. The following unit specification characters are allowed:
+
+ d - days (86400 seconds)
+ h - hours (3600 seconds)
+ m - minutes (60 seconds)
+ s - seconds (allowed for completeness)
+
+ Thus, the above session announcement could also have been written:
+
+ r=7d 1h 0 25h
+
+ Monthly and yearly repeats cannot be directly specified with a single
+ SDP repeat time; instead, separate "t=" fields should be used to
+ explicitly list the session times.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 18]
+
+RFC 4566 SDP July 2006
+
+
+5.11. Time Zones ("z=")
+
+ z=<adjustment time> <offset> <adjustment time> <offset> ....
+
+ To schedule a repeated session that spans a change from daylight
+ saving time to standard time or vice versa, it is necessary to
+ specify offsets from the base time. This is required because
+ different time zones change time at different times of day, different
+ countries change to or from daylight saving time on different dates,
+ and some countries do not have daylight saving time at all.
+
+ Thus, in order to schedule a session that is at the same time winter
+ and summer, it must be possible to specify unambiguously by whose
+ time zone a session is scheduled. To simplify this task for
+ receivers, we allow the sender to specify the NTP time that a time
+ zone adjustment happens and the offset from the time when the session
+ was first scheduled. The "z=" field allows the sender to specify a
+ list of these adjustment times and offsets from the base time.
+
+ An example might be the following:
+
+ z=2882844526 -1h 2898848070 0
+
+ This specifies that at time 2882844526, the time base by which the
+ session's repeat times are calculated is shifted back by 1 hour, and
+ that at time 2898848070, the session's original time base is
+ restored. Adjustments are always relative to the specified start
+ time -- they are not cumulative. Adjustments apply to all "t=" and
+ "r=" lines in a session description.
+
+ If a session is likely to last several years, it is expected that the
+ session announcement will be modified periodically rather than
+ transmit several years' worth of adjustments in one session
+ announcement.
+
+5.12. Encryption Keys ("k=")
+
+ k=<method>
+ k=<method>:<encryption key>
+
+ If transported over a secure and trusted channel, the Session
+ Description Protocol MAY be used to convey encryption keys. A simple
+ mechanism for key exchange is provided by the key field ("k="),
+ although this is primarily supported for compatibility with older
+ implementations and its use is NOT RECOMMENDED. Work is in progress
+ to define new key exchange mechanisms for use with SDP [27] [28], and
+ it is expected that new applications will use those mechanisms.
+
+
+
+
+Handley, et al. Standards Track [Page 19]
+
+RFC 4566 SDP July 2006
+
+
+ A key field is permitted before the first media entry (in which case
+ it applies to all media in the session), or for each media entry as
+ required. The format of keys and their usage are outside the scope
+ of this document, and the key field provides no way to indicate the
+ encryption algorithm to be used, key type, or other information about
+ the key: this is assumed to be provided by the higher-level protocol
+ using SDP. If there is a need to convey this information within SDP,
+ the extensions mentioned previously SHOULD be used. Many security
+ protocols require two keys: one for confidentiality, another for
+ integrity. This specification does not support transfer of two keys.
+
+ The method indicates the mechanism to be used to obtain a usable key
+ by external means, or from the encoded encryption key given. The
+ following methods are defined:
+
+ k=clear:<encryption key>
+
+ The encryption key is included untransformed in this key field.
+ This method MUST NOT be used unless it can be guaranteed that
+ the SDP is conveyed over a secure channel. The encryption key
+ is interpreted as text according to the charset attribute; use
+ the "k=base64:" method to convey characters that are otherwise
+ prohibited in SDP.
+
+ k=base64:<encoded encryption key>
+
+ The encryption key is included in this key field but has been
+ base64 encoded [12] because it includes characters that are
+ prohibited in SDP. This method MUST NOT be used unless it can
+ be guaranteed that the SDP is conveyed over a secure channel.
+
+ k=uri:<URI to obtain key>
+
+ A Uniform Resource Identifier is included in the key field.
+ The URI refers to the data containing the key, and may require
+ additional authentication before the key can be returned. When
+ a request is made to the given URI, the reply should specify
+ the encoding for the key. The URI is often an Secure Socket
+ Layer/Transport Layer Security (SSL/TLS)-protected HTTP URI
+ ("https:"), although this is not required.
+
+ k=prompt
+
+ No key is included in this SDP description, but the session or
+ media stream referred to by this key field is encrypted. The
+ user should be prompted for the key when attempting to join the
+ session, and this user-supplied key should then be used to
+
+
+
+
+Handley, et al. Standards Track [Page 20]
+
+RFC 4566 SDP July 2006
+
+
+ decrypt the media streams. The use of user-specified keys is
+ NOT RECOMMENDED, since such keys tend to have weak security
+ properties.
+
+ The key field MUST NOT be used unless it can be guaranteed that the
+ SDP is conveyed over a secure and trusted channel. An example of
+ such a channel might be SDP embedded inside an S/MIME message or a
+ TLS-protected HTTP session. It is important to ensure that the
+ secure channel is with the party that is authorised to join the
+ session, not an intermediary: if a caching proxy server is used, it
+ is important to ensure that the proxy is either trusted or unable to
+ access the SDP.
+
+5.13. Attributes ("a=")
+
+ a=<attribute>
+ a=<attribute>:<value>
+
+ Attributes are the primary means for extending SDP. Attributes may
+ be defined to be used as "session-level" attributes, "media-level"
+ attributes, or both.
+
+ A media description may have any number of attributes ("a=" fields)
+ that are media specific. These are referred to as "media-level"
+ attributes and add information about the media stream. Attribute
+ fields can also be added before the first media field; these
+ "session-level" attributes convey additional information that applies
+ to the conference as a whole rather than to individual media.
+
+ Attribute fields may be of two forms:
+
+ o A property attribute is simply of the form "a=<flag>". These are
+ binary attributes, and the presence of the attribute conveys that
+ the attribute is a property of the session. An example might be
+ "a=recvonly".
+
+ o A value attribute is of the form "a=<attribute>:<value>". For
+ example, a whiteboard could have the value attribute "a=orient:
+ landscape"
+
+ Attribute interpretation depends on the media tool being invoked.
+ Thus receivers of session descriptions should be configurable in
+ their interpretation of session descriptions in general and of
+ attributes in particular.
+
+ Attribute names MUST use the US-ASCII subset of ISO-10646/UTF-8.
+
+
+
+
+
+Handley, et al. Standards Track [Page 21]
+
+RFC 4566 SDP July 2006
+
+
+ Attribute values are octet strings, and MAY use any octet value
+ except 0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default, attribute
+ values are to be interpreted as in ISO-10646 character set with UTF-8
+ encoding. Unlike other text fields, attribute values are NOT
+ normally affected by the "charset" attribute as this would make
+ comparisons against known values problematic. However, when an
+ attribute is defined, it can be defined to be charset dependent, in
+ which case its value should be interpreted in the session charset
+ rather than in ISO-10646.
+
+ Attributes MUST be registered with IANA (see Section 8). If an
+ attribute is received that is not understood, it MUST be ignored by
+ the receiver.
+
+5.14. Media Descriptions ("m=")
+
+ m=<media> <port> <proto> <fmt> ...
+
+ A session description may contain a number of media descriptions.
+ Each media description starts with an "m=" field and is terminated by
+ either the next "m=" field or by the end of the session description.
+ A media field has several sub-fields:
+
+ <media> is the media type. Currently defined media are "audio",
+ "video", "text", "application", and "message", although this list
+ may be extended in the future (see Section 8).
+
+ <port> is the transport port to which the media stream is sent. The
+ meaning of the transport port depends on the network being used as
+ specified in the relevant "c=" field, and on the transport
+ protocol defined in the <proto> sub-field of the media field.
+ Other ports used by the media application (such as the RTP Control
+ Protocol (RTCP) port [19]) MAY be derived algorithmically from the
+ base media port or MAY be specified in a separate attribute (for
+ example, "a=rtcp:" as defined in [22]).
+
+ If non-contiguous ports are used or if they don't follow the
+ parity rule of even RTP ports and odd RTCP ports, the "a=rtcp:"
+ attribute MUST be used. Applications that are requested to send
+ media to a <port> that is odd and where the "a=rtcp:" is present
+ MUST NOT subtract 1 from the RTP port: that is, they MUST send the
+ RTP to the port indicated in <port> and send the RTCP to the port
+ indicated in the "a=rtcp" attribute.
+
+ For applications where hierarchically encoded streams are being
+ sent to a unicast address, it may be necessary to specify multiple
+ transport ports. This is done using a similar notation to that
+ used for IP multicast addresses in the "c=" field:
+
+
+
+Handley, et al. Standards Track [Page 22]
+
+RFC 4566 SDP July 2006
+
+
+ m=<media> <port>/<number of ports> <proto> <fmt> ...
+
+ In such a case, the ports used depend on the transport protocol.
+ For RTP, the default is that only the even-numbered ports are used
+ for data with the corresponding one-higher odd ports used for the
+ RTCP belonging to the RTP session, and the <number of ports>
+ denoting the number of RTP sessions. For example:
+
+ m=video 49170/2 RTP/AVP 31
+
+ would specify that ports 49170 and 49171 form one RTP/RTCP pair
+ and 49172 and 49173 form the second RTP/RTCP pair. RTP/AVP is the
+ transport protocol and 31 is the format (see below). If non-
+ contiguous ports are required, they must be signalled using a
+ separate attribute (for example, "a=rtcp:" as defined in [22]).
+
+ If multiple addresses are specified in the "c=" field and multiple
+ ports are specified in the "m=" field, a one-to-one mapping from
+ port to the corresponding address is implied. For example:
+
+ c=IN IP4 224.2.1.1/127/2
+ m=video 49170/2 RTP/AVP 31
+
+ would imply that address 224.2.1.1 is used with ports 49170 and
+ 49171, and address 224.2.1.2 is used with ports 49172 and 49173.
+
+ The semantics of multiple "m=" lines using the same transport
+ address are undefined. This implies that, unlike limited past
+ practice, there is no implicit grouping defined by such means and
+ an explicit grouping framework (for example, [18]) should instead
+ be used to express the intended semantics.
+
+ <proto> is the transport protocol. The meaning of the transport
+ protocol is dependent on the address type field in the relevant
+ "c=" field. Thus a "c=" field of IP4 indicates that the transport
+ protocol runs over IP4. The following transport protocols are
+ defined, but may be extended through registration of new protocols
+ with IANA (see Section 8):
+
+ * udp: denotes an unspecified protocol running over UDP.
+
+ * RTP/AVP: denotes RTP [19] used under the RTP Profile for Audio
+ and Video Conferences with Minimal Control [20] running over
+ UDP.
+
+ * RTP/SAVP: denotes the Secure Real-time Transport Protocol [23]
+ running over UDP.
+
+
+
+
+Handley, et al. Standards Track [Page 23]
+
+RFC 4566 SDP July 2006
+
+
+ The main reason to specify the transport protocol in addition to
+ the media format is that the same standard media formats may be
+ carried over different transport protocols even when the network
+ protocol is the same -- a historical example is vat Pulse Code
+ Modulation (PCM) audio and RTP PCM audio; another might be TCP/RTP
+ PCM audio. In addition, relays and monitoring tools that are
+ transport-protocol-specific but format-independent are possible.
+
+ <fmt> is a media format description. The fourth and any subsequent
+ sub-fields describe the format of the media. The interpretation
+ of the media format depends on the value of the <proto> sub-field.
+
+ If the <proto> sub-field is "RTP/AVP" or "RTP/SAVP" the <fmt>
+ sub-fields contain RTP payload type numbers. When a list of
+ payload type numbers is given, this implies that all of these
+ payload formats MAY be used in the session, but the first of these
+ formats SHOULD be used as the default format for the session. For
+ dynamic payload type assignments the "a=rtpmap:" attribute (see
+ Section 6) SHOULD be used to map from an RTP payload type number
+ to a media encoding name that identifies the payload format. The
+ "a=fmtp:" attribute MAY be used to specify format parameters (see
+ Section 6).
+
+ If the <proto> sub-field is "udp" the <fmt> sub-fields MUST
+ reference a media type describing the format under the "audio",
+ "video", "text", "application", or "message" top-level media
+ types. The media type registration SHOULD define the packet
+ format for use with UDP transport.
+
+ For media using other transport protocols, the <fmt> field is
+ protocol specific. Rules for interpretation of the <fmt> sub-
+ field MUST be defined when registering new protocols (see Section
+ 8.2.2).
+
+6. SDP Attributes
+
+ The following attributes are defined. Since application writers may
+ add new attributes as they are required, this list is not exhaustive.
+ Registration procedures for new attributes are defined in Section
+ 8.2.4.
+
+ a=cat:<category>
+
+ This attribute gives the dot-separated hierarchical category of
+ the session. This is to enable a receiver to filter unwanted
+ sessions by category. There is no central registry of
+ categories. It is a session-level attribute, and it is not
+ dependent on charset.
+
+
+
+Handley, et al. Standards Track [Page 24]
+
+RFC 4566 SDP July 2006
+
+
+ a=keywds:<keywords>
+
+ Like the cat attribute, this is to assist identifying wanted
+ sessions at the receiver. This allows a receiver to select
+ interesting session based on keywords describing the purpose of
+ the session; there is no central registry of keywords. It is a
+ session-level attribute. It is a charset-dependent attribute,
+ meaning that its value should be interpreted in the charset
+ specified for the session description if one is specified, or
+ by default in ISO 10646/UTF-8.
+
+ a=tool:<name and version of tool>
+
+ This gives the name and version number of the tool used to
+ create the session description. It is a session-level
+ attribute, and it is not dependent on charset.
+
+ a=ptime:<packet time>
+
+ This gives the length of time in milliseconds represented by
+ the media in a packet. This is probably only meaningful for
+ audio data, but may be used with other media types if it makes
+ sense. It should not be necessary to know ptime to decode RTP
+ or vat audio, and it is intended as a recommendation for the
+ encoding/packetisation of audio. It is a media-level
+ attribute, and it is not dependent on charset.
+
+ a=maxptime:<maximum packet time>
+
+ This gives the maximum amount of media that can be encapsulated
+ in each packet, expressed as time in milliseconds. The time
+ SHALL be calculated as the sum of the time the media present in
+ the packet represents. For frame-based codecs, the time SHOULD
+ be an integer multiple of the frame size. This attribute is
+ probably only meaningful for audio data, but may be used with
+ other media types if it makes sense. It is a media-level
+ attribute, and it is not dependent on charset. Note that this
+ attribute was introduced after RFC 2327, and non-updated
+ implementations will ignore this attribute.
+
+ a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding
+ parameters>]
+
+ This attribute maps from an RTP payload type number (as used in
+ an "m=" line) to an encoding name denoting the payload format
+ to be used. It also provides information on the clock rate and
+ encoding parameters. It is a media-level attribute that is not
+ dependent on charset.
+
+
+
+Handley, et al. Standards Track [Page 25]
+
+RFC 4566 SDP July 2006
+
+
+ Although an RTP profile may make static assignments of payload
+ type numbers to payload formats, it is more common for that
+ assignment to be done dynamically using "a=rtpmap:" attributes.
+ As an example of a static payload type, consider u-law PCM
+ coded single-channel audio sampled at 8 kHz. This is
+ completely defined in the RTP Audio/Video profile as payload
+ type 0, so there is no need for an "a=rtpmap:" attribute, and
+ the media for such a stream sent to UDP port 49232 can be
+ specified as:
+
+ m=audio 49232 RTP/AVP 0
+
+ An example of a dynamic payload type is 16-bit linear encoded
+ stereo audio sampled at 16 kHz. If we wish to use the dynamic
+ RTP/AVP payload type 98 for this stream, additional information
+ is required to decode it:
+
+ m=audio 49232 RTP/AVP 98
+ a=rtpmap:98 L16/16000/2
+
+ Up to one rtpmap attribute can be defined for each media format
+ specified. Thus, we might have the following:
+
+ m=audio 49230 RTP/AVP 96 97 98
+ a=rtpmap:96 L8/8000
+ a=rtpmap:97 L16/8000
+ a=rtpmap:98 L16/11025/2
+
+ RTP profiles that specify the use of dynamic payload types MUST
+ define the set of valid encoding names and/or a means to
+ register encoding names if that profile is to be used with SDP.
+ The "RTP/AVP" and "RTP/SAVP" profiles use media subtypes for
+ encoding names, under the top-level media type denoted in the
+ "m=" line. In the example above, the media types are
+ "audio/l8" and "audio/l16".
+
+ For audio streams, <encoding parameters> indicates the number
+ of audio channels. This parameter is OPTIONAL and may be
+ omitted if the number of channels is one, provided that no
+ additional parameters are needed.
+
+ For video streams, no encoding parameters are currently
+ specified.
+
+ Additional encoding parameters MAY be defined in the future,
+ but codec-specific parameters SHOULD NOT be added. Parameters
+ added to an "a=rtpmap:" attribute SHOULD only be those required
+ for a session directory to make the choice of appropriate media
+
+
+
+Handley, et al. Standards Track [Page 26]
+
+RFC 4566 SDP July 2006
+
+
+ to participate in a session. Codec-specific parameters should
+ be added in other attributes (for example, "a=fmtp:").
+
+ Note: RTP audio formats typically do not include information
+ about the number of samples per packet. If a non-default (as
+ defined in the RTP Audio/Video Profile) packetisation is
+ required, the "ptime" attribute is used as given above.
+
+ a=recvonly
+
+ This specifies that the tools should be started in receive-only
+ mode where applicable. It can be either a session- or media-
+ level attribute, and it is not dependent on charset. Note that
+ recvonly applies to the media only, not to any associated
+ control protocol (e.g., an RTP-based system in recvonly mode
+ SHOULD still send RTCP packets).
+
+ a=sendrecv
+
+ This specifies that the tools should be started in send and
+ receive mode. This is necessary for interactive conferences
+ with tools that default to receive-only mode. It can be either
+ a session or media-level attribute, and it is not dependent on
+ charset.
+
+ If none of the attributes "sendonly", "recvonly", "inactive",
+ and "sendrecv" is present, "sendrecv" SHOULD be assumed as the
+ default for sessions that are not of the conference type
+ "broadcast" or "H332" (see below).
+
+ a=sendonly
+
+ This specifies that the tools should be started in send-only
+ mode. An example may be where a different unicast address is
+ to be used for a traffic destination than for a traffic source.
+ In such a case, two media descriptions may be used, one
+ sendonly and one recvonly. It can be either a session- or
+ media-level attribute, but would normally only be used as a
+ media attribute. It is not dependent on charset. Note that
+ sendonly applies only to the media, and any associated control
+ protocol (e.g., RTCP) SHOULD still be received and processed as
+ normal.
+
+ a=inactive
+
+ This specifies that the tools should be started in inactive
+ mode. This is necessary for interactive conferences where
+ users can put other users on hold. No media is sent over an
+
+
+
+Handley, et al. Standards Track [Page 27]
+
+RFC 4566 SDP July 2006
+
+
+ inactive media stream. Note that an RTP-based system SHOULD
+ still send RTCP, even if started inactive. It can be either a
+ session or media-level attribute, and it is not dependent on
+ charset.
+
+ a=orient:<orientation>
+
+ Normally this is only used for a whiteboard or presentation
+ tool. It specifies the orientation of a the workspace on the
+ screen. It is a media-level attribute. Permitted values are
+ "portrait", "landscape", and "seascape" (upside-down
+ landscape). It is not dependent on charset.
+
+ a=type:<conference type>
+
+ This specifies the type of the conference. Suggested values
+ are "broadcast", "meeting", "moderated", "test", and "H332".
+ "recvonly" should be the default for "type:broadcast" sessions,
+ "type:meeting" should imply "sendrecv", and "type:moderated"
+ should indicate the use of a floor control tool and that the
+ media tools are started so as to mute new sites joining the
+ conference.
+
+ Specifying the attribute "type:H332" indicates that this
+ loosely coupled session is part of an H.332 session as defined
+ in the ITU H.332 specification [26]. Media tools should be
+ started "recvonly".
+
+ Specifying the attribute "type:test" is suggested as a hint
+ that, unless explicitly requested otherwise, receivers can
+ safely avoid displaying this session description to users.
+
+ The type attribute is a session-level attribute, and it is not
+ dependent on charset.
+
+ a=charset:<character set>
+
+ This specifies the character set to be used to display the
+ session name and information data. By default, the ISO-10646
+ character set in UTF-8 encoding is used. If a more compact
+ representation is required, other character sets may be used.
+ For example, the ISO 8859-1 is specified with the following SDP
+ attribute:
+
+ a=charset:ISO-8859-1
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 28]
+
+RFC 4566 SDP July 2006
+
+
+ This is a session-level attribute and is not dependent on
+ charset. The charset specified MUST be one of those registered
+ with IANA, such as ISO-8859-1. The character set identifier is
+ a US-ASCII string and MUST be compared against the IANA
+ identifiers using a case-insensitive comparison. If the
+ identifier is not recognised or not supported, all strings that
+ are affected by it SHOULD be regarded as octet strings.
+
+ Note that a character set specified MUST still prohibit the use
+ of bytes 0x00 (Nul), 0x0A (LF), and 0x0d (CR). Character sets
+ requiring the use of these characters MUST define a quoting
+ mechanism that prevents these bytes from appearing within text
+ fields.
+
+ a=sdplang:<language tag>
+
+ This can be a session-level attribute or a media-level
+ attribute. As a session-level attribute, it specifies the
+ language for the session description. As a media-level
+ attribute, it specifies the language for any media-level SDP
+ information field associated with that media. Multiple sdplang
+ attributes can be provided either at session or media level if
+ multiple languages in the session description or media use
+ multiple languages, in which case the order of the attributes
+ indicates the order of importance of the various languages in
+ the session or media from most important to least important.
+
+ In general, sending session descriptions consisting of multiple
+ languages is discouraged. Instead, multiple descriptions
+ SHOULD be sent describing the session, one in each language.
+ However, this is not possible with all transport mechanisms,
+ and so multiple sdplang attributes are allowed although NOT
+ RECOMMENDED.
+
+ The "sdplang" attribute value must be a single RFC 3066
+ language tag in US-ASCII [9]. It is not dependent on the
+ charset attribute. An "sdplang" attribute SHOULD be specified
+ when a session is of sufficient scope to cross geographic
+ boundaries where the language of recipients cannot be assumed,
+ or where the session is in a different language from the
+ locally assumed norm.
+
+ a=lang:<language tag>
+
+ This can be a session-level attribute or a media-level
+ attribute. As a session-level attribute, it specifies the
+ default language for the session being described. As a media-
+ level attribute, it specifies the language for that media,
+
+
+
+Handley, et al. Standards Track [Page 29]
+
+RFC 4566 SDP July 2006
+
+
+ overriding any session-level language specified. Multiple lang
+ attributes can be provided either at session or media level if
+ the session description or media use multiple languages, in
+ which case the order of the attributes indicates the order of
+ importance of the various languages in the session or media
+ from most important to least important.
+
+ The "lang" attribute value must be a single RFC 3066 language
+ tag in US-ASCII [9]. It is not dependent on the charset
+ attribute. A "lang" attribute SHOULD be specified when a
+ session is of sufficient scope to cross geographic boundaries
+ where the language of recipients cannot be assumed, or where
+ the session is in a different language from the locally assumed
+ norm.
+
+ a=framerate:<frame rate>
+
+ This gives the maximum video frame rate in frames/sec. It is
+ intended as a recommendation for the encoding of video data.
+ Decimal representations of fractional values using the notation
+ "<integer>.<fraction>" are allowed. It is a media-level
+ attribute, defined only for video media, and it is not
+ dependent on charset.
+
+ a=quality:<quality>
+
+ This gives a suggestion for the quality of the encoding as an
+ integer value. The intention of the quality attribute for
+ video is to specify a non-default trade-off between frame-rate
+ and still-image quality. For video, the value is in the range
+ 0 to 10, with the following suggested meaning:
+
+ 10 - the best still-image quality the compression scheme can
+ give.
+ 5 - the default behaviour given no quality suggestion.
+ 0 - the worst still-image quality the codec designer thinks
+ is still usable.
+
+ It is a media-level attribute, and it is not dependent on
+ charset.
+
+ a=fmtp:<format> <format specific parameters>
+
+ This attribute allows parameters that are specific to a
+ particular format to be conveyed in a way that SDP does not
+ have to understand them. The format must be one of the formats
+ specified for the media. Format-specific parameters may be any
+ set of parameters required to be conveyed by SDP and given
+
+
+
+Handley, et al. Standards Track [Page 30]
+
+RFC 4566 SDP July 2006
+
+
+ unchanged to the media tool that will use this format. At most
+ one instance of this attribute is allowed for each format.
+
+ It is a media-level attribute, and it is not dependent on
+ charset.
+
+7. Security Considerations
+
+ SDP is frequently used with the Session Initiation Protocol [15]
+ using the offer/answer model [17] to agree on parameters for unicast
+ sessions. When used in this manner, the security considerations of
+ those protocols apply.
+
+ SDP is a session description format that describes multimedia
+ sessions. Entities receiving and acting upon an SDP message SHOULD
+ be aware that a session description cannot be trusted unless it has
+ been obtained by an authenticated transport protocol from a known and
+ trusted source. Many different transport protocols may be used to
+ distribute session description, and the nature of the authentication
+ will differ from transport to transport. For some transports,
+ security features are often not deployed. In case a session
+ description has not been obtained in a trusted manner, the endpoint
+ SHOULD exercise care because, among other attacks, the media sessions
+ received may not be the intended ones, the destination where media is
+ sent to may not be the expected one, any of the parameters of the
+ session may be incorrect, or the media security may be compromised.
+ It is up to the endpoint to make a sensible decision taking into
+ account the security risks of the application and the user
+ preferences and may decide to ask the user whether or not to accept
+ the session.
+
+ One transport that can be used to distribute session descriptions is
+ the Session Announcement Protocol (SAP). SAP provides both
+ encryption and authentication mechanisms, but due to the nature of
+ session announcements it is likely that there are many occasions
+ where the originator of a session announcement cannot be
+ authenticated because the originator is previously unknown to the
+ receiver of the announcement and because no common public key
+ infrastructure is available.
+
+ On receiving a session description over an unauthenticated transport
+ mechanism or from an untrusted party, software parsing the session
+ should take a few precautions. Session descriptions contain
+ information required to start software on the receiver's system.
+ Software that parses a session description MUST NOT be able to start
+ other software except that which is specifically configured as
+ appropriate software to participate in multimedia sessions. It is
+ normally considered inappropriate for software parsing a session
+
+
+
+Handley, et al. Standards Track [Page 31]
+
+RFC 4566 SDP July 2006
+
+
+ description to start, on a user's system, software that is
+ appropriate to participate in multimedia sessions, without the user
+ first being informed that such software will be started and giving
+ the user's consent. Thus, a session description arriving by session
+ announcement, email, session invitation, or WWW page MUST NOT deliver
+ the user into an interactive multimedia session unless the user has
+ explicitly pre-authorised such action. As it is not always simple to
+ tell whether or not a session is interactive, applications that are
+ unsure should assume sessions are interactive.
+
+ In this specification, there are no attributes that would allow the
+ recipient of a session description to be informed to start multimedia
+ tools in a mode where they default to transmitting. Under some
+ circumstances it might be appropriate to define such attributes. If
+ this is done, an application parsing a session description containing
+ such attributes SHOULD either ignore them or inform the user that
+ joining this session will result in the automatic transmission of
+ multimedia data. The default behaviour for an unknown attribute is
+ to ignore it.
+
+ In certain environments, it has become common for intermediary
+ systems to intercept and analyse session descriptions contained
+ within other signalling protocols. This is done for a range of
+ purposes, including but not limited to opening holes in firewalls to
+ allow media streams to pass, or to mark, prioritize, or block traffic
+ selectively. In some cases, such intermediary systems may modify the
+ session description, for example, to have the contents of the session
+ description match NAT bindings dynamically created. These behaviours
+ are NOT RECOMMENDED unless the session description is conveyed in
+ such a manner that allows the intermediary system to conduct proper
+ checks to establish the authenticity of the session description, and
+ the authority of its source to establish such communication sessions.
+ SDP by itself does not include sufficient information to enable these
+ checks: they depend on the encapsulating protocol (e.g., SIP or
+ RTSP).
+
+ Use of the "k=" field poses a significant security risk, since it
+ conveys session encryption keys in the clear. SDP MUST NOT be used
+ to convey key material, unless it can be guaranteed that the channel
+ over which the SDP is delivered is both private and authenticated.
+ Moreover, the "k=" line provides no way to indicate or negotiate
+ cryptographic key algorithms. As it provides for only a single
+ symmetric key, rather than separate keys for confidentiality and
+ integrity, its utility is severely limited. The use of the "k=" line
+ is NOT RECOMMENDED, as discussed in Section 5.12.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 32]
+
+RFC 4566 SDP July 2006
+
+
+8. IANA Considerations
+
+8.1. The "application/sdp" Media Type
+
+ One media type registration from RFC 2327 is to be updated, as
+ defined below.
+
+ Subject: Registration of media type "application/sdp"
+
+ Type name: application
+
+ Subtype name: sdp
+
+ Required parameters: None.
+
+ Optional parameters: None.
+
+ Encoding considerations:
+ SDP files are primarily UTF-8 format text. The "a=charset:"
+ attribute may be used to signal the presence of other
+ character sets in certain parts of an SDP file (see
+ Section 6 of RFC 4566). Arbitrary binary content cannot
+ be directly represented in SDP.
+
+ Security considerations:
+ See Section 7 of RFC 4566
+
+ Interoperability considerations:
+ See RFC 4566
+
+ Published specification:
+ See RFC 4566
+
+ Applications which use this media type:
+ Voice over IP, video teleconferencing, streaming media, instant
+ messaging, among others. See also Section 3 of RFC 4566.
+
+ Additional information:
+
+ Magic number(s): None.
+ File extension(s): The extension ".sdp" is commonly used.
+ Macintosh File Type Code(s): "sdp "
+
+ Person & email address to contact for further information:
+ Mark Handley <[email protected]>
+ Colin Perkins <[email protected]>
+ IETF MMUSIC working group <[email protected]>
+
+
+
+Handley, et al. Standards Track [Page 33]
+
+RFC 4566 SDP July 2006
+
+
+ Intended usage: COMMON
+
+ Author/Change controller:
+ Authors of RFC 4566
+ IETF MMUSIC working group delegated from the IESG
+
+8.2. Registration of Parameters
+
+ There are seven field names that may be registered with IANA. Using
+ the terminology in the SDP specification Backus-Naur Form (BNF), they
+ are "media", "proto", "fmt", "att-field", "bwtype", "nettype", and
+ "addrtype".
+
+8.2.1. Media Types ("media")
+
+ The set of media types is intended to be small and SHOULD NOT be
+ extended except under rare circumstances. The same rules should
+ apply for media names as for top-level media content types, and where
+ possible the same name should be registered for SDP as for MIME. For
+ media other than existing top-level media content types, a Standards
+ Track RFC MUST be produced for a new top-level content type to be
+ registered, and the registration MUST provide good justification why
+ no existing media name is appropriate (the "Standards Action" policy
+ of RFC 2434 [8].
+
+ This memo registers the media types "audio", "video", "text",
+ "application", and "message".
+
+ Note: The media types "control" and "data" were listed as valid in
+ the previous version of this specification [6]; however, their
+ semantics were never fully specified and they are not widely used.
+ These media types have been removed in this specification, although
+ they still remain valid media type capabilities for a SIP user agent
+ as defined in RFC 3840 [24]. If these media types are considered
+ useful in the future, a Standards Track RFC MUST be produced to
+ document their use. Until that is done, applications SHOULD NOT use
+ these types and SHOULD NOT declare support for them in SIP
+ capabilities declarations (even though they exist in the registry
+ created by RFC 3840).
+
+8.2.2. Transport Protocols ("proto")
+
+ The "proto" field describes the transport protocol used. This SHOULD
+ reference a standards-track protocol RFC. This memo registers three
+ values: "RTP/AVP" is a reference to RTP [19] used under the RTP
+ Profile for Audio and Video Conferences with Minimal Control [20]
+
+
+
+
+
+Handley, et al. Standards Track [Page 34]
+
+RFC 4566 SDP July 2006
+
+
+ running over UDP/IP, "RTP/SAVP" is a reference to the Secure Real-
+ time Transport Protocol [23], and "udp" indicates an unspecified
+ protocol over UDP.
+
+ If other RTP profiles are defined in the future, their "proto" name
+ SHOULD be specified in the same manner. For example, an RTP profile
+ whose short name is "XYZ" would be denoted by a "proto" field of
+ "RTP/XYZ".
+
+ New transport protocols SHOULD be registered with IANA.
+ Registrations MUST reference an RFC describing the protocol. Such an
+ RFC MAY be Experimental or Informational, although it is preferable
+ that it be Standards Track. Registrations MUST also define the rules
+ by which their "fmt" namespace is managed (see below).
+
+8.2.3. Media Formats ("fmt")
+
+ Each transport protocol, defined by the "proto" field, has an
+ associated "fmt" namespace that describes the media formats that may
+ be conveyed by that protocol. Formats cover all the possible
+ encodings that might want to be transported in a multimedia session.
+
+ RTP payload formats under the "RTP/AVP" and "RTP/SAVP" profiles MUST
+ use the payload type number as their "fmt" value. If the payload
+ type number is dynamically assigned by this session description, an
+ additional "rtpmap" attribute MUST be included to specify the format
+ name and parameters as defined by the media type registration for the
+ payload format. It is RECOMMENDED that other RTP profiles that are
+ registered (in combination with RTP) as SDP transport protocols
+ specify the same rules for the "fmt" namespace.
+
+ For the "udp" protocol, new formats SHOULD be registered. Use of an
+ existing media subtype for the format is encouraged. If no media
+ subtype exists, it is RECOMMENDED that a suitable one be registered
+ through the IETF process [31] by production of, or reference to, a
+ standards-track RFC that defines the transport protocol for the
+ format.
+
+ For other protocols, formats MAY be registered according to the rules
+ of the associated "proto" specification.
+
+ Registrations of new formats MUST specify which transport protocols
+ they apply to.
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 35]
+
+RFC 4566 SDP July 2006
+
+
+8.2.4. Attribute Names ("att-field")
+
+ Attribute field names ("att-field") MUST be registered with IANA and
+ documented, because of noticeable issues due to conflicting
+ attributes under the same name. Unknown attributes in SDP are simply
+ ignored, but conflicting ones that fragment the protocol are a
+ serious problem.
+
+ New attribute registrations are accepted according to the
+ "Specification Required" policy of RFC 2434, provided that the
+ specification includes the following information:
+
+ o contact name, email address, and telephone number
+
+ o attribute name (as it will appear in SDP)
+
+ o long-form attribute name in English
+
+ o type of attribute (session level, media level, or both)
+
+ o whether the attribute value is subject to the charset attribute
+
+ o a one-paragraph explanation of the purpose of the attribute
+
+ o a specification of appropriate attribute values for this attribute
+
+ The above is the minimum that IANA will accept. Attributes that are
+ expected to see widespread use and interoperability SHOULD be
+ documented with a standards-track RFC that specifies the attribute
+ more precisely.
+
+ Submitters of registrations should ensure that the specification is
+ in the spirit of SDP attributes, most notably that the attribute is
+ platform independent in the sense that it makes no implicit
+ assumptions about operating systems and does not name specific pieces
+ of software in a manner that might inhibit interoperability.
+
+ IANA has registered the following initial set of attribute names
+ ("att-field" values), with definitions as in Section 6 of this memo
+ (these definitions update those in RFC 2327):
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 36]
+
+RFC 4566 SDP July 2006
+
+
+ Name | Session or Media level? | Dependent on charset?
+ ----------+-------------------------+----------------------
+ cat | Session | No
+ keywds | Session | Yes
+ tool | Session | No
+ ptime | Media | No
+ maxptime | Media | No
+ rtpmap | Media | No
+ recvonly | Either | No
+ sendrecv | Either | No
+ sendonly | Either | No
+ inactive | Either | No
+ orient | Media | No
+ type | Session | No
+ charset | Session | No
+ sdplang | Either | No
+ lang | Either | No
+ framerate | Media | No
+ quality | Media | No
+ fmtp | Media | No
+
+8.2.5. Bandwidth Specifiers ("bwtype")
+
+ A proliferation of bandwidth specifiers is strongly discouraged.
+
+ New bandwidth specifiers ("bwtype" fields) MUST be registered with
+ IANA. The submission MUST reference a standards-track RFC specifying
+ the semantics of the bandwidth specifier precisely, and indicating
+ when it should be used, and why the existing registered bandwidth
+ specifiers do not suffice.
+
+ IANA has registered the bandwidth specifiers "CT" and "AS" with
+ definitions as in Section 5.8 of this memo (these definitions update
+ those in RFC 2327).
+
+8.2.6. Network Types ("nettype")
+
+ New network types (the "nettype" field) may be registered with IANA
+ if SDP needs to be used in the context of non-Internet environments.
+ Although these are not normally the preserve of IANA, there may be
+ circumstances when an Internet application needs to interoperate with
+ a non-Internet application, such as when gatewaying an Internet
+ telephone call into the Public Switched Telephone Network (PSTN).
+ The number of network types should be small and should be rarely
+ extended. A new network type cannot be registered without
+ registering at least one address type to be used with that network
+
+
+
+
+
+Handley, et al. Standards Track [Page 37]
+
+RFC 4566 SDP July 2006
+
+
+ type. A new network type registration MUST reference an RFC that
+ gives details of the network type and address type and specifies how
+ and when they would be used.
+
+ IANA has registered the network type "IN" to represent the Internet,
+ with definition as in Sections 5.2 and 5.7 of this memo (these
+ definitions update those in RFC 2327).
+
+8.2.7. Address Types ("addrtype")
+
+ New address types ("addrtype") may be registered with IANA. An
+ address type is only meaningful in the context of a network type, and
+ any registration of an address type MUST specify a registered network
+ type or be submitted along with a network type registration. A new
+ address type registration MUST reference an RFC giving details of the
+ syntax of the address type. Address types are not expected to be
+ registered frequently.
+
+ IANA has registered the address types "IP4" and "IP6" with
+ definitions as in Sections 5.2 and 5.7 of this memo (these
+ definitions update those in RFC 2327).
+
+8.2.8. Registration Procedure
+
+ In the RFC documentation that registers SDP "media", "proto", "fmt",
+ "bwtype", "nettype", and "addrtype" fields, the authors MUST include
+ the following information for IANA to place in the appropriate
+ registry:
+
+ o contact name, email address, and telephone number
+
+ o name being registered (as it will appear in SDP)
+
+ o long-form name in English
+
+ o type of name ("media", "proto", "fmt", "bwtype", "nettype", or
+ "addrtype")
+
+ o a one-paragraph explanation of the purpose of the registered name
+
+ o a reference to the specification for the registered name (this
+ will typically be an RFC number)
+
+ IANA may refer any registration to the IESG for review, and may
+ request revisions to be made before a registration will be made.
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 38]
+
+RFC 4566 SDP July 2006
+
+
+8.3. Encryption Key Access Methods
+
+ The IANA previously maintained a table of SDP encryption key access
+ method ("enckey") names. This table is obsolete, since the "k=" line
+ is not extensible. New registrations MUST NOT be accepted.
+
+9. SDP Grammar
+
+ This section provides an Augmented BNF grammar for SDP. ABNF is
+ defined in [4].
+
+ ; SDP Syntax
+ session-description = proto-version
+ origin-field
+ session-name-field
+ information-field
+ uri-field
+ email-fields
+ phone-fields
+ connection-field
+ bandwidth-fields
+ time-fields
+ key-field
+ attribute-fields
+ media-descriptions
+
+ proto-version = %x76 "=" 1*DIGIT CRLF
+ ;this memo describes version 0
+
+ origin-field = %x6f "=" username SP sess-id SP sess-version SP
+ nettype SP addrtype SP unicast-address CRLF
+
+ session-name-field = %x73 "=" text CRLF
+
+ information-field = [%x69 "=" text CRLF]
+
+ uri-field = [%x75 "=" uri CRLF]
+
+ email-fields = *(%x65 "=" email-address CRLF)
+
+ phone-fields = *(%x70 "=" phone-number CRLF)
+
+ connection-field = [%x63 "=" nettype SP addrtype SP
+ connection-address CRLF]
+ ;a connection field must be present
+ ;in every media description or at the
+ ;session-level
+
+
+
+
+Handley, et al. Standards Track [Page 39]
+
+RFC 4566 SDP July 2006
+
+
+ bandwidth-fields = *(%x62 "=" bwtype ":" bandwidth CRLF)
+
+ time-fields = 1*( %x74 "=" start-time SP stop-time
+ *(CRLF repeat-fields) CRLF)
+ [zone-adjustments CRLF]
+
+ repeat-fields = %x72 "=" repeat-interval SP typed-time
+ 1*(SP typed-time)
+
+ zone-adjustments = %x7a "=" time SP ["-"] typed-time
+ *(SP time SP ["-"] typed-time)
+
+ key-field = [%x6b "=" key-type CRLF]
+
+ attribute-fields = *(%x61 "=" attribute CRLF)
+
+ media-descriptions = *( media-field
+ information-field
+ *connection-field
+ bandwidth-fields
+ key-field
+ attribute-fields )
+
+ media-field = %x6d "=" media SP port ["/" integer]
+ SP proto 1*(SP fmt) CRLF
+
+ ; sub-rules of 'o='
+ username = non-ws-string
+ ;pretty wide definition, but doesn't
+ ;include space
+
+ sess-id = 1*DIGIT
+ ;should be unique for this username/host
+
+ sess-version = 1*DIGIT
+
+ nettype = token
+ ;typically "IN"
+
+ addrtype = token
+ ;typically "IP4" or "IP6"
+
+ ; sub-rules of 'u='
+ uri = URI-reference
+ ; see RFC 3986
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 40]
+
+RFC 4566 SDP July 2006
+
+
+ ; sub-rules of 'e=', see RFC 2822 for definitions
+ email-address = address-and-comment / dispname-and-address
+ / addr-spec
+ address-and-comment = addr-spec 1*SP "(" 1*email-safe ")"
+ dispname-and-address = 1*email-safe 1*SP "<" addr-spec ">"
+
+ ; sub-rules of 'p='
+ phone-number = phone *SP "(" 1*email-safe ")" /
+ 1*email-safe "<" phone ">" /
+ phone
+
+ phone = ["+"] DIGIT 1*(SP / "-" / DIGIT)
+
+ ; sub-rules of 'c='
+ connection-address = multicast-address / unicast-address
+
+ ; sub-rules of 'b='
+ bwtype = token
+
+ bandwidth = 1*DIGIT
+
+ ; sub-rules of 't='
+ start-time = time / "0"
+
+ stop-time = time / "0"
+
+ time = POS-DIGIT 9*DIGIT
+ ; Decimal representation of NTP time in
+ ; seconds since 1900. The representation
+ ; of NTP time is an unbounded length field
+ ; containing at least 10 digits. Unlike the
+ ; 64-bit representation used elsewhere, time
+ ; in SDP does not wrap in the year 2036.
+
+ ; sub-rules of 'r=' and 'z='
+ repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
+
+ typed-time = 1*DIGIT [fixed-len-time-unit]
+
+ fixed-len-time-unit = %x64 / %x68 / %x6d / %x73
+
+ ; sub-rules of 'k='
+ key-type = %x70 %x72 %x6f %x6d %x70 %x74 / ; "prompt"
+ %x63 %x6c %x65 %x61 %x72 ":" text / ; "clear:"
+ %x62 %x61 %x73 %x65 "64:" base64 / ; "base64:"
+ %x75 %x72 %x69 ":" uri ; "uri:"
+
+ base64 = *base64-unit [base64-pad]
+
+
+
+Handley, et al. Standards Track [Page 41]
+
+RFC 4566 SDP July 2006
+
+
+ base64-unit = 4base64-char
+ base64-pad = 2base64-char "==" / 3base64-char "="
+ base64-char = ALPHA / DIGIT / "+" / "/"
+
+ ; sub-rules of 'a='
+ attribute = (att-field ":" att-value) / att-field
+
+ att-field = token
+
+ att-value = byte-string
+
+ ; sub-rules of 'm='
+ media = token
+ ;typically "audio", "video", "text", or
+ ;"application"
+
+ fmt = token
+ ;typically an RTP payload type for audio
+ ;and video media
+
+ proto = token *("/" token)
+ ;typically "RTP/AVP" or "udp"
+
+ port = 1*DIGIT
+
+ ; generic sub-rules: addressing
+ unicast-address = IP4-address / IP6-address / FQDN / extn-addr
+
+ multicast-address = IP4-multicast / IP6-multicast / FQDN
+ / extn-addr
+
+ IP4-multicast = m1 3( "." decimal-uchar )
+ "/" ttl [ "/" integer ]
+ ; IPv4 multicast addresses may be in the
+ ; range 224.0.0.0 to 239.255.255.255
+
+ m1 = ("22" ("4"/"5"/"6"/"7"/"8"/"9")) /
+ ("23" DIGIT )
+
+ IP6-multicast = hexpart [ "/" integer ]
+ ; IPv6 address starting with FF
+
+ ttl = (POS-DIGIT *2DIGIT) / "0"
+
+ FQDN = 4*(alpha-numeric / "-" / ".")
+ ; fully qualified domain name as specified
+ ; in RFC 1035 (and updates)
+
+
+
+
+Handley, et al. Standards Track [Page 42]
+
+RFC 4566 SDP July 2006
+
+
+ IP4-address = b1 3("." decimal-uchar)
+
+ b1 = decimal-uchar
+ ; less than "224"
+
+ ; The following is consistent with RFC 2373 [30], Appendix B.
+ IP6-address = hexpart [ ":" IP4-address ]
+
+ hexpart = hexseq / hexseq "::" [ hexseq ] /
+ "::" [ hexseq ]
+
+ hexseq = hex4 *( ":" hex4)
+
+ hex4 = 1*4HEXDIG
+
+ ; Generic for other address families
+ extn-addr = non-ws-string
+
+ ; generic sub-rules: datatypes
+ text = byte-string
+ ;default is to interpret this as UTF8 text.
+ ;ISO 8859-1 requires "a=charset:ISO-8859-1"
+ ;session-level attribute to be used
+
+ byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
+ ;any byte except NUL, CR, or LF
+
+ non-ws-string = 1*(VCHAR/%x80-FF)
+ ;string of visible characters
+
+ token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
+ / %x41-5A / %x5E-7E
+
+ token = 1*(token-char)
+
+ email-safe = %x01-09/%x0B-0C/%x0E-27/%x2A-3B/%x3D/%x3F-FF
+ ;any byte except NUL, CR, LF, or the quoting
+ ;characters ()<>
+
+ integer = POS-DIGIT *DIGIT
+
+ ; generic sub-rules: primitives
+ alpha-numeric = ALPHA / DIGIT
+
+ POS-DIGIT = %x31-39 ; 1 - 9
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 43]
+
+RFC 4566 SDP July 2006
+
+
+ decimal-uchar = DIGIT
+ / POS-DIGIT DIGIT
+ / ("1" 2*(DIGIT))
+ / ("2" ("0"/"1"/"2"/"3"/"4") DIGIT)
+ / ("2" "5" ("0"/"1"/"2"/"3"/"4"/"5"))
+
+ ; external references:
+ ; ALPHA, DIGIT, CRLF, SP, VCHAR: from RFC 4234
+ ; URI-reference: from RFC 3986
+ ; addr-spec: from RFC 2822
+
+10. Summary of Changes from RFC 2327
+
+ The memo has been significantly restructured, incorporating a large
+ number of clarifications to the specification in light of use. With
+ the exception of those items noted below, the changes to the memo are
+ intended to be backward-compatible clarifications. However, due to
+ inconsistencies and unclear definitions in RFC 2327 it is likely that
+ some implementations interpreted that memo in ways that differ from
+ this version of SDP.
+
+ The ABNF grammar in Section 9 has been extensively revised and
+ updated, correcting a number of mistakes and incorporating the RFC
+ 3266 IPv6 extensions. Known inconsistencies between the grammar and
+ the specification text have been resolved.
+
+ A media type registration for SDP is included. Requirements for the
+ registration of attributes and other parameters with IANA have been
+ clarified and tightened (Section 8). It is noted that "text" and
+ "message" are valid media types for use with SDP, but that "control"
+ and "data" are under-specified and deprecated.
+
+ RFC 2119 terms are now used throughout to specify requirements
+ levels. Certain of those requirements, in particular in relation to
+ parameter registration, are stricter than those in RFC 2327.
+
+ The "RTP/SAVP" RTP profile and its "fmt" namespace are registered.
+
+ The attributes "a=inactive" and "a=maxptime" have been added.
+
+ RFC 2327 mandated that either "e=" or "p=" was required. Both are
+ now optional, to reflect actual usage.
+
+ The significant limitations of the "k=" field are noted, and its use
+ is deprecated.
+
+ Most uses of the "x-" prefix notation for experimental parameters are
+ disallowed and the other uses are deprecated.
+
+
+
+Handley, et al. Standards Track [Page 44]
+
+RFC 4566 SDP July 2006
+
+
+11. Acknowledgements
+
+ Many people in the IETF Multiparty Multimedia Session Control
+ (MMUSIC) working group have made comments and suggestions
+ contributing to this document. In particular, we would like to thank
+ Eve Schooler, Steve Casner, Bill Fenner, Allison Mankin, Ross
+ Finlayson, Peter Parnes, Joerg Ott, Carsten Bormann, Steve Hanna,
+ Jonathan Lennox, Keith Drage, Sean Olson, Bernie Hoeneisen, Jonathan
+ Rosenberg, John Elwell, Flemming Andreasen, Jon Peterson, and Spencer
+ Dawkins.
+
+12. References
+
+12.1. Normative References
+
+ [1] Mockapetris, P., "Domain names - concepts and facilities", STD
+ 13, RFC 1034, November 1987.
+
+ [2] Mockapetris, P., "Domain names - implementation and
+ specification", STD 13, RFC 1035, November 1987.
+
+ [3] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119, March 1997.
+
+ [4] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 4234, October 2005.
+
+ [5] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD
+ 63, RFC 3629, November 2003.
+
+ [6] Handley, M. and V. Jacobson, "SDP: Session Description
+ Protocol", RFC 2327, April 1998.
+
+ [7] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986,
+ January 2005.
+
+ [8] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
+ Considerations Section in RFCs", BCP 26, RFC 2434, October
+ 1998.
+
+ [9] Alvestrand, H., "Tags for the Identification of Languages", BCP
+ 47, RFC 3066, January 2001.
+
+ [10] Olson, S., Camarillo, G., and A. Roach, "Support for IPv6 in
+ Session Description Protocol (SDP)", RFC 3266, June 2002.
+
+
+
+
+
+Handley, et al. Standards Track [Page 45]
+
+RFC 4566 SDP July 2006
+
+
+ [11] Faltstrom, P., Hoffman, P., and A. Costello,
+ "Internationalizing Domain Names in Applications (IDNA)", RFC
+ 3490, March 2003.
+
+ [12] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings",
+ RFC 3548, July 2003.
+
+12.2. Informative References
+
+ [13] Mills, D., "Network Time Protocol (Version 3) Specification,
+ Implementation", RFC 1305, March 1992.
+
+ [14] Handley, M., Perkins, C., and E. Whelan, "Session Announcement
+ Protocol", RFC 2974, October 2000.
+
+ [15] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A.,
+ Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP:
+ Session Initiation Protocol", RFC 3261, June 2002.
+
+ [16] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming
+ Protocol (RTSP)", RFC 2326, April 1998.
+
+ [17] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model with
+ Session Description Protocol (SDP)", RFC 3264, June 2002.
+
+ [18] Camarillo, G., Eriksson, G., Holler, J., and H. Schulzrinne,
+ "Grouping of Media Lines in the Session Description Protocol
+ (SDP)", RFC 3388, December 2002.
+
+ [19] Schulzrinne, H., Casner, S., Frederick, R., and V. Jacobson,
+ "RTP: A Transport Protocol for Real-Time Applications", STD 64,
+ RFC 3550, July 2003.
+
+ [20] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video
+ Conferences with Minimal Control", STD 65, RFC 3551, July 2003.
+
+ [21] Casner, S., "Session Description Protocol (SDP) Bandwidth
+ Modifiers for RTP Control Protocol (RTCP) Bandwidth", RFC 3556,
+ July 2003.
+
+ [22] Huitema, C., "Real Time Control Protocol (RTCP) attribute in
+ Session Description Protocol (SDP)", RFC 3605, October 2003.
+
+ [23] Baugher, M., McGrew, D., Naslund, M., Carrara, E., and K.
+ Norrman, "The Secure Real-time Transport Protocol (SRTP)", RFC
+ 3711, March 2004.
+
+
+
+
+
+Handley, et al. Standards Track [Page 46]
+
+RFC 4566 SDP July 2006
+
+
+ [24] Rosenberg, J., Schulzrinne, H., and P. Kyzivat, "Indicating
+ User Agent Capabilities in the Session Initiation Protocol
+ (SIP)", RFC 3840, August 2004.
+
+ [25] Westerlund, M., "A Transport Independent Bandwidth Modifier for
+ the Session Description Protocol (SDP)", RFC 3890, September
+ 2004.
+
+ [26] International Telecommunication Union, "H.323 extended for
+ loosely coupled conferences", ITU Recommendation H.332,
+ September 1998.
+
+ [27] Arkko, J., Carrara, E., Lindholm, F., Naslund, M., and K.
+ Norrman, "Key Management Extensions for Session Description
+ Protocol (SDP) and Real Time Streaming Protocol (RTSP)", RFC
+ 4567, July 2006.
+
+ [28] Andreasen, F., Baugher, M., and D. Wing, "Session Description
+ Protocol (SDP) Security Descriptions for Media Streams", RFC
+ 4568, July 2006.
+
+ [29] Resnick, P., "Internet Message Format", RFC 2822, April 2001.
+
+ [30] Hinden, R. and S. Deering, "IP Version 6 Addressing
+ Architecture", RFC 2373, July 1998.
+
+ [31] Freed, N. and J. Klensin, "Media Type Specifications and
+ Registration Procedures", BCP 13, RFC 4288, December 2005.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 47]
+
+RFC 4566 SDP July 2006
+
+
+Authors' Addresses
+
+ Mark Handley
+ University College London
+ Department of Computer Science
+ Gower Street
+ London WC1E 6BT
+ UK
+
+
+
+ Van Jacobson
+ Packet Design
+ 2465 Latham Street
+ Mountain View, CA 94040
+ USA
+
+
+
+ Colin Perkins
+ University of Glasgow
+ Department of Computing Science
+ 17 Lilybank Gardens
+ Glasgow G12 8QQ
+ UK
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 48]
+
+RFC 4566 SDP July 2006
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2006).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at
+
+Acknowledgement
+
+ Funding for the RFC Editor function is provided by the IETF
+ Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Handley, et al. Standards Track [Page 49]
+
diff --git a/lib/megaco/ebin/.gitignore b/lib/megaco/ebin/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/megaco/ebin/.gitignore
diff --git a/lib/megaco/examples/meas/Makefile b/lib/megaco/examples/meas/Makefile
new file mode 100644
index 0000000000..0a6cbb44a6
--- /dev/null
+++ b/lib/megaco/examples/meas/Makefile
@@ -0,0 +1,132 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug -W
+endif
+
+EBIN = .
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+MEAS_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/meas
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ifeq ($(WARN_UNUSED_WARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ifeq ($(USE_MEGACO_HIPE),true)
+ERL_COMPILE_FLAGS += +native
+endif
+
+ifeq ($(USE_VERBOSE_STATS),true)
+ERL_COMPILE_FLAGS += -DVERBOSE_STATS=true
+endif
+
+ifneq ($(MSTONE_TIME),)
+ERL_COMPILE_FLAGS += -DMSTONE_TIME=$(MSTONE_TIME)
+endif
+
+ERL_COMPILE_FLAGS += \
+ -pa $(ERL_TOP)/lib/megaco/ebin \
+ -I../include
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(EXAMPLE_RELSYSDIR)
+ $(INSTALL_DIR) $(MEAS_RELSYSDIR)
+ $(INSTALL_DATA) $(MESSAGE_PACKAGES) $(MEAS_RELSYSDIR)
+ $(INSTALL_DATA) $(SCRIPT_SKELETONS) $(MEAS_RELSYSDIR)
+ $(INSTALL_DATA) $(TARGET_FILES) $(MEAS_RELSYSDIR)
+ $(INSTALL_DATA) $(ERL_FILES) $(MEAS_RELSYSDIR)
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+megaco_codec_transform.$(EMULATOR): megaco_codec_transform.erl
+
+megaco_codec_meas.$(EMULATOR): megaco_codec_meas.erl
+
+megaco_codec_mstone1.$(EMULATOR): megaco_codec_mstone1.erl
+
+megaco_codec_mstone2.$(EMULATOR): megaco_codec_mstone2.erl
+
+megaco_codec_mstone_lib.$(EMULATOR): megaco_codec_mstone_lib.erl
+
diff --git a/lib/megaco/examples/meas/meas.sh.skel b/lib/megaco/examples/meas/meas.sh.skel
new file mode 100644
index 0000000000..4bbc6a5f7e
--- /dev/null
+++ b/lib/megaco/examples/meas/meas.sh.skel
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# Skeleton for a script intended to run the meas test.
+#
+
+ERL_HOME=<path to otp top dir>
+MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir>
+MEAS_HOME=$MEGACO_HOME/examples/meas
+PATH=$ERL_HOME/bin:$PATH
+
+# MEAS_TIME_TEST="-s megaco_codec_meas start time_test"
+MEAS_DEFAULT="-s megaco_codec_meas t"
+STOP="-s init stop"
+
+ERL="erl \
+ -noshell \
+ -pa $MEAS_HOME \
+ $MEAS_DEFAULT \
+ $STOP"
+
+echo $ERL
+$ERL | tee meas.log
+
diff --git a/lib/megaco/examples/meas/megaco_codec_meas.erl b/lib/megaco/examples/meas/megaco_codec_meas.erl
new file mode 100644
index 0000000000..88b34105ac
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_meas.erl
@@ -0,0 +1,655 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Measure megaco codec's encoding & decoding time's
+%%
+%% Measurement process consists of:
+%% For each message in a directory:
+%% Pre: Read message from the file, close the file
+%% Measurement: 1) measure decode
+%% 2) measure encode (of the previously decoded message)
+%% Post: Print average
+%% For each directory:
+%% A summery is written, both to the console and to a file,
+%% in an excel compatible format.
+%%
+%% megaco_codec_meas:t().
+%% megaco_codec_meas:t([pretty, compact]).
+%% megaco_codec_meas:t([per, pretty, compact]).
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_meas).
+
+%% -compile(export_all).
+
+
+%% API
+-export([start/0, start/1]).
+-export([start1/0]).
+
+%% Internal exports
+-export([do_measure_codec/7, do_measure_codec_loop/7]).
+-export([flex_scanner_handler/1]).
+
+
+-include_lib("kernel/include/file.hrl").
+
+-define(V3, v3).
+
+-define(MEASURE_TIMEOUT, 100000). % 100 sec
+
+-ifndef(MEASURE_COUNT_TIME).
+-define(MEASURE_COUNT_TIME, 1*1000*1000). % 1 seconds
+-endif.
+
+-ifndef(MEASURE_TIME).
+-define(MEASURE_TIME, 10000).
+-endif.
+
+-ifndef(MEASURE_CODECS).
+-define(MEASURE_CODECS, megaco_codec_transform:codecs()).
+-endif.
+
+-define(DEFAULT_MESSAGE_PACKAGE, megaco_codec_transform:default_message_package()).
+
+-record(stat, {name, ecount, etime, dcount, dtime, size}).
+
+
+%% Runs the measurement on all "official" codecs
+
+start1() ->
+ put(everbose,true),
+ start().
+
+start() ->
+ meas_init(?DEFAULT_MESSAGE_PACKAGE, ?MEASURE_CODECS).
+
+start([MessagePackage]) ->
+ do_start(MessagePackage, ?MEASURE_CODECS);
+start(MessagePackage) ->
+ do_start(MessagePackage, ?MEASURE_CODECS).
+
+do_start(MessagePackageRaw, Codecs) ->
+ MessagePackage = parse_message_package(MessagePackageRaw),
+ meas_init(MessagePackage, Codecs).
+
+parse_message_package(MessagePackageRaw) when is_list(MessagePackageRaw) ->
+ list_to_atom(MessagePackageRaw);
+parse_message_package(MessagePackage) when is_atom(MessagePackage) ->
+ MessagePackage;
+parse_message_package(BadMessagePackage) ->
+ throw({error, {bad_message_package, BadMessagePackage}}).
+
+
+%% Dirs is a list of directories containing files,
+%% each with a single megaco message.
+%%
+%% Note that it is a requirement that each dir has
+%% the name of the codec with which the messages has
+%% been encoded:
+%%
+%% pretty | compact | ber | per | erlang
+%%
+
+meas_init(MessagePackage, Codecs) ->
+ %% process_flag(trap_exit, true),
+ io:format("~nRun meas on message package: ~p~n~n", [MessagePackage]),
+ display_os_info(),
+ display_system_info(),
+ display_app_info(),
+ io:format("~n", []),
+ Started = now(),
+ case megaco_codec_transform:messages(MessagePackage) of
+ Messages when is_list(Messages) ->
+ ExpandedMessages = expand_messages(Codecs, Messages),
+ Results = t1(ExpandedMessages, []),
+ display_time(Started, now()),
+ store_results(Results);
+ Error ->
+ Error
+ end.
+
+display_os_info() ->
+ V = case os:version() of
+ {Major, Minor, Release} ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w", [Major, Minor, Release]));
+ Str ->
+ Str
+ end,
+ case os:type() of
+ {OsFam, OsName} ->
+ io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]);
+ OsFam ->
+ io:format("OS: ~p: ~s~n", [OsFam, V])
+ end.
+
+display_system_info() ->
+ SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
+ SysVer = string:strip(erlang:system_info(system_version),right,$\n),
+ io:format("System architecture: ~s~n", [SysArch]),
+ io:format("System version: ~s~n", [SysVer]),
+ ok.
+
+
+display_app_info() ->
+ display_megaco_info(),
+ display_asn1_info().
+
+display_megaco_info() ->
+ MI = megaco:module_info(),
+ {value, {attributes, Attr}} = lists:keysearch(attributes, 1, MI),
+ {value, {app_vsn, Ver}} = lists:keysearch(app_vsn, 1, Attr),
+ FlexStr =
+ case megaco_flex_scanner:is_enabled() of
+ true ->
+ case megaco_flex_scanner:is_reentrant_enabled() of
+ true ->
+ "reentrant flex";
+ false ->
+ "non-reentrant flex"
+ end;
+ false ->
+ "no flex"
+ end,
+ io:format("Megaco version: ~s (~s)~n", [Ver, FlexStr]).
+
+display_asn1_info() ->
+ AI = megaco_ber_bin_drv_media_gateway_control_v1:info(),
+ Vsn =
+ case lists:keysearch(vsn, 1, AI) of
+ {value, {vsn, V}} when is_atom(V) ->
+ atom_to_list(V);
+ {value, {vsn, V}} when is_list(V) ->
+ V;
+ _ ->
+ "unknown"
+ end,
+ io:format("ASN.1 version: ~s~n", [Vsn]).
+
+
+%% {MegaSec, Sec, MicroSec}
+display_time(Start, Fin) ->
+ FormatDate1 = format_timestamp(Start),
+ FormatDate2 = format_timestamp(Fin),
+ FormatDiff = format_diff(Start, Fin),
+ io:format("Started: ~s~n", [FormatDate1]),
+ io:format("Finished: ~s~n", [FormatDate2]),
+ io:format(" ~s~n~n~n", [FormatDiff]),
+ ok.
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+format_diff(Start, Fin) ->
+ DateTime1 = calendar:now_to_universal_time(Start),
+ DateTime2 = calendar:now_to_universal_time(Fin),
+ T1 = calendar:datetime_to_gregorian_seconds(DateTime1),
+ T2 = calendar:datetime_to_gregorian_seconds(DateTime2),
+ {_, Diff} = calendar:gregorian_seconds_to_datetime(T2 - T1),
+ Tmp =
+ case Diff of
+ {0, 0, S} ->
+ io_lib:format("~.2.0w sec", [S]);
+ {0, M, S} ->
+ io_lib:format("~w min ~.2.0w sec", [M,S]);
+ {H, M, S} ->
+ io_lib:format("~w hour ~w min ~.2.0w sec", [H,M,S])
+ end,
+ lists:flatten(Tmp).
+
+
+
+t1([], Results) ->
+ lists:reverse(Results);
+t1([{Id, Codec, Conf, _, _} = ECodec|EMsgs], Results) ->
+ case (catch measure(ECodec)) of
+ {'EXIT', Reason} ->
+ error("measure of codec ~p exited: ~n~p", [Codec, Reason]),
+ t1(EMsgs, Results);
+ {error, Reason} ->
+ error("skipping codec ~p: ~n~p", [Codec, Reason]),
+ t1(EMsgs, Results);
+ {ok, Res} ->
+ t1(EMsgs, [{Id, Conf, Res}| Results])
+ end.
+
+
+measure({Id, Codec, Conf, Count, Msgs}) ->
+ io:format("measure using codec ~p ~p~n ", [Codec, Conf]),
+ {Init, Conf1} = measure_init(Conf),
+ Conf2 = [{version3,?V3}|Conf1],
+ Res = measure(Id, Codec, Conf2, Msgs, [], Count),
+ measure_fin(Init),
+ Res.
+
+
+expand_messages(Codecs, Messages) ->
+ ECodecs = expand_codecs(Codecs, []),
+ expand_messages(ECodecs, Messages, []).
+
+expand_messages([], _, EMessages) ->
+ lists:reverse(EMessages);
+expand_messages([{Id, Codec, Conf, Count} | ECodecs], Messages, EMessages) ->
+ case lists:keysearch(Id, 1, Messages) of
+ {value, {Id, Msgs}} ->
+ expand_messages(ECodecs, Messages,
+ [{Id, Codec, Conf, Count, Msgs}|EMessages]);
+ false ->
+ exit({error, {no_such_codec_data, Id}})
+ end.
+
+expand_codecs([], ECodecs) ->
+ lists:reverse(lists:flatten(ECodecs));
+expand_codecs([Codec|Codecs], ECodecs) when is_atom(Codec) ->
+ ECodec = expand_codec(Codec),
+ expand_codecs(Codecs, [ECodec|ECodecs]).
+
+expand_codec(Codec) ->
+ case Codec of
+ pretty ->
+ [{Codec, megaco_pretty_text_encoder, [flex_scanner], 2000},
+ {Codec, megaco_pretty_text_encoder, [], 1000}];
+ compact ->
+ [{Codec, megaco_compact_text_encoder, [flex_scanner], 3000},
+ {Codec, megaco_compact_text_encoder, [], 1500}];
+ ber ->
+ [{Codec, megaco_ber_bin_encoder, [driver,native], 4000},
+ {Codec, megaco_ber_bin_encoder, [native], 3000},
+ {Codec, megaco_ber_bin_encoder, [driver], 3000},
+ {Codec, megaco_ber_bin_encoder, [], 1000}];
+ per ->
+ [{Codec, megaco_per_bin_encoder, [driver,native], 4000},
+ {Codec, megaco_per_bin_encoder, [native], 3000},
+ {Codec, megaco_per_bin_encoder, [driver], 3000},
+ {Codec, megaco_per_bin_encoder, [], 1000}];
+ erlang ->
+ [
+ {Codec, megaco_erl_dist_encoder, [megaco_compressed,compressed], 500},
+ {Codec, megaco_erl_dist_encoder, [compressed], 400},
+ {Codec, megaco_erl_dist_encoder, [megaco_compressed], 10000},
+ {Codec, megaco_erl_dist_encoder, [], 10000}
+ ];
+ Else ->
+ exit({error, {invalid_codec, Else}})
+ end.
+
+
+measure_init([flex_scanner]) ->
+ start_flex_scanner();
+measure_init(Conf) ->
+ {undefined, Conf}.
+
+
+measure_fin(Pid) when is_pid(Pid) ->
+ stop_flex_scanner(Pid),
+ ok;
+measure_fin(_) ->
+ ok.
+
+
+measure(_Dir, _Codec, _Conf, [], [], _MCount) ->
+ {error, no_messages};
+
+measure(_Dir, _Codec, _Conf, [], Res, _MCount) ->
+
+ Eavg = avg([Etime/Ecnt || #stat{ecount = Ecnt, etime = Etime} <- Res]),
+ Davg = avg([Dtime/Dcnt || #stat{dcount = Dcnt, dtime = Dtime} <- Res]),
+ Savg = avg([Size || #stat{size = Size} <- Res]),
+
+ io:format("~n Measurment on ~p messages:"
+ "~n Average size: ~w bytes, "
+ "~n encode: ~w microsec, "
+ "~n decode: ~w microsec~n~n",
+ [length(Res), Savg, Eavg, Davg]),
+
+ {ok, lists:reverse(Res)};
+
+measure(Dir, Codec, Conf, [{Name, Bin}|Msgs], Results, MCount) ->
+ io:format(" ~p", [Name]),
+ case (catch do_measure(Dir, Codec, Conf, Name, Bin, MCount)) of
+ {ok, Stat} ->
+ measure(Dir, Codec, Conf, Msgs, [Stat | Results], MCount);
+
+ {error, S} ->
+ io:format("~n~s failed: ~n", [Name]),
+ error(S,[]),
+ measure(Dir, Codec, Conf, Msgs, Results, MCount);
+
+ {info, S} ->
+ case get(verbose) of
+ true ->
+ io:format("~n", []),
+ info(S,[]);
+ _ ->
+ io:format("~n~s skipped~n", [Name])
+ end,
+ measure(Dir, Codec, Conf, Msgs, Results, MCount)
+
+ end.
+
+
+do_measure(_Id, Codec, Conf, Name, BinMsg, MCount) ->
+ %% io:format("~n~s~n", [binary_to_list(BinMsg)]),
+ {Version, NewBin} = detect_version(Codec, Conf, BinMsg),
+ {Msg, Dcnt, Dtime} = measure_decode(Codec, Conf, Version, NewBin, MCount),
+ {_, Ecnt, Etime} = measure_encode(Codec, Conf, Version, Msg, MCount),
+
+ {ok, #stat{name = Name,
+ ecount = Ecnt, etime = Etime,
+ dcount = Dcnt, dtime = Dtime,
+ size = size(NewBin)}}.
+
+detect_version(Codec, Conf, Bin) ->
+ case (catch Codec:version_of(Conf, Bin)) of
+ {ok, V} ->
+ io:format("[~w]", [V]),
+ {ok, M} = Codec:decode_message(Conf, V, Bin),
+ {ok, NewBin} = Codec:encode_message(Conf, V, M),
+ io:format("[~w]", [size(NewBin)]),
+ {V, NewBin};
+ Error ->
+ io:format("~nversion detection failed:~n~p", [Error]),
+ Error
+ end.
+
+
+measure_decode(Codec, Conf, Version, Bin, MCount) ->
+ case measure_codec(Codec, decode_message, Conf, Version, Bin, MCount) of
+ {ok, Res} ->
+ Res;
+ {error, Reason} ->
+ S = format("decode failed for ~p:~n~p", [Codec, Reason]),
+ throw({error, S})
+ end.
+
+measure_encode(Codec, Conf, Version, Bin, MCount) ->
+ case measure_codec(Codec, encode_message, Conf, Version, Bin, MCount) of
+ {ok, Res} ->
+ Res;
+ {error, Reason} ->
+ S = format("encode failed for ~p:~n~p", [Codec, Reason]),
+ throw({error, S})
+ end.
+
+
+measure_codec(Codec, Func, Conf, Version, Bin, MCount) ->
+ Pid = spawn_link(?MODULE, do_measure_codec,
+ [self(), Codec, Func, Conf, Version, Bin, MCount]),
+ receive
+ {measure_result, Pid, Func, Res} ->
+ {ok, Res};
+ {error, Pid, Error} ->
+ {error, Error};
+ Else ->
+ {error, {unexpected_result, Else}}
+ after ?MEASURE_TIMEOUT ->
+ Info =
+ case (catch process_info(Pid)) of
+ I when is_list(I) ->
+ exit(Pid, kill),
+ I;
+ _ ->
+ undefined
+ end,
+ {error, {timeout, MCount, Info}}
+ end.
+
+
+do_measure_codec(Parent, Codec, Func, Conf, Version, Bin, MCount) ->
+ {ok, Count} = measure_warmup(Codec, Func, Conf, Version, Bin, MCount),
+ Res = timer:tc(?MODULE, do_measure_codec_loop,
+ [Codec, Func, Conf, Version, Bin, Count, dummy]),
+ case Res of
+ {Time, {ok, M}} ->
+ %% io:format("~w ", [Time]),
+ Parent ! {measure_result, self(), Func, {M, Count, Time}};
+ {_Time, Error} ->
+ Parent ! {error, self(), Error}
+ end,
+ unlink(Parent). % Make sure Parent don't get our exit signal
+
+
+%% This function does more mor less what the real measure function
+%% above does. But with the diff:
+%% 1) Warmup to ensure that all used code are loaded
+%% 2) To aproximate the encoding time, to ensure that
+%% the real encode is done with enough iterations.
+measure_warmup(Codec, Func, Conf, Version, M, MCount) ->
+ Res = timer:tc(?MODULE, do_measure_codec_loop,
+ [Codec, Func, Conf, Version, M, MCount, dummy]),
+ case Res of
+ {Time, {ok, _}} ->
+ %% OK so far, now calculate the count:
+ Count = round(?MEASURE_COUNT_TIME/(Time/MCount)),
+ %% io:format("~w ", [Count]),
+ {ok, Count};
+ {_Time, Error} ->
+ {error, {warmup_failed, Error}}
+ end.
+
+
+do_measure_codec_loop(_Codec, _Func, _Conf, _Version, _Bin, 0, M) ->
+ {ok, M};
+do_measure_codec_loop(Codec, Func, Conf, Version, Bin, Count, _) ->
+ {ok, M} = apply(Codec, Func, [Conf, Version, Bin]),
+ do_measure_codec_loop(Codec, Func, Conf, Version, Bin, Count - 1, M).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+store_results(Results) ->
+ io:format("storing: ~n", []),
+ store_excel_message_size(Results),
+ store_excel_decode_time(Results),
+ store_excel_encode_time(Results),
+ store_excel_total_time(Results),
+ io:format("~n", []),
+ ok.
+
+
+store_excel_message_size(Res) ->
+ Filename = "message_size.xls",
+ io:format(" creating ~s~n", [Filename]),
+ {ok, Fd} = file:open(Filename,[write]),
+ Sizes = message_sizes(Res, []),
+ store_excel_tab(Fd, Sizes),
+ ok.
+
+store_excel_decode_time(Res) ->
+ Filename = "decode_time.xls",
+ io:format(" creating ~s~n", [Filename]),
+ {ok, Fd} = file:open(Filename,[write]),
+ Decodes = dec_times(Res, []),
+ store_excel_tab(Fd, Decodes),
+ ok.
+
+store_excel_encode_time(Res) ->
+ Filename = "encode_time.xls",
+ io:format(" creating ~s~n", [Filename]),
+ {ok, Fd} = file:open(Filename,[write]),
+ Encodes = enc_times(Res, []),
+ store_excel_tab(Fd, Encodes),
+ ok.
+
+store_excel_total_time(Res) ->
+ Filename = "total_time.xls",
+ io:format(" creating ~s~n", [Filename]),
+ {ok, Fd} = file:open(Filename,[write]),
+ Totals = tot_times(Res, []),
+ store_excel_tab(Fd, Totals),
+ ok.
+
+
+message_sizes([], Sizes) ->
+ lists:reverse(Sizes);
+message_sizes([{Dir, Conf, Res}|T], Acc) ->
+ Sizes = [Size || #stat{size = Size} <- Res],
+ Avg = avg(Sizes),
+ message_sizes(T, [{Dir, Conf, Avg, Sizes}|Acc]).
+
+dec_times([], Times) ->
+ lists:reverse(Times);
+dec_times([{Dir, Conf, Res}|T], Acc) ->
+ Times = [Time/Count || #stat{dcount = Count, dtime = Time} <- Res],
+ Avg = avg(Times),
+ dec_times(T, [{Dir, Conf, Avg, Times}|Acc]).
+
+enc_times([], Times) ->
+ lists:reverse(Times);
+enc_times([{Dir, Conf, Res}|T], Acc) ->
+ Times = [Time/Count || #stat{ecount = Count, etime = Time} <- Res],
+ Avg = avg(Times),
+ enc_times(T, [{Dir, Conf, Avg, Times}|Acc]).
+
+tot_times([], Times) ->
+ lists:reverse(Times);
+tot_times([{Dir, Conf, Res}|T], Acc) ->
+ Times = [(Etime/Ecnt)+(Dtime/Dcnt) || #stat{ecount = Ecnt,
+ etime = Etime,
+ dcount = Dcnt,
+ dtime = Dtime} <- Res],
+ Avg = avg(Times),
+ tot_times(T, [{Dir, Conf, Avg, Times}|Acc]).
+
+
+avg(Vals) ->
+ round(lists:sum(Vals)/length(Vals)).
+
+
+store_excel_tab(_Fd, []) ->
+ ok; % Just in case there was something wrong with the test
+store_excel_tab(Fd, Res) ->
+ %% For all elements of this list, the Values is of the same length...
+ [{_, _, _, Values}|_] = Res,
+ store_excel_tab_header(Fd, length(Values), 1),
+ store_excel_tab1(Fd, Res).
+
+store_excel_tab1(Fd, []) ->
+ io:format(Fd, "~n", []);
+store_excel_tab1(Fd, [{Dir, Conf, Avg, Values}|T]) when is_list(Conf) ->
+ io:format(Fd, "~s~s (~w)",
+ [filename:basename(Dir), config_to_string(Conf), Avg]),
+ store_excel_tab_row(Fd, Values),
+ store_excel_tab1(Fd, T).
+
+config_to_string([]) ->
+ "";
+config_to_string([C]) when is_atom(C) ->
+ io_lib:format("_~w", [C]);
+config_to_string([C|Cs]) when is_atom(C) ->
+ lists:flatten(io_lib:format("_~w", [C]) ++ config_to_string(Cs)).
+
+store_excel_tab_header(Fd, 0, _) ->
+ io:format(Fd, "~n", []);
+store_excel_tab_header(Fd, N, M) ->
+ io:format(Fd, "\t~w", [M]),
+ store_excel_tab_header(Fd, N-1, M+1).
+
+store_excel_tab_row(Fd, []) ->
+ io:format(Fd, "~n", []);
+store_excel_tab_row(Fd, [Value|Values]) ->
+ io:format(Fd, "\t~w", [round(Value)]),
+ store_excel_tab_row(Fd, Values).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_flex_scanner() ->
+ Pid = proc_lib:spawn(?MODULE, flex_scanner_handler, [self()]),
+ receive
+ {flex_scanner_started, Pid, Conf} ->
+ {Pid, [Conf]};
+ {flex_scanner_error, {failed_loading_flex_scanner_driver, Reason}} ->
+ throw({error, {failed_loading_flex_scanner_driver, Reason}});
+ {flex_scanner_error, Reason} ->
+ throw({error, {failed_loading_flex_scanner_driver, Reason}})
+ after 10000 ->
+ exit(Pid, kill),
+ throw({error, {failed_starting_flex_scanner, timeout}})
+ end.
+
+stop_flex_scanner(Pid) ->
+ Pid ! stop_flex_scanner.
+
+flex_scanner_handler(Pid) ->
+ case (catch megaco_flex_scanner:start()) of
+ {ok, Port} when is_port(Port) ->
+ Pid ! {flex_scanner_started, self(), {flex, Port}},
+ flex_scanner_handler(Pid, Port);
+ {ok, Ports} when is_tuple(Ports) ->
+ Pid ! {flex_scanner_started, self(), {flex, Ports}},
+ flex_scanner_handler(Pid, Ports);
+ {error, {load_driver, {open_error, Reason}}} ->
+ Error = {failed_loading_flex_scanner_driver, Reason},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error);
+ Else ->
+ Error = {unknown_result_from_start_flex_scanner, Else},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error)
+ end.
+
+flex_scanner_handler(Pid, PortOrPorts) ->
+ receive
+ {ping, Pinger} ->
+ Pinger ! {pong, self()},
+ flex_scanner_handler(Pid, PortOrPorts);
+ {'EXIT', Port, Reason} ->
+ case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
+ true ->
+ Pid ! {flex_scanner_exit, Reason},
+ exit({flex_scanner_exit, Reason});
+ false ->
+ info("exit signal from unknown port ~p"
+ "~n Reason: ~p", [Port, Reason]),
+ flex_scanner_handler(Pid, PortOrPorts)
+ end;
+ stop_flex_scanner ->
+ megaco_flex_scanner:stop(PortOrPorts),
+ exit(normal);
+ Other ->
+ info("flex scanner handler got something:~n~p", [Other]),
+ flex_scanner_handler(Pid, PortOrPorts)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+info(F, A) ->
+ io:format(F ++ "~n", A).
+
+
+error(F, A) ->
+ io:format("ERROR: " ++ F ++ "~n", A).
+
+
+format(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone1.erl b/lib/megaco/examples/meas/megaco_codec_mstone1.erl
new file mode 100644
index 0000000000..9ab7822df8
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_mstone1.erl
@@ -0,0 +1,408 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: mstone measurement
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_mstone1).
+
+
+%% API
+-export([
+ start/0, start/1, start/2,
+ start_flex/0, start_flex/1, start_flex/2,
+ start_no_drv/0, start_no_drv/1, start_no_drv/2,
+ start_only_drv/0, start_only_drv/1, start_only_drv/2
+ ]).
+
+%% Internal exports
+-export([mstone_runner_init/5]).
+
+
+-define(LIB, megaco_codec_mstone_lib).
+
+-ifndef(MSTONE_TIME).
+-define(MSTONE_TIME, 10).
+-endif.
+-define(MSTONE_RUN_TIME, timer:minutes(?MSTONE_TIME)).
+
+-ifndef(MSTONE_VERSION3).
+-define(MSTONE_VERSION3, v3).
+-endif.
+-define(VERSION3, ?MSTONE_VERSION3).
+
+-ifndef(MSTONE_CODECS).
+-define(MSTONE_CODECS, megaco_codec_transform:codecs()).
+-endif.
+
+-define(DEFAULT_MESSAGE_PACKAGE, megaco_codec_transform:default_message_package()).
+-define(DEFAULT_FACTOR, 1).
+-define(DEFAULT_DRV_INCLUDE, ignore).
+
+%% -define(VERBOSE_STATS,true).
+
+-ifndef(MSTONE_RUNNER_MIN_HEAP_SZ).
+-define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#ffff).
+-endif.
+-define(MSTONE_RUNNER_OPTS,
+ [link, {min_heap_size, ?MSTONE_RUNNER_MIN_HEAP_SZ}]).
+
+-record(mstone, {id, count, codec, econf, heap_size, reds}).
+
+
+start() ->
+ start(?DEFAULT_FACTOR).
+
+start([Factor]) ->
+ start(?DEFAULT_MESSAGE_PACKAGE, Factor);
+start([MessagePackage, Factor]) ->
+ start(MessagePackage, Factor);
+start(Factor) ->
+ start(?DEFAULT_MESSAGE_PACKAGE, Factor).
+
+start(MessagePackage, Factor) ->
+ do_start(MessagePackage, Factor, ?DEFAULT_DRV_INCLUDE).
+
+
+start_flex() ->
+ start_flex(?DEFAULT_FACTOR).
+
+start_flex([Factor]) ->
+ start_flex(?DEFAULT_MESSAGE_PACKAGE, Factor);
+start_flex([MessagePackage, Factor]) ->
+ start_flex(MessagePackage, Factor);
+start_flex(Factor) ->
+ start_flex(?DEFAULT_MESSAGE_PACKAGE, Factor).
+
+start_flex(MessagePackage, Factor) ->
+ do_start(MessagePackage, Factor, flex).
+
+
+start_only_drv() ->
+ start_only_drv(?DEFAULT_FACTOR).
+
+start_only_drv([Factor]) ->
+ start_only_drv(?DEFAULT_MESSAGE_PACKAGE, Factor);
+start_only_drv([MessagePackage, Factor]) ->
+ start_only_drv(MessagePackage, Factor);
+start_only_drv(Factor) ->
+ start_only_drv(?DEFAULT_MESSAGE_PACKAGE, Factor).
+
+start_only_drv(MessagePackage, Factor) ->
+ do_start(MessagePackage, Factor, only_drv).
+
+
+start_no_drv() ->
+ start_no_drv(?DEFAULT_FACTOR).
+
+start_no_drv([Factor]) ->
+ start_no_drv(?DEFAULT_MESSAGE_PACKAGE, Factor);
+start_no_drv([MessagePackage, Factor]) ->
+ start_no_drv(MessagePackage, Factor);
+start_no_drv(Factor) ->
+ start_no_drv(?DEFAULT_MESSAGE_PACKAGE, Factor).
+
+start_no_drv(MessagePackage, Factor) ->
+ do_start(MessagePackage, Factor, no_drv).
+
+
+do_start(MessagePackageRaw, FactorRaw, DrvInclude) ->
+ Factor = parse_factor(FactorRaw),
+ MessagePackage = parse_message_package(MessagePackageRaw),
+ mstone_init(MessagePackage, Factor, DrvInclude).
+
+
+
+parse_factor(FactorAtom) when is_atom(FactorAtom) ->
+ case (catch list_to_integer(atom_to_list(FactorAtom))) of
+ Factor when is_integer(Factor) andalso (Factor > 0) ->
+ Factor;
+ _ ->
+ io:format("ERROR: Bad factor value: ~p~n", [FactorAtom]),
+ throw({error, {bad_factor, FactorAtom}})
+ end;
+parse_factor(FactorRaw) when is_list(FactorRaw) ->
+ case (catch list_to_integer(FactorRaw)) of
+ Factor when is_integer(Factor) andalso (Factor > 0) ->
+ Factor;
+ _ ->
+ io:format("ERROR: Bad factor value: ~p~n", [FactorRaw]),
+ throw({error, {bad_factor, FactorRaw}})
+ end;
+parse_factor(Factor) when is_integer(Factor) andalso (Factor > 0) ->
+ Factor;
+parse_factor(BadFactor) ->
+ throw({error, {bad_factor, BadFactor}}).
+
+
+parse_message_package(MessagePackageRaw) when is_list(MessagePackageRaw) ->
+ list_to_atom(MessagePackageRaw);
+parse_message_package(MessagePackage) when is_atom(MessagePackage) ->
+ MessagePackage;
+parse_message_package(BadMessagePackage) ->
+ throw({error, {bad_message_package, BadMessagePackage}}).
+
+
+%% Codecs is a list of megaco codec shortnames:
+%%
+%% pretty | compact | ber | per | erlang
+%%
+
+mstone_init(MessagePackage, Factor, DrvInclude) ->
+%% io:format("mstone_init -> entry with"
+%% "~n MessagePackage: ~p"
+%% "~n Factor: ~p"
+%% "~n DrvInclude: ~p"
+%% "~n", [MessagePackage, Factor, DrvInclude]),
+ Codecs = ?MSTONE_CODECS,
+ mstone_init(MessagePackage, Factor, Codecs, DrvInclude).
+
+mstone_init(MessagePackage, Factor, Codecs, DrvInclude) ->
+ Parent = self(),
+ Pid = spawn(
+ fun() ->
+ process_flag(trap_exit, true),
+ do_mstone(MessagePackage, Factor, Codecs, DrvInclude),
+ Parent ! {done, self()}
+ end),
+ receive
+ {done, Pid} ->
+ ok
+ end.
+
+do_mstone(MessagePackage, Factor, Codecs, DrvInclude) ->
+ io:format("~n", []),
+ ?LIB:set_default_sched_bind(),
+ ?LIB:display_os_info(),
+ ?LIB:display_system_info(),
+ ?LIB:display_app_info(),
+ io:format("~n", []),
+ (catch asn1rt_driver_handler:load_driver()),
+ {Pid, Conf} = ?LIB:start_flex_scanner(),
+ put(flex_scanner_conf, Conf),
+ EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, DrvInclude),
+ EMsgs = duplicate(Factor, EMessages),
+ MStone = t1(EMsgs),
+ ?LIB:stop_flex_scanner(Pid),
+ io:format("~n", []),
+ io:format("MStone: ~p~n", [MStone]).
+
+duplicate(N, Elements) ->
+ duplicate(N, Elements, []).
+
+duplicate(_N, [], Acc) ->
+ lists:flatten(Acc);
+duplicate(N, [H|T], Acc) ->
+ duplicate(N, T, [lists:duplicate(N, H)|Acc]).
+
+t1(EMsgs) ->
+ io:format(" * starting runners [~w] ", [length(EMsgs)]),
+ t1(EMsgs, []).
+
+t1([], Runners) ->
+ io:format(" done~n * await runners ready ", []),
+ await_runners_ready(Runners),
+ io:format(" done~n * now snooze", []),
+ receive after 5000 -> ok end,
+ io:format("~n * release them~n", []),
+ lists:foreach(fun(P) -> P ! {go, self()} end, Runners),
+ t2(1, [], Runners);
+t1([H|T], Runners) ->
+ Runner = init_runner(H),
+ io:format(".", []),
+ t1(T, [Runner|Runners]).
+
+await_runners_ready([]) ->
+ ok;
+await_runners_ready(Runners) ->
+ receive
+ {ready, Runner} ->
+ io:format(".", []),
+ %% i("runner ~w ready", [Runner]),
+ await_runners_ready(lists:delete(Runner, Runners));
+ {'EXIT', Pid, Reason} ->
+ case lists:member(Pid, Runners) of
+ true ->
+ io:format("~nERROR: "
+ "received (unexpected) exit signal "
+ "from from runner ~p:"
+ "~n~p~n", [Pid, Reason]),
+ exit(Reason);
+ false ->
+ await_runners_ready(Runners)
+ end
+ end.
+
+-ifdef(VERBOSE_STATS).
+print_runner_stats(RunnerStats) ->
+ Sorted = lists:keysort(2, RunnerStats),
+ lists:foreach(fun(#mstone{id = Id,
+ count = Num,
+ codec = Codec,
+ econf = EConf,
+ heap_size = HeapSz,
+ reds = Reds}) ->
+ i("runner: ~w"
+ "~n Count: ~w"
+ "~n Codec: ~w"
+ "~n Encoding config: ~p"
+ "~n Heap size: ~p"
+ "~n Reductions: ~p",
+ [Id, Num, Codec, EConf, HeapSz, Reds]) end,
+ Sorted),
+ ok.
+-else.
+print_runner_stats(_) ->
+ ok.
+-endif.
+
+t2(_, Acc, []) ->
+ i("~n~w runners", [length(Acc)]),
+ print_runner_stats(Acc),
+
+ HeapSzAcc = lists:sort([HS || #mstone{heap_size = HS} <- Acc]),
+ i("Runner heap size data:"
+ "~n Min: ~w"
+ "~n Max: ~w"
+ "~n Avg: ~w",
+ [hd(HeapSzAcc),
+ hd(lists:reverse(HeapSzAcc)),
+ (lists:sum(HeapSzAcc) div length(HeapSzAcc))]),
+
+ RedsAcc = lists:sort([R || #mstone{reds = R} <- Acc]),
+ i("Runner reductions data:"
+ "~n Min: ~w"
+ "~n Max: ~w"
+ "~n Avg: ~w",
+ [hd(RedsAcc),
+ hd(lists:reverse(RedsAcc)),
+ (lists:sum(RedsAcc) div length(RedsAcc))]),
+
+ lists:sum([Num || #mstone{count = Num} <- Acc]);
+t2(N, Acc, Runners) ->
+ receive
+ {'EXIT', Pid, {runner_done, Codec, Conf, Num, Info}} ->
+ {value, {_, HeapSz}} = lists:keysearch(heap_size, 1, Info),
+ {value, {_, Reds}} = lists:keysearch(reductions, 1, Info),
+ MStone = #mstone{id = N,
+ count = Num,
+ codec = Codec,
+ econf = Conf,
+ heap_size = HeapSz,
+ reds = Reds},
+ t2(N + 1, [MStone|Acc], lists:delete(Pid, Runners))
+ end.
+
+init_runner({Codec, Mod, Conf, Msgs}) ->
+ Conf1 = runner_conf(Conf),
+ Conf2 = [{version3,?VERSION3}|Conf1],
+ Pid = spawn_opt(?MODULE, mstone_runner_init,
+ [Codec, self(), Mod, Conf2, Msgs],
+ ?MSTONE_RUNNER_OPTS),
+ Pid.
+
+runner_conf([flex_scanner]) ->
+ get(flex_scanner_conf);
+runner_conf(Conf) ->
+ Conf.
+
+
+
+detect_versions(Codec, _Conf, [], []) ->
+ exit({no_messages_found_for_codec, Codec});
+detect_versions(_Codec, _Conf, [], Acc) ->
+ lists:reverse(Acc);
+detect_versions(Codec, Conf, [{_Name, Bin}|Bins], Acc) ->
+ Data = ?LIB:detect_version(Codec, Conf, Bin),
+ detect_versions(Codec, Conf, Bins, [Data|Acc]).
+
+
+mstone_runner_init(_Codec, Parent, Mod, Conf, Msgs0) ->
+ Msgs = detect_versions(Mod, Conf, Msgs0, []),
+ warmup(Mod, Conf, Msgs, []),
+ Parent ! {ready, self()},
+ receive
+ {go, Parent} ->
+ ok
+ end,
+ erlang:send_after(?MSTONE_RUN_TIME, self(), stop),
+ mstone_runner_loop(Parent, Mod, Conf, 0, Msgs).
+
+mstone_runner_loop(Parent, Mod, Conf, N, Msgs1) ->
+ receive
+ stop ->
+ exit({runner_done, Mod, Conf, N, mstone_runner_process_info()})
+ after 0 ->
+ {Inc, Msgs2} = mstone_all(Mod, Conf, Msgs1, []),
+ mstone_runner_loop(Parent, Mod, Conf, N+Inc, Msgs2)
+ end.
+
+mstone_runner_process_info() ->
+ PI = process_info(self()),
+ FL = [heap_size, stack_size, reductions],
+ lists:filter(fun({Key, _}) -> lists:member(Key, FL) end, PI).
+
+
+mstone_all(_Codec, _Conf, [], Acc) ->
+ {length(Acc), lists:reverse(Acc)};
+mstone_all(Codec, Conf, [{V, Bin}|Bins], Acc) when is_binary(Bin) ->
+ {ok, Msg} = apply(Codec, decode_message, [Conf, V, Bin]),
+ mstone_all(Codec, Conf, Bins, [{V, Msg}|Acc]);
+mstone_all(Codec, Conf, [{V, Msg}|Msgs], Acc) ->
+ {ok, Bin} = apply(Codec, encode_message, [Conf, V, Msg]),
+ mstone_all(Codec, Conf, Msgs, [{V, Bin}|Acc]).
+
+warmup(_Codec, _Conf, [], Acc) ->
+ lists:reverse(Acc);
+warmup(Codec, Conf, [{V, M}|Msgs], Acc) ->
+%% io:format("~p warmup -> entry with"
+%% "~n Codec: ~p"
+%% "~n Conf: ~p"
+%% "~n", [self(), Codec, Conf]),
+ case (catch apply(Codec, decode_message, [Conf, V, M])) of
+ {ok, Msg} ->
+ case (catch apply(Codec, encode_message, [Conf, V, Msg])) of
+ {ok, Bin} ->
+ warmup(Codec, Conf, Msgs, [Bin|Acc]);
+ EncodeError ->
+ emsg("failed encoding message: ~n~p", [EncodeError])
+ end;
+ DecodeError ->
+ emsg("failed decoding message: "
+ "~n DecodeError: ~p"
+ "~n V: ~p"
+ "~n M: ~p", [DecodeError, V, M])
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+emsg(F, A) ->
+ error_logger:error_msg(F ++ "~n", A).
+
+%% i(F) ->
+%% i(F, []).
+i(F, A) ->
+ io:format(F ++ "~n", A).
+
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone2.erl b/lib/megaco/examples/meas/megaco_codec_mstone2.erl
new file mode 100644
index 0000000000..f3588f2e3d
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_mstone2.erl
@@ -0,0 +1,400 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%
+%% megaco_codec_mstone2:start().
+%% megaco_codec_mstone2:start_no_drv().
+%% megaco_codec_mstone2:start_only_drv().
+%%
+%%----------------------------------------------------------------------
+%% Purpose: mstone 2 measurement
+%% This module implement a simple performence measurment case.
+%% The architecture is as followes:
+%% - One loader process:
+%% It keeps a list of all codec combinations, including
+%% all the messages (in a list) for each codec.
+%% Initially it creates a timer (finished) (circa 10 minutes).
+%% It spawns a worker process for each codec config (it also
+%% creates a monitor to each process so it knows when they
+%% exit). When the result comes in from a process (in the
+%% form of a DOWN message), spawns a new worker process for
+%% this codec config and update's the statistics.
+%% When the finished timer expires, it will stop respawing
+%% the worker processes, and instead just wait for them all
+%% to finish.
+%% The test is finished by printing the statistics.
+%% - A worker process for each codec combination.
+%% This process is spawned by the loader process. It receives
+%% at start a list of messages. It shall decode and then
+%% encode each message. When all messages has been processed
+%% it exits (normally).
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_mstone2).
+
+
+%% Exports
+-export([
+ start/0, start/1,
+ start_flex/0, start_flex/1,
+ start_no_drv/0, start_no_drv/1,
+ start_only_drv/0, start_only_drv/1
+ ]).
+
+
+%%%----------------------------------------------------------------------
+%%% Macros
+%%%----------------------------------------------------------------------
+
+-define(LIB, megaco_codec_mstone_lib).
+
+-ifndef(MSTONE_TIME).
+-define(MSTONE_TIME, 10).
+-endif.
+-define(MSTONE_RUN_TIME, timer:minutes(?MSTONE_TIME)).
+
+-ifndef(MSTONE_VERSION3).
+-define(MSTONE_VERSION3, v3).
+-endif.
+-define(VERSION3, ?MSTONE_VERSION3).
+
+-ifndef(MSTONE_CODECS).
+-define(MSTONE_CODECS, megaco_codec_transform:codecs()).
+-endif.
+
+-define(DEFAULT_MESSAGE_PACKAGE, megaco_codec_transform:default_message_package()).
+-define(DEFAULT_FACTOR, 1).
+-define(DEFAULT_DRV_INCLUDE, ignore).
+
+-ifndef(MSTONE_RUNNER_MIN_HEAP_SZ).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#7fff).
+-define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#ffff).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#17ffe).
+%% -define(MSTONE_RUNNER_MIN_HEAP_SZ, 16#1ffff).
+%% -define(MSTONE_RUNNER_OPTS, [link]).
+-endif.
+-define(MSTONE_RUNNER_OPTS,
+ [link, {min_heap_size, ?MSTONE_RUNNER_MIN_HEAP_SZ}]).
+
+
+%%%----------------------------------------------------------------------
+%%% Records
+%%%----------------------------------------------------------------------
+
+-record(codec_data, {ref, mod, config = [], msgs = []}).
+
+-record(state, {timer, running = [], idle = [], flex_handler, flex_conf}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start() ->
+ start(?DEFAULT_MESSAGE_PACKAGE).
+
+start([MessagePackage]) ->
+ do_start(MessagePackage, ?DEFAULT_DRV_INCLUDE);
+start(MessagePackage) ->
+ do_start(MessagePackage, ?DEFAULT_DRV_INCLUDE).
+
+
+start_flex() ->
+ start_flex(?DEFAULT_MESSAGE_PACKAGE).
+
+start_flex([MessagePackage]) ->
+ do_start(MessagePackage, flex);
+start_flex(MessagePackage) ->
+ do_start(MessagePackage, flex).
+
+
+start_no_drv() ->
+ start_no_drv(?DEFAULT_MESSAGE_PACKAGE).
+
+start_no_drv([MessagePackage]) ->
+ do_start(MessagePackage, no_drv);
+start_no_drv(MessagePackage) ->
+ do_start(MessagePackage, no_drv).
+
+
+start_only_drv() ->
+ start_only_drv(?DEFAULT_MESSAGE_PACKAGE).
+
+start_only_drv([MessagePackage]) ->
+ do_start(MessagePackage, only_drv);
+start_only_drv(MessagePackage) ->
+ do_start(MessagePackage, only_drv).
+
+
+do_start(MessagePackageRaw, DrvInclude) ->
+%% io:format("do_start -> entry with"
+%% "~n MessagePackageRaw: ~p"
+%% "~n DrvInclude: ~p"
+%% "~n", [MessagePackageRaw, DrvInclude]),
+ MessagePackage = parse_message_package(MessagePackageRaw),
+ mstone_init(MessagePackage, DrvInclude).
+
+parse_message_package(MessagePackageRaw) when is_list(MessagePackageRaw) ->
+ list_to_atom(MessagePackageRaw);
+parse_message_package(MessagePackage) when is_atom(MessagePackage) ->
+ MessagePackage;
+parse_message_package(BadMessagePackage) ->
+ throw({error, {bad_message_package, BadMessagePackage}}).
+
+
+mstone_init(MessagePackage, DrvInclude) ->
+ io:format("~n", []),
+ ?LIB:set_default_sched_bind(),
+ ?LIB:display_os_info(),
+ ?LIB:display_system_info(),
+ ?LIB:display_app_info(),
+ io:format("~n", []),
+ Ref = erlang:monitor(process,
+ spawn(fun() ->
+ loader(MessagePackage, DrvInclude)
+ end)),
+ receive
+ {'DOWN', Ref, process, _Pid, {done, Result}} ->
+ display_result(Result);
+ {'DOWN', Ref, process, _Pid, Result} ->
+ io:format("Unexpected result:~n~p~n", [Result]),
+ ok
+ end.
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+display_result(Result) ->
+ {value, {worker_cnt, WC}} = lists:keysearch(worker_cnt, 1, Result),
+ CodecStat =
+ [{Mod, Conf, Cnt} || {{codec_cnt, Mod, Conf}, Cnt} <- Result],
+ MStone = lists:sum([Cnt || {_, _, Cnt} <- CodecStat]),
+ io:format("Number of procs spawned: ~w~n"
+ "MStone: ~w~n"
+ "~n", [WC, MStone]),
+ display_worker_result(lists:keysort(3, CodecStat)),
+ ok.
+
+display_worker_result([]) ->
+ io:format("~n", []);
+display_worker_result([{Mod, Conf, Cnt}|Res]) ->
+ io:format("~s: ~w~n", [image_of(Mod, Conf), Cnt]),
+ display_worker_result(Res).
+
+image_of(megaco_per_bin_encoder, Conf) ->
+ bin_image("per_bin", Conf);
+image_of(megaco_ber_bin_encoder, Conf) ->
+ bin_image("ber_bin", Conf);
+image_of(megaco_pretty_text_encoder, Conf) ->
+ text_image("pretty", Conf);
+image_of(megaco_compact_text_encoder, Conf) ->
+ text_image("compact", Conf);
+image_of(megaco_erl_dist_encoder, Conf) ->
+ erl_image("erl_dist", Conf).
+
+bin_image(Bin, Conf) ->
+ Drv =
+ case lists:member(driver, Conf) of
+ true ->
+ [driver];
+ false ->
+ []
+ end,
+ Nat =
+ case lists:member(native, Conf) of
+ true ->
+ [native];
+ false ->
+ []
+ end,
+ io_lib:format("~s ~w", [Bin, Drv ++ Nat]).
+
+text_image(Txt, Conf) ->
+ Flex =
+ case lists:keysearch(flex, 1, Conf) of
+ false ->
+ [];
+ _ ->
+ [flex]
+ end,
+ io_lib:format("~s ~w", [Txt, Flex]).
+
+erl_image(Erl, Conf) ->
+ MC =
+ case lists:member(megaco_compressed, Conf) of
+ true ->
+ [megaco_compressed];
+ false ->
+ []
+ end,
+ C =
+ case lists:member(compressed, Conf) of
+ true ->
+ [compressed];
+ false ->
+ []
+ end,
+ io_lib:format("~s ~w", [Erl, MC ++ C]).
+
+
+%%%----------------------------------------------------------------------
+
+loader(MessagePackage, DrvInclude) ->
+ loader(?MSTONE_CODECS, MessagePackage, DrvInclude).
+
+
+%% Codecs is a list of megaco codec shortnames:
+%%
+%% pretty | compact | ber | per | erlang
+%%
+
+loader(Codecs, MessagePackage, DrvInclude) ->
+ process_flag(trap_exit, true),
+ case (catch init(Codecs, MessagePackage, DrvInclude)) of
+ {ok, State} ->
+ loader_loop(running, State);
+ Error ->
+ exit(Error)
+ end.
+
+init(Codecs, MessagePackage, DrvInclude) ->
+ ets:new(mstone, [set, private, named_table, {keypos, 1}]),
+ ets:insert(mstone, {worker_cnt, 0}),
+ {Pid, FlexConf} = ?LIB:start_flex_scanner(),
+ io:format("prepare messages", []),
+ EMessages = ?LIB:expanded_messages(MessagePackage, Codecs, DrvInclude),
+ io:format("~ninit codec data", []),
+ CodecData = init_codec_data(EMessages, FlexConf),
+ Timer = erlang:send_after(?MSTONE_RUN_TIME, self(), mstone_finished),
+ io:format("~n", []),
+ {ok, #state{timer = Timer,
+ idle = CodecData,
+ flex_handler = Pid,
+ flex_conf = FlexConf}}.
+
+init_codec_data(EMsgs, FlexConf) ->
+ [init_codec_data(Codec, Mod, Conf, Msgs, FlexConf) ||
+ {Codec, Mod, Conf, Msgs} <- EMsgs].
+
+init_codec_data(Codec, Mod, Conf0, Msgs0, FlexConf)
+ when is_atom(Codec) andalso
+ is_atom(Mod) andalso
+ is_list(Conf0) andalso
+ is_list(Msgs0) ->
+ io:format(".", []),
+ Conf = [{version3,?VERSION3}|init_codec_conf(FlexConf, Conf0)],
+ Msgs = [?LIB:detect_version(Mod, Conf, Bin) || {_, Bin} <- Msgs0],
+ ets:insert(mstone, {{codec_cnt, Mod, Conf}, 0}),
+ #codec_data{mod = Mod, config = Conf, msgs = Msgs}.
+
+
+init_codec_conf(FlexConf, [flex_scanner]) ->
+ FlexConf;
+init_codec_conf(_, Conf) ->
+ Conf.
+
+
+%% -- Main loop --
+
+loader_loop(finishing, #state{flex_handler = Pid, running = []}) ->
+ %% we are done
+ io:format("~n", []),
+ ?LIB:stop_flex_scanner(Pid),
+ exit({done, lists:sort(ets:tab2list(mstone))});
+
+loader_loop(finishing, State) ->
+ receive
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ loader_loop(finishing, done_worker(Ref, Codec, Conf, Cnt, State))
+ end;
+
+loader_loop(running, #state{idle = []} = State) ->
+ receive
+ mstone_finished ->
+ loader_loop(finishing, State);
+
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ loader_loop(running, done_worker(Ref, Codec, Conf, Cnt, State))
+ end;
+
+loader_loop(running, State) ->
+ receive
+ mstone_finished ->
+ loader_loop(finishing, State);
+
+ {'DOWN', Ref, process, _Pid, {mstone_done, Codec, Conf, Cnt}} ->
+ State2 = done_worker(Ref, Codec, Conf, Cnt, State),
+ loader_loop(running, State2)
+
+ after 0 ->
+ loader_loop(running, start_worker(State))
+ end.
+
+done_worker(Ref, Codec, Conf, Cnt,
+ #state{running = Running, idle = Idle} = State) ->
+ %% io:format("worker ~w ~w done with ~w~n", [Codec, Conf, Cnt]),
+ ets:update_counter(mstone, worker_cnt, 1),
+ ets:update_counter(mstone, {codec_cnt, Codec, Conf}, Cnt),
+ Running2 = lists:keydelete(Ref, #codec_data.ref, Running),
+ CD = Running -- Running2,
+ State#state{running = Running2, idle = lists:append(Idle, CD)}.
+
+start_worker(#state{running = Running, idle = [H|T]} = State) ->
+ #codec_data{mod = Codec, config = Conf, msgs = Msgs} = H,
+ Worker = fun() -> worker(Codec, Conf, Msgs, 0) end,
+ Ref = erlang:monitor(process, spawn(Worker)),
+ CD = H#codec_data{ref = Ref},
+ State#state{running = [CD | Running], idle = T}.
+
+
+%%%----------------------------------------------------------------------
+
+worker(Codec, Conf, [], Cnt) ->
+ exit({mstone_done, Codec, Conf, Cnt});
+worker(Codec, Conf, [{V, Msg}|Msgs], Cnt) ->
+ work(Codec, Conf, V, Msg),
+ worker(Codec, Conf, Msgs, Cnt + 1).
+
+work(Codec, Conf, V, M) ->
+ case (catch apply(Codec, decode_message, [Conf, V, M])) of
+ {ok, Msg} ->
+ case (catch apply(Codec, encode_message, [Conf, V, Msg])) of
+ {ok, Bin} when is_binary(Bin) ->
+ ok;
+ EncodeError ->
+ emsg("failed encoding message: ~n~p", [EncodeError]),
+ exit({mstone_worker_encode_failure, EncodeError})
+ end;
+ DecodeError ->
+ emsg("failed decoding message: ~n~p", [DecodeError]),
+ exit({mstone_worker_decode_failure, DecodeError})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+emsg(F, A) ->
+ error_logger:error_msg(F ++ "~n", A).
+
+
diff --git a/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
new file mode 100644
index 0000000000..31df945777
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_mstone_lib.erl
@@ -0,0 +1,534 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Misc utility functions for the mstone modules
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_mstone_lib).
+
+
+%% API
+-export([start_flex_scanner/0, stop_flex_scanner/1,
+ expanded_messages/2, expanded_messages/3,
+ set_default_sched_bind/0,
+ display_os_info/0,
+ display_system_info/0,
+ display_alloc_info/0,
+ display_app_info/0,
+ detect_version/3]).
+
+%% Internal exports
+-export([flex_scanner_handler/1]).
+
+-include_lib("kernel/include/file.hrl").
+
+
+%%----------------------------------------------------------------------
+%%
+%% D e t e c t V e r s i o n
+%%
+%%----------------------------------------------------------------------
+
+detect_version(Codec, Conf, Bin) ->
+ case (catch Codec:version_of(Conf, Bin)) of
+ {ok, V} ->
+ case (catch Codec:decode_message(Conf, V, Bin)) of
+ {ok, M} ->
+ case (catch Codec:encode_message(Conf, V, M)) of
+ {ok, NewBin} ->
+ {V, NewBin};
+ Error1 ->
+ error({encode_failed, Error1, Codec, Conf, M})
+ end;
+ Error2 ->
+ error({decode_failed, Error2, Codec, Conf, Bin})
+ end;
+ Error3 ->
+ error({version_of_failed, Error3, Codec, Conf, Bin})
+ end.
+
+
+%%----------------------------------------------------------------------
+%%
+%% S c h e d u l e r b i n d t y p e
+%%
+%%----------------------------------------------------------------------
+
+set_default_sched_bind() ->
+ (catch erlang:system_flag(scheduler_bind_type, default_bind)).
+
+
+%%----------------------------------------------------------------------
+%%
+%% D i s p l a y O s I n f o
+%%
+%%----------------------------------------------------------------------
+
+display_os_info() ->
+ V = case os:version() of
+ {Major, Minor, Release} ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w", [Major, Minor, Release]));
+ Str ->
+ Str
+ end,
+ case os:type() of
+ {OsFam, OsName} ->
+ io:format("OS: ~p-~p: ~s~n", [OsFam, OsName, V]);
+ OsFam ->
+ io:format("OS: ~p: ~s~n", [OsFam, V])
+ end.
+
+
+%%----------------------------------------------------------------------
+%%
+%% D i s p l a y S y s t e m I n f o
+%%
+%%----------------------------------------------------------------------
+
+display_system_info() ->
+ SysArch = system_architecture(),
+ OtpRel = otp_release(),
+ SysVer = system_version(),
+ SysHT = heap_type(),
+ SysGHSz = global_heaps_size(),
+ SysSMP = smp_support(),
+ SysNumSched = schedulers(),
+ SysProcLimit = process_limit(),
+ SysThreads = threads(),
+ SysTPSz = thread_pool_size(),
+ SchedBindings = scheduler_bindings(),
+ SchedBindType = scheduler_bind_type(),
+ CpuTopology = cpu_topology(),
+ io:format("System architecture: ~s~n", [SysArch]),
+ io:format("OTP release: ~s~n", [OtpRel]),
+ io:format("System version: ~s~n", [SysVer]),
+ io:format("Heap type: ~s~n", [SysHT]),
+ io:format("Global heap size: ~s~n", [SysGHSz]),
+ io:format("Thread support: ~s~n", [SysThreads]),
+ io:format("Thread pool size: ~s~n", [SysTPSz]),
+ io:format("Process limit: ~s~n", [SysProcLimit]),
+ io:format("SMP support: ~s~n", [SysSMP]),
+ io:format("Num schedulers: ~s~n", [SysNumSched]),
+ io:format("Scheduler bindings: ~s~n", [SchedBindings]),
+ io:format("Scheduler bind type: ~s~n", [SchedBindType]),
+ io:format("Cpu topology: ~s~n", [CpuTopology]),
+ ok.
+
+
+system_architecture() ->
+ string:strip(system_info(system_architecture, string),right,$\n).
+
+otp_release() ->
+ system_info(otp_release, string).
+
+system_version() ->
+ string:strip(system_info(system_version, string),right,$\n).
+
+heap_type() ->
+ system_info(heap_type, any).
+
+global_heaps_size() ->
+ system_info(global_heaps_size, any).
+
+smp_support() ->
+ system_info(smp_support, any).
+
+schedulers() ->
+ system_info(schedulers, any).
+
+process_limit() ->
+ system_info(process_limit, any).
+
+threads() ->
+ system_info(threads, any).
+
+thread_pool_size() ->
+ system_info(thread_pool_size, any).
+
+scheduler_bindings() ->
+ system_info(scheduler_bindings, any).
+
+scheduler_bind_type() ->
+ system_info(scheduler_bind_type, any).
+
+cpu_topology() ->
+ system_info(cpu_topology, any).
+
+system_info(Tag, Type) ->
+ case (catch erlang:system_info(Tag)) of
+ {'EXIT', _} ->
+ "-";
+ Info when is_list(Info) andalso (Type =:= string) ->
+ Info;
+ Info ->
+ lists:flatten(io_lib:format("~w", [Info]))
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%%
+%% D i s p l a y A l l o c a t o r I n f o
+%%
+%%----------------------------------------------------------------------
+
+display_alloc_info() ->
+ io:format("Allocator memory information:~n", []),
+ AllocInfo = alloc_info(),
+ display_alloc_info(AllocInfo).
+
+display_alloc_info([]) ->
+ ok;
+display_alloc_info([{Alloc, Mem}|AllocInfo]) ->
+ io:format(" ~15w: ~10w~n", [Alloc, Mem]),
+ display_alloc_info(AllocInfo).
+
+alloc_info() ->
+ case erlang:system_info(allocator) of
+ {_Allocator, _Version, Features, _Settings} ->
+ alloc_info(Features);
+ _ ->
+ []
+ end.
+
+alloc_info(Allocators) ->
+ Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc,
+ ets_alloc, binary_alloc, driver_alloc],
+ alloc_info(Allocators, Allocs, []).
+
+alloc_info([], _, Acc) ->
+ lists:reverse(Acc);
+alloc_info([Allocator | Allocators], Allocs, Acc) ->
+ case lists:member(Allocator, Allocs) of
+ true ->
+ Instances0 = erlang:system_info({allocator, Allocator}),
+ Instances =
+ if
+ is_list(Instances0) ->
+ [Instance || Instance <- Instances0,
+ element(1, Instance) =:= instance];
+ true ->
+ []
+ end,
+ AllocatorMem = alloc_mem_info(Instances),
+ alloc_info(Allocators, Allocs, [{Allocator, AllocatorMem} | Acc]);
+
+ false ->
+ alloc_info(Allocators, Allocs, Acc)
+ end.
+
+
+alloc_mem_info(Instances) ->
+ alloc_mem_info(Instances, []).
+
+alloc_mem_info([], Acc) ->
+ lists:sum([Mem || {instance, _, Mem} <- Acc]);
+alloc_mem_info([{instance, N, Info}|Instances], Acc) ->
+ InstanceMemInfo = alloc_instance_mem_info(Info),
+ alloc_mem_info(Instances, [{instance, N, InstanceMemInfo} | Acc]).
+
+alloc_instance_mem_info(InstanceInfo) ->
+ MBCS = alloc_instance_mem_info(mbcs, InstanceInfo),
+ SBCS = alloc_instance_mem_info(sbcs, InstanceInfo),
+ MBCS + SBCS.
+
+alloc_instance_mem_info(Key, InstanceInfo) ->
+ case lists:keysearch(Key, 1, InstanceInfo) of
+ {value, {Key, Info}} ->
+ case lists:keysearch(blocks_size, 1, Info) of
+ {value, {blocks_size, Mem, _, _}} ->
+ Mem;
+ _ ->
+ 0
+ end;
+ _ ->
+ 0
+ end.
+
+
+%%----------------------------------------------------------------------
+%%
+%% D i s p l a y A p p I n f o
+%%
+%%----------------------------------------------------------------------
+
+display_app_info() ->
+ display_megaco_info(),
+ display_asn1_info().
+
+display_megaco_info() ->
+ MI = megaco:module_info(),
+ {value, {attributes, Attr}} = lists:keysearch(attributes, 1, MI),
+ {value, {app_vsn, Ver}} = lists:keysearch(app_vsn, 1, Attr),
+ io:format("Megaco version: ~s~n", [Ver]).
+
+display_asn1_info() ->
+ AI = megaco_ber_bin_drv_media_gateway_control_v1:info(),
+ Vsn =
+ case lists:keysearch(vsn, 1, AI) of
+ {value, {vsn, V}} when is_atom(V) ->
+ atom_to_list(V);
+ {value, {vsn, V}} when is_list(V) ->
+ V;
+ _ ->
+ "unknown"
+ end,
+ io:format("ASN.1 version: ~s~n", [Vsn]).
+
+
+%%----------------------------------------------------------------------
+%%
+%% E x p a n d M e s s a g e s
+%%
+%%----------------------------------------------------------------------
+
+expanded_messages(Codecs, DrvInclude) ->
+ MessagePackage = time_test,
+ expanded_messages(MessagePackage, Codecs, DrvInclude).
+
+expanded_messages(MessagePackage, Codecs, DrvInclude) ->
+ ECodecs = expand_codecs(Codecs, DrvInclude),
+ Messages = megaco_codec_transform:messages(MessagePackage),
+ expanded_messages2(ECodecs, Messages, []).
+
+expanded_messages2([], _Messages, EMessages) ->
+ lists:reverse(EMessages);
+expanded_messages2([{Codec, Mod, Conf}|ECodecs], Messages, EMessages) ->
+ case lists:keysearch(Codec, 1, Messages) of
+ {value, {Codec, Msgs}} ->
+ expanded_messages2(ECodecs, Messages,
+ [{Codec, Mod, Conf, Msgs}|EMessages]);
+ false ->
+ exit({error, {no_such_codec_data, Codec}})
+ end.
+
+
+%%----------------------------------------------------------------------
+%%
+%% E x p a n d C o d e c s
+%%
+%%----------------------------------------------------------------------
+
+expand_codecs(Codecs, DrvInclude) ->
+ expand_codecs(Codecs, DrvInclude, []).
+
+expand_codecs([], _, ECodecs) ->
+ lists:reverse(lists:flatten(ECodecs));
+expand_codecs([Codec|Codecs], DrvInclude, ECodecs) when is_atom(Codec) ->
+ ECodec = expand_codec(Codec, DrvInclude),
+ expand_codecs(Codecs, DrvInclude, [ECodec|ECodecs]).
+
+expand_codec(Codec, flex) ->
+ case Codec of
+ pretty ->
+ [{Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]}];
+ compact ->
+ [{Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]}];
+ ber ->
+ [];
+ per ->
+ [];
+ erlang ->
+ [];
+ Else ->
+ error({invalid_codec, Else})
+ end;
+expand_codec(Codec, only_drv) ->
+ case Codec of
+ pretty ->
+ [{Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, [flex_scanner]}];
+ compact ->
+ [{Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, [flex_scanner]}];
+ ber ->
+ [{Codec, megaco_ber_bin_encoder, [driver,native]},
+ {Codec, megaco_ber_bin_encoder, [driver]},
+ {Codec, megaco_ber_bin_encoder, [driver,native]},
+ {Codec, megaco_ber_bin_encoder, [driver]}];
+ per ->
+ [{Codec, megaco_per_bin_encoder, [driver,native]},
+ {Codec, megaco_per_bin_encoder, [native]},
+ {Codec, megaco_per_bin_encoder, [driver,native]},
+ {Codec, megaco_per_bin_encoder, [native]}];
+ erlang ->
+ Encoder = megaco_erl_dist_encoder,
+ [
+ {Codec, Encoder, [megaco_compressed,compressed]},
+ {Codec, Encoder, [compressed]},
+ {Codec, Encoder, [megaco_compressed,compressed]},
+ {Codec, Encoder, [compressed]}
+ ];
+ Else ->
+ error({invalid_codec, Else})
+ end;
+expand_codec(Codec, no_drv) ->
+ case Codec of
+ pretty ->
+ [{Codec, megaco_pretty_text_encoder, []},
+ {Codec, megaco_pretty_text_encoder, []}];
+ compact ->
+ [{Codec, megaco_compact_text_encoder, []},
+ {Codec, megaco_compact_text_encoder, []}];
+ ber ->
+ [{Codec, megaco_ber_bin_encoder, [native]},
+ {Codec, megaco_ber_bin_encoder, []},
+ {Codec, megaco_ber_bin_encoder, [native]},
+ {Codec, megaco_ber_bin_encoder, []}];
+ per ->
+ [{Codec, megaco_per_bin_encoder, [native]},
+ {Codec, megaco_per_bin_encoder, []},
+ {Codec, megaco_per_bin_encoder, [native]},
+ {Codec, megaco_per_bin_encoder, []}];
+ erlang ->
+ Encoder = megaco_erl_dist_encoder,
+ [
+ {Codec, Encoder, [megaco_compressed]},
+ {Codec, Encoder, []},
+ {Codec, Encoder, [megaco_compressed]},
+ {Codec, Encoder, []}
+ ];
+ Else ->
+ error({invalid_codec, Else})
+ end;
+expand_codec(Codec, _) ->
+ case Codec of
+ pretty ->
+ [{Codec, megaco_pretty_text_encoder, [flex_scanner]},
+ {Codec, megaco_pretty_text_encoder, []}];
+ compact ->
+ [{Codec, megaco_compact_text_encoder, [flex_scanner]},
+ {Codec, megaco_compact_text_encoder, []}];
+ ber ->
+ [{Codec, megaco_ber_bin_encoder, [driver,native]},
+ {Codec, megaco_ber_bin_encoder, [native]},
+ {Codec, megaco_ber_bin_encoder, [driver]},
+ {Codec, megaco_ber_bin_encoder, []}];
+ per ->
+ [{Codec, megaco_per_bin_encoder, [driver,native]},
+ {Codec, megaco_per_bin_encoder, [native]},
+ {Codec, megaco_per_bin_encoder, [driver]},
+ {Codec, megaco_per_bin_encoder, []}];
+ erlang ->
+ Encoder = megaco_erl_dist_encoder,
+ [
+ {Codec, Encoder, [megaco_compressed,compressed]},
+ {Codec, Encoder, [compressed]},
+ {Codec, Encoder, [megaco_compressed]},
+ {Codec, Encoder, []}
+ ];
+ Else ->
+ error({invalid_codec, Else})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%----------------------------------------------------------------------
+%%
+%% S t a r t F l e x S c a n n e r H a n d l e r
+%%
+%%----------------------------------------------------------------------
+
+start_flex_scanner() ->
+ Pid = proc_lib:spawn(?MODULE, flex_scanner_handler, [self()]),
+ receive
+ {flex_scanner_started, Pid, Conf} ->
+ {Pid, [Conf]};
+ {flex_scanner_error, {failed_loading_flex_scanner_driver, Reason}} ->
+ error({failed_loading_flex_scanner_driver, Reason});
+ {flex_scanner_error, Reason} ->
+ error({failed_loading_flex_scanner_driver, Reason})
+ after 10000 ->
+ exit(Pid, kill),
+ error({failed_starting_flex_scanner, timeout})
+ end.
+
+%%----------------------------------------------------------------------
+%%
+%% S t o p F l e x S c a n n e r H a n d l e r
+%%
+%%----------------------------------------------------------------------
+
+stop_flex_scanner(Pid) ->
+ Pid ! stop_flex_scanner.
+
+flex_scanner_handler(Pid) ->
+ case (catch megaco_flex_scanner:start()) of
+ {ok, PortOrPorts} ->
+ Pid ! {flex_scanner_started, self(), {flex, PortOrPorts}},
+ flex_scanner_handler_loop(Pid, PortOrPorts);
+ {error, {load_driver, {open_error, Reason}}} ->
+ Error = {failed_loading_flex_scanner_driver, Reason},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error);
+ Else ->
+ Error = {unknown_result_from_start_flex_scanner, Else},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error)
+ end.
+
+flex_scanner_handler_loop(Pid, PortOrPorts) ->
+ receive
+ {ping, Pinger} ->
+ Pinger ! {pong, self()},
+ flex_scanner_handler_loop(Pid, PortOrPorts);
+ {'EXIT', Port, Reason} when (Port =:= PortOrPorts) ->
+ Pid ! {flex_scanner_exit, Reason},
+ exit({flex_scanner_exit, Reason});
+ {'EXIT', Port, Reason} when is_port(Port) ->
+ case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
+ true ->
+ Pid ! {flex_scanner_exit, Reason},
+ exit({flex_scanner_exit, Reason});
+ false ->
+ %% Just ignore this crap
+ flex_scanner_handler_loop(Pid, PortOrPorts)
+ end;
+ stop_flex_scanner ->
+ megaco_flex_scanner:stop(PortOrPorts),
+ exit(normal);
+ _Other ->
+ flex_scanner_handler_loop(Pid, PortOrPorts)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/megaco/examples/meas/megaco_codec_transform.erl b/lib/megaco/examples/meas/megaco_codec_transform.erl
new file mode 100644
index 0000000000..cfe832ff26
--- /dev/null
+++ b/lib/megaco/examples/meas/megaco_codec_transform.erl
@@ -0,0 +1,305 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Megaco message transformation
+%%
+%% Usage: From a base message file, messages for every codec is
+%% generated. The file should have the following structure:
+%%
+%% {Codec, Messages}.
+%%
+%% Codec = pretty | compact | ber | per | erlang
+%% Messages = [{Name, binary()}]
+%% Name = atom
+%%
+%% The function messages/0 is used by the meas and mstone
+%% tools, but messages/1 can also be used if another base
+%% message file is to be used.
+%%
+%% The messages can also be exported to the old format,
+%% e.g. a directory for each of the codec's and the
+%% each message as a file in those directories.
+%%
+%% Pretty text: pretty
+%% Compact text: compact
+%% Binary ber: ber
+%% Binary per: per
+%% Erlang: erlang
+%%
+%%
+%% <message package>/pretty/<message-files>
+%% compact/<message-files>
+%% per/<message-files>
+%% ber/<message-files>
+%% erlang/<message-files>
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_transform).
+
+-include_lib("kernel/include/file.hrl").
+
+-export([
+ codecs/0,
+ default_message_package/0,
+ messages/0, messages/1,
+ export_messages/0, export_messages/1
+ ]).
+
+-define(DEFAULT_MESSAGE_PACKAGE, time_test).
+-define(ALL_CODECS, [pretty, compact, per, ber, erlang]).
+-define(V3, v3).
+
+codecs() ->
+ ?ALL_CODECS.
+
+default_message_package() ->
+ ?DEFAULT_MESSAGE_PACKAGE.
+
+messages() ->
+ messages(?DEFAULT_MESSAGE_PACKAGE).
+
+messages(MessagePackage) when is_atom(MessagePackage) ->
+ %% Try the CWD first, and if that does not work try the installation directory
+ case load_messages(".", MessagePackage) of
+ {error, _Reason} ->
+ AppLibDir = code:lib_dir(megaco),
+ Dir = filename:join([AppLibDir, examples, meas]),
+ load_messages(Dir, MessagePackage);
+ Else ->
+ Else
+ end.
+
+load_messages(Dir, MessagePackage) ->
+ %% io:format("try loading messages from ~s~n", [Dir]),
+ Filename = filename:join([Dir, atom_to_list(MessagePackage) ++ ".msgs"]),
+ case file:consult(Filename) of
+ {ok, [{Codec, Msgs}]} when is_atom(Codec) andalso is_list(Msgs) ->
+ case lists:member(Codec, ?ALL_CODECS) of
+ true ->
+ messages(Codec, Msgs);
+ false ->
+ {error, {unknown_codec, Codec}}
+ end;
+
+ {ok, [{BadCodec, Msgs}]} when is_list(Msgs) ->
+ {error, {bad_codec, BadCodec}};
+
+ %% No codec specified, try with pretty
+ {ok, [Msgs]} when is_list(Msgs) ->
+ messages(pretty, Msgs);
+
+ {ok, Crap} ->
+ {error, {bad_messages, Crap}};
+
+ Error ->
+ Error
+ end.
+
+messages(BaseCodec, Msgs) ->
+ OutCodecs = lists:delete(BaseCodec, ?ALL_CODECS),
+ transform_messages(BaseCodec, Msgs, OutCodecs).
+
+
+export_messages() ->
+ export_messages(?DEFAULT_MESSAGE_PACKAGE).
+
+export_messages(MessagePackage) when is_atom(MessagePackage) ->
+ case messages(MessagePackage) of
+ TMsgs when is_list(TMsgs) ->
+ (catch export_messages(MessagePackage, TMsgs));
+ Error ->
+ Error
+ end.
+
+export_messages(MessagePackage, TMsgs) ->
+ case file:make_dir(MessagePackage) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ throw(Error)
+ end,
+ do_export_messages(MessagePackage, TMsgs).
+
+do_export_messages(_MessagePackage, []) ->
+ ok;
+do_export_messages(MessagePackage, [{Codec, Msgs} | TMsgs]) ->
+ ems(MessagePackage, Codec, Msgs),
+ do_export_messages(MessagePackage, TMsgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+transform_messages(BaseCodec, BaseMsgs, OutCodecs) ->
+ [{BaseCodec, BaseMsgs} |
+ [{Codec, tms(BaseMsgs, BaseCodec, Codec)} || Codec <- OutCodecs]].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tms(FromMsgs, FromCodec, ToCodec) ->
+ [{Name, tm(FromBin, FromCodec, ToCodec)} || {Name, FromBin} <- FromMsgs].
+
+tm(FromBin, FromCodec, ToCodec) ->
+ FromMsg = decode_message(FromCodec, FromBin),
+ encode_message(ToCodec, FromMsg).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ems(MessagePackage, Codec, Msgs) ->
+ Dir = filename:join([MessagePackage, Codec]),
+ case file:make_dir(Dir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ throw(Error)
+ end,
+ Extension = extension_of(Codec),
+ F = fun({Name, Bin}) -> em(MessagePackage, Codec, Name, Extension, Bin) end,
+ lists:foreach(F, Msgs).
+
+em(MessagePackage, Codec, Name, Extension, Bin) ->
+ Filename = filename:join([MessagePackage, Codec, atom_to_list(Name) ++ Extension]),
+ case file:open(Filename, [raw, binary, write]) of
+ {ok, Fd} ->
+ case file:write(Fd, Bin) of
+ ok ->
+ file:close(Fd),
+ ok;
+ {error, Reason} ->
+ S = format("failed writing ~w message ~w (~p bytes): ~p",
+ [Codec, Name, size(Bin), Reason]),
+ file:close(Fd),
+ throw({error, S})
+ end;
+
+ {error, Reason} ->
+ S = format("failed open file ~s: ~p", [Filename, Reason]),
+ throw({error, S})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_message(pretty, BinMsg) ->
+ Mod = megaco_pretty_text_encoder,
+ Conf = [{version3,?V3}],
+ do_decode(Mod, Conf, BinMsg);
+decode_message(compact, BinMsg) ->
+ Mod = megaco_compact_text_encoder,
+ Conf = [{version3,?V3}],
+ do_decode(Mod, Conf, BinMsg);
+decode_message(ber, BinMsg) ->
+ Mod = megaco_ber_bin_encoder,
+ Conf = [{version3,?V3}],
+ do_decode(Mod, Conf, BinMsg);
+decode_message(per, BinMsg) ->
+ Mod = megaco_per_bin_encoder,
+ Conf = [{version3,?V3}],
+ do_decode(Mod, Conf, BinMsg);
+decode_message(erlang, BinMsg) ->
+ Mod = megaco_erl_dist_encoder,
+ Conf = [{version3,?V3}],
+ do_decode(Mod, Conf, BinMsg).
+
+
+do_decode(Mod, Conf, Bin) ->
+ case (catch Mod:decode_message(Conf, Bin)) of
+ {ok, Msg} ->
+ Msg;
+ {error, Reason} ->
+ S = format("decode error: ~p", [Reason]),
+ throw({error, S});
+ {'EXIT', Reason} ->
+ S = format("decode exit: ~p", [Reason]),
+ throw({error, S});
+ Other ->
+ S = format("unknwon decode result: ~p", [Other]),
+ throw({error, S})
+ end.
+
+
+%% encode_message
+%% Note: See note above (decode_message)
+
+encode_message(pretty, Msg) ->
+ Mod = megaco_pretty_text_encoder,
+ Conf = [{version3,?V3}],
+ do_encode(Mod, Conf, Msg);
+encode_message(compact, Msg) ->
+ Mod = megaco_compact_text_encoder,
+ Conf = [{version3,?V3}],
+ do_encode(Mod, Conf, Msg);
+encode_message(ber, Msg) ->
+ Mod = megaco_ber_bin_encoder,
+ Conf = [{version3,?V3}],
+ do_encode(Mod, Conf, Msg);
+encode_message(per, Msg) ->
+ Mod = megaco_per_bin_encoder,
+ Conf = [{version3,?V3}],
+ do_encode(Mod, Conf, Msg);
+encode_message(erlang, Msg) ->
+ Mod = megaco_erl_dist_encoder,
+ Conf = [{version3,?V3}],
+ do_encode(Mod, Conf, Msg).
+
+
+do_encode(Mod, Conf, Msg) ->
+ case (catch Mod:encode_message(Conf, Msg)) of
+ {ok, Bin} ->
+ Bin;
+ {error, Reason} ->
+ S = format("encode error: ~p", [Reason]),
+ throw({error, S});
+ {'EXIT', Reason} ->
+ S = format("encode exit: ~p", [Reason]),
+ throw({error, S});
+ Other ->
+ S = format("unknwon encode result: ~p", [Other]),
+ throw({error, S})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+extension_of(pretty) ->
+ ".txt";
+extension_of(compact) ->
+ ".txt";
+extension_of(ber) ->
+ ".bin";
+extension_of(per) ->
+ ".bin";
+extension_of(erlang) ->
+ ".bin".
+
+%% d(F) ->
+%% d(F, []).
+%% d(F, A) ->
+%% io:format(F ++ "~n", A).
+
+format(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
diff --git a/lib/megaco/examples/meas/modules.mk b/lib/megaco/examples/meas/modules.mk
new file mode 100644
index 0000000000..8f1b45c8a6
--- /dev/null
+++ b/lib/megaco/examples/meas/modules.mk
@@ -0,0 +1,35 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+SCRIPT_SKELETONS = \
+ meas.sh.skel \
+ mstone1.sh.skel
+
+MESSAGE_PACKAGES = \
+ time_test.msgs
+
+MODULES = \
+ megaco_codec_transform \
+ megaco_codec_mstone_lib \
+ megaco_codec_mstone1 \
+ megaco_codec_mstone2 \
+ megaco_codec_meas
+
+README = MEAS_README
+
diff --git a/lib/megaco/examples/meas/mstone1.sh.skel b/lib/megaco/examples/meas/mstone1.sh.skel
new file mode 100644
index 0000000000..b7c7e41007
--- /dev/null
+++ b/lib/megaco/examples/meas/mstone1.sh.skel
@@ -0,0 +1,239 @@
+#!/bin/sh
+
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+# Skeleton for a script intended to run the mstone1(N)
+# performance test.
+#
+
+# Get the name of the program
+program=`echo $0 | sed 's#.*/##g'`
+
+usage="\
+Usage: $program [options]
+
+This shell script is used to run the mstone 1 (factor) performance
+test. It is not intended to test the megaco stack but instead to
+give a \"performance value\" of the host on which it is run.
+
+Options:
+ -help display this help and exit.
+ -mp <message package> message package to use for test
+ default is time_test
+ -h <num> default process heap size
+ -a <num> async thread pool size (default is 0)
+ -f <factor> normally the test is run with 16 processes
+ (factor 1), one for each codec config. The test
+ can however be run with other factors, e.g.
+ factor 10 means that 10 processes will be started
+ for each megaco codec config.
+ The options -s and -f cannot both be present.
+ -s <num sched> normally the test is run with a fixed factor,
+ but if this option is given, the number of
+ schedulers is fixed (to the value set by this option)
+ and the factor is the variable.
+ The options -s and -f cannot both be present.
+ -d <drv-mode> driver mode for the test:
+ std - all codec config(s) will be used
+ flex - only the text codec config(s) utilizing the
+ flex scanner will be used
+ nd - only codec config(s) without drivers will be used
+ od - only codec config(s) with drivers will be used
+ -- everything after this is just passed on to erl.
+"
+
+ERL_HOME=<path to otp top dir>
+MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir>
+MEAS_HOME=$MEGACO_HOME/examples/meas
+PATH=$ERL_HOME/bin:$PATH
+
+MODULE=megaco_codec_mstone1
+STARTF="start"
+FACTOR=""
+MSG_PACK=time_test
+
+while test $# != 0; do
+ # echo "DBG: Value = $1"
+ case $1 in
+ -help)
+ echo "$usage" ;
+ exit 0;;
+
+ -mp)
+ MSG_PACK="$2";
+ shift ; shift ;;
+
+ -h)
+ PHS="+h $2";
+ shift ; shift ;;
+
+ -a)
+ ATP="+A $2";
+ shift ; shift ;;
+
+ -d)
+ case $2 in
+ std)
+ STARTF="start";
+ shift ; shift ;;
+ flex)
+ STARTF="start_flex";
+ shift ; shift ;;
+ nd)
+ STARTF="start_no_drv";
+ shift ; shift ;;
+ od)
+ STARTF="start_only_drv";
+ shift ; shift ;;
+ *)
+ echo "unknown driver mode: $2";
+ echo "$usage" ;
+ exit 0
+ esac;;
+
+ -f)
+ if [ "x$SCHED" != "x" ]; then
+ echo "option(s) -s and -f cannot both be given" ;
+ echo "$usage" ;
+ exit 0
+ fi
+ FACTOR="$2";
+ TYPE=factor;
+ shift ; shift ;;
+
+ -s)
+ if [ "x$FACTOR" != "x" ]; then
+ echo "option(s) -f and -s cannot both be given" ;
+ echo "$usage" ;
+ exit 0
+ fi
+ SCHED="$2";
+ TYPE=sched;
+ shift ; shift ;;
+
+ --)
+ shift ;
+ break;;
+
+ *)
+ echo "unknown option: $1";
+ echo "$usage" ;
+ exit 0
+ esac
+done
+
+if [ $TYPE = factor ]; then
+
+ MSTONE="-s $MODULE $STARTF $MSG_PACK $FACTOR"
+
+ # SCHEDS="no_smp 01 02 04"
+ # SCHEDS="no_smp 01 02 04 08"
+ # SCHEDS="no_smp 01 02 04 08 16"
+ # SCHEDS="no_smp 01 02 04 08 16 32"
+ # SCHEDS="no_smp 01 02 04 08 16 32 64"
+ SCHEDS="no_smp 01 02 03 04 05 06 07 08"
+
+ for i in `echo $SCHEDS`; do
+ case $i in
+ no_smp)
+ SMP_INFO="No SMP"
+ SMP_OPTS="-smp disable" # THIS IS THE R12B WAY TO DISABLE SMP
+ LOG="mstone1-f$FACTOR-s00.log"
+ ;;
+
+ 01)
+ SMP_INFO="SMP: 1 scheduler"
+ SMP_OPTS="-smp +S $i"
+ LOG="mstone1-f$FACTOR-s$i.log"
+ ;;
+
+ *)
+ SMP_INFO="SMP: $i schedulers"
+ SMP_OPTS="-smp +S $i"
+ LOG="mstone1-f$FACTOR-s$i.log"
+ ;;
+ esac
+
+ echo ""
+ echo "---------------------------------------------"
+ echo "$SMP_INFO"
+ echo ""
+
+ ERL="erl \
+ -noshell \
+ $PHS \
+ $ATP \
+ $SMP_OPTS \
+ -pa $MEAS_HOME \
+ $MSTONE \
+ $* \
+ -s init stop"
+
+ echo $ERL
+ $ERL | tee $LOG
+ done
+
+elif [ $TYPE = sched ]; then
+
+ MSTONE="-s $MODULE $STARTF $MSG_PACK"
+
+ # FACTORS="01 02 03 04"
+ # FACTORS="01 02 03 04 05 06 07 08 09 10"
+ FACTORS="01 02 04 08 16 32"
+ # FACTORS="001 010 100"
+
+ case $SCHED in
+ no_smp)
+ SMP_OPTS="-smp disable" # THIS IS THE R12B WAY TO DISABLE SMP
+ ;;
+
+ *)
+ SMP_OPTS="-smp +S $SCHED"
+ ;;
+ esac
+
+ for i in `echo $FACTORS`; do
+ LOG="mstone1-s$SCHED-f$i.log"
+
+ echo ""
+ echo "---------------------------------------------"
+ echo "Factor $i"
+ echo ""
+
+ ERL="erl \
+ -noshell \
+ $PHS \
+ $ATP \
+ $SMP_OPTS \
+ -pa $MEAS_HOME \
+ $MSTONE $i \
+ $* \
+ -s init stop"
+
+ echo $ERL
+ $ERL | tee $LOG
+ done
+
+
+else
+ echo "Either option -f or -s must be specified"
+ echo "$usage" ;
+ exit 0
+
+fi
diff --git a/lib/megaco/examples/meas/time_test.msgs b/lib/megaco/examples/meas/time_test.msgs
new file mode 100644
index 0000000000..d8ac2bf1a2
--- /dev/null
+++ b/lib/megaco/examples/meas/time_test.msgs
@@ -0,0 +1,149 @@
+{pretty, [{msg01a,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 9999 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive,\n\t\t\t\t\t\ttdmc/gain=2,\n\t\t\t\t\t\ttdmc/ec=g165\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 0\na=fmtp:PCMU VAD=X-NNVAD\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 2222 {\n\t\t\t\tal/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg01b,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 9999 {\n\tContext = - {\n\t\tModify = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive,\n\t\t\t\t\t\ttdmc/gain=2,\n\t\t\t\t\t\ttdmc/ec=g165\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 0\na=fmtp:PCMU VAD=X-NNVAD\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 2222 {\n\t\t\t\tal/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg02,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 9999 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive,\n\t\t\t\t\t\ttdmc/gain=2,\n\t\t\t\t\t\ttdmc/ec=g165\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 0\na=fmtp:PCMU VAD=X-NNVAD\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 2222 {\n\t\t\t\tal/of {\n\t\t\t\t\tstrict=exact\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg03,<<"MEGACO/1 [124.124.124.222]:55555\nTransaction = 10000 {\n\tContext = - {\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg04,<<"MEGACO/1 [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg05,<<"MEGACO/1 [123.123.123.4]:55555\nReply = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t\t}\n\t}\n}">>},
+ {msg06a,<<"MEGACO/1 [124.124.124.222]:55555\nReply = 9999 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000\n\t}\n}">>},
+ {msg06b,<<"MEGACO/1 [125.125.125.111]:55555\nReply = 9999 {\n\tContext = - {\n\t\tModify = 11111111/11111111/00000000\n\t}\n}">>},
+ {msg07,<<"MEGACO/1 [123.123.123.4]:55555\nReply = 10000 {\n\tContext = - {\n\t\tNotify = 11111111/00000000/00000000\n\t}\n}">>},
+ {msg08a,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on,\n\t\t\t\tdd/ce {\n\t\t\t\t\tDigitMap = dialplan00\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg08b,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on,\n\t\t\t\tdd/ce {\n\t\t\t\t\tDigitMap = dialplan00\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\tT:1,\n\t\t\t\tS:23,\n\t\t\t\tL:99,\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg09,<<"MEGACO/1 [124.124.124.222]:55555\nTransaction = 10002 {\n\tContext = - {\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2223 {\n\t\t\t\t19990729T22010001:dd/ce {\n\t\t\t\t\tds=916135551212\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg10,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 10003 {\n\tContext = $ {\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = $ {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = ReceiveOnly,\n\t\t\t\t\t\tnt/jit=40\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 4\na=ptime:30\nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 0\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg11,<<"MEGACO/1 [124.124.124.222]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 124.124.124.222\nm=audio 2222 RTP/AVP 4\na=a=ptime:30\na=recvonly\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg12,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 50003 {\n\tContext = $ {\n\t\tAdd = 11111111/11111111/00000000 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tal/ri\n\t\t\t}\n\t\t},\n\t\tAdd = $ {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive,\n\t\t\t\t\t\tnt/jit=40\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 $ \nm=audio $ RTP/AVP 4\na=ptime:30\n\n\t\t\t\t\t},\n\t\t\t\t\tRemote { \nv=0\nc=IN IP4 124.124.124.222\nm=audio 2222 RTP/AVP 4\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg13,<<"MEGACO/1 [125.125.125.111]:55555\nReply = 50003 {\n\tContext = 5000 {\n\t\tAdd = 11111111/11111111/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 125.125.125.111\nm=audio 1111 RTP/AVP 4\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg14,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 10005 {\n\tContext = 2000 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t}\n\t\t},\n\t\tModify = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tRemote { \nv=0\nc=IN IP4 125.125.125.111\nm=audio 1111 RTP/AVP 4\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg15,<<"MEGACO/1 [124.124.124.222]:55555\nReply = 10005 {\n\tContext = 2000 {\n\t\tModify = 11111111/00000000/00000000,\n\t\tModify = 11111111/00000000/11111111\n\t}\n}">>},
+ {msg16,<<"MEGACO/1 [125.125.125.111]:55555\nTransaction = 50005 {\n\tContext = 5000 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1234 {\n\t\t\t\t19990729T22020002:al/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg17,<<"MEGACO/1 [123.123.123.4]:55555\nReply = 50005 {\n\tContext = - {\n\t\tNotify = 11111111/11111111/00000000\n\t}\n}">>},
+ {msg18,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 50006 {\n\tContext = 5000 {\n\t\tModify = 11111111/11111111/00000000 {\n\t\t\tEvents = 1235 {\n\t\t\t\tal/on\n\t\t\t},\n\t\t\tSignals\n\t\t}\n\t}\n}">>},
+ {msg19,<<"MEGACO/1 [125.125.125.111]:55555\nReply = 50006 {\n\tContext = 5000 {\n\t\tModify = 11111111/00000000/11111111\n\t}\n}">>},
+ {msg20,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 10006 {\n\tContext = 2000 {\n\t\tModify = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals\n\t\t}\n\t}\n}">>},
+ {msg21,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia,\n\t\t\t\tEvents,\n\t\t\t\tSignals,\n\t\t\t\tDigitMap,\n\t\t\t\tStatistics,\n\t\t\t\tPackages\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg22a,<<"MEGACO/1 [125.125.125.111]:55555\nReply = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode = SendReceive,\n\t\t\t\t\t\tnt/jit=40\n\t\t\t\t\t},\n\t\t\t\t\tLocal { \nv=0\nc=IN IP4 125.125.125.111\nm=audio 1111 RTP/AVP 4\na=ptime:30\n\n\t\t\t\t\t},\n\t\t\t\t\tRemote { \nv=0\nc=IN IP4 124.124.124.222\nm=audio 2222 RTP/AVP 4\na=ptime:30\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tPackages {\n\t\t\t\tnt-1,\n\t\t\t\tnt-1\n\t\t\t},\n\t\t\tStatistics {\n\t\t\t\trtp/ps = 1200,\n\t\t\t\tnt/os = 62300,\n\t\t\t\trtp/pr = 700,\n\t\t\t\tnt/or = 45100,\n\t\t\t\trtp/pl = 0.2,\n\t\t\t\trtp/jit = 20,\n\t\t\t\trtp/delay = 40\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg23a,<<"MEGACO/1 [125.125.125.111]:55555\nTransaction = 50008 {\n\tContext = 5000 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg23b,<<"MEGACO/1 [125.125.125.111]:55555\nTransaction = 50008 {\n\tContext = 5000 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t},\n\tContext = 5001 {\n\t\tNotify = 11111111/11111111/11111111 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg23c,<<"MEGACO/1 [125.125.125.111]:55555\nTransaction = 50008 {\n\tContext = 5000 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}Transaction = 50009 {\n\tContext = 5001 {\n\t\tNotify = 11111111/11111111/11111111 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg23d,<<"MEGACO/1 [125.125.125.111]:55555\nTransaction = 50008 {\n\tContext = 5000 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t},\n\tContext = 5001 {\n\t\tNotify = 11111111/11111111/11111111 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}Transaction = 50009 {\n\tContext = 5003 {\n\t\tNotify = 11111111/11111111/00000000 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t},\n\tContext = 5004 {\n\t\tNotify = 11111111/11111111/11111111 {\n\t\t\tObservedEvents = 1235 {\n\t\t\t\t19990729T24020002:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg24,<<"MEGACO/1 [123.123.123.4]:55555\nTransaction = 50009 {\n\tContext = 5000 {\n\t\tSubtract = 11111111/11111111/00000000 {\n\t\t\tAudit {\n\t\t\t\tStatistics\n\t\t\t}\n\t\t},\n\t\tSubtract = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tStatistics\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg25,<<"MEGACO/1 [125.125.125.111]:55555\nReply = 50009 {\n\tContext = 5000 {\n\t\tSubtract = 11111111/11111111/00000000 {\n\t\t\tStatistics {\n\t\t\t\tnt/os = 45123,\n\t\t\t\tnt/dur = 40\n\t\t\t}\n\t\t},\n\t\tSubtract = 11111111/11111111/11111111 {\n\t\t\tStatistics {\n\t\t\t\trtp/ps = 1245,\n\t\t\t\tnt/os = 62345\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg30a,<<"MEGACO/1 [125.125.125.111]:55555\nTransactionResponseAck {\n\t9\n}">>},
+ {msg30b,<<"MEGACO/1 [125.125.125.111]:55555\nTransactionResponseAck {\n\t9-13\n}">>},
+ {msg30c,<<"MEGACO/1 [125.125.125.111]:55555\nTransactionResponseAck {\n\t9-13,\n\t15,\n\t33-40,\n\t50-60,\n\t70-80,\n\t85-90,\n\t101-105,\n\t109-119,\n\t121-130,\n\t140-160,\n\t170-175,\n\t180-189,\n\t201-205,\n\t209-219,\n\t221-230,\n\t240-260,\n\t270-275,\n\t280-289,\n\t301-305,\n\t309-319,\n\t321-330,\n\t340-360,\n\t370-375,\n\t380-389,\n\t401-405,\n\t409-419,\n\t421-430,\n\t440-460,\n\t470-475,\n\t480-489,\n\t501-505,\n\t509-519,\n\t521-530,\n\t540-560,\n\t570-575,\n\t580-589\n}">>},
+ {msg30d,<<"MEGACO/1 [125.125.125.111]:55555\nTransactionResponseAck {\n\t9-13,\n\t15,\n\t33-40,\n\t50-60,\n\t70-80,\n\t85-90\n}TransactionResponseAck {\n\t101-105,\n\t109-119,\n\t121-130,\n\t140-160,\n\t170-175,\n\t180-189\n}TransactionResponseAck {\n\t201-205,\n\t209-219,\n\t221-230,\n\t240-260,\n\t270-275,\n\t280-289\n}TransactionResponseAck {\n\t301-305,\n\t309-319,\n\t321-330,\n\t340-360,\n\t370-375,\n\t380-389\n}TransactionResponseAck {\n\t401-405,\n\t409-419,\n\t421-430,\n\t440-460,\n\t470-475,\n\t480-489\n}TransactionResponseAck {\n\t501-505,\n\t509-519,\n\t521-530,\n\t540-560,\n\t570-575,\n\t580-589\n}">>},
+ {msg51a,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\ttdmc/gain\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51b,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\tnt/jit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51c,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\tServiceStates\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51d,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\tBuffer\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51e,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\tMode\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51f,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\tReservedValue\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51g,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\tReservedGroup\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51h,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStream = 123 {\n\t\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\t\t\tnt/jit\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg51i,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStream = 123 {\n\t\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\t\t\tMode,\n\t\t\t\t\t\t\t\t\tReservedValue,\n\t\t\t\t\t\t\t\t\tReservedGroup,\n\t\t\t\t\t\t\t\t\tnt/jit,\n\t\t\t\t\t\t\t\t\ttdmc/ec\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg52,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tEvents = 1235 {\n\t\t\t\t\ttonedet/std\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg53,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tEventBuffer {\n\t\t\t\t\ttonedet/std {\n\t\t\t\t\t\tStream = 1\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg54a,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tSignals {\n\t\t\t\t\ttonegen/pt\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg54b,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tSignals {\n\t\t\t\t\tdg/d0\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg54c,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tSignals {\n\t\t\t\t\tSignalList = 4321 {\n\t\t\t\t\t\tct/ct\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg55,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tDigitMap = dialplan00\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg56,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tStatistics {\n\t\t\t\t\tnt/dur\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg57,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tPackages {\n\t\t\t\t\tal-1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg58a,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\ttdmc/gain\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tEvents = 1235 {\n\t\t\t\t\ttonedet/std\n\t\t\t\t},\n\t\t\t\tEventBuffer {\n\t\t\t\t\ttonedet/std {\n\t\t\t\t\t\tStream = 1\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tSignals {\n\t\t\t\t\ttonegen/pt\n\t\t\t\t},\n\t\t\t\tDigitMap = dialplan00,\n\t\t\t\tStatistics {\n\t\t\t\t\tnt/dur\n\t\t\t\t},\n\t\t\t\tPackages {\n\t\t\t\t\tal-1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg58b,<<"MEGACO/2 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\tBuffer\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tEvents = 1235 {\n\t\t\t\t\ttonedet/std\n\t\t\t\t},\n\t\t\t\tEventBuffer {\n\t\t\t\t\ttonedet/std {\n\t\t\t\t\t\tStream = 1\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tSignals {\n\t\t\t\t\tSignalList = 4321 {\n\t\t\t\t\t\tct/ct\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tDigitMap = dialplan00,\n\t\t\t\tStatistics {\n\t\t\t\t\tnt/dur\n\t\t\t\t},\n\t\t\t\tPackages {\n\t\t\t\t\tal-1\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg61a,<<"MEGACO/2 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergencyOffToken,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg61b,<<"MEGACO/2 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg61c,<<"MEGACO/2 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71a,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tEmergency,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b03,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tEmergencyOff,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b04,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b05,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b06,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b07,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b08,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b09,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b10,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway,\n\t\t\tOnewayBoth\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b11,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway,\n\t\t\tOnewayExternal\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b12,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tIEPSCall = ON,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b13,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b14,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tContextAttr {\n\t\t\ttdmc/gain=2\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b15,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tContextAttr {\n\t\t\ttdmc/gain>2\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b16,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tContextAttr {\n\t\t\ttdmc/gain = [ 2:10 ] \n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b17,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tContextAttr {\n\t\t\tnt/jit = [\n\t\t\t40,\n\t\t\t50,\n\t\t\t50\n\t\t]\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b18,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = ON,\n\t\tContextAttr {\n\t\t\ttdmc/gain = {\n\t\t\t2,\n\t\t\t4,\n\t\t\t8\n\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b19,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b20,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\ttdmc/gain = {\n\t\t\t2,\n\t\t\t4,\n\t\t\t8\n\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b21,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\tContextList = {\n\t\t\t\t10191,\n\t\t\t\t10192\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71b22,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\ttdmc/gain = {\n\t\t\t2,\n\t\t\t4,\n\t\t\t8\n\t\t}\n\t\t},\n\t\tContextAttr {\n\t\t\tContextList = {\n\t\t\t\t10191,\n\t\t\t\t10192\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c03,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tPriority\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c04,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tEmergency,\n\t\t\tPriority\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c05,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tPriority\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c06,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tEmergency\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c07,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c08,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tPriority,\n\t\t\tIEPSCall\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c09,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c10,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c11,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tEmergencyValue = Emergency\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c12,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tEmergencyValue = Emergency,\n\t\t\tIEPSCall = OFF\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c13,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tEmergencyValue = EmergencyOff,\n\t\t\tIEPSCall = ON\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c14,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tEmergencyValue = Emergency,\n\t\t\tIEPSCall = ON,\n\t\t\tORLgc\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71c15,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tORLgc\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71d01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71d02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tIEPSCall = ON,\n\t\tContextAttr {\n\t\t\ttdmc/gain#2\n\t\t},\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71d03,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\ttdmc/gain#2\n\t\t},\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg71d04,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 9898 {\n\tContext = 1 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\ttdmc/gain#2\n\t\t},\n\t\tContextAttr {\n\t\t\tContextList = {\n\t\t\t\t10191,\n\t\t\t\t10192\n\t\t\t}\n\t\t},\n\t\tContextAudit {\n\t\t\tTopology,\n\t\t\tEmergency,\n\t\t\tPriority,\n\t\t\tIEPSCall,\n\t\t\ttdmc/gain,\n\t\t\tnt/jit,\n\t\t\tPriority = 10,\n\t\t\tEmergencyValue = Emergency,\n\t\t\tIEPSCall = ON,\n\t\t\tORLgc\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000000:al/of\n\t\t\t}\n\t\t},\n\t\tNotify = 11111111/00000000/00000000 {\n\t\t\tObservedEvents = 2222 {\n\t\t\t\t19990729T22000111:al/on\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg72a01,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tEmergencyOff,\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg72a02,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg72a03,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tBothway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg72b01,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { } \n\t}\n}">>},
+ {msg72b02,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergencyOff,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tIsolate,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { } \n\t}\n}">>},
+ {msg72b03,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tIEPSCall = ON,\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { } \n\t}\n}">>},
+ {msg72b04,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tBothway\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { } \n\t}\n}">>},
+ {msg72c01,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { \"Just another error string\" } \n\t}\n}">>},
+ {msg72c02,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tOneway\n\t\t},\n\t\tContextAttr {\n\t\t\ttdmc/gain=2\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { \"Just another error string\" } \n\t}\n}">>},
+ {msg72c03,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = ON,\n\t\tContextAttr {\n\t\t\ttdmc/gain = {\n\t\t\t2,\n\t\t\t4,\n\t\t\t8\n\t\t}\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { \"Just another error string\" } \n\t}\n}">>},
+ {msg72c04,<<"MEGACO/3 [123.123.123.4]:55555\nReply = 10003 {\n\tContext = 2000 {\n\t\tPriority = 15,\n\t\tEmergency,\n\t\tTopology {\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/00001111,\n\t\t\tOneway,\n\t\t\t11111111/00001111/00000000,\n\t\t\t11111111/00001111/00001111,\n\t\t\tIsolate\n\t\t},\n\t\tIEPSCall = OFF,\n\t\tContextAttr {\n\t\t\ttdmc/gain = {\n\t\t\t2,\n\t\t\t4,\n\t\t\t8\n\t\t}\n\t\t},\n\t\tAdd = 11111111/00000000/00000000,\n\t\tAdd = 11111111/00000000/11111111 {\n\t\t\tMedia {\n\t\t\t\tStream = 1 {\n\t\t\t\t\tLocal { \nv=0\r\nc=IN IP4 124.124.124.222\r\nm=audio 2222 RTP/AVP 4\r\na=a=ptime:30\r\na=recvonly\r\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tError = 502 { \"Just another error string\" } \n\t}\n}">>},
+ {msg73a,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7302 {\n\tContext = 7301 {\n\t\tAdd = 11111111/00001111/00000000 {\n\t\t\tStatistics {\n\t\t\t\trtp/ps,\n\t\t\t\tnt/os = 62300,\n\t\t\t\trtp/pr = 700,\n\t\t\t\tnt/or = 45100,\n\t\t\t\trtp/pl = 0.2,\n\t\t\t\trtp/jit = 20,\n\t\t\t\trtp/delay = 40\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg73b01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7312 {\n\tContext = 7311 {\n\t\tAuditValue = 11111111/00001111/00000000 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStatistics {\n\t\t\t\t\t\t\tnt/dur\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg73b02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7312 {\n\tContext = 7311 {\n\t\tAuditValue = 11111111/00001111/00000000 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStream = 303 {\n\t\t\t\t\t\tStatistics {\n\t\t\t\t\t\t\t\tnt/dur\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg73c01,<<"MEGACO/3 [124.124.124.222]:55555\nReply = 8899 {\n\tContext = 606 {\n\t\tMove = 11111111/00001111/00000000 {\n\t\t\tMedia {\n\t\t\t\tStream = 505 {\n\t\t\t\t\tStatistics {\n\t\t\t\t\t\trtp/ps,\n\t\t\t\t\t\tnt/os = 62300,\n\t\t\t\t\t\trtp/pr = 700,\n\t\t\t\t\t\tnt/or = 45100,\n\t\t\t\t\t\trtp/pl = 0.2,\n\t\t\t\t\t\trtp/jit = 20,\n\t\t\t\t\t\trtp/delay = 40\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg73c02,<<"MEGACO/3 [124.124.124.222]:55555\nReply = 8899 {\n\tContext = 606 {\n\t\tMove = 11111111/00001111/00000000 {\n\t\t\tMedia {\n\t\t\t\tStream = 505 {\n\t\t\t\t\tStatistics {\n\t\t\t\t\t\trtp/ps,\n\t\t\t\t\t\tnt/os = 62300,\n\t\t\t\t\t\trtp/pr = 700,\n\t\t\t\t\t\tnt/or = 45100,\n\t\t\t\t\t\trtp/pl = 0.2,\n\t\t\t\t\t\trtp/jit = 20,\n\t\t\t\t\t\trtp/delay = 40\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7421 {\n\tContext = 7411 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tcg/rt {\n\t\t\t\t\tSPADirection = Internal\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7422 {\n\tContext = 7412 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tcg/rt {\n\t\t\t\t\tSPADirection = Both\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a03,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7423 {\n\tContext = 7413 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tcg/rt {\n\t\t\t\t\tSPADirection = External,\n\t\t\t\t\tSPARequestID = 7433\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a04,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7424 {\n\tContext = 7414 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tcg/rt {\n\t\t\t\t\tSPADirection = Both,\n\t\t\t\t\tSPARequestID = 7434\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a05,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7425 {\n\tContext = 7415 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tal/ri {\n\t\t\t\t\tStream = 7401,\n\t\t\t\t\tSignalType = Brief,\n\t\t\t\t\tDuration = 7499,\n\t\t\t\t\tNotifyCompletion = {\n\t\t\t\t\t\tTimeOut,\n\t\t\t\t\t\tOtherReason\n\t\t\t\t\t},\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tSPADirection = Both,\n\t\t\t\t\tSPARequestID = 7435\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg74a06,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7426 {\n\tContext = 7416 {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tSignals {\n\t\t\t\tal/ri {\n\t\t\t\t\tStream = 7401,\n\t\t\t\t\tSignalType = Brief,\n\t\t\t\t\tDuration = 7499,\n\t\t\t\t\tNotifyCompletion = {\n\t\t\t\t\t\tTimeOut,\n\t\t\t\t\t\tOtherReason\n\t\t\t\t\t},\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tSPADirection = Internal,\n\t\t\t\t\tSPARequestID = 7436\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg75a01,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7502 {\n\tContext = 7501 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg75a02,<<"MEGACO/3 [124.124.124.222]:55555\nTransaction = 7502 {\n\tContext = 7501 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\",\n\t\t\t\tServiceChangeInc\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg76a01,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 50076 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStream = 123 {\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\t\tReservedValue,\n\t\t\t\t\t\t\t\tReservedGroup,\n\t\t\t\t\t\t\t\tnt/jit,\n\t\t\t\t\t\t\t\ttdmc/ec,\n\t\t\t\t\t\t\t\tMode = ReceiveOnly\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg76a02,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 50076 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tStream = 123 {\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\t\t\tReservedValue,\n\t\t\t\t\t\t\t\tReservedGroup,\n\t\t\t\t\t\t\t\ttdmc/gain,\n\t\t\t\t\t\t\t\ttdmc/gain=2,\n\t\t\t\t\t\t\t\ttdmc/gain,\n\t\t\t\t\t\t\t\ttdmc/gain=3,\n\t\t\t\t\t\t\t\tMode = ReceiveOnly\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg76b01,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 50076 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tMedia {\n\t\t\t\t\tTerminationState {\n\t\t\t\t\t\tServiceStates = OutOfService\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg77a01,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 50007 {\n\tContext = - {\n\t\tAuditValue = 11111111/11111111/11111111 {\n\t\t\tAudit {\n\t\t\t\tSignals {\n\t\t\t\t\ttonegen/pt {\n\t\t\t\t\t\tSPARequestID = 7701\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a01,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7801,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tImmediateNotify\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a02,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7802,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tNeverNotify\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a03,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7803,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a04,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7824,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tEvents = 7814 {\n\t\t\t\t\t\t\t\tal/on\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a05,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7805,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tSignals\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a06,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7826,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\tcg/rt {\n\t\t\t\t\t\t\t\t\tSPADirection = External\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEvents = 7816 {\n\t\t\t\t\t\t\t\tal/on\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a07,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7827,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\tcg/rt {\n\t\t\t\t\t\t\t\t\tSPADirection = External\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEvents = 7817 {\n\t\t\t\t\t\t\t\tal/on\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tResetEventsDescriptor\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a08,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7836,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\tcg/rt {\n\t\t\t\t\t\t\t\t\tSPADirection = External\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEvents = 7826 {\n\t\t\t\t\t\t\t\tal/of {\n\t\t\t\t\t\t\t\t\tStream = 7816,\n\t\t\t\t\t\t\t\t\tKeepActive,\n\t\t\t\t\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\t\t\t\t\tal/ri {\n\t\t\t\t\t\t\t\t\t\t\t\t\tSPADirection = Both\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tResetEventsDescriptor\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tResetEventsDescriptor\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg78a09,<<"MEGACO/3 [125.125.125.111]:55555\nTransaction = 10001 {\n\tContext = - {\n\t\tModify = 11111111/00000000/00000000 {\n\t\t\tEvents = 2223 {\n\t\t\t\tal/on {\n\t\t\t\t\tstrict=state\n\t\t\t\t},\n\t\t\t\tal/on {\n\t\t\t\t\tStream = 7899,\n\t\t\t\t\tstrict=state,\n\t\t\t\t\tKeepActive,\n\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\tcg/rt {\n\t\t\t\t\t\t\t\t\tStream = 7869,\n\t\t\t\t\t\t\t\t\tSignalType = Brief,\n\t\t\t\t\t\t\t\t\tDuration = 17809,\n\t\t\t\t\t\t\t\t\tNotifyCompletion = {\n\t\t\t\t\t\t\t\t\t\tTimeOut,\n\t\t\t\t\t\t\t\t\t\tOtherReason\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tKeepActive,\n\t\t\t\t\t\t\t\t\tSPADirection = External,\n\t\t\t\t\t\t\t\t\tSPARequestID = 7879,\n\t\t\t\t\t\t\t\t\tIntersignal = 7889\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEvents = 7859 {\n\t\t\t\t\t\t\t\tal/of {\n\t\t\t\t\t\t\t\t\tStream = 7849,\n\t\t\t\t\t\t\t\t\tKeepActive,\n\t\t\t\t\t\t\t\t\tDigitMap = dialplan00,\n\t\t\t\t\t\t\t\t\tRegulatedNotify {\n\t\t\t\t\t\t\t\t\t\tEmbed {\n\t\t\t\t\t\t\t\t\t\t\tSignals {\n\t\t\t\t\t\t\t\t\t\t\t\tcg/rt {\n\t\t\t\t\t\t\t\t\t\t\t\t\tStream = 7819,\n\t\t\t\t\t\t\t\t\t\t\t\t\tSignalType = TimeOut,\n\t\t\t\t\t\t\t\t\t\t\t\t\tDuration = 7898,\n\t\t\t\t\t\t\t\t\t\t\t\t\tNotifyCompletion = {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tTimeOut,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntByEvent,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tOtherReason\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\tSPADirection = Both,\n\t\t\t\t\t\t\t\t\t\t\t\t\tSPARequestID = 7829,\n\t\t\t\t\t\t\t\t\t\t\t\t\tIntersignal = 7839\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tResetEventsDescriptor\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tResetEventsDescriptor\n\t\t\t\t}\n\t\t\t},\n\t\t\tSignals {\n\t\t\t\tcg/rt\n\t\t\t},\n\t\t\tDigitMap = dialplan00 {\n\t\t\t\t(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg79a01,<<"MEGACO/3 [125.125.125.111]:55555\nReply = 7931 {\n\tContext = 7921 {\n\t\tAuditValue = [\n\t\t\t11111111/00000000/00000000,\n\t\t\t11111111/00000000/11111111,\n\t\t\t11111111/11111111/00000000\n\t\t] {\n\t\t\tError = 502 { } ,\n\t\t\tEvents = 7911 {\n\t\t\t\tal/of\n\t\t\t},\n\t\t\tMedia,\n\t\t\tDigitMap,\n\t\t\tStatistics,\n\t\t\tPackages\n\t\t}\n\t}\n}">>},
+ {msg80a01,<<"MEGACO/3 [124.124.124.222]:55555\nReply = 8000/1 {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg80a02,<<"MEGACO/3 [125.125.125.111]:55555\nReply = 8000/1000 {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg80a03,<<"MEGACO/3 [125.124.123.122]:55555\nReply = 8000/65535 {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg80b01,<<"MEGACO/3 [124.124.124.222]:55555\nReply = 8989/1/END {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg80b02,<<"MEGACO/3 [125.125.125.111]:55555\nReply = 8989/1000/END {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg80b03,<<"MEGACO/3 [125.124.123.122]:55555\nReply = 8989/65535/END {\n\tContext = 80 {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1\n\t\t\t}\n\t\t}\n\t}\n}">>},
+ {msg81a01,<<"MEGACO/3 [124.124.124.222]:55555\nSegment = 8101/1">>},
+ {msg81a02,<<"MEGACO/3 [125.125.125.111]:55555\nSegment = 8101/1000">>},
+ {msg81a03,<<"MEGACO/3 [125.124.123.122]:55555\nSegment = 8101/65535">>},
+ {msg81b01,<<"MEGACO/3 [124.124.124.222]:55555\nSegment = 8102/1/END">>},
+ {msg81b02,<<"MEGACO/3 [125.125.125.111]:55555\nSegment = 8102/1000/END">>},
+ {msg81b03,<<"MEGACO/3 [125.124.123.122]:55555\nSegment = 8102/65535/END">>}]}.
diff --git a/lib/megaco/examples/simple/Makefile b/lib/megaco/examples/simple/Makefile
new file mode 100644
index 0000000000..f91d1d886f
--- /dev/null
+++ b/lib/megaco/examples/simple/Makefile
@@ -0,0 +1,153 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug -W
+endif
+
+EBIN = .
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+MODULES = $(MG_MODULES) $(MGC_MODULES) $(COMMON_MODULES)
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR))
+
+MEGACO_ROOT_DIR = $(shell (cd .. ; dirname `pwd`))
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(WARN_UNUSED_WARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += \
+ -pa $(ERL_TOP)/lib/megaco/ebin \
+ -I../../include
+
+ifneq ($(MGC_HOST),)
+MG_START_ARGS = "{mgc_host, $(MGC_HOST)}"
+endif
+
+ifneq ($(MG_INLINE_TRACE),true)
+MG_MEGACO_FILTER = -s megaco_filter
+MG_START_ARGS += "{trace,false}"
+else
+MG_START_ARGS += "{trace,true}"
+endif
+
+ifneq ($(MG_DEBUG),)
+MG_START_ARGS += "{debug,true}"
+else
+MG_START_ARGS += "{debug,false}"
+endif
+
+
+ifneq ($(MGC_INLINE_TRACE),true)
+MGC_MEGACO_FILTER = -s megaco_filter
+MGC_START_ARGS += "{trace,false}"
+else
+MGC_START_ARGS += "{trace,true}"
+endif
+
+ifneq ($(MGC_DEBUG),)
+MGC_START_ARGS += "{debug,true}"
+else
+MGC_START_ARGS += "{debug,false}"
+endif
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+opt: $(TARGET_FILES)
+
+debug:
+ @${MAKE} TYPE=debug opt
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MEGACO_ROOT_DIR = $(MEGACO_ROOT_DIR)"
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+mg: opt
+ erl -noshell -pa $(MEGACO_ROOT_DIR)/ebin \
+ $(MG_MEGACO_FILTER) \
+ -s megaco \
+ -s megaco_simple_mg start_batch $(MG_START_ARGS)
+
+mgc: opt
+ erl -noshell -pa $(MEGACO_ROOT_DIR)/ebin \
+ $(MGC_MEGACO_FILTER) \
+ -s megaco \
+ -s megaco_simple_mgc start_batch $(MGC_START_ARGS)
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/examples
+ $(INSTALL_DIR) $(RELSYSDIR)/examples/simple
+ $(INSTALL_DATA) $(ERL_FILES) $(TARGET_FILES) $(RELSYSDIR)/examples/simple
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
diff --git a/lib/megaco/examples/simple/megaco_simple_mg.erl b/lib/megaco/examples/simple/megaco_simple_mg.erl
new file mode 100644
index 0000000000..95efaf5df3
--- /dev/null
+++ b/lib/megaco/examples/simple/megaco_simple_mg.erl
@@ -0,0 +1,437 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Simple example of an MG
+%%
+%% Example usage:
+%%
+%% cd megaco/examples/simple
+%% erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+%% megaco_simple_mg:start().
+%%----------------------------------------------------------------------
+
+-module(megaco_simple_mg).
+
+-behaviour(megaco_user).
+
+-export([
+ start_batch/0, start_batch/1, init_batch/4,
+ start/0, start/3,
+ start/4, %% ????????????????????????
+ stop/0, stop/1,
+ start_tcp_text/2, start_tcp_binary/2,
+ start_udp_text/2, start_udp_binary/2
+ ]).
+
+-export([
+ handle_connect/2,
+ handle_disconnect/3,
+ handle_syntax_error/3,
+ handle_message_error/3,
+ handle_trans_request/3,
+ handle_trans_long_request/3,
+ handle_trans_reply/4,
+ handle_trans_ack/4,
+ handle_unexpected_trans/3,
+ handle_trans_request_abort/4
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+
+%%----------------------------------------------------------------------
+%% To be used at command line: erl -s ?MODULE start_batch
+%%----------------------------------------------------------------------
+
+start_batch() ->
+ start_batch([]).
+
+start_batch(Args0) when is_list(Args0) ->
+ {ok, LocalHost} = inet:gethostname(),
+ Defs = [{mgc_host, LocalHost}, {trace,false}, {debug, false}],
+ Args = parse_args(Args0, Defs),
+ MgcHost = get_arg(mgc_host, Args),
+ Trace = get_arg(trace, Args),
+ Debug = get_arg(debug, Args),
+ Pid = spawn(?MODULE, init_batch, [self(), MgcHost, Trace, Debug]),
+ receive
+ {init_batch, Pid, Res} ->
+ io:format("~p(~p): ~p~n", [?MODULE, ?LINE, Res]),
+ Res
+ end.
+
+parse_args([], Acc) ->
+ Acc;
+parse_args([Arg|Args], Acc) when is_atom(Arg) ->
+ case string:tokens(atom_to_list(Arg),"{},") of
+ ["mgc_host", Host] when is_list(Host) ->
+ parse_args(Args, parse_args(mgc_host, Host, Acc));
+ ["trace",Trace] ->
+ parse_args(Args, parse_args(trace, list_to_atom(Trace), Acc));
+ ["debug",Debug] ->
+ parse_args(Args, parse_args(debug, list_to_atom(Debug), Acc));
+ _Invalid ->
+ parse_args(Args, Acc)
+ end.
+
+parse_args(Key, Val, Args) ->
+ Entry = {Key, Val},
+ case lists:keyreplace(Key, 1, Args, {Key, Val}) of
+ Args ->
+ [Entry|Args];
+ Args2 ->
+ Args2
+ end.
+
+get_arg(Key, Args) ->
+ {value, {Key, Val}} = lists:keysearch(Key, 1, Args),
+ Val.
+
+init_batch(ReplyTo, MgcHost, Trace, Debug) ->
+ register(?MODULE, self()),
+ Res = start(MgcHost, Trace, Debug),
+ ReplyTo ! {init_batch, self(), Res},
+ receive
+ after infinity -> Res
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Starting the MG
+%%----------------------------------------------------------------------
+
+%% -----------------------------------------------------------------------
+
+init_inline_trace(true) ->
+ megaco:enable_trace(max, io);
+init_inline_trace(_) ->
+ ok.
+
+%% -----------------------------------------------------------------------
+
+
+start() ->
+ {ok, LocalHost} = inet:gethostname(),
+ start(LocalHost, false, false).
+
+%% Used when calling from the erlang shell:
+start(MgcHost, Trace, Debug)
+ when is_atom(MgcHost) andalso is_atom(Trace) andalso is_atom(Debug) ->
+ start(atom_to_list(MgcHost), Trace, Debug);
+
+start(MgcHost, Trace, Debug)
+ when is_list(MgcHost) andalso is_atom(Trace) andalso is_atom(Debug) ->
+ put(debug, Debug),
+ d("start -> entry with"
+ "~n MgcHost: ~s"
+ "~n Trace: ~p", [MgcHost, Trace]),
+ init_inline_trace(Trace),
+ Starters = [fun start_tcp_text/2,
+ fun start_tcp_binary/2,
+ fun start_udp_text/2,
+ fun start_udp_binary/2],
+ [Fun(MgcHost, []) || Fun <- Starters].
+
+start_tcp_text(MgcHost, Default) ->
+ d("start_tcp_text -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_tcp} | Default],
+ Mid = {deviceName, "gateway_tt"},
+ {Mid, start(MgcHost, ?megaco_ip_port_text, Mid, Config)}.
+
+start_tcp_binary(MgcHost, Default) ->
+ d("start_tcp_binary -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_binary_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_tcp} | Default],
+ Mid = {deviceName, "gateway_tb"},
+ {Mid, start(MgcHost, ?megaco_ip_port_binary, Mid, Config)}.
+
+start_udp_text(MgcHost, Default) ->
+ d("start_udp_text -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_udp} | Default],
+ Mid = {deviceName, "gateway_ut"},
+ {Mid, start(MgcHost, ?megaco_ip_port_text, Mid, Config)}.
+
+start_udp_binary(MgcHost, Default) ->
+ d("start_udp_binary -> entry with"
+ "~n MgcHost: ~p", [MgcHost]),
+ Config = [{encoding_mod, megaco_binary_encoder},
+ {encoding_config, []},
+ {send_mod, megaco_udp} | Default],
+ Mid = {deviceName, "gateway_ub"},
+ {Mid, start(MgcHost, ?megaco_ip_port_binary, Mid, Config)}.
+
+start(MgcHost, MgcPort, Mid, Config) ->
+ case megaco:start_user(Mid, [{user_mod, ?MODULE} | Config]) of
+ ok ->
+ case start_transport(MgcHost, MgcPort, Mid) of
+ {ok, ConnHandle} ->
+ service_change(ConnHandle);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, {start_user, Reason}}
+ end.
+
+start_transport(MgcHost, MgcPort, Mid) ->
+ RecHandle = megaco:user_info(Mid, receive_handle),
+ case RecHandle#megaco_receive_handle.send_mod of
+ megaco_tcp -> start_tcp(MgcHost, MgcPort, RecHandle);
+ megaco_udp -> start_udp(MgcHost, MgcPort, RecHandle);
+ SendMod -> {error, {bad_send_mod, SendMod}}
+ end.
+
+start_tcp(MgcHost, MgcPort, RecHandle) ->
+ d("start_tcp -> start transport"),
+ case megaco_tcp:start_transport() of
+ {ok, Pid} ->
+ d("start_tcp -> transport started: ~p", [Pid]),
+ Options = [{host, MgcHost},
+ {port, MgcPort},
+ {receive_handle, RecHandle}],
+ case megaco_tcp:connect(Pid, Options) of
+ {ok, SendHandle, ControlPid} ->
+ d("start_tcp -> connected: ~p", [ControlPid]),
+ MgcMid = preliminary_mid,
+ megaco:connect(RecHandle, MgcMid, SendHandle, ControlPid);
+ {error, Reason} ->
+ d("start_tcp -> connection failed: ~p", [Reason]),
+ {error, {megaco_tcp_connect, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_tcp -> failed starting transport: ~p", [Reason]),
+ {error, {megaco_tcp_start_transport, Reason}}
+ end.
+
+start_udp(MgcHost, MgcPort, RecHandle) ->
+ d("start_udp -> start transport"),
+ case megaco_udp:start_transport() of
+ {ok, SupPid} ->
+ d("start_udp -> transport started: ~p", [SupPid]),
+ Options = [{port, 0}, {receive_handle, RecHandle}],
+ case megaco_udp:open(SupPid, Options) of
+ {ok, Handle, ControlPid} ->
+ d("start_udp -> port opened: ~p", [ControlPid]),
+ %% Socket = megaco_udp:socket(Handle),
+ %% MgPort = inet:port(Socket), BUGBUG BUGBUG
+ MgcMid = preliminary_mid,
+ SendHandle = megaco_udp:create_send_handle(Handle,
+ MgcHost, % BUGBUG BUGBUG
+ MgcPort),
+ megaco:connect(RecHandle, MgcMid, SendHandle, ControlPid);
+ {error, Reason} ->
+ d("start_udp -> failed open port: ~p", [Reason]),
+ {error, {megaco_udp_open, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_udp -> failed starting transport: ~p", [Reason]),
+ {error, {megaco_udp_start_transport, Reason}}
+ end.
+
+service_change(ConnHandle) ->
+ service_change(ConnHandle, restart, ?megaco_cold_boot).
+
+service_change(ConnHandle, Method, Reason) ->
+ SCP = #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeReason = [Reason]},
+ TermId = [?megaco_root_termination_id],
+ SCR = #'ServiceChangeRequest'{terminationID = TermId,
+ serviceChangeParms = SCP},
+ CR = #'CommandRequest'{command = {serviceChangeReq, SCR}},
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ megaco:call(ConnHandle, [AR], []).
+
+%%----------------------------------------------------------------------
+%% Stopping the MG
+%%----------------------------------------------------------------------
+
+stop() ->
+ [{Mid, stop(Mid)} || Mid <- megaco:system_info(users)].
+
+stop(Mid) ->
+ Reason = stopped_by_user,
+ Disco = fun(CH) ->
+ Pid = megaco:conn_info(CH, control_pid),
+ megaco:disconnect(CH, Reason),
+ megaco:cancel(CH, Reason),
+ exit(Pid, Reason)
+ end,
+ lists:map(Disco, megaco:user_info(Mid, connections)),
+ megaco:stop_user(Mid).
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(ConnHandle, ProtocolVersion) ->
+ d("handle_connect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p", [ConnHandle, ProtocolVersion]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, ProtocolVersion, Reason) ->
+ d("handle_disconnect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Reason: ~p", [ConnHandle, ProtocolVersion, Reason]),
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ d("handle_disconnect -> done", []),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_syntax_error -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p",
+ [ReceiveHandle, ProtocolVersion, ErrorDescriptor]),
+ reply.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_message_error -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p",
+ [ConnHandle, ProtocolVersion, ErrorDescriptor]),
+ no_reply.
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ d("handle_trans_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActionRequests: ~p",
+ [ConnHandle, ProtocolVersion, ActionRequests]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) ->
+ d("handle_trans_long_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ReqData: ~p", [ConnHandle, ProtocolVersion, ReqData]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ d("handle_trans_reply -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActualReply: ~p"
+ "~n ReplyData: ~p",
+ [ConnHandle, ProtocolVersion, ActualReply, ReplyData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) ->
+ d("handle_trans_ack -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n AckStatus: ~p"
+ "~n AckData: ~p",
+ [ConnHandle, ProtocolVersion, AckStatus, AckData]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) ->
+ d("handle_unexpected_trans -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n AckStatus: ~p"
+ "~n AckData: ~p",
+ [ConnHandle, ProtocolVersion, Trans]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId, Pid) ->
+ d("handle_trans_request_abort -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n TransId: ~p"
+ "~n Pid: ~p",
+ [ConnHandle, ProtocolVersion, TransId, Pid]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% DEBUGGING
+%%----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F,A) ->
+ d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("SIMPLE_MG: " ++ F ++ "~n", A);
+d(_, _F, _A) ->
+ ok.
+
+
+
+
diff --git a/lib/megaco/examples/simple/megaco_simple_mgc.erl b/lib/megaco/examples/simple/megaco_simple_mgc.erl
new file mode 100644
index 0000000000..04493b983f
--- /dev/null
+++ b/lib/megaco/examples/simple/megaco_simple_mgc.erl
@@ -0,0 +1,455 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Simple example of an MGC
+%%
+%% Example usage:
+%%
+%% cd megaco/examples/simple
+%% erl -pa ../../../megaco/ebin -s megaco_filter -s megaco
+%% megaco_simple_mgc:start().
+%%----------------------------------------------------------------------
+
+-module(megaco_simple_mgc).
+
+-behaviour(megaco_user).
+
+-export([
+ start_batch/0, start_batch/1, init_batch/3,
+ start/0, start/2,
+ start/4,
+ stop/0, stop/1
+ ]).
+
+-export([
+ handle_connect/2,
+ handle_disconnect/3,
+ handle_syntax_error/3,
+ handle_message_error/3,
+ handle_trans_request/3,
+ handle_trans_long_request/3,
+ handle_trans_reply/4,
+ handle_trans_ack/4,
+ handle_unexpected_trans/3,
+ handle_trans_request_abort/4
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Starting the MGC
+%%----------------------------------------------------------------------
+
+start() ->
+ start(false, false).
+
+start(Trace, Debug) ->
+ start({deviceName, "controller"}, [], Trace, Debug).
+
+start(Mid, Config, Trace, Debug) ->
+ put(debug, Debug),
+ d("start -> entry with"
+ "~n Mid: ~p"
+ "~n Config: ~p"
+ "~n Trace: ~p", [Mid, Config, Trace]),
+ init_inline_trace(Trace),
+ case megaco:start_user(Mid, [{user_mod, ?MODULE} | Config]) of
+ ok ->
+ d("start -> user started"),
+ case catch do_start(Mid) of
+ {'EXIT', Reason} ->
+ d("start -> exited: ~n~p",[Reason]),
+ {error, Reason};
+ Other ->
+ d("start -> Other: ~n~p",[Other]),
+ Other
+ end;
+ {error, Reason} ->
+ d("start -> user start failed: ~n~p", [Reason]),
+ {error, {start_user, Reason}}
+ end.
+
+
+%% -----------------------------------------------------------------------
+
+init_inline_trace(true) ->
+ megaco:enable_trace(max, io);
+init_inline_trace(_) ->
+ ok.
+
+%% -----------------------------------------------------------------------
+
+do_start(Mid) ->
+ d("do_start -> entry"),
+ RecHandle = megaco:user_info(Mid, receive_handle),
+ d("do_start -> RecHandle: ~n~p",[RecHandle]),
+
+ TextMod = megaco_pretty_text_encoder,
+ TextTcp = RecHandle#megaco_receive_handle{encoding_mod = TextMod,
+ encoding_config = [],
+ send_mod = megaco_tcp},
+ d("do_start -> TextTcp: ~n~p",[TextTcp]),
+ TextUdp = TextTcp#megaco_receive_handle{send_mod = megaco_udp},
+ d("do_start -> TextUdp: ~n~p",[TextUdp]),
+
+ BinMod = megaco_binary_encoder,
+ BinTcp = RecHandle#megaco_receive_handle{encoding_mod = BinMod,
+ encoding_config = [],
+ send_mod = megaco_tcp},
+ d("do_start -> BinTcp: ~n~p",[BinTcp]),
+ BinUdp = BinTcp#megaco_receive_handle{send_mod = megaco_udp},
+ d("do_start -> BinUdp: ~n~p",[BinUdp]),
+
+ ListenTo = [{?megaco_ip_port_text, TextTcp},
+ {?megaco_ip_port_text, TextUdp},
+ {?megaco_ip_port_binary, BinTcp},
+ {?megaco_ip_port_binary, BinUdp}
+ ],
+
+ d("do_start -> start transports"),
+ Transports =
+ [{start_transport(Port, RH), Port, RH} || {Port, RH} <- ListenTo],
+ d("do_start -> Transports: ~n~p",[Transports]),
+
+ {ok, Transports}.
+
+start_transport(MgcPort, RecHandle) ->
+ case RecHandle#megaco_receive_handle.send_mod of
+ megaco_tcp -> start_tcp(MgcPort, RecHandle);
+ megaco_udp -> start_udp(MgcPort, RecHandle);
+ SendMod -> {error, {bad_send_mod, SendMod}}
+ end.
+
+start_udp(MgcPort, RecHandle) ->
+ d("start_udp -> entry with"
+ "~n MgcPort: ~p"
+ "~n RecHandle: ~p", [MgcPort, RecHandle]),
+ case megaco_udp:start_transport() of
+ {ok, SupPid} ->
+ Options = [{port, MgcPort}, {receive_handle, RecHandle}],
+ case megaco_udp:open(SupPid, Options) of
+ {ok, _SendHandle, _ControlPid} ->
+ ok;
+ {error, Reason} ->
+ {error, {megaco_udp_open, Reason}}
+ end;
+ {error, Reason} ->
+ {error, {megaco_udp_start_transport, Reason}}
+ end.
+
+start_tcp(MgcPort, RecHandle) ->
+ d("start_tcp -> entry with"
+ "~n MgcPort: ~p"
+ "~n RecHandle: ~p", [MgcPort, RecHandle]),
+ case megaco_tcp:start_transport() of
+ {ok, SupPid} ->
+ d("start_tcp -> transport started: "
+ "~n SupPid: ~p", [SupPid]),
+ Options = [{port, MgcPort}, {receive_handle, RecHandle}],
+ case megaco_tcp:listen(SupPid, Options) of
+ ok ->
+ d("start_tcp -> listen ok"),
+ ok;
+ {error, Reason} ->
+ d("start_tcp -> listen failed: "
+ "~n Reason: ~p", [Reason]),
+ {error, {megaco_tcp_listen, Reason}}
+ end;
+ {error, Reason} ->
+ d("start_tcp -> transport start failed: "
+ "~n Reason: ~p", [Reason]),
+ {error, {megaco_tcp_start_transport, Reason}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Stopping the MGC
+%%----------------------------------------------------------------------
+
+stop() ->
+ [{Mid, stop(Mid)} || Mid <- megaco:system_info(users)].
+
+stop(Mid) ->
+ d("stop -> entry with~n Mid: ~p", [Mid]),
+ Disco = fun(CH) ->
+ d("stop -> CH: ~p", [CH]),
+ Reason = stopped_by_user,
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+
+ d("stop -> disconnect", []),
+ megaco:disconnect(CH, Reason),
+ d("stop -> cancel", []),
+ megaco:cancel(CH, Reason),
+ d("stop -> close transport"
+ "~n SendMod: ~p"
+ "~n SendHandle: ~p", [SendMod, SendHandle]),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end
+ end,
+ Conns = megaco:user_info(Mid, connections),
+ d("stop -> Conns: ~p", [Conns]),
+ Disconns = lists:map(Disco, Conns),
+ d("stop -> Disconns: ~p", [Disconns]),
+ megaco:stop_user(Mid),
+ case whereis(?MODULE) of
+ undefined ->
+ ignore;
+ Pid ->
+ d("stop -> Pid: ~p", [Pid]),
+ unlink(Pid),
+ exit(Pid, shutdown)
+ end,
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(ConnHandle, ProtocolVersion) ->
+ d("handle_connect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "", [ConnHandle, ProtocolVersion]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, ProtocolVersion, Reason) ->
+ d("handle_disconnect -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Reason: ~p"
+ "", [ConnHandle, ProtocolVersion, Reason]),
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_syntax_error -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p"
+ "", [ReceiveHandle, ProtocolVersion, ErrorDescriptor]),
+ reply.
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor) ->
+ d("handle_message_error -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ErrorDescriptor: ~p"
+ "", [ConnHandle, ProtocolVersion, ErrorDescriptor]),
+ no_reply.
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ d("handle_trans_request -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActionRequests: ~p"
+ "", [ConnHandle, ProtocolVersion, ActionRequests]),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only single service change on null context handled"},
+ case ActionRequests of
+ [AR] ->
+ ContextId = AR#'ActionRequest'.contextId,
+ case AR#'ActionRequest'.commandRequests of
+ [CR] when ContextId =:= ?megaco_null_context_id ->
+ case CR#'CommandRequest'.command of
+ {serviceChangeReq, Req} ->
+ Rep = service_change(ConnHandle, ProtocolVersion, Req),
+ {discard_ack,
+ [#'ActionReply'{contextId = ContextId,
+ commandReply = [{serviceChangeReply, Rep}]}]};
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end.
+
+service_change(ConnHandle, _ProtocolVersion, SCR) ->
+ SCP = SCR#'ServiceChangeRequest'.serviceChangeParms,
+ #'ServiceChangeParm'{serviceChangeAddress = Address,
+ serviceChangeProfile = Profile} = SCP,
+ TermId = SCR#'ServiceChangeRequest'.terminationID,
+ if
+ TermId == [?megaco_root_termination_id] ->
+ MyMid = ConnHandle#megaco_conn_handle.local_mid,
+ Res = {serviceChangeResParms,
+ #'ServiceChangeResParm'{serviceChangeMgcId = MyMid,
+ serviceChangeAddress = Address,
+ serviceChangeProfile = Profile}},
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res};
+ true ->
+ Res = {errorDescriptor,
+ #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only handled for root"}},
+
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res}
+ end.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(_ConnHandle, _ProtocolVersion, _ReqData) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {discard_ack, ED}.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ d("handle_trans_eply -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ActualReply: ~p"
+ "~n ReplyData: ~p"
+ "", [ConnHandle, ProtocolVersion, ActualReply, ReplyData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) ->
+ d("handle_trans_ack -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n ckStatus: ~p"
+ "~n AckData: ~p"
+ "", [ConnHandle, ProtocolVersion, AckStatus, AckData]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) ->
+ d("handle_unexpected_trans -> entry with"
+ "~n ConnHandle: ~p"
+ "~n ProtocolVersion: ~p"
+ "~n Trans: ~p"
+ "", [ConnHandle, ProtocolVersion, Trans]),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% To be used at command line: erl -s ?MODULE start_batch
+%%----------------------------------------------------------------------
+
+start_batch() ->
+ start_batch([false]).
+
+start_batch(Args0) ->
+ Defs = [{trace,false}, {debug, false}],
+ Args = parse_args(Args0, Defs),
+ Trace = get_arg(trace, Args),
+ Debug = get_arg(debug, Args),
+ Pid = spawn(?MODULE, init_batch, [self(), Trace, Debug]),
+ receive
+ {init_batch, Pid, Res} ->
+ io:format("~p(~p): ~p~n", [?MODULE, ?LINE, Res]),
+ Res
+ end.
+
+init_batch(ReplyTo, Trace, Debug) ->
+ register(?MODULE, self()),
+ Res = start(Trace, Debug),
+ ReplyTo ! {init_batch, self(), Res},
+ receive
+ after infinity -> Res
+ end.
+
+
+parse_args([], Acc) ->
+ Acc;
+parse_args([Arg|Args], Acc) when is_atom(Arg) ->
+ case string:tokens(atom_to_list(Arg),"{},") of
+ ["trace",Trace] ->
+ parse_args(Args, parse_args(trace, list_to_atom(Trace), Acc));
+ ["debug",Debug] ->
+ parse_args(Args, parse_args(debug, list_to_atom(Debug), Acc));
+ _Invalid ->
+ parse_args(Args, Acc)
+ end.
+
+parse_args(Key, Val, Args) ->
+ Entry = {Key, Val},
+ case lists:keyreplace(Key, 1, Args, {Key, Val}) of
+ Args ->
+ [Entry|Args];
+ Args2 ->
+ Args2
+ end.
+
+get_arg(Key, Args) ->
+ {value, {Key, Val}} = lists:keysearch(Key, 1, Args),
+ Val.
+
+
+%%----------------------------------------------------------------------
+%% DEBUGGING
+%%----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F,A) ->
+ d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("SIMPLE_MGC: " ++ F ++ "~n", A);
+d(_, _F, _A) ->
+ ok.
+
diff --git a/lib/megaco/examples/simple/modules.mk b/lib/megaco/examples/simple/modules.mk
new file mode 100644
index 0000000000..bcba5666a1
--- /dev/null
+++ b/lib/megaco/examples/simple/modules.mk
@@ -0,0 +1,27 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MG_MODULES = \
+ megaco_simple_mg
+
+MGC_MODULES = \
+ megaco_simple_mgc
+
+COMMON_MODULES =
+
diff --git a/lib/megaco/include/megaco.hrl b/lib/megaco/include/megaco.hrl
new file mode 100644
index 0000000000..4045fa9461
--- /dev/null
+++ b/lib/megaco/include/megaco.hrl
@@ -0,0 +1,333 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define common data structures and error codes
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Receive handle
+%%
+%% The receive handle contains enough information in order
+%% to be able to decode a message and send a reply to the
+%% originator.
+%%----------------------------------------------------------------------
+
+-record(megaco_receive_handle,
+ {
+ local_mid,
+ encoding_mod,
+ encoding_config,
+ send_mod,
+ protocol_version = dynamic % dynamic | integer()
+ }).
+
+%%----------------------------------------------------------------------
+%% Connection handle
+%%
+%% The connecion handle provides a locally unique identity of a
+%% connection. It is generated when a connection is established.
+%%----------------------------------------------------------------------
+
+-record(megaco_conn_handle,
+ {
+ local_mid,
+ remote_mid
+ }).
+
+%%----------------------------------------------------------------------
+%% Incremental timer
+%%
+%% The timer sleeps in WaitFor milli seconds and when it
+%% times out, a new time out value is computed:
+%%
+%% WaitFor2 = WaitFor * Factor + Incr
+%%
+%% And the timer starts all over again with the new WaitFor value.
+%% The procedure is repeated at at most MaxRetries.
+%%
+%% There is a special case for this timer. When the max_retries has
+%% the value infinity_restartable it means that the timer is
+%% restartable as long as some external event occurs (e.g. receipt of
+%% a pending message for instance). But the timer will never be
+%% restarted "by itself". I.e. when the timer expires (whatever the
+%% timeout time), so does the timer. Whever the timer is restarted,
+%% the timeout time will be calculated in the usual way!
+%%
+%%----------------------------------------------------------------------
+
+-record(megaco_incr_timer,
+ {wait_for = timer:seconds(7),% Initial timeout (milli seconds)
+ factor = 2, % Factor to multiply with at timeout
+ incr = 0, % Milli seconds to add at timeout
+ max_retries = infinity}). % infinity | infinity_restartable | Integer
+
+%%----------------------------------------------------------------------
+%% The internal representation of a termination id
+%%----------------------------------------------------------------------
+%%
+%% id() -> [level()]
+%% level() -> [char()]
+%% char() -> wildcard() | $0 | $1 | text_only_char()
+%% text_only_char() -> $2..$9 | $a..$z | $_ | $. | $@
+%% wildcard() -> all() | choose()
+%% all() -> $*
+%% choose() -> $$
+%% contains_wildcards() -> true | false
+%%
+%% The id field contains all info about the termination id, while the
+%% presense of the contains_wildcards field is just as a matter of
+%% convenience in order to make it simple to determine whether a
+%% simple id lookup will suffice or if some more complicated matching
+%% algorithm is needed.
+%%
+%% Some text encoding examples:
+%%
+%% "ROOT" -> {megaco_term_id, false, [[$r,$o,$o,$t]]}
+%% "*" -> {megaco_term_id, true, [[$*]]}
+%% "$" -> {megaco_term_id, true, [[$$]]}
+%% "R1/101/1" -> {megaco_term_id, false, [[$r, $1], [$1, $0, $1], [$1]]}
+%% "R1/1*1/*" -> {megaco_term_id, true, [[$r, $1], [$1, all, $1]], [$*]}
+%% "R1/1*" -> {megaco_term_id, true, [[$r, $1], [$1, $*]]}
+%% "R1/1*/" -> {megaco_term_id, true, [[$r, $1], [$1, $*], []]}
+%%
+%% Given the terminations "R1/10", "R1/101/0" and "R1/101/1" the above
+%% termination identifiers would be resolved to the following ones:
+%%
+%% "ROOT" -> "ROOT"
+%% "*" -> "R1/10" and "R1/101/0" and "R1/101/1"
+%% "$" -> "R1/10" or "R1/101/0" or "R1/101/1"
+%% "R1/101/1" -> "R1/101/1"
+%% "R1/1*1/*" -> "R1/101/1" and "R1/101/0"
+%% "R1/1*" -> "R1/10" and "R1/101/0" and "R1/101/1"
+%% "R1/1*/" -> "R1/10"
+%%
+%% In the binary encoding it is possible to express whether the last
+%% wildcard pertains to a certain level, in the hierarchical naming
+%% scheme (in the internal form this is expressed as an empty list as
+%% last level, see the internal form for "R1/1*/" above) or if the
+%% match also should include all lower levels recursively (see the
+%% internal form for "R1/1*" above).
+%%
+%% Observe that a termination id with a trailing slash (such as
+%% "R1/1*/") violates the text encoding protocol. But we allow it
+%% anyway since the corresponding internal form is needed for the
+%% binary encoding. It is also nice to be able to pretty print any
+%% binary termination id as text.
+%%
+%% A fully specified binary termination id:
+%%
+%% #'TerminationID'{wildcard = [],
+%% id = [2#00000001, 02#0011110, 2#00000000]}
+%%
+%% is internally represented as:
+%%
+%% #megaco_term_id{contains_wildcards = false,
+%% id = [[$0, $0, $0, $1, $1, $1, $1, $0],
+%% [$0, $1, $0, $1, $0, $1, $0, $1],
+%% [$0, $0, $0, $0, $0, $0, $0, $0]]}
+%%
+%% Addressing all names with prefix 00000001 00011110 is done as follows:
+%%
+%% #'TerminationID'{wildcard = [2#10000111],
+%% id = [2#00000001, 2#00011110, 2#00000000]}
+%%
+%% is internally represented as:
+%%
+%% #megaco_term_id{contains_wildcards = true,
+%% id = [[$0, $0, $0, $0, $0, $0, $0, $1],
+%% [$0, $0, $0, $1, $1, $1, $1, $0],
+%% [?megaco_all]}
+%%
+%% Indicating to the receiver that is must choose a name with 00011110 as
+%% the second octet is done as follows:
+%%
+%% #'TerminationID'{wildcard = [2#00010111, 2#00000111],
+%% id = [2#00000000, 2#00011110, 2#00000000]}
+%%
+%% is internally represented as:
+%%
+%% #megaco_term_id{contains_wildcards = true,
+%% id = [[?megaco_choose],
+%% [$0, $0, $0, $1, $1, $1, $1, $0],
+%% [?megaco_choose]]}
+%%
+%% Finally, a choose-wildcarded name with the highest level of the name
+%% equal to 00000001 is specified as follows:
+%%
+%% #'TerminationID'{wildcard = [2#01001111],
+%% id = [2#00000001, 2#00000000, 2#00000000]}
+%%
+%% is internally represented as:
+%%
+%% #megaco_term_id{contains_wildcards = true,
+%% id = [[$0, $0, $0, $0, $0, $0, $0, $1],
+%% [?megaco_choose],
+%% [?megaco_choose]]}
+%%----------------------------------------------------------------------
+
+-record(megaco_term_id, {contains_wildcards = false, id}).
+
+-define(megaco_root_termination_id, #megaco_term_id{id = [[$r,$o,$o,$t]]}).
+
+-define(megaco_all, $*).
+-define(megaco_choose, $$).
+
+%%----------------------------------------------------------------------
+%% Predefined context identifiers
+%%----------------------------------------------------------------------
+
+-define(megaco_null_context_id, 0). % 0
+-define(megaco_choose_context_id, 16#FFFFFFFE). % 4294967294
+-define(megaco_all_context_id, 16#FFFFFFFF). % 4294967295
+
+%%----------------------------------------------------------------------
+%% Predefined request identifiers
+%%----------------------------------------------------------------------
+
+-define(megaco_all_request_id, 16#FFFFFFFF). % 4294967295
+
+%%----------------------------------------------------------------------
+%% Command error codes
+%%----------------------------------------------------------------------
+
+-define(megaco_bad_request, 400).
+-define(megaco_protocol_error, 401).
+-define(megaco_unauthorized, 402).
+-define(megaco_syntax_error_in_transaction, 403).
+-define(megaco_version_not_supported, 406).
+-define(megaco_incorrect_identifier, 410).
+-define(megaco_unknown_context_id, 411).
+-define(megaco_no_context_id_available, 412).
+-define(megaco_num_of_trans_exceeds_max, 413). % v3
+-define(megaco_unknown_action_or_illegal_combination_of_actions, 421).
+-define(megaco_syntax_error_in_action, 422).
+-define(megaco_unknown_termination_id, 430).
+-define(megaco_no_termination_id_matched_a_wildcard, 431).
+-define(megaco_out_of_termination_ids_or_no_termination_id_available, 432).
+-define(megaco_termination_id_already_in_context, 433).
+-define(megaco_max_number_of_terminations_in_context_exceeded, 434). % v2
+-define(megaco_terminations_id_not_in_specified_context, 435). % v2
+
+-define(megaco_unsupported_or_unknown_package, 440).
+-define(megaco_missing_remote_or_local_descriptor, 441). % v2
+-define(megaco_missing_remote_descriptor,
+ ?megaco_missing_remote_or_local_descriptor).
+-define(megaco_missing_local_descriptor,
+ ?megaco_missing_remote_or_local_descriptor).
+-define(megaco_syntax_error_in_command, 442).
+-define(megaco_unsupported_or_unknown_command, 443).
+-define(megaco_unsupported_or_unknown_descriptor, 444).
+-define(megaco_unsupported_or_unknown_property, 445).
+-define(megaco_unsupported_or_unknown_parameter, 446).
+-define(megaco_descriptor_not_legal_in_this_command, 447).
+-define(megaco_descriptor_appears_twice_in_this_command, 448).
+-define(megaco_unsup_or_unknown_param_or_prop_value, 449). % v3
+-define(megaco_unsupported_parameter_value,
+ ?megaco_unsup_or_unknown_param_or_prop_value).
+-define(megaco_unsupported_proprty_value,
+ ?megaco_unsup_or_unknown_param_or_prop_value).
+-define(megaco_unknown_parameter_value,
+ ?megaco_unsup_or_unknown_param_or_prop_value).
+-define(megaco_unknown_proprty_value,
+ ?megaco_unsup_or_unknown_param_or_prop_value).
+-define(megaco_no_such_property_in_this_package, 450).
+-define(megaco_no_such_event_in_this_package, 451).
+-define(megaco_no_such_signal_in_this_package, 452).
+-define(megaco_no_such_statistic_in_this_package, 453).
+-define(megaco_no_such_parameter_in_this_package, 454).
+-define(megaco_property_illegal_in_this_descriptor, 455). % v2
+-define(megaco_parameter_illegal_in_this_descriptor,
+ ?megaco_property_illegal_in_this_descriptor).
+-define(megaco_property_appears_twice_in_this_descriptor, 456). % v2
+-define(megaco_parameter_or_property_appears_twice_in_this_descriptor,
+ ?megaco_property_appears_twice_in_this_descriptor).
+-define(megaco_missing_parameter_in_signal_or_event, 457). % v2
+-define(megaco_unexpected_event_or_request_id, 458). % v3
+-define(megaco_unexpected_event,
+ ?megaco_unexpected_event_or_request_id).
+-define(megaco_unexpected_request_id,
+ ?megaco_unexpected_event_or_request_id).
+-define(megaco_segments_not_received, 459). % v3
+-define(megaco_unable_to_set_statistic_on_stream, 460). % v3
+-define(megaco_implied_add_for_multiplex_failure, 471).
+-define(megaco_internal_gateway_error, 500).
+-define(megaco_not_implemented, 501).
+-define(megaco_not_ready, 502).
+-define(megaco_service_unavailable, 503).
+-define(megaco_command_received_from_unauthorized_entity, 504).
+-define(megaco_transaction_req_received_before_servicechange_reply, 505). % v2
+-define(megaco_command_received_before_restart_response,
+ ?megaco_transaction_req_received_before_servicechange_reply).
+-define(megaco_number_of_transactionpending_exceeded, 506). % v2
+-define(megaco_insufficient_resources, 510).
+-define(megaco_mg_unequipped_to_detect_requested_event, 512).
+-define(megaco_mg_unequipped_to_generate_requested_signals, 513).
+-define(megaco_mg_cannot_send_the_specified_announcement, 514).
+-define(megaco_unsupported_media_type, 515).
+-define(megaco_unsupported_or_invalid_mode, 517).
+-define(megaco_event_buffer_full, 518).
+-define(megaco_out_of_space_to_store_digit_map, 519).
+-define(megaco_mg_does_not_have_a_digit_map, 520).
+-define(megaco_termination_is_service_changing, 521).
+-define(megaco_unsupported_func_req_in_topology_triple, 522). % v3
+-define(megaco_insufficient_bandwidth, 526).
+-define(megaco_internal_hardware_failure, 529).
+-define(megaco_temporary_network_failure, 530).
+-define(megaco_permanent_network_failure, 531).
+-define(megaco_audit_prop_stat_event_or_sig_does_not_exist, 532). % v2
+-define(megaco_response_exceeds_maximum_transport_pdu_size, 533). % v2
+-define(megaco_illegal_write_of_read_only_property, 534). % v2
+-define(megaco_unexpected_initial_hook_state, 540). % v2
+-define(megaco_command_not_allowed_on_this_termination, 542). % v3
+-define(megaco_does_not_exist, 581).
+
+
+%%----------------------------------------------------------------------
+%% Service change reasons
+%%----------------------------------------------------------------------
+
+-define(megaco_service_restored, "900").
+-define(megaco_cold_boot, "901").
+-define(megaco_warm_boot, "902").
+-define(megaco_mgc_directed_change, "903").
+-define(megaco_termination_malfunctioning, "904").
+-define(megaco_termination_taken_out_of_service, "905").
+-define(megaco_loss_of_lower_layer_connectivity, "906").
+-define(megaco_transmission_failure, "907").
+-define(megaco_mg_impending_failure, "908").
+-define(megaco_mgc_impending_failure, "909").
+-define(megaco_media_capability_failure, "910").
+-define(megaco_modem_capability_failure, "911").
+-define(megaco_mux_capability_failure, "912").
+-define(megaco_signal_capability_failure, "913").
+-define(megaco_event_capability_failure, "914").
+-define(megaco_state_loss, "915").
+-define(megaco_packages_change, "916"). % v2
+-define(megaco_capabilities_change, "917"). % v2
+-define(megaco_cancel_gracefull, "918"). % v3
+-define(megaco_warm_failover, "919"). % v3
+-define(megaco_cold_failover, "920"). % v3
+
+
+%%----------------------------------------------------------------------
+%% MGC listen ports for both TCP/IP and UDP/IP
+%% The port numbers are standardized by IANA (ww.iana.org).
+%%----------------------------------------------------------------------
+
+-define(megaco_ip_port_text, 2944).
+-define(megaco_ip_port_binary, 2945).
diff --git a/lib/megaco/include/megaco_message_prev3a.hrl b/lib/megaco/include/megaco_message_prev3a.hrl
new file mode 100644
index 0000000000..7b7a60fdae
--- /dev/null
+++ b/lib/megaco/include/megaco_message_prev3a.hrl
@@ -0,0 +1,599 @@
+%%<copyright>
+%% <year>2004-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+
+ %% with extension mark -- prev3a --
+
+ %% Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ %% Erlang Note: The only reason why we need to include
+ %% Erlang Note: these definitions in this version is
+ %% Erlang Note: that we cannot distinguish between v3
+ %% Erlang Note: versions in the megaco_messenger module
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+%% SegmentReply only used internally (in the engine)
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+
+ %% with extension mark -- prev3a --
+
+ iepsCallind = asn1_NOVALUE, % V3 Fixed
+ contextProp = asn1_NOVALUE
+ }).
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+
+ %% with extension mark -- prev3a --
+
+ iepsCallind = asn1_NOVALUE, % V3 Fixed
+ contextPropAud = asn1_NOVALUE
+ }).
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection,
+
+ %% After extension mark
+ streamID = asn1_NOVALUE %% Only in ASN.1
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor
+ }). % with extension mark
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE,
+ %% with extensions
+ auditPropertyToken = asn1_NOVALUE
+ }).
+
+
+%% --- v2 start ---
+
+-record('IndAudMediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudStreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }). % with extension mark
+
+-record('IndAudStreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+ remoteDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+
+ %% with extension mark -- prev3a --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudPropertyParm',
+ {
+ name
+ }). % with extension mark
+
+-record('IndAudLocalRemoteDescriptor',
+ {
+ propGroupID = asn1_NOVALUE,
+ propGrps
+ }). % with extension mark
+
+%% BUGBUG
+%% In text, it can only be one of them in each record.
+%% So, in case it's eventBufferControl or serviceState
+%% propertyParms will be an empty list.
+-record('IndAudTerminationStateDescriptor',
+ {
+ propertyParms = [], %% Optional in text...
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE, %% Only optional in ASN.1
+ pkgdName,
+ streamID = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventBufferDescriptor',
+ {
+ eventName,
+ %% This is an ugly hack to allow the eventParameterName
+ %% which only exist in text!!
+ %% streamID = asn1_NOVALUE | integer() |
+ %% {eventParameterName, Name} <- BUGBUG: ONLY IN TEXT
+ %% Note that the binary codecs will fail to encode
+ %% if the streamID is not aither asn1_NOVALUE or an integer()
+ %% So it is recommended to refrain from using this text feature...
+ streamID = asn1_NOVALUE
+
+ %% eventParameterName = asn1_NOVALUE %% BUGBUG: ONLY IN TEXT
+
+ }). % with extension mark
+
+-record('IndAudSeqSigList',
+ {
+ id,
+ signalList = asn1_NOVALUE %% Only in ASN1
+ }). % with extension mark
+
+-record('IndAudSignal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE %% Optional in ASN1 & non-existent in text
+ }). % with extension mark
+
+-record('IndAudDigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE %% OPTIONAL in ASN.1 but not in text
+ }).
+
+-record('IndAudStatisticsDescriptor',
+ {
+ statName
+ }).
+
+-record('IndAudPackagesDescriptor',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+
+%% --- v2 end ---
+
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+
+ %% with extension mark -- prev3a --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SecondEventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+
+ %% with extension mark -- prev3a --
+
+ direction = asn1_NOVALUE,
+ requestID = asn1_NOVALUE
+ }).
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE,
+
+ %% with extension mark -- prev3a (serviceChangeIncompleteFlag) --
+
+ serviceChangeInfo = asn1_NOVALUE,
+ serviceChangeIncompleteFlag = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+%% %% String of at least 1 character and at most 67 characters (ASN.1).
+%% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+%% -record('ServiceChangeProfile',
+%% {
+%% profileName
+%% }
+%% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_message_prev3b.hrl b/lib/megaco/include/megaco_message_prev3b.hrl
new file mode 100644
index 0000000000..cfabb29941
--- /dev/null
+++ b/lib/megaco/include/megaco_message_prev3b.hrl
@@ -0,0 +1,599 @@
+%%<copyright>
+%% <year>2005-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+
+ %% with extension mark -- prev3b --
+
+ %% Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ %% Erlang Note: The only reason why we need to include
+ %% Erlang Note: these definitions in this version is
+ %% Erlang Note: that we cannot distinguish between v3
+ %% Erlang Note: versions in the megaco_messenger module
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+%% SegmentReply only used internally (in the engine)
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE
+ }).
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE
+ }).
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection,
+
+ %% After extension mark
+ streamID = asn1_NOVALUE %% Only in ASN.1
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor
+ }). % with extension mark
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE,
+ %% with extensions
+ auditPropertyToken = asn1_NOVALUE
+ }).
+
+
+%% --- v2 start ---
+
+-record('IndAudMediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudStreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }). % with extension mark
+
+-record('IndAudStreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+ remoteDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudPropertyParm',
+ {
+ name
+ }). % with extension mark
+
+-record('IndAudLocalRemoteDescriptor',
+ {
+ propGroupID = asn1_NOVALUE,
+ propGrps
+ }). % with extension mark
+
+%% BUGBUG
+%% In text, it can only be one of them in each record.
+%% So, in case it's eventBufferControl or serviceState
+%% propertyParms will be an empty list.
+-record('IndAudTerminationStateDescriptor',
+ {
+ propertyParms = [], %% Optional in text...
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE, %% Only optional in ASN.1
+ pkgdName,
+ streamID = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventBufferDescriptor',
+ {
+ eventName,
+ %% This is an ugly hack to allow the eventParameterName
+ %% which only exist in text!!
+ %% streamID = asn1_NOVALUE | integer() |
+ %% {eventParameterName, Name} <- BUGBUG: ONLY IN TEXT
+ %% Note that the binary codecs will fail to encode
+ %% if the streamID is not aither asn1_NOVALUE or an integer()
+ %% So it is recommended to refrain from using this text feature...
+ streamID = asn1_NOVALUE
+
+ %% eventParameterName = asn1_NOVALUE %% BUGBUG: ONLY IN TEXT
+
+ }). % with extension mark
+
+-record('IndAudSeqSigList',
+ {
+ id,
+ signalList = asn1_NOVALUE %% Only in ASN1
+ }). % with extension mark
+
+-record('IndAudSignal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE %% Optional in ASN1 & non-existent in text
+ }). % with extension mark
+
+-record('IndAudDigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE %% OPTIONAL in ASN.1 but not in text
+ }).
+
+-record('IndAudStatisticsDescriptor',
+ {
+ statName
+ }).
+
+-record('IndAudPackagesDescriptor',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+
+%% --- v2 end ---
+
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SecondEventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+
+ %% with extension mark -- prev3b --
+
+ direction = asn1_NOVALUE,
+ requestID = asn1_NOVALUE
+ }).
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b (serviceChangeIncompleteFlag) --
+
+ serviceChangeInfo = asn1_NOVALUE,
+ serviceChangeIncompleteFlag = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+%% %% String of at least 1 character and at most 67 characters (ASN.1).
+%% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+%% -record('ServiceChangeProfile',
+%% {
+%% profileName
+%% }
+%% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_message_prev3c.hrl b/lib/megaco/include/megaco_message_prev3c.hrl
new file mode 100644
index 0000000000..32024c9a02
--- /dev/null
+++ b/lib/megaco/include/megaco_message_prev3c.hrl
@@ -0,0 +1,784 @@
+%%<copyright>
+%% <year>2005-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+
+%% Transaction ::= CHOICE
+%% {
+%% transactionRequest TransactionRequest,
+%% transactionPending TransactionPending,
+%% transactionReply TransactionReply,
+%% transactionResponseAck TransactionResponseAck,
+%% -- use of response acks is dependent on underlying transport
+%% ...,
+%% segmentReply SegmentReply
+%% }
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+
+ %% with extension mark -- v3 --
+
+ %% Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ %% Erlang Note: The only reason why we need to include
+ %% Erlang Note: these definitions in this version is
+ %% Erlang Note: that we cannot distinguish between v3
+ %% Erlang Note: versions in the megaco_messenger module
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+
+%% -- v3 --
+%% -record('SegmentReply',
+%% {
+%% transactionId,
+%% segmentNumber,
+%% segmentationComplete = asn1_NOVALUE
+%% }). % with extension mark
+
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ contextList = asn1_NOVALUE
+
+ }).
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE
+ }).
+
+
+%% SelectLogic ::= CHOICE
+%% {
+%% andAUDITSelect NULL, -- all selection conditions satisfied
+%% orAUDITSelect NULL, -- at least one selection condition satisfied
+%% ...
+%% }
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection,
+
+ %% After extension mark
+ streamID = asn1_NOVALUE,
+
+ %% -- prev3c --
+ %% This is actually not according to the standard,
+ %% but without it 'TopologyRequest' will be useless.
+ topologyDirectionExtension = asn1_NOVALUE
+
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor,
+
+ %% -- prev3c (after extension mark) --
+
+ terminationIDList = asn1_NOVALUE
+
+ }).
+
+%% AuditReply := CHOICE
+%% {
+%% contextAuditResult TerminationIDList,
+%% error ErrorDescriptor,
+%% auditResult AuditResult,
+%% ...
+%% auditResultTermList TermListAuditResult
+%% }
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('TermListAuditResult',
+ {
+ terminationIDList,
+ terminationAuditResult = []
+ }). % with extension mark
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE,
+ %% with extensions
+ auditPropertyToken = asn1_NOVALUE
+ }).
+
+
+%% --- v2 start ---
+
+-record('IndAudMediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudStreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }). % with extension mark
+
+-record('IndAudStreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+ remoteDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ streamModeSel = asn1_NOVALUE
+
+ }).
+
+-record('IndAudPropertyParm',
+ {
+ name,
+
+ %% -- prev3c (after extension mark) --
+
+ propertyParms = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalRemoteDescriptor',
+ {
+ propGroupID = asn1_NOVALUE,
+ propGrps
+ }). % with extension mark
+
+%% IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+
+%% BUGBUG
+%% In text, it can only be one of them in each record.
+%% So, in case it's eventBufferControl or serviceState
+%% propertyParms will be an empty list.
+-record('IndAudTerminationStateDescriptor',
+ {
+ propertyParms = [], %% Optional in text...
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ serviceStateSel = asn1_NOVALUE
+
+ }).
+
+-record('IndAudEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE, %% Only optional in ASN.1
+ pkgdName,
+ streamID = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventBufferDescriptor',
+ {
+ eventName,
+ %% This is an ugly hack to allow the eventParameterName
+ %% which only exist in text!!
+ %% streamID = asn1_NOVALUE | integer() |
+ %% {eventParameterName, Name} <- BUGBUG: ONLY IN TEXT
+ %% Note that the binary codecs will fail to encode
+ %% if the streamID is not aither asn1_NOVALUE or an integer()
+ %% So it is recommended to refrain from using this text feature...
+ streamID = asn1_NOVALUE
+
+ %% eventParameterName = asn1_NOVALUE %% BUGBUG: ONLY IN TEXT
+
+ }). % with extension mark
+
+-record('IndAudSeqSigList',
+ {
+ id,
+ signalList = asn1_NOVALUE %% Only in ASN1
+ }). % with extension mark
+
+-record('IndAudSignal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE, % Optional in ASN1 & non-existent in text
+
+ %% -- prev3c (after extension mark) --
+
+ signalRequestID = asn1_NOVALUE
+
+ }). % with extension mark
+
+-record('IndAudDigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE %% OPTIONAL in ASN.1 but not in text
+ }).
+
+-record('IndAudStatisticsDescriptor',
+ {
+ statName
+ }).
+
+-record('IndAudPackagesDescriptor',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+
+%% --- v2 end ---
+
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+%% TerminationIDList ::= SEQUENCE OF TerminationID
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+%% StreamMode ::= ENUMERATED
+%% {
+%% sendOnly(0),
+%% recvOnly(1),
+%% sendRecv(2),
+%% inactive(3),
+%% loopBack(4),
+%% ...
+%% }
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+%% EventBufferControl ::= ENUMERATED
+%% {
+%% off(0),
+%% lockStep(1),
+%% ...
+%% }
+
+%% ServiceState ::= ENUMERATED
+%% {
+%% test(0),
+%% outOfSvc(1),
+%% inSvc(2),
+%% ...
+%% }
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+%% -- prev3c --
+-record('RegulatedEmbeddedDescriptor',
+ {
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+%% NotifyBehaviour ::= CHOICE
+%% {
+%% notifyImmediate NULL,
+%% notifyRegulated RegulatedEmbeddedDescriptor,
+%% neverNotify NULL,
+%% ...
+%% }
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE
+
+ }).
+
+-record('SecondEventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE
+
+ }).
+
+
+%% EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+
+%% SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+%% SignalRequest ::= CHOICE
+%% {
+%% signal Signal,
+%% seqSigList SeqSigList,
+%% ...
+%% }
+
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+
+ %% with extension mark -- prev3b --
+
+ direction = asn1_NOVALUE,
+ requestID = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ intersigDelay = asn1_NOVALUE
+
+ }).
+
+%% SignalType ::= ENUMERATED
+%% {
+%% brief(0),
+%% onOff(1),
+%% timeOut(2),
+%% ...
+%% }
+
+%% SignalDirection ::= ENUMERATED
+%% {
+%% internal(0),
+%% external(1),
+%% both(3),
+%% ...
+%% }
+
+%% SignalName ::= PkgdName
+
+%% NotifyCompletion ::= BIT STRING
+%% {
+%% onTimeOut(0), onInterruptByEvent(1),
+%% onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+%% }
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b (serviceChangeIncompleteFlag) --
+
+ serviceChangeInfo = asn1_NOVALUE,
+ serviceChangeIncompleteFlag = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+%% %% String of at least 1 character and at most 67 characters (ASN.1).
+%% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+%% -record('ServiceChangeProfile',
+%% {
+%% profileName
+%% }
+%% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_message_v1.hrl b/lib/megaco/include/megaco_message_v1.hrl
new file mode 100644
index 0000000000..ba50b50c80
--- /dev/null
+++ b/lib/megaco/include/megaco_message_v1.hrl
@@ -0,0 +1,439 @@
+%%<copyright>
+%% <year>2000-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult
+ }). % with extension mark
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE
+ }). % with extension mark
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor
+ }). % with extension mark
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SecondEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = []
+ }). % with extension mark
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody
+ }). % with extension mark
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+% %% String of at least 1 character and at most 67 characters (ASN.1).
+% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+% -record('ServiceChangeProfile',
+% {
+% profileName
+% }
+% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_message_v2.hrl b/lib/megaco/include/megaco_message_v2.hrl
new file mode 100644
index 0000000000..6190ea7ac4
--- /dev/null
+++ b/lib/megaco/include/megaco_message_v2.hrl
@@ -0,0 +1,561 @@
+%%<copyright>
+%% <year>2003-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult
+ }). % with extension mark
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE
+ }). % with extension mark
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection,
+
+ %% After extension mark
+ streamID = asn1_NOVALUE
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor
+ }). % with extension mark
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE,
+ %% with extensions
+ auditPropertyToken = asn1_NOVALUE
+ }).
+
+
+%% --- v2 start ---
+
+-record('IndAudMediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudStreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }). % with extension mark
+
+-record('IndAudStreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+ remoteDescriptor = asn1_NOVALUE %% NOTE: NOT IN TEXT
+ }). % with extension mark
+
+-record('IndAudLocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudPropertyParm',
+ {
+ name
+ }). % with extension mark
+
+-record('IndAudLocalRemoteDescriptor',
+ {
+ propGroupID = asn1_NOVALUE,
+ propGrps
+ }). % with extension mark
+
+%% BUGBUG
+%% In text, it can only be one of them in each record.
+%% So, in case it's eventBufferControl or serviceState
+%% propertyParms will be an empty list.
+-record('IndAudTerminationStateDescriptor',
+ {
+ propertyParms = [], %% Optional in text...
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE, %% Only optional in ASN.1
+ pkgdName,
+ streamID = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventBufferDescriptor',
+ {
+ eventName,
+ %% This is an ugly hack to allow the eventParameterName
+ %% which only exist in text!!
+ %% streamID = asn1_NOVALUE | integer() |
+ %% {eventParameterName, Name} <- BUGBUG: ONLY IN TEXT
+ %% Note that the binary codecs will fail to encode
+ %% if the streamID is not aither asn1_NOVALUE or an integer()
+ %% So it is recommended to refrain from using this text feature...
+ streamID = asn1_NOVALUE
+
+ %% eventParameterName = asn1_NOVALUE %% BUGBUG: ONLY IN TEXT
+
+ }). % with extension mark
+
+-record('IndAudSeqSigList',
+ {
+ id,
+ signalList = asn1_NOVALUE %% Only in ASN1
+ }). % with extension mark
+
+-record('IndAudSignal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE %% Optional in ASN1 & non-existent in text
+ }). % with extension mark
+
+-record('IndAudDigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE %% OPTIONAL in ASN.1 but not in text
+ }).
+
+-record('IndAudStatisticsDescriptor',
+ {
+ statName
+ }).
+
+-record('IndAudPackagesDescriptor',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+
+%% --- v2 end ---
+
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SecondEventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = []
+ }). % with extension mark
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE,
+ %% with extension mark
+ serviceChangeInfo = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+%% %% String of at least 1 character and at most 67 characters (ASN.1).
+%% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+%% -record('ServiceChangeProfile',
+%% {
+%% profileName
+%% }
+%% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_message_v3.hrl b/lib/megaco/include/megaco_message_v3.hrl
new file mode 100644
index 0000000000..7a1bc80571
--- /dev/null
+++ b/lib/megaco/include/megaco_message_v3.hrl
@@ -0,0 +1,779 @@
+%%<copyright>
+%% <year>2005-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+
+%% Transaction ::= CHOICE
+%% {
+%% transactionRequest TransactionRequest,
+%% transactionPending TransactionPending,
+%% transactionReply TransactionReply,
+%% transactionResponseAck TransactionResponseAck,
+%% -- use of response acks is dependent on underlying transport
+%% ...,
+%% segmentReply SegmentReply
+%% }
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions = []
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+-record('TransactionReply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+
+ %% with extension mark -- v3 --
+
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+
+%% -- v3 --
+-record('SegmentReply',
+ {
+ transactionId,
+ segmentNumber,
+ segmentationComplete = asn1_NOVALUE
+ }). % with extension mark
+
+%% SegmentNumber ::= INTEGER(0..65535)
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('ActionRequest',
+ {
+ contextId,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = []
+ }).
+
+-record('ActionReply',
+ {
+ contextId,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []
+ }).
+
+-record('ContextRequest',
+ {
+ priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ contextList = asn1_NOVALUE
+
+ }).
+
+-record('ContextAttrAuditRequest',
+ {
+ topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE
+ }).
+
+
+%% SelectLogic ::= CHOICE
+%% {
+%% andAUDITSelect NULL, -- all selection conditions satisfied
+%% orAUDITSelect NULL, -- at least one selection condition satisfied
+%% ...
+%% }
+
+-record('CommandRequest',
+ {
+ command,
+ optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE
+ }). % with extension mark
+
+-record('TopologyRequest',
+ {
+ terminationFrom,
+ terminationTo,
+ topologyDirection,
+
+ %% After extension mark
+ streamID = asn1_NOVALUE,
+
+ %% -- prev3c --
+ %% This is actually not according to the standard,
+ %% but without it 'TopologyRequest' will be useless.
+ topologyDirectionExtension = asn1_NOVALUE
+
+ }).
+
+-record('AmmRequest',
+ {
+ terminationID = [],
+ descriptors = []
+ }). % with extension mark
+
+-record('AmmsReply',
+ {
+ terminationID = [],
+ terminationAudit = asn1_NOVALUE
+ }). % with extension mark
+
+-record('SubtractRequest',
+ {
+ terminationID = [],
+ auditDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('AuditRequest',
+ {
+ terminationID,
+ auditDescriptor,
+
+ %% -- prev3c (after extension mark) --
+
+ terminationIDList = asn1_NOVALUE
+
+ }).
+
+%% AuditReply := CHOICE
+%% {
+%% contextAuditResult TerminationIDList,
+%% error ErrorDescriptor,
+%% auditResult AuditResult,
+%% ...
+%% auditResultTermList TermListAuditResult
+%% }
+
+-record('AuditResult',
+ {
+ terminationID,
+ terminationAuditResult = []
+ }).
+
+-record('TermListAuditResult',
+ {
+ terminationIDList,
+ terminationAuditResult = []
+ }). % with extension mark
+
+-record('AuditDescriptor',
+ {
+ auditToken = asn1_NOVALUE,
+ %% with extensions
+ auditPropertyToken = asn1_NOVALUE
+ }).
+
+
+%% --- v2 start ---
+
+-record('IndAudMediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudStreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }). % with extension mark
+
+-record('IndAudStreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+ remoteDescriptor = asn1_NOVALUE, %% NOTE: NOT IN TEXT
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ streamModeSel = asn1_NOVALUE
+
+ }).
+
+-record('IndAudPropertyParm',
+ {
+ name,
+
+ %% -- prev3c (after extension mark) --
+
+ propertyParms = asn1_NOVALUE
+ }).
+
+-record('IndAudLocalRemoteDescriptor',
+ {
+ propGroupID = asn1_NOVALUE,
+ propGrps
+ }). % with extension mark
+
+%% IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+
+%% BUGBUG
+%% In text, it can only be one of them in each record.
+%% So, in case it's eventBufferControl or serviceState
+%% propertyParms will be an empty list.
+-record('IndAudTerminationStateDescriptor',
+ {
+ propertyParms = [], %% Optional in text...
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ serviceStateSel = asn1_NOVALUE
+
+ }).
+
+-record('IndAudEventsDescriptor',
+ {
+ requestID = asn1_NOVALUE, %% Only optional in ASN.1
+ pkgdName,
+ streamID = asn1_NOVALUE
+ }). % with extension mark
+
+-record('IndAudEventBufferDescriptor',
+ {
+ eventName,
+ %% This is an ugly hack to allow the eventParameterName
+ %% which only exist in text!!
+ %% streamID = asn1_NOVALUE | integer() |
+ %% {eventParameterName, Name} <- BUGBUG: ONLY IN TEXT
+ %% Note that the binary codecs will fail to encode
+ %% if the streamID is not aither asn1_NOVALUE or an integer()
+ %% So it is recommended to refrain from using this text feature...
+ streamID = asn1_NOVALUE
+
+ %% eventParameterName = asn1_NOVALUE %% BUGBUG: ONLY IN TEXT
+
+ }). % with extension mark
+
+-record('IndAudSeqSigList',
+ {
+ id,
+ signalList = asn1_NOVALUE %% Only in ASN1
+ }). % with extension mark
+
+-record('IndAudSignal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE, % Optional in ASN1 & non-existent in text
+
+ %% -- prev3c (after extension mark) --
+
+ signalRequestID = asn1_NOVALUE
+
+ }). % with extension mark
+
+-record('IndAudDigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE %% OPTIONAL in ASN.1 but not in text
+ }).
+
+-record('IndAudStatisticsDescriptor',
+ {
+ statName
+ }).
+
+-record('IndAudPackagesDescriptor',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+
+%% --- v2 end ---
+
+
+-record('NotifyRequest',
+ {
+ terminationID = [],
+ observedEventsDescriptor,
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('NotifyReply',
+ {
+ terminationID = [],
+ errorDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ObservedEventsDescriptor',
+ {
+ requestId,
+ observedEventLst = []
+ }).
+
+-record('ObservedEvent',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = [],
+ timeNotation = asn1_NOVALUE
+ }). % with extension mark
+
+%% This value field of this record is already encoded and will
+%% be inserted as is.
+%% This record could be used either when there is a bug in the
+%% encoder or if an "external" package, unknown to the megaco app,
+%% where the value part requires a special encode.
+-record(megaco_event_parameter,
+ {
+ name,
+ value
+ }).
+
+-record('EventParameter',
+ {
+ eventParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ServiceChangeRequest',
+ {
+ terminationID = [],
+ serviceChangeParms
+ }). % with extension mark
+
+-record('ServiceChangeReply',
+ {
+ terminationID = [],
+ serviceChangeResult = []
+ }). % with extension mark
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
+%% TerminationIDList ::= SEQUENCE OF TerminationID
+
+-record('MediaDescriptor',
+ {
+ termStateDescr = asn1_NOVALUE,
+ streams = asn1_NOVALUE
+ }). % with extension mark
+
+-record('StreamDescriptor',
+ {
+ streamID,
+ streamParms
+ }).
+
+-record('StreamParms',
+ {
+ localControlDescriptor = asn1_NOVALUE,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b --
+
+ statisticsDescriptor = asn1_NOVALUE
+ }).
+
+-record('LocalControlDescriptor',
+ {
+ streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []
+ }). % with extension mark
+
+%% StreamMode ::= ENUMERATED
+%% {
+%% sendOnly(0),
+%% recvOnly(1),
+%% sendRecv(2),
+%% inactive(3),
+%% loopBack(4),
+%% ...
+%% }
+
+-record('PropertyParm',
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('LocalRemoteDescriptor',
+ {
+ propGrps = []
+ }). % with extension mark
+
+-record('TerminationStateDescriptor',
+ {
+ propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE
+ }). % with extension mark
+
+%% EventBufferControl ::= ENUMERATED
+%% {
+%% off(0),
+%% lockStep(1),
+%% ...
+%% }
+
+%% ServiceState ::= ENUMERATED
+%% {
+%% test(0),
+%% outOfSvc(1),
+%% inSvc(2),
+%% ...
+%% }
+
+-record('MuxDescriptor',
+ {
+ muxType,
+ termList = [],
+ nonStandardData = asn1_NOVALUE
+ }). % with extension mark
+
+-record('EventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('RequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+%% -- prev3c --
+-record('RegulatedEmbeddedDescriptor',
+ {
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE
+ }). % with extension mark
+
+%% NotifyBehaviour ::= CHOICE
+%% {
+%% notifyImmediate NULL,
+%% notifyRegulated RegulatedEmbeddedDescriptor,
+%% neverNotify NULL,
+%% ...
+%% }
+
+-record('RequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE
+
+ }).
+
+-record('SecondEventsDescriptor',
+ {
+ requestID,
+ %% BUGBUG: IG 6.82 was withdrawn
+ %% requestID = asn1_NOVALUE,
+ eventList = []
+ }). % with extension mark
+
+-record('SecondRequestedEvent',
+ {
+ pkgdName,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []
+ }). % with extension mark
+
+-record('SecondRequestedActions',
+ {
+ keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+
+ %% -- prev3c (after extension mark) --
+
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE
+
+ }).
+
+
+%% EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+-record('EventSpec',
+ {
+ eventName,
+ streamID = asn1_NOVALUE,
+ eventParList = []
+ }). % with extension mark
+
+
+%% SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+%% SignalRequest ::= CHOICE
+%% {
+%% signal Signal,
+%% seqSigList SeqSigList,
+%% ...
+%% }
+
+
+-record('SeqSigList',
+ {
+ id,
+ signalList = []
+ }).
+
+-record('Signal',
+ {
+ signalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+
+ %% with extension mark -- prev3b --
+
+ direction = asn1_NOVALUE,
+ requestID = asn1_NOVALUE,
+
+ %% -- prev3c --
+
+ intersigDelay = asn1_NOVALUE
+
+ }).
+
+%% SignalType ::= ENUMERATED
+%% {
+%% brief(0),
+%% onOff(1),
+%% timeOut(2),
+%% ...
+%% }
+
+%% SignalDirection ::= ENUMERATED
+%% {
+%% internal(0),
+%% external(1),
+%% both(3),
+%% ...
+%% }
+
+%% SignalName ::= PkgdName
+
+%% NotifyCompletion ::= BIT STRING
+%% {
+%% onTimeOut(0), onInterruptByEvent(1),
+%% onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+%% }
+
+-record('SigParameter',
+ {
+ sigParameterName,
+ value,
+ extraInfo = asn1_NOVALUE
+ }). % with extension mark
+
+-record('ModemDescriptor',
+ {
+ mtl,
+ mpl,
+ nonStandardData = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeParm',
+ {
+ serviceChangeMethod,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ serviceChangeReason,
+ serviceChangeDelay = asn1_NOVALUE,
+ serviceChangeMgcId = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE,
+ nonStandardData = asn1_NOVALUE,
+
+ %% with extension mark -- prev3b (serviceChangeIncompleteFlag) --
+
+ serviceChangeInfo = asn1_NOVALUE,
+ serviceChangeIncompleteFlag = asn1_NOVALUE
+ }).
+
+-record('ServiceChangeResParm',
+ {
+ serviceChangeMgcId = asn1_NOVALUE,
+ serviceChangeAddress = asn1_NOVALUE,
+ serviceChangeVersion = asn1_NOVALUE,
+ serviceChangeProfile = asn1_NOVALUE,
+ timeStamp = asn1_NOVALUE
+ }). % with extension mark
+
+
+%% This is the actual ASN.1 type and it is as this it will
+%% be represented if the encoding config [native] is choosen.
+%% %% String of at least 1 character and at most 67 characters (ASN.1).
+%% %% 64 characters for name, 1 for "/", 2 for version to match ABNF
+%% -record('ServiceChangeProfile',
+%% {
+%% profileName
+%% }
+%% ).
+
+-record('ServiceChangeProfile',
+ {
+ profileName,
+ version
+ }).
+
+
+-record('PackagesItem',
+ {
+ packageName,
+ packageVersion
+ }). % with extension mark
+
+-record('StatisticsParameter',
+ {
+ statName,
+ statValue = asn1_NOVALUE
+ }).
+
+-record('TimeNotation',
+ {
+ date,
+ time
+ }).
+
diff --git a/lib/megaco/include/megaco_sdp.hrl b/lib/megaco/include/megaco_sdp.hrl
new file mode 100644
index 0000000000..e6d9f92edd
--- /dev/null
+++ b/lib/megaco/include/megaco_sdp.hrl
@@ -0,0 +1,1471 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+%%
+%%
+%% Explanaition of the fields in the SDP body
+%% (See RFC 4566 for the complete decription)
+%%
+%% Session descriptions
+%%
+%% v protocol version
+%% o owner/creator and session identifier
+%% s session name (optional)
+%% i session information (optional)
+%% u URI of description (optional)
+%% e email address (optional)
+%% p phone number (optional)
+%% c connection information (optional)
+%% b bandwidth information (optional)
+%% One or more time descriptions ("t=" and "r=" lines; see below)
+%% z time zone adjustment (optional)
+%% k encryption key (optional)
+%% a zero or more session attribute lines (optional)
+%% Zero or more media descriptions
+%%
+%% Time descriptions
+%%
+%% t time the session is active
+%% r zero or more repeat times (optional)
+%%
+%% Media descriptions, if present
+%%
+%% m media name and transport address
+%% i media title (optional)
+%% c connection information - optional if included at session-level
+%% b bandwidth information (optional)
+%% k encryption key (optional)
+%% a zero or more media attribute lines (optional)
+%%
+%%
+%% An example SDP description is:
+%%
+%% v=0
+%% o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
+%% s=SDP Seminar
+%% i=A Seminar on the session description protocol
+%% u=http://www.example.com/seminars/sdp.pdf
+%% [email protected] (Jane Doe)
+%% c=IN IP4 224.2.17.12/127
+%% t=2873397496 2873404696
+%% a=recvonly
+%% m=audio 49170 RTP/AVP 0
+%% m=video 51372 RTP/AVP 99
+%% a=rtpmap:99 h263-1998/90000
+%%
+%%
+%%----------------------------------------------------------------------
+
+-ifndef(megaco_sdp_).
+-define(megaco_sdp_, true).
+
+
+%% ===================================================================
+%%
+%% Protocol Version ("v=")
+%%
+%% v=0
+%%
+%% The "v=" field gives the version of the Session Description
+%% Protocol. This memo defines version 0. There is no minor version
+%% number
+%%
+
+-record(megaco_sdp_v, {
+ version % integer()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Origin ("o=")
+%%
+%% o=<username> <sess-id> <sess-version> <nettype> <addrtype>
+%% <unicast-address>
+%%
+%% The "o=" field gives the originator of the session (their username
+%% and the address of the user's host) plus a session id and session
+%% version number:
+%%
+%% <username> is the user's login on the originating host, or it is
+%% "-" if the originating host does not support the concept of
+%% user IDs. The <username> MUST NOT contain spaces.
+%%
+%% <sess-id> is a numeric string such that the tuple of <username>,
+%% <sess-id>, <nettype>, <addrtype> and <unicast-address> form a
+%% globally unique identifier for the session. The method of
+%% <sess-id> allocation is up to the creating tool, but it has
+%% been suggested that a Network Time Protocol (NTP)
+%% timestamp be used to ensure uniqueness [13].
+%%
+%% <sess-version> is a version number for this announcement. Its
+%% usage is up to the creating tool, so long as <sess-version>
+%% is increased when a modification is made to the session data.
+%% Again, it is RECOMMENDED that an NTP format timestamp is used
+%%
+%% <nettype> is a text string giving the type of network.
+%% Initially "IN" is defined to have the meaning "Internet", but
+%% other values MAY be registered in the future (see Section 8
+%% of RFC 4566).
+%%
+%% <addrtype> is a text string giving the type of the address that
+%% follows. Initially "IP4" and "IP6" are defined, but other
+%% values MAY be registered in the future (see Section 8
+%% of RFC 4566).
+%%
+%% <unicast-address> is the address of the machine from which the
+%% session was created. For an address type of IP4, this is
+%% either the fully qualified domain name of the machine or the
+%% dotted-decimal representation of the IP version 4 address of
+%% the machine. For an address type of IP6, this is either the
+%% fully qualified domain name of the machine or the compressed
+%% textual representation of the IP version 6 address of the
+%% machine. For both IP4 and IP6, the fully qualified domain name
+%% is the form that SHOULD be given unless this is unavailable,
+%% in which case the globally unique address MAY be substituted.
+%% A local IP address MUST NOT be used in any context where the
+%% SDP description might leave the scope in which the address is
+%% meaningful (for example, a local address MUST NOT be included
+%% in an application-level referral that might leave the scope).
+%%
+%% In general, the "o=" field serves as a globally unique identifier
+%% for this version of this session description, and the subfields
+%% excepting the version taken together identify the session
+%% irrespective of any modifications.
+%%
+%% For privacy reasons, it is sometimes desirable to obfuscate the
+%% username and IP address of the session originator. If this is a
+%% concern, an arbitrary <username> and private <unicast-address> MAY be
+%% chosen to populate the "o=" field, provided that these are selected
+%% in a manner that does not affect the global uniqueness of the field.
+%%
+%%
+
+-record(megaco_sdp_o, {
+ user_name, % <username> string()
+ session_id, % <sess-id> integer()
+ version, % <sess-version> integer()
+ network_type = in, % <nettype> in | string()
+ address_type = ip4, % <addrtype> ip4 | ip6 | string()
+ address % <unicast-address> string()
+ }
+ ).
+
+
+%% ===================================================================
+%%
+%% Session Name ("s=")
+%%
+%% s=<session name>
+%%
+%% The "s=" field is the textual session name. There MUST be one and
+%% only one "s=" field per session description. The "s=" field MUST
+%% NOT be empty and SHOULD contain ISO 10646 characters (but see also
+%% the "a=charset" attribute). If a session has no meaningful name,
+%% the value "s= " SHOULD be used (i.e., a single space as the session
+%% name).
+%%
+
+-record(megaco_sdp_s, {
+ name % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Session and Media Information ("i=")
+%%
+%% i=<session description>
+%%
+%% The "i=" field provides textual information about the session.
+%% There MUST be at most one session-level "i=" field per session
+%% description, and at most one "i=" field per media. If the
+%% "a=charset" attribute is present, it specifies the character set
+%% used in the "i=" field. If the "a=charset" attribute is not
+%% present, the "i=" field MUST contain ISO 10646 characters in
+%% UTF-8 encoding.
+%%
+%% A single "i=" field MAY also be used for each media definition.
+%% In media definitions, "i=" fields are primarily intended for
+%% labelling media streams. As such, they are most likely to be
+%% useful when a single session has more than one distinct media
+%% stream of the same media type. An example would be two different
+%% whiteboards, one for slides and one for feedback and questions.
+%%
+%% The "i=" field is intended to provide a free-form human-readable
+%% description of the session or the purpose of a media stream. It
+%% is not suitable for parsing by automata.
+%%
+
+-record(megaco_sdp_i, {
+ session_descriptor % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% URI ("u=")
+%%
+%% u=<URI>
+%%
+%% A URI is a Uniform Resource Identifier as used by WWW clients [7].
+%% The URI should be a pointer to additional information about the
+%% session. This field is OPTIONAL, but if it is present it MUST be
+%% specified before the first media field. No more than one URI field
+%% is allowed per session description.
+%%
+
+-record(megaco_sdp_u, {
+ uri % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Email Address and Phone Number ("e=" and "p=")
+%%
+%% e=<email address>
+%% p=<phone number>
+%%
+%% The "e=" and "p=" lines specify contact information for the person
+%% responsible for the conference. This is not necessarily the same
+%% person that created the conference announcement.
+%%
+%% Inclusion of an email address or phone number is OPTIONAL. Note
+%% that the previous version of SDP specified that either an email
+%% field or a phone field MUST be specified, but this was widely
+%% ignored. The change brings the specification into line with
+%% common usage.
+%%
+%% If an email address or phone number is present, it MUST be
+%% specified before the first media field. More than one email or
+%% phone field can be given for a session description.
+%%
+%% Phone numbers SHOULD be given in the form of an international
+%% public telecommunication number (see ITU-T Recommendation E.164)
+%% preceded by a "+". Spaces and hyphens may be used to split up a
+%% phone field to aid readability if desired. For example:
+%%
+%% p=+1 617 555-6011
+%%
+%% Both email addresses and phone numbers can have an OPTIONAL free
+%% text string associated with them, normally giving the name of the
+%% person who may be contacted. This MUST be enclosed in parentheses
+%% if it is present. For example:
+%%
+%% [email protected] (Jane Doe)
+%%
+%% The alternative RFC 2822 [29] name quoting convention is also
+%% allowed for both email addresses and phone numbers. For example:
+%%
+%% e=Jane Doe <[email protected]>
+%%
+%% The free text string SHOULD be in the ISO-10646 character set with
+%% UTF-8 encoding, or alternatively in ISO-8859-1 or other encodings
+%% if the appropriate session-level "a=charset" attribute is set.
+%%
+
+-record(megaco_sdp_e, {
+ email % string()
+ }
+ ).
+
+-record(megaco_sdp_p, {
+ phone_number % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Connection Data ("c=")
+%%
+%% c=<nettype> <addrtype> <connection-address>
+%%
+%% The "c=" field contains connection data.
+%%
+%% A session description MUST contain either at least one "c=" field
+%% in each media description or a single "c=" field at the session
+%% level. It MAY contain a single session-level "c=" field and
+%% additional "c=" field(s) per media description, in which case the
+%% per-media values override the session-level settings for the
+%% respective media.
+%%
+%% The first sub-field ("<nettype>") is the network type, which is a
+%% text string giving the type of network. Initially, "IN" is
+%% defined to have the meaning "Internet", but other values MAY be
+%% registered in the future (see Section 8 of RFC 4566).
+%%
+%% The second sub-field ("<addrtype>") is the address type. This
+%% allows SDP to be used for sessions that are not IP based. This
+%% memo only defines IP4 and IP6, but other values MAY be registered
+%% in the future (see Section 8 of RFC 4566).
+%%
+%% The third sub-field ("<connection-address>") is the connection
+%% address. OPTIONAL sub-fields MAY be added after the connection
+%% address depending on the value of the <addrtype> field.
+%%
+%% When the <addrtype> is IP4 and IP6, the connection address is
+%% defined as follows:
+%%
+%% o If the session is multicast, the connection address will be an
+%% IP multicast group address. If the session is not multicast,
+%% then the connection address contains the unicast IP address of
+%% the expected data source or data relay or data sink as
+%% determined by additional attribute fields. It is not expected
+%% that unicast addresses will be given in a session description
+%% that is communicated by a multicast announcement, though this
+%% is not prohibited.
+%%
+%% o Sessions using an IPv4 multicast connection address MUST also
+%% have a time to live (TTL) value present in addition to the
+%% multicast address. The TTL and the address together define the
+%% scope with which multicast packets sent in this conference will
+%% be sent. TTL values MUST be in the range 0-255. Although the
+%% TTL MUST be specified, its use to scope multicast traffic is
+%% deprecated; applications SHOULD use an administratively scoped
+%% address instead.
+%%
+%% The TTL for the session is appended to the address using a slash
+%% as a separator. An example is:
+%%
+%% c=IN IP4 224.2.36.42/127
+%%
+%% IPv6 multicast does not use TTL scoping, and hence the TTL value
+%% MUST NOT be present for IPv6 multicast. It is expected that IPv6
+%% scoped addresses will be used to limit the scope of conferences.
+%%
+%% Hierarchical or layered encoding schemes are data streams where
+%% the encoding from a single media source is split into a number of
+%% layers. The receiver can choose the desired quality (and hence
+%% bandwidth) by only subscribing to a subset of these layers. Such
+%% layered encodings are normally transmitted in multiple multicast
+%% groups to allow multicast pruning. This technique keeps unwanted
+%% traffic from sites only requiring certain levels of the hierarchy.
+%% For applications requiring multiple multicast groups, we allow the
+%% following notation to be used for the connection address:
+%%
+%% <base multicast address>[/<ttl>]/<number of addresses>
+%%
+%% If the number of addresses is not given, it is assumed to be one.
+%% Multicast addresses so assigned are contiguously allocated above
+%% the base address, so that, for example:
+%%
+%% c=IN IP4 224.2.1.1/127/3
+%%
+%% would state that addresses 224.2.1.1, 224.2.1.2, and 224.2.1.3 are
+%% to be used at a TTL of 127. This is semantically identical to
+%% including multiple "c=" lines in a media description:
+%%
+%% c=IN IP4 224.2.1.1/127
+%% c=IN IP4 224.2.1.2/127
+%% c=IN IP4 224.2.1.3/127
+%%
+%% Similarly, an IPv6 example would be:
+%%
+%% c=IN IP6 FF15::101/3
+%%
+%% which is semantically equivalent to:
+%%
+%% c=IN IP6 FF15::101
+%% c=IN IP6 FF15::102
+%% c=IN IP6 FF15::103
+%%
+%% (remembering that the TTL field is not present in IPv6 multicast).
+%%
+%% Multiple addresses or "c=" lines MAY be specified on a per-media
+%% basis only if they provide multicast addresses for different layers
+%% in a hierarchical or layered encoding scheme. They MUST NOT be
+%% specified for a session-level "c=" field.
+%%
+%% The slash notation for multiple addresses described above MUST NOT
+%% be used for IP unicast addresses.
+%%
+
+-record(megaco_sdp_c, {
+ network_type = in, % <nettype> in | string()
+ address_type = ip4, % <addrtype> ip4 | ip6 | string()
+ connection_addr % <connection-address> string() | conn_addr()
+ }).
+
+%% Only if address type = ip4
+%% conn_addr() -> #megaco_sdp_c_conn_addr{}
+-record(megaco_sdp_c_conn_addr, {
+ base, % <base multicast address> string()
+ ttl, % <ttl> integer()
+ num_of % <number of addresses> undefined | integer()
+ }).
+
+
+
+%% ===================================================================
+%%
+%% Bandwidth ("b=")
+%%
+%% b=<bwtype>:<bandwidth>
+%%
+%% This OPTIONAL field denotes the proposed bandwidth to be used by
+%% the session or media. The <bwtype> is an alphanumeric modifier
+%% giving the meaning of the <bandwidth> figure. Two values are
+%% defined in this specification, but other values MAY be registered
+%% in the future (see Section 8 of RFC 4566 and [21], [25]):
+%%
+%% CT If the bandwidth of a session or media in a session is
+%% different from the bandwidth implicit from the scope, a
+%% "b=CT:..." line SHOULD be supplied for the session giving the
+%% proposed upper limit to the bandwidth used (the "conference
+%% total" bandwidth). The primary purpose of this is to give an
+%% approximate idea as to whether two or more sessions can coexist
+%% simultaneously. When using the CT modifier with RTP, if
+%% several RTP sessions are part of the conference, the conference
+%% total refers to total bandwidth of all RTP sessions.
+%%
+%% AS The bandwidth is interpreted to be application specific (it
+%% will be the application's concept of maximum bandwidth).
+%% Normally, this will coincide with what is set on the
+%% application's "maximum bandwidth" control if applicable. For
+%% RTP-based applications, AS gives the RTP "session bandwidth"
+%% as defined in Section 6.2 of [19].
+%%
+%% Note that CT gives a total bandwidth figure for all the media at
+%% all sites. AS gives a bandwidth figure for a single media at a
+%% single site, although there may be many sites sending
+%% simultaneously.
+%%
+%% A prefix "X-" is defined for <bwtype> names. This is intended
+%% for experimental purposes only. For example:
+%%
+%% b=X-YZ:128
+%%
+%% Use of the "X-" prefix is NOT RECOMMENDED: instead new modifiers
+%% SHOULD be registered with IANA in the standard namespace. SDP
+%% parsers MUST ignore bandwidth fields with unknown modifiers.
+%% Modifiers MUST be alphanumeric and, although no length limit is
+%% given, it is recommended that they be short.
+%%
+%% The <bandwidth> is interpreted as kilobits per second by default.
+%% The definition of a new <bwtype> modifier MAY specify that the
+%% bandwidth is to be interpreted in some alternative unit (the "CT"
+%% and "AS" modifiers defined in this memo use the default units).
+%%
+
+%% bwtype() -> ct | as | string()
+-record(megaco_sdp_b, {
+ bwtype, % bwtype()
+ bandwidth % integer()
+ }).
+
+
+
+
+%% ===================================================================
+%%
+%% Times ("t=")
+%%
+%% t=<start time> <stop time>
+%%
+%% The "t=" lines specify the start and stop times for a session.
+%% Multiple "t=" lines MAY be used if a session is active at
+%% multiple irregularly spaced times; each additional "t=" line
+%% specifies an additional period of time for which the session will
+%% be active. If the session is active at regular times, an "r="
+%% line (see below) should be used in addition to, and following, a
+%% "t=" line -- in which case the "t=" line specifies the start and
+%% stop times of the repeat sequence.
+%%
+%% The first and second sub-fields give the start and stop times,
+%% respectively, for the session. These values are the decimal
+%% representation of Network Time Protocol (NTP) time values in
+%% seconds since 1900 [13]. To convert these values to UNIX time,
+%% subtract decimal 2208988800.
+%%
+%% NTP timestamps are elsewhere represented by 64-bit values, which
+%% wrap sometime in the year 2036. Since SDP uses an arbitrary length
+%% decimal representation, this should not cause an issue (SDP
+%% timestamps MUST continue counting seconds since 1900, NTP will use
+%% the value modulo the 64-bit limit).
+%%
+%% If the <stop-time> is set to zero, then the session is not bounded,
+%% though it will not become active until after the <start-time>. If
+%% the <start-time> is also zero, the session is regarded as
+%% permanent.
+%%
+%% User interfaces SHOULD strongly discourage the creation of
+%% unbounded and permanent sessions as they give no information about
+%% when the session is actually going to terminate, and so make
+%% scheduling difficult.
+%%
+%% The general assumption may be made, when displaying unbounded
+%% sessions that have not timed out to the user, that an unbounded
+%% session will only be active until half an hour from the current
+%% time or the session start time, whichever is the later. If
+%% behaviour other than this is required, an end-time SHOULD be given
+%% and modified as appropriate when new information becomes available
+%% about when the session should really end.
+%%
+%% Permanent sessions may be shown to the user as never being active
+%% unless there are associated repeat times that state precisely when
+%% the session will be active.
+%%
+
+-record(megaco_sdp_t, {
+ start, % integer()
+ stop % integer()
+ }).
+
+
+
+%% ===================================================================
+%%
+%% Repeat Times ("r=")
+%%
+%% r=<repeat interval> <active duration> <offsets from start-time>
+%%
+%% "r=" fields specify repeat times for a session. For example, if a
+%% session is active at 10am on Monday and 11am on Tuesday for one
+%% hour each week for three months, then the <start-time> in the
+%% corresponding "t=" field would be the NTP representation of 10am
+%% on the first Monday, the <repeat interval> would be 1 week, the
+%% <active duration> would be 1 hour, and the offsets would be zero
+%% and 25 hours. The corresponding "t=" field stop time would be
+%% the NTP representation of the end of the last session three months
+%% later. By default, all fields are in seconds, so the "r=" and
+%% "t=" fields might be the following:
+%%
+%% t=3034423619 3042462419
+%% r=604800 3600 0 90000
+%%
+%% To make description more compact, times may also be given in units
+%% of days, hours, or minutes. The syntax for these is a number
+%% immediately followed by a single case-sensitive character.
+%% Fractional units are not allowed -- a smaller unit should be used
+%% instead. The following unit specification characters are allowed:
+%%
+%% d - days (86400 seconds)
+%% h - hours (3600 seconds)
+%% m - minutes (60 seconds)
+%% s - seconds (allowed for completeness)
+%%
+%% Thus, the above session announcement could also have been written:
+%%
+%% r=7d 1h 0 25h
+%%
+%% Monthly and yearly repeats cannot be directly specified with a
+%% single SDP repeat time; instead, separate "t=" fields should be
+%% used to explicitly list the session times.
+%%
+
+-record(megaco_sdp_r, {
+ repeat_interval, % string()
+ active_duration, % string()
+ list_of_offsets % [ string() ]
+ }
+ ).
+
+
+
+%% ===================================================================
+%%
+%% Time Zones ("z=")
+%%
+%% z=<adjustment time> <offset> <adjustment time> <offset> ....
+%%
+%% To schedule a repeated session that spans a change from daylight
+%% saving time to standard time or vice versa, it is necessary to
+%% specify offsets from the base time. This is required because
+%% different time zones change time at different times of day,
+%% different countries change to or from daylight saving time on
+%% different dates, and some countries do not have daylight saving
+%% time at all.
+%%
+%% Thus, in order to schedule a session that is at the same time
+%% winter and summer, it must be possible to specify unambiguously by
+%% whose time zone a session is scheduled. To simplify this task for
+%% receivers, we allow the sender to specify the NTP time that a time
+%% zone adjustment happens and the offset from the time when the
+%% session was first scheduled. The "z=" field allows the sender to
+%% specify a list of these adjustment times and offsets from the base
+%% time.
+%%
+%% An example might be the following:
+%%
+%% z=2882844526 -1h 2898848070 0
+%%
+%% This specifies that at time 2882844526, the time base by which the
+%% session's repeat times are calculated is shifted back by 1 hour,
+%% and that at time 2898848070, the session's original time base is
+%% restored. Adjustments are always relative to the specified start
+%% time -- they are not cumulative. Adjustments apply to all "t="
+%% and "r=" lines in a session description.
+%%
+%% If a session is likely to last several years, it is expected that
+%% the session announcement will be modified periodically rather than
+%% transmit several years' worth of adjustments in one session
+%% announcement.
+%%
+
+%% adjustment() -> #megaco_sdp_z_adjustement{}
+-record(megaco_sdp_z, {
+ list_of_adjustments % [ adjustment() ]
+ }
+ ).
+
+-record(megaco_sdp_z_adjustement, {
+ time, % string()
+ offset % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Encryption Keys ("k=")
+%%
+%% k=<method>
+%% k=<method>:<encryption key>
+%%
+%% If transported over a secure and trusted channel, the Session
+%% Description Protocol MAY be used to convey encryption keys. A
+%% simple mechanism for key exchange is provided by the key field
+%% ("k="), although this is primarily supported for compatibility
+%% with older implementations and its use is NOT RECOMMENDED. Work
+%% is in progress to define new key exchange mechanisms for use with
+%% SDP [27] [28], and it is expected that new applications will use
+%% those mechanisms. A key field is permitted before the first media
+%% entry (in which case it applies to all media in the session), or
+%% for each media entry as required. The format of keys and their
+%% usage are outside the scope of this document, and the key field
+%% provides no way to indicate the encryption algorithm to be used,
+%% key type, or other information about the key: this is assumed to
+%% be provided by the higher-level protocol using SDP. If there is
+%% a need to convey this information within SDP, the extensions
+%% mentioned previously SHOULD be used. Many security protocols
+%% require two keys: one for confidentiality, another for integrity.
+%% This specification does not support transfer of two keys.
+%%
+%% The method indicates the mechanism to be used to obtain a usable
+%% key by external means, or from the encoded encryption key given.
+%% The following methods are defined:
+%%
+%% k=clear:<encryption key>
+%%
+%% The encryption key is included untransformed in this key
+%% field. This method MUST NOT be used unless it can be
+%% guaranteed that the SDP is conveyed over a secure channel.
+%% The encryption key is interpreted as text according to the
+%% charset attribute; use the "k=base64:" method to convey
+%% characters that are otherwise prohibited in SDP.
+%%
+%% k=base64:<encoded encryption key>
+%%
+%% The encryption key is included in this key field but has
+%% been base64 encoded [12] because it includes characters
+%% that are prohibited in SDP. This method MUST NOT be used
+%% unless it can be guaranteed that the SDP is conveyed over
+%% a secure channel.
+%%
+%% k=uri:<URI to obtain key>
+%%
+%% A Uniform Resource Identifier is included in the key field.
+%% The URI refers to the data containing the key, and may
+%% require additional authentication before the key can be
+%% returned. When a request is made to the given URI, the
+%% reply should specify the encoding for the key. The URI is
+%% often an Secure Socket Layer/Transport Layer Security
+%% (SSL/TLS)-protected HTTP URI ("https:"), although this is
+%% not required.
+%%
+%% k=prompt
+%%
+%% No key is included in this SDP description, but the session
+%% or media stream referred to by this key field is encrypted.
+%% The user should be prompted for the key when attempting to
+%% join the session, and this user-supplied key should then be
+%% used to decrypt the media streams. The use of
+%% user-specified keys is NOT RECOMMENDED, since such keys tend
+%% to have weak security properties.
+%%
+%% The key field MUST NOT be used unless it can be guaranteed that
+%% the SDP is conveyed over a secure and trusted channel. An example
+%% of such a channel might be SDP embedded inside an S/MIME message
+%% or a TLS-protected HTTP session. It is important to ensure that
+%% the secure channel is with the party that is authorised to join the
+%% session, not an intermediary: if a caching proxy server is used, it
+%% is important to ensure that the proxy is either trusted or unable
+%% to access the SDP.
+%%
+
+%% method() -> clear | base64 | uri | prompt
+-record(megaco_sdp_k, {
+ method, % method() | string()
+ encryption_key % undefined | string()
+ }
+ ).
+
+
+%% ===================================================================
+%%
+%% Attributes ("a=")
+%%
+%% a=<attribute>
+%% a=<attribute>:<value>
+%%
+%% Attributes are the primary means for extending SDP. Attributes
+%% may be defined to be used as "session-level" attributes,
+%% "media-level" attributes, or both.
+%%
+%% A media description may have any number of attributes ("a="
+%% fields) that are media specific. These are referred to as
+%% "media-level" attributes and add information about the media
+%% stream. Attribute fields can also be added before the first
+%% media field; these "session-level" attributes convey additional
+%% information that applies to the conference as a whole rather than
+%% to individual media.
+%%
+%% Attribute fields may be of two forms:
+%%
+%% o A property attribute is simply of the form "a=<flag>". These
+%% are binary attributes, and the presence of the attribute
+%% conveys that the attribute is a property of the session. An
+%% example might be "a=recvonly".
+%%
+%% o A value attribute is of the form "a=<attribute>:<value>". For
+%% example, a whiteboard could have the value attribute "a=orient:
+%% landscape"
+%%
+%% Attribute interpretation depends on the media tool being invoked.
+%% Thus receivers of session descriptions should be configurable in
+%% their interpretation of session descriptions in general and of
+%% attributes in particular.
+%%
+%% Attribute names MUST use the US-ASCII subset of ISO-10646/UTF-8.
+%%
+%% Attribute values are octet strings, and MAY use any octet value
+%% except 0x00 (Nul), 0x0A (LF), and 0x0D (CR). By default,
+%% attribute values are to be interpreted as in ISO-10646 character
+%% set with UTF-8 encoding. Unlike other text fields, attribute
+%% values are NOT normally affected by the "charset" attribute as
+%% this would make comparisons against known values problematic.
+%% However, when an attribute is defined, it can be defined to be
+%% charset dependent, in which case its value should be interpreted
+%% in the session charset rather than in ISO-10646.
+%%
+%% Attributes MUST be registered with IANA (see Section 8 of RFC
+%% 4566). If an attribute is received that is not understood, it
+%% MUST be ignored by the receiver.
+%%
+%% SDP Attributes
+%%
+%% The following attributes are defined. Since application writers
+%% may add new attributes as they are required, this list is not
+%% exhaustive. Registration procedures for new attributes are defined
+%% in Section 8.2.4 of RFC 4566.
+%%
+%% a=cat:<category>
+%%
+%% This attribute gives the dot-separated hierarchical category
+%% of the session. This is to enable a receiver to filter
+%% unwanted sessions by category. There is no central registry
+%% of categories. It is a session-level attribute, and it is
+%% not dependent on charset.
+%%
+%% a=keywds:<keywords>
+%%
+%% Like the cat attribute, this is to assist identifying wanted
+%% sessions at the receiver. This allows a receiver to select
+%% interesting session based on keywords describing the purpose
+%% of the session; there is no central registry of keywords. It
+%% is a session-level attribute. It is a charset-dependent
+%% attribute, meaning that its value should be interpreted in the
+%% charset specified for the session description if one is
+%% specified, or by default in ISO 10646/UTF-8.
+%%
+%% a=tool:<name and version of tool>
+%%
+%% This gives the name and version number of the tool used to
+%% create the session description. It is a session-level
+%% attribute, and it is not dependent on charset.
+%%
+%% a=ptime:<packet time>
+%%
+%% This gives the length of time in milliseconds represented by
+%% the media in a packet. This is probably only meaningful for
+%% audio data, but may be used with other media types if it
+%% makes sense. It should not be necessary to know ptime to
+%% decode RTP or vat audio, and it is intended as a
+%% recommendation for the encoding/packetisation of audio. It
+%% is a media-level attribute, and it is not dependent on charset.
+%%
+%% a=maxptime:<maximum packet time>
+%%
+%% This gives the maximum amount of media that can be encapsulated
+%% in each packet, expressed as time in milliseconds. The time
+%% SHALL be calculated as the sum of the time the media present in
+%% the packet represents. For frame-based codecs, the time SHOULD
+%% be an integer multiple of the frame size. This attribute is
+%% probably only meaningful for audio data, but may be used with
+%% other media types if it makes sense. It is a media-level
+%% attribute, and it is not dependent on charset. Note that this
+%% attribute was introduced after RFC 2327, and non-updated
+%% implementations will ignore this attribute.
+%%
+%% a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding
+%% parameters>]
+%%
+%% This attribute maps from an RTP payload type number (as used in
+%% an "m=" line) to an encoding name denoting the payload format
+%% to be used. It also provides information on the clock rate and
+%% encoding parameters. It is a media-level attribute that is not
+%% dependent on charset.
+%%
+%% Although an RTP profile may make static assignments of payload
+%% type numbers to payload formats, it is more common for that
+%% assignment to be done dynamically using "a=rtpmap:" attributes.
+%% As an example of a static payload type, consider u-law PCM
+%% coded single-channel audio sampled at 8 kHz. This is
+%% completely defined in the RTP Audio/Video profile as payload
+%% type 0, so there is no need for an "a=rtpmap:" attribute, and
+%% the media for such a stream sent to UDP port 49232 can be
+%% specified as:
+%%
+%% m=audio 49232 RTP/AVP 0
+%%
+%% An example of a dynamic payload type is 16-bit linear encoded
+%% stereo audio sampled at 16 kHz. If we wish to use the dynamic
+%% RTP/AVP payload type 98 for this stream, additional
+%% information is required to decode it:
+%%
+%% m=audio 49232 RTP/AVP 98
+%% a=rtpmap:98 L16/16000/2
+%%
+%% Up to one rtpmap attribute can be defined for each media
+%% format specified. Thus, we might have the following:
+%%
+%% m=audio 49230 RTP/AVP 96 97 98
+%% a=rtpmap:96 L8/8000
+%% a=rtpmap:97 L16/8000
+%% a=rtpmap:98 L16/11025/2
+%%
+%% RTP profiles that specify the use of dynamic payload types
+%% MUST define the set of valid encoding names and/or a means to
+%% register encoding names if that profile is to be used with
+%% SDP. The "RTP/AVP" and "RTP/SAVP" profiles use media subtypes
+%% for encoding names, under the top-level media type denoted in
+%% the "m=" line. In the example above, the media types are
+%% "audio/l8" and "audio/l16".
+%%
+%% For audio streams, <encoding parameters> indicates the number
+%% of audio channels. This parameter is OPTIONAL and may be
+%% omitted if the number of channels is one, provided that no
+%% additional parameters are needed.
+%%
+%% For video streams, no encoding parameters are currently
+%% specified.
+%%
+%% Additional encoding parameters MAY be defined in the future,
+%% but codec-specific parameters SHOULD NOT be added.
+%% Parameters added to an "a=rtpmap:" attribute SHOULD only be
+%% those required for a session directory to make the choice of
+%% appropriate media to participate in a session. Codec-specific
+%% parameters should be added in other attributes (for example,
+%% "a=fmtp:").
+%%
+%% Note: RTP audio formats typically do not include information
+%% about the number of samples per packet. If a non-default (as
+%% defined in the RTP Audio/Video Profile) packetisation is
+%% required, the "ptime" attribute is used as given above.
+%%
+%% a=recvonly
+%%
+%% This specifies that the tools should be started in
+%% receive-only mode where applicable. It can be either a
+%% session- or media-level attribute, and it is not dependent
+%% on charset. Note that recvonly applies to the media only,
+%% not to any associated control protocol (e.g., an RTP-based
+%% system in recvonly mode SHOULD still send RTCP packets).
+%%
+%% a=sendrecv
+%%
+%% This specifies that the tools should be started in send and
+%% receive mode. This is necessary for interactive conferences
+%% with tools that default to receive-only mode. It can be
+%% either a session or media-level attribute, and it is not
+%% dependent on charset.
+%%
+%% If none of the attributes "sendonly", "recvonly", "inactive",
+%% and "sendrecv" is present, "sendrecv" SHOULD be assumed as
+%% the default for sessions that are not of the conference type
+%% "broadcast" or "H332" (see below).
+%%
+%% a=sendonly
+%%
+%% This specifies that the tools should be started in send-only
+%% mode. An example may be where a different unicast address is
+%% to be used for a traffic destination than for a traffic
+%% source. In such a case, two media descriptions may be used,
+%% one sendonly and one recvonly. It can be either a session-
+%% or media-level attribute, but would normally only be used as
+%% a media attribute. It is not dependent on charset. Note
+%% that sendonly applies only to the media, and any associated
+%% control protocol (e.g., RTCP) SHOULD still be received and
+%% processed as normal.
+%%
+%% a=inactive
+%%
+%% This specifies that the tools should be started in inactive
+%% mode. This is necessary for interactive conferences where
+%% users can put other users on hold. No media is sent over an
+%% inactive media stream. Note that an RTP-based system SHOULD
+%% still send RTCP, even if started inactive. It can be either
+%% a session or media-level attribute, and it is not dependent
+%% on charset.
+%%
+%% a=orient:<orientation>
+%%
+%% Normally this is only used for a whiteboard or presentation
+%% tool. It specifies the orientation of a the workspace on
+%% the screen. It is a media-level attribute. Permitted
+%% values are "portrait", "landscape", and "seascape"
+%% (upside-down landscape). It is not dependent on charset.
+%%
+%% a=type:<conference type>
+%%
+%% This specifies the type of the conference. Suggested
+%% values are "broadcast", "meeting", "moderated", "test", and
+%% "H332". "recvonly" should be the default for
+%% "type:broadcast" sessions, "type:meeting" should imply
+%% "sendrecv", and "type:moderated" should indicate the use of
+%% a floor control tool and that the media tools are started
+%% so as to mute new sites joining the conference.
+%%
+%% Specifying the attribute "type:H332" indicates that this
+%% loosely coupled session is part of an H.332 session as
+%% defined in the ITU H.332 specification [26]. Media tools
+%% should be started "recvonly".
+%%
+%% Specifying the attribute "type:test" is suggested as a hint
+%% that, unless explicitly requested otherwise, receivers can
+%% safely avoid displaying this session description to users.
+%%
+%% The type attribute is a session-level attribute, and it is
+%% not dependent on charset.
+%%
+%% a=charset:<character set>
+%%
+%% This specifies the character set to be used to display the
+%% session name and information data. By default, the
+%% ISO-10646 character set in UTF-8 encoding is used. If a
+%% more compact representation is required, other character
+%% sets may be used. For example, the ISO 8859-1 is specified
+%% with the following SDP attribute:
+%%
+%% a=charset:ISO-8859-1
+%%
+%% This is a session-level attribute and is not dependent on
+%% charset. The charset specified MUST be one of those
+%% registered with IANA, such as ISO-8859-1. The character
+%% set identifier is a US-ASCII string and MUST be compared
+%% against the IANA identifiers using a case-insensitive
+%% comparison. If the identifier is not recognised or not
+%% supported, all strings that are affected by it SHOULD be
+%% regarded as octet strings.
+%%
+%% Note that a character set specified MUST still prohibit
+%% the use of bytes 0x00 (Nul), 0x0A (LF), and 0x0d (CR).
+%% Character sets requiring the use of these characters MUST
+%% define a quoting mechanism that prevents these bytes from
+%% appearing within text fields.
+%%
+%% a=sdplang:<language tag>
+%%
+%% This can be a session-level attribute or a media-level
+%% attribute. As a session-level attribute, it specifies the
+%% language for the session description. As a media-level
+%% attribute, it specifies the language for any media-level
+%% SDP information field associated with that media. Multiple
+%% sdplang attributes can be provided either at session or
+%% media level if multiple languages in the session description
+%% or media use multiple languages, in which case the order of
+%% the attributes indicates the order of importance of the
+%% various languages in the session or media from most important
+%% to least important.
+%%
+%% In general, sending session descriptions consisting of
+%% multiple languages is discouraged. Instead, multiple
+%% descriptions SHOULD be sent describing the session, one in
+%% each language. However, this is not possible with all
+%% transport mechanisms, and so multiple sdplang attributes
+%% are allowed although NOT RECOMMENDED.
+%%
+%% The "sdplang" attribute value must be a single RFC 3066
+%% language tag in US-ASCII [9]. It is not dependent on the
+%% charset attribute. An "sdplang" attribute SHOULD be
+%% specified when a session is of sufficient scope to cross
+%% geographic boundaries where the language of recipients
+%% cannot be assumed, or where the session is in a different
+%% language from the locally assumed norm.
+%%
+%% a=lang:<language tag>
+%%
+%% This can be a session-level attribute or a media-level
+%% attribute. As a session-level attribute, it specifies the
+%% default language for the session being described. As a
+%% media-level attribute, it specifies the language for that
+%% media, overriding any session-level language specified.
+%% Multiple lang attributes can be provided either at session
+%% or media level if the session description or media use
+%% multiple languages, in which case the order of the
+%% attributes indicates the order of importance of the various
+%% languages in the session or media from most important to
+%% least important.
+%%
+%% The "lang" attribute value must be a single RFC 3066
+%% language tag in US-ASCII [9]. It is not dependent on the
+%% charset attribute. A "lang" attribute SHOULD be specified
+%% when a session is of sufficient scope to cross geographic
+%% boundaries where the language of recipients cannot be
+%% assumed, or where the session is in a different language
+%% from the locally assumed norm.
+%%
+%% a=framerate:<frame rate>
+%%
+%% This gives the maximum video frame rate in frames/sec.
+%% It is intended as a recommendation for the encoding of
+%% video data. Decimal representations of fractional values
+%% using the notation "<integer>.<fraction>" are allowed. It
+%% is a media-level attribute, defined only for video media,
+%% and it is not dependent on charset.
+%%
+%% a=quality:<quality>
+%%
+%% This gives a suggestion for the quality of the encoding
+%% as an integer value. The intention of the quality
+%% attribute for video is to specify a non-default trade-off
+%% between frame-rate and still-image quality. For video,
+%% the value is in the range 0 to 10, with the following
+%% suggested meaning:
+%%
+%% 10 - the best still-image quality the compression
+%% scheme can give.
+%% 5 - the default behaviour given no quality suggestion.
+%% 0 - the worst still-image quality the codec designer
+%% thinks is still usable.
+%%
+%% It is a media-level attribute, and it is not dependent on
+%% charset.
+%%
+%% a=fmtp:<format> <format specific parameters>
+%%
+%% This attribute allows parameters that are specific to a
+%% particular format to be conveyed in a way that SDP does
+%% not have to understand them. The format must be one of
+%% the formats specified for the media. Format-specific
+%% parameters may be any set of parameters required to be
+%% conveyed by SDP and given unchanged to the media tool that
+%% will use this format. At most one instance of this
+%% attribute is allowed for each format.
+%%
+%% It is a media-level attribute, and it is not dependent on
+%% charset.
+%%
+
+
+%% a=<attribute>
+%% a=<attribute>:<value>
+-record(megaco_sdp_a, {
+ attribute, % string()
+ value % undefined | string()
+ }
+ ).
+
+%% a=cat:<category>
+-record(megaco_sdp_a_cat, {
+ category % string()
+ }
+ ).
+
+%% a=keywds:<keywords>
+-record(megaco_sdp_a_keywds, {
+ keywords % string()
+ }
+ ).
+
+%% a=tool:<name and version of tool>
+-record(megaco_sdp_a_tool, {
+ name_and_version % string()
+ }
+ ).
+
+%% a=ptime:<packet time>
+-record(megaco_sdp_a_ptime, {
+ packet_time % integer()
+ }
+ ).
+
+%% a=maxptime:<maximum packet time>
+-record(megaco_sdp_a_maxptime, {
+ maximum_packet_time % integer()
+ }
+ ).
+
+%% a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
+-record(megaco_sdp_a_rtpmap, {
+ payload_type, % <payload type> integer()
+ encoding_name, % <encoding name> string()
+ clock_rate, % <clock rate> integer()
+ encoding_parms = [] % <encoding parameters> [ string() ]
+ }
+ ).
+
+%% a=orient:<orientation>
+%% orientation() -> portrait | landscape | seascape
+-record(megaco_sdp_a_orient, {
+ orientation % orientation()
+ }
+ ).
+
+
+%% a=type:<conference type>
+-record(megaco_sdp_a_type, {
+ conf_type % string()
+ }
+ ).
+
+
+%% a=charset:<character set>
+-record(megaco_sdp_a_charset, {
+ char_set % string()
+ }
+ ).
+
+
+%% a=sdplang:<language tag>
+-record(megaco_sdp_a_sdplang, {
+ tag % string()
+ }
+ ).
+
+
+%% a=lang:<language tag>
+-record(megaco_sdp_a_lang, {
+ tag % string()
+ }
+ ).
+
+
+%% a=framerate:<frame rate>
+-record(megaco_sdp_a_framerate, {
+ frame_rate % string()
+ }
+ ).
+
+
+%% a=quality:<quality>
+-record(megaco_sdp_a_quality, {
+ quality % integer()
+ }
+ ).
+
+
+%% a=fmtp:<format> <format specific parameters>
+-record(megaco_sdp_a_fmtp, {
+ format, % string()
+ param % string()
+ }
+ ).
+
+
+
+
+%% ===================================================================
+%%
+%% Media Announcements ("m=")
+%%
+%% m=<media> <port> <proto> <fmt> ...
+%%
+%% A session description may contain a number of media descriptions.
+%% Each media description starts with an "m=" field and is terminated
+%% by either the next "m=" field or by the end of the session
+%% description. A media field has several sub-fields:
+%%
+%% <media> is the media type. Currently defined media are "audio",
+%% "video", "text", "application", and "message", although this
+%% list may be extended in the future (see Section 8 of RFC 4566).
+%%
+%% <port> is the transport port to which the media stream is sent.
+%% The meaning of the transport port depends on the network being
+%% used as specified in the relevant "c=" field, and on the
+%% transport protocol defined in the <proto> sub-field of the
+%% media field. Other ports used by the media application (such as
+%% the RTP Control Protocol (RTCP) port [19]) MAY be derived
+%% algorithmically from the base media port or MAY be specified in
+%% a separate attribute (for example, "a=rtcp:" as defined in
+%% [22]).
+%%
+%% If non-contiguous ports are used or if they don't follow the
+%% parity rule of even RTP ports and odd RTCP ports, the "a=rtcp:"
+%% attribute MUST be used. Applications that are requested to send
+%% media to a <port> that is odd and where the "a=rtcp:" is present
+%% MUST NOT subtract 1 from the RTP port: that is, they MUST send
+%% the RTP to the port indicated in <port> and send the RTCP to the
+%% port indicated in the "a=rtcp" attribute.
+%%
+%% For applications where hierarchically encoded streams are being
+%% sent to a unicast address, it may be necessary to specify
+%% multiple transport ports. This is done using a similar notation
+%% to that used for IP multicast addresses in the "c=" field:
+%%
+%% m=<media> <port>/<number of ports> <proto> <fmt> ...
+%%
+%% In such a case, the ports used depend on the transport protocol.
+%% For RTP, the default is that only the even-numbered ports are
+%% used for data with the corresponding one-higher odd ports used
+%% for the RTCP belonging to the RTP session, and the
+%% <number of ports> denoting the number of RTP sessions. For
+%% example:
+%%
+%% m=video 49170/2 RTP/AVP 31
+%%
+%% would specify that ports 49170 and 49171 form one RTP/RTCP pair
+%% and 49172 and 49173 form the second RTP/RTCP pair. RTP/AVP is
+%% the transport protocol and 31 is the format (see below). If
+%% non-contiguous ports are required, they must be signalled using
+%% a separate attribute (for example, "a=rtcp:" as defined in
+%% [22]).
+%%
+%% If multiple addresses are specified in the "c=" field and
+%% multiple ports are specified in the "m=" field, a one-to-one
+%% mapping from port to the corresponding address is implied. For
+%% example:
+%%
+%% c=IN IP4 224.2.1.1/127/2
+%% m=video 49170/2 RTP/AVP 31
+%%
+%% would imply that address 224.2.1.1 is used with ports 49170
+%% and 49171, and address 224.2.1.2 is used with ports 49172 and
+%% 49173.
+%%
+%% The semantics of multiple "m=" lines using the same transport
+%% address are undefined. This implies that, unlike limited past
+%% practice, there is no implicit grouping defined by such means
+%% and an explicit grouping framework (for example, [18]) should
+%% instead be used to express the intended semantics.
+%%
+%% <proto> is the transport protocol. The meaning of the transport
+%% protocol is dependent on the address type field in the
+%% relevant "c=" field. Thus a "c=" field of IP4 indicates that
+%% the transport protocol runs over IP4. The following transport
+%% protocols are defined, but may be extended through
+%% registration of new protocols with IANA (see Section 8 of RFC
+%% 4566):
+%%
+%% * udp: denotes an unspecified protocol running over UDP.
+%%
+%% * RTP/AVP: denotes RTP [19] used under the RTP Profile for
+%% Audio and Video Conferences with Minimal Control [20]
+%% running over UDP.
+%%
+%% * RTP/SAVP: denotes the Secure Real-time Transport Protocol
+%% [23] running over UDP.
+%%
+%% The main reason to specify the transport protocol in addition
+%% to the media format is that the same standard media formats
+%% may be carried over different transport protocols even when
+%% the network protocol is the same -- a historical example is
+%% vat Pulse Code Modulation (PCM) audio and RTP PCM audio;
+%% another might be TCP/RTP PCM audio. In addition, relays and
+%% monitoring tools that are transport-protocol-specific but
+%% format-independent are possible.
+%%
+%% <fmt> is a media format description. The fourth and any
+%% subsequent sub-fields describe the format of the media. The
+%% interpretation of the media format depends on the value of
+%% the <proto> sub-field.
+%%
+%% If the <proto> sub-field is "RTP/AVP" or "RTP/SAVP" the <fmt>
+%% sub-fields contain RTP payload type numbers. When a list of
+%% payload type numbers is given, this implies that all of these
+%% payload formats MAY be used in the session, but the first of
+%% these formats SHOULD be used as the default format for the
+%% session. For dynamic payload type assignments the "a=rtpmap:"
+%% attribute (see Section 6 of RFC 4566) SHOULD be used to map
+%% from an RTP payload type number to a media encoding name that
+%% identifies the payload format. The "a=fmtp:" attribute MAY
+%% be used to specify format parameters (see Section 6 of RFC
+%% 4566).
+%%
+%% If the <proto> sub-field is "udp" the <fmt> sub-fields MUST
+%% reference a media type describing the format under the
+%% "audio", "video", "text", "application", or "message"
+%% top-level media types. The media type registration SHOULD
+%% define the packet format for use with UDP transport.
+%%
+%% For media using other transport protocols, the <fmt> field is
+%% protocol specific. Rules for interpretation of the <fmt> sub-
+%% field MUST be defined when registering new protocols (see
+%% Section 8.2.2 of RFC 4566).
+%%
+
+%% ma_media() -> audio | video | application | data | control
+-record(megaco_sdp_m, {
+ media, % ma_media() | string()
+ port, % integer()
+ num_ports, % undefined | integer()
+ transport, % string()
+ fmt_list = [] % [ string() ]
+ }).
+
+
+
+
+%% ===================================================================
+%%
+%% References
+%%
+%% Normative References
+%%
+%% [1] Mockapetris, P., "Domain names - concepts and facilities", STD
+%% 13, RFC 1034, November 1987.
+%%
+%% [2] Mockapetris, P., "Domain names - implementation and
+%% specification", STD 13, RFC 1035, November 1987.
+%%
+%% [3] Bradner, S., "Key words for use in RFCs to Indicate Requirement
+%% Levels", BCP 14, RFC 2119, March 1997.
+%%
+%% [4] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
+%% Specifications: ABNF", RFC 4234, October 2005.
+%%
+%% [5] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD
+%% 63, RFC 3629, November 2003.
+%%
+%% [6] Handley, M. and V. Jacobson, "SDP: Session Description
+%% Protocol", RFC 2327, April 1998.
+%%
+%% [7] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+%% Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986,
+%% January 2005.
+%%
+%% [8] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA
+%% Considerations Section in RFCs", BCP 26, RFC 2434, October
+%% 1998.
+%%
+%% [9] Alvestrand, H., "Tags for the Identification of Languages", BCP
+%% 47, RFC 3066, January 2001.
+%%
+%% [10] Olson, S., Camarillo, G., and A. Roach, "Support for IPv6 in
+%% Session Description Protocol (SDP)", RFC 3266, June 2002.
+%%
+%% [11] Faltstrom, P., Hoffman, P., and A. Costello,
+%% "Internationalizing Domain Names in Applications (IDNA)", RFC
+%% 3490, March 2003.
+%%
+%% [12] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings",
+%% RFC 3548, July 2003.
+%%
+%%
+%% Informative References
+%%
+%% [13] Mills, D., "Network Time Protocol (Version 3) Specification,
+%% Implementation", RFC 1305, March 1992.
+%%
+%% [14] Handley, M., Perkins, C., and E. Whelan, "Session Announcement
+%% Protocol", RFC 2974, October 2000.
+%%
+%% [15] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A.,
+%% Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP:
+%% Session Initiation Protocol", RFC 3261, June 2002.
+%%
+%% [16] Schulzrinne, H., Rao, A., and R. Lanphier, "Real Time Streaming
+%% Protocol (RTSP)", RFC 2326, April 1998.
+%%
+%% [17] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model with
+%% Session Description Protocol (SDP)", RFC 3264, June 2002.
+%%
+%% [18] Camarillo, G., Eriksson, G., Holler, J., and H. Schulzrinne,
+%% "Grouping of Media Lines in the Session Description Protocol
+%% (SDP)", RFC 3388, December 2002.
+%%
+%% [19] Schulzrinne, H., Casner, S., Frederick, R., and V. Jacobson,
+%% "RTP: A Transport Protocol for Real-Time Applications", STD 64,
+%% RFC 3550, July 2003.
+%%
+%% [20] Schulzrinne, H. and S. Casner, "RTP Profile for Audio and Video
+%% Conferences with Minimal Control", STD 65, RFC 3551, July 2003.
+%%
+%% [21] Casner, S., "Session Description Protocol (SDP) Bandwidth
+%% Modifiers for RTP Control Protocol (RTCP) Bandwidth", RFC 3556,
+%% July 2003.
+%%
+%% [22] Huitema, C., "Real Time Control Protocol (RTCP) attribute in
+%% Session Description Protocol (SDP)", RFC 3605, October 2003.
+%%
+%% [23] Baugher, M., McGrew, D., Naslund, M., Carrara, E., and K.
+%% Norrman, "The Secure Real-time Transport Protocol (SRTP)", RFC
+%% 3711, March 2004.
+%%
+%% [24] Rosenberg, J., Schulzrinne, H., and P. Kyzivat, "Indicating
+%% User Agent Capabilities in the Session Initiation Protocol
+%% (SIP)", RFC 3840, August 2004.
+%%
+%% [25] Westerlund, M., "A Transport Independent Bandwidth Modifier for
+%% the Session Description Protocol (SDP)", RFC 3890, September
+%% 2004.
+%%
+%% [26] International Telecommunication Union, "H.323 extended for
+%% loosely coupled conferences", ITU Recommendation H.332,
+%% September 1998.
+%%
+%% [27] Arkko, J., Carrara, E., Lindholm, F., Naslund, M., and K.
+%% Norrman, "Key Management Extensions for Session Description
+%% Protocol (SDP) and Real Time Streaming Protocol (RTSP)", RFC
+%% 4567, July 2006.
+%%
+%% [28] Andreasen, F., Baugher, M., and D. Wing, "Session Description
+%% Protocol (SDP) Security Descriptions for Media Streams", RFC
+%% 4568, July 2006.
+%%
+%% [29] Resnick, P., "Internet Message Format", RFC 2822, April 2001.
+%%
+%% [30] Hinden, R. and S. Deering, "IP Version 6 Addressing
+%% Architecture", RFC 2373, July 1998.
+%%
+%% [31] Freed, N. and J. Klensin, "Media Type Specifications and
+%% Registration Procedures", BCP 13, RFC 4288, December 2005.
+%%
+
+
+-endif.
diff --git a/lib/megaco/info b/lib/megaco/info
new file mode 100644
index 0000000000..e6d588f29e
--- /dev/null
+++ b/lib/megaco/info
@@ -0,0 +1,5 @@
+group: comm
+short: Megaco/H.248 is a protocol for control of elements in a physically
+short: decomposed multimedia gateway, enabling separation of call control
+short: from media conversion.
+
diff --git a/lib/megaco/prebuild.skip b/lib/megaco/prebuild.skip
new file mode 100644
index 0000000000..27747e4dc9
--- /dev/null
+++ b/lib/megaco/prebuild.skip
@@ -0,0 +1,2 @@
+ebin/megaco_flex_scanner.beam
+ebin/megaco_flex_scanner_handler.beam
diff --git a/lib/megaco/priv/lib/.gitignore b/lib/megaco/priv/lib/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/megaco/priv/lib/.gitignore
diff --git a/lib/megaco/src/Makefile b/lib/megaco/src/Makefile
new file mode 100644
index 0000000000..d2d66d2c89
--- /dev/null
+++ b/lib/megaco/src/Makefile
@@ -0,0 +1,37 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SPECIAL_TARGETS = setup
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+setup:
+ (cd flex && $(MAKE) $@)
+
diff --git a/lib/megaco/src/app/Makefile b/lib/megaco/src/app/Makefile
new file mode 100644
index 0000000000..01dfb9b860
--- /dev/null
+++ b/lib/megaco/src/app/Makefile
@@ -0,0 +1,129 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+APP_FILE = megaco.app
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+APPUP_FILE = megaco.appup
+APPUP_SRC = $(APPUP_FILE).src
+APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/app
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/app
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/app/depend.mk b/lib/megaco/src/app/depend.mk
new file mode 100644
index 0000000000..27394d6f29
--- /dev/null
+++ b/lib/megaco/src/app/depend.mk
@@ -0,0 +1,22 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+$(EBIN)/megaco.$(EMULATOR): megaco.erl \
+ megaco_internal.hrl
+
diff --git a/lib/megaco/src/app/megaco.app.src b/lib/megaco/src/app/megaco.app.src
new file mode 100644
index 0000000000..503fcd7176
--- /dev/null
+++ b/lib/megaco/src/app/megaco.app.src
@@ -0,0 +1,143 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+{application, megaco,
+ [{description, "Megaco/H.248 protocol"},
+ {vsn, "%VSN%"},
+ {modules,
+ [
+ megaco,
+ megaco_ber_bin_encoder,
+ megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a,
+ megaco_ber_bin_drv_media_gateway_control_prev3b,
+ megaco_ber_bin_drv_media_gateway_control_prev3c,
+ megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a,
+ megaco_ber_bin_media_gateway_control_prev3b,
+ megaco_ber_bin_media_gateway_control_prev3c,
+ megaco_ber_bin_media_gateway_control_v3,
+ megaco_ber_encoder,
+ megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3a,
+ megaco_ber_media_gateway_control_prev3b,
+ megaco_ber_media_gateway_control_prev3c,
+ megaco_ber_media_gateway_control_v3,
+ megaco_binary_encoder,
+ megaco_binary_encoder_lib,
+ megaco_binary_name_resolver_v1,
+ megaco_binary_name_resolver_v2,
+ megaco_binary_name_resolver_prev3a,
+ megaco_binary_name_resolver_prev3b,
+ megaco_binary_name_resolver_prev3c,
+ megaco_binary_name_resolver_v3,
+ megaco_binary_term_id,
+ megaco_binary_term_id_gen,
+ megaco_binary_transformer_v1,
+ megaco_binary_transformer_v2,
+ megaco_binary_transformer_prev3a,
+ megaco_binary_transformer_prev3b,
+ megaco_binary_transformer_prev3c,
+ megaco_binary_transformer_v3,
+ megaco_compact_text_encoder,
+ megaco_compact_text_encoder_v1,
+ megaco_compact_text_encoder_v2,
+ megaco_compact_text_encoder_prev3a,
+ megaco_compact_text_encoder_prev3b,
+ megaco_compact_text_encoder_prev3c,
+ megaco_compact_text_encoder_v3,
+ megaco_config,
+ megaco_digit_map,
+ megaco_encoder,
+ megaco_edist_compress,
+ megaco_erl_dist_encoder,
+ megaco_erl_dist_encoder_mc,
+ megaco_filter,
+ megaco_flex_scanner,
+ megaco_flex_scanner_handler,
+ megaco_messenger,
+ megaco_messenger_misc,
+ megaco_misc_sup,
+ megaco_monitor,
+ megaco_per_encoder,
+ megaco_per_media_gateway_control_v1,
+ megaco_per_media_gateway_control_v2,
+ megaco_per_media_gateway_control_prev3a,
+ megaco_per_media_gateway_control_prev3b,
+ megaco_per_media_gateway_control_prev3c,
+ megaco_per_media_gateway_control_v3,
+ megaco_per_bin_encoder,
+ megaco_per_bin_drv_media_gateway_control_v1,
+ megaco_per_bin_drv_media_gateway_control_v2,
+ megaco_per_bin_drv_media_gateway_control_prev3a,
+ megaco_per_bin_drv_media_gateway_control_prev3b,
+ megaco_per_bin_drv_media_gateway_control_prev3c,
+ megaco_per_bin_drv_media_gateway_control_v3,
+ megaco_per_bin_media_gateway_control_v1,
+ megaco_per_bin_media_gateway_control_v2,
+ megaco_per_bin_media_gateway_control_prev3a,
+ megaco_per_bin_media_gateway_control_prev3b,
+ megaco_per_bin_media_gateway_control_prev3c,
+ megaco_per_bin_media_gateway_control_v3,
+ megaco_pretty_text_encoder,
+ megaco_pretty_text_encoder_v1,
+ megaco_pretty_text_encoder_v2,
+ megaco_pretty_text_encoder_prev3a,
+ megaco_pretty_text_encoder_prev3b,
+ megaco_pretty_text_encoder_prev3c,
+ megaco_pretty_text_encoder_v3,
+ megaco_sdp,
+ megaco_stats,
+ megaco_sup,
+ megaco_tcp,
+ megaco_tcp_accept,
+ megaco_tcp_accept_sup,
+ megaco_tcp_connection,
+ megaco_tcp_connection_sup,
+ megaco_tcp_sup,
+ megaco_text_mini_decoder,
+ megaco_text_mini_parser,
+ megaco_text_parser_v1,
+ megaco_text_parser_v2,
+ megaco_text_parser_prev3a,
+ megaco_text_parser_prev3b,
+ megaco_text_parser_prev3c,
+ megaco_text_parser_v3,
+ megaco_text_scanner,
+ megaco_timer,
+ megaco_trans_sender,
+ megaco_trans_sup,
+ megaco_transport,
+ megaco_udp,
+ megaco_udp_server,
+ megaco_udp_sup,
+ megaco_user_default
+ ]},
+ {registered, [megaco_config, megaco_monitor,
+ megaco_trans_sup, megaco_misc_sup, megaco_sup]},
+ {applications, [stdlib, kernel]},
+ {env, []},
+ {mod, {megaco_sup, []}}
+ ]}.
+
+
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
new file mode 100644
index 0000000000..163ff06651
--- /dev/null
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -0,0 +1,165 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% 3.4.3
+%% |
+%% v
+%% 3.4.4
+%% / \
+%% | |
+%% v v
+%% 3.5 3.4.5
+%% | |
+%% v v
+%% 3.5.1 <- 3.4.6
+%% |
+%% v
+%% 3.5.2
+%% |
+%% v
+%% 3.5.3
+%% |
+%% v
+%% 3.6
+%% |
+%% v
+%% 3.6.0.1
+%% |
+%% v
+%% 3.6.1
+%% |
+%% v
+%% 3.6.2
+%% / \
+%% | |
+%% v |
+%% 3.7 3.6.3
+%% | |
+%% v v
+%% 3.7.1 <- 3.6.4
+%% | |
+%% v v
+%% 3.7.2 <- 3.6.5
+%% | |
+%% v v
+%% 3.7.3 <- 3.6.6
+%% | |
+%% v v
+%% 3.7.4 <- 3.6.7
+%% | |
+%% v v
+%% 3.7.5 <- 3.6.9
+%% |
+%% v
+%% 3.8
+%% |
+%% v
+%% 3.8.1
+%% |
+%% v
+%% 3.8.2
+%% |
+%% v
+%% 3.9
+%% |
+%% v
+%% 3.9.1
+%% |
+%% v
+%% 3.9.1.1
+%% |
+%% v
+%% 3.9.2
+%% |
+%% v
+%% 3.9.3
+%% |
+%% v
+%% 3.9.4
+%% |
+%% v
+%% 3.10
+%% |
+%% v
+%% 3.10.0.1
+%% |
+%% v
+%% 3.10.1
+%% |
+%% v
+%% 3.11
+%% |
+%% v
+%% 3.11.1
+%% |
+%% v
+%% 3.11.2
+%% |
+%% v
+%% 3.11.3
+%% |
+%% v
+%% 3.12
+%% |
+%% v
+%% 3.13
+%%
+%%
+{"%VSN%",
+ [
+ {"3.12",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.11.3",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge,
+ [megaco_config, megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, {advanced, upgrade_from_pre_3_12},
+ soft_purge, soft_purge, []}
+ ]
+ }
+ ],
+ [
+ {"3.12",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge, [megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []}
+ ]
+ },
+ {"3.11.3",
+ [
+ {load_module, megaco_udp, soft_purge, soft_purge, []},
+ {load_module, megaco_messenger, soft_purge, soft_purge,
+ [megaco_config, megaco_monitor]},
+ {update, megaco_monitor, soft, soft_purge, soft_purge, []},
+ {update, megaco_config, {advanced, downgrade_to_pre_3_12},
+ soft_purge, soft_purge, []}
+ ]
+ }
+ ]
+}.
+
diff --git a/lib/megaco/src/app/megaco.erl b/lib/megaco/src/app/megaco.erl
new file mode 100644
index 0000000000..215a516d77
--- /dev/null
+++ b/lib/megaco/src/app/megaco.erl
@@ -0,0 +1,1017 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Main API for Megaco/H.248 protocol stack
+%%----------------------------------------------------------------------
+
+-module(megaco).
+
+%%-----------------------------------------------------------------
+%% Public interface
+%%-----------------------------------------------------------------
+
+-export([
+ start/0,
+ stop/0,
+
+ start_user/2,
+ stop_user/1,
+
+ info/0,
+ user_info/1, user_info/2,
+ update_user_info/3,
+ conn_info/1, conn_info/2,
+ update_conn_info/3,
+ system_info/0, system_info/1,
+
+ connect/4, connect/5,
+ disconnect/2,
+
+ call/3,
+ cast/3,
+ cancel/2,
+ process_received_message/4, process_received_message/5,
+ receive_message/4, receive_message/5,
+
+ encode_actions/3,
+
+ token_tag2string/1, token_tag2string/2, token_tag2string/3,
+
+ parse_digit_map/1,
+ eval_digit_map/1,
+ eval_digit_map/2,
+ report_digit_event/2,
+ test_digit_event/2,
+
+ encode_binary_term_id/2,
+ decode_binary_term_id/2,
+
+ encode_sdp/1,
+ decode_sdp/1,
+
+ versions1/0, versions2/0,
+ print_version_info/0, print_version_info/1,
+ ms/0, nc/0, nc/1, ni/0, ni/1,
+
+ enable_trace/2, disable_trace/0, set_trace/1,
+
+ report_event/4, report_event/5,
+
+ test_request/5,
+ test_reply/5
+ ]).
+
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+%% Deprecated
+-export([format_versions/1]).
+
+%% Internal
+-export([format_timestamp/1]).
+
+%% This is for XREF
+-deprecated([{format_versions, 1, eventually}]).
+
+
+-include("megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Starts the Megaco application
+%%-----------------------------------------------------------------
+
+start() ->
+ application:start(?APPLICATION).
+
+
+%%-----------------------------------------------------------------
+%% Stops the Megaco application
+%%-----------------------------------------------------------------
+
+stop() ->
+ application:stop(?APPLICATION).
+
+
+%%-----------------------------------------------------------------
+%% Initial configuration of a user
+%%-----------------------------------------------------------------
+
+start_user(UserMid, Config) ->
+ megaco_config:start_user(UserMid, Config).
+
+
+%%-----------------------------------------------------------------
+%% Delete the configuration of a user
+%%-----------------------------------------------------------------
+
+stop_user(UserMid) ->
+ megaco_config:stop_user(UserMid).
+
+
+%%-----------------------------------------------------------------
+%% Lookup user information
+%%-----------------------------------------------------------------
+
+user_info(UserMid) ->
+ [{requests, user_info(UserMid, requests)},
+ {replies, user_info(UserMid, replies)} | user_info(UserMid, all)].
+
+user_info(UserMid, requests) ->
+ megaco_messenger:which_requests(UserMid);
+user_info(UserMid, replies) ->
+ megaco_messenger:which_replies(UserMid);
+user_info(UserMid, Item) ->
+ megaco_config:user_info(UserMid, Item).
+
+
+%%-----------------------------------------------------------------
+%% Update information about a user
+%%-----------------------------------------------------------------
+
+update_user_info(UserMid, Item, Value) ->
+ megaco_config:update_user_info(UserMid, Item, Value).
+
+
+%%-----------------------------------------------------------------
+%% Lookup information about an active connection
+%%-----------------------------------------------------------------
+
+conn_info(ConnHandle) ->
+ [{requests, conn_info(ConnHandle, requests)},
+ {replies, conn_info(ConnHandle, replies)} | conn_info(ConnHandle, all)].
+
+conn_info(ConnHandle, requests) ->
+ megaco_messenger:which_requests(ConnHandle);
+conn_info(ConnHandle, replies) ->
+ megaco_messenger:which_replies(ConnHandle);
+conn_info(ConnHandle, Item) ->
+ megaco_config:conn_info(ConnHandle, Item).
+
+
+%%-----------------------------------------------------------------
+%% Update information about an active connection
+%%-----------------------------------------------------------------
+
+update_conn_info(ConnHandle, Item, Value) ->
+ megaco_config:update_conn_info(ConnHandle, Item, Value).
+
+
+%%-----------------------------------------------------------------
+%% All information for the application
+%%-----------------------------------------------------------------
+
+info() ->
+ Stats =
+ case get_stats() of
+ {ok, Statistics} ->
+ Statistics;
+ _ ->
+ []
+ end,
+ SysInfo = system_info(),
+ [{statistics, Stats} | info(SysInfo)].
+
+info(SysInfo) ->
+ info(SysInfo, []).
+
+info([], Acc) ->
+ lists:reverse(Acc);
+info([{connections, Conns} | SysInfo], Acc) ->
+ Conns2 = extend_conns_info(Conns),
+ info(SysInfo, [{connections, Conns2} | Acc]);
+info([{users, Users} | SysInfo], Acc) ->
+ Users2 = extend_users_info(Users),
+ info(SysInfo, [{users, Users2} | Acc]);
+info([Info | SysInfo], Acc) ->
+ info(SysInfo, [Info | Acc]).
+
+extend_conns_info(Conns) ->
+ extend_conns_info(Conns, []).
+
+extend_conns_info([], Acc) ->
+ lists:reverse(Acc);
+extend_conns_info([Conn | Conns], Acc) ->
+ ConnInfo = conn_info(Conn),
+ extend_conns_info(Conns, [{Conn, ConnInfo} | Acc]).
+
+extend_users_info(Users) ->
+ extend_users_info(Users, []).
+
+extend_users_info([], Acc) ->
+ lists:reverse(Acc);
+extend_users_info([User | Users], Acc) ->
+ UserInfo = user_info(User),
+ extend_users_info(Users, [{User, UserInfo} | Acc]).
+
+
+%%-----------------------------------------------------------------
+%% Lookup system information
+%%-----------------------------------------------------------------
+
+system_info_items() ->
+ [
+ text_config,
+ connections,
+ users,
+ n_active_requests,
+ n_active_replies,
+ n_active_connections,
+ pending_counters
+ ].
+
+system_info() ->
+ [{Item, system_info(Item)} || Item <- system_info_items()].
+
+system_info(Item) ->
+ megaco_config:system_info(Item).
+
+
+%%-----------------------------------------------------------------
+%% Establish a "virtual" connection
+%%-----------------------------------------------------------------
+
+connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid) ->
+ megaco_messenger:connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid).
+
+connect(ReceiveHandle, RemoteMid, SendHandle, ControlPid, Extra)
+ when (Extra =/= ?default_user_callback_extra) ->
+ megaco_messenger:connect(ReceiveHandle, RemoteMid, SendHandle,
+ ControlPid, Extra).
+
+
+%%-----------------------------------------------------------------
+%% Tear down a "virtual" connection
+%%-----------------------------------------------------------------
+
+disconnect(ConnHandle, Reason) ->
+ megaco_messenger:disconnect(ConnHandle, {user_disconnect, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% Sends a transaction request and waits for a reply
+%%-----------------------------------------------------------------
+
+call(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:call(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Sends a transaction request but does NOT wait for a reply
+%%-----------------------------------------------------------------
+
+cast(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:cast(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Test the validity of the actions
+%%-----------------------------------------------------------------
+
+test_request(ConnHandle, Version, EncodingMod, EncodingConfig,
+ ActionRequests) ->
+ megaco_messenger:test_request(ConnHandle, ActionRequests,
+ Version, EncodingMod, EncodingConfig).
+
+%% This tests the actual_reply() type of return from the
+%% handle_trans_request function.
+%%
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig,
+ Reply) ->
+ megaco_messenger:test_reply(ConnHandle, Version,
+ EncodingMod, EncodingConfig, Reply).
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_messenger:get_stats().
+
+get_stats(SendHandle) ->
+ megaco_messenger:get_stats(SendHandle).
+
+get_stats(SendHandle, Counter) ->
+ megaco_messenger:get_stats(SendHandle, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_messenger:reset_stats().
+
+reset_stats(SendHandle) ->
+ megaco_messenger:reset_stats(SendHandle).
+
+
+%%-----------------------------------------------------------------
+%% Cancel all outstanding messages for this connection
+%%-----------------------------------------------------------------
+
+cancel(ConnHandle, Reason) ->
+ megaco_messenger:cancel(ConnHandle, {user_cancel, Reason}).
+
+
+%%-----------------------------------------------------------------
+%% Process a received message
+%%-----------------------------------------------------------------
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ megaco_messenger:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ megaco_messenger:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ megaco_messenger:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ megaco_messenger:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra).
+
+
+%%-----------------------------------------------------------------
+%% Encode the actions list for one or more transactions.
+%%-----------------------------------------------------------------
+
+encode_actions(ConnHandle, ActionRequests, Options) ->
+ megaco_messenger:encode_actions(ConnHandle, ActionRequests, Options).
+
+
+%%-----------------------------------------------------------------
+%% Convert the (token) tags found in a decoded message into a
+%% printable string.
+%%-----------------------------------------------------------------
+
+token_tag2string(Tag) ->
+ token_tag2string(Tag, pretty).
+
+token_tag2string(Tag, pretty) ->
+ token_tag2string(Tag, megaco_pretty_text_encoder);
+token_tag2string(Tag, compact) ->
+ token_tag2string(Tag, megaco_compact_text_encoder);
+token_tag2string(Tag, Mod) when is_atom(Tag) and is_atom(Mod) ->
+ Mod:token_tag2string(Tag).
+
+token_tag2string(Tag, pretty, V) ->
+ token_tag2string(Tag, megaco_pretty_text_encoder, V);
+token_tag2string(Tag, compact, V) ->
+ token_tag2string(Tag, megaco_compact_text_encoder, V);
+token_tag2string(Tag, Mod, V) when is_atom(Tag) and is_atom(Mod) ->
+ Mod:token_tag2string(Tag, V).
+
+
+%%-----------------------------------------------------------------
+%% Parses a digit map body
+%%-----------------------------------------------------------------
+
+parse_digit_map(DigitMapBody) ->
+ megaco_digit_map:parse(DigitMapBody).
+
+
+%%-----------------------------------------------------------------
+%% Collect digit map letters according to the digit map
+%%-----------------------------------------------------------------
+
+eval_digit_map(DigitMap) ->
+ megaco_digit_map:eval(DigitMap).
+
+eval_digit_map(DigitMap, Timers) ->
+ megaco_digit_map:eval(DigitMap, Timers).
+
+
+%%-----------------------------------------------------------------
+%% Send one or more events to event collector process
+%%-----------------------------------------------------------------
+
+report_digit_event(DigitMapEvalPid, Event) ->
+ megaco_digit_map:report(DigitMapEvalPid, Event).
+
+
+%%-----------------------------------------------------------------
+%% Feed digit map collector with events and return the result
+%%-----------------------------------------------------------------
+
+test_digit_event(DigitMap, Events) ->
+ megaco_digit_map:test(DigitMap, Events).
+
+
+%%-----------------------------------------------------------------
+%% encode_binary_term_id(Config, MegacoTermId) ->
+%%
+%% {ok, TerminationId} | {error, Reason}
+%%
+%% Encode the Megaco internal form of a termination id (a
+%% megaco_term_id record) into ASN.1'1 internal form of a termination
+%% id (a 'TerminationId' record).
+%% %%-----------------------------------------------------------------
+
+encode_binary_term_id(Config, TermId) ->
+ megaco_binary_term_id:encode(Config, TermId).
+
+
+%%-----------------------------------------------------------------
+%% decode_binary_term_id(Config, TerminationId) ->
+%%
+%% {ok, MegacoTermId} | {error, Reason}
+%%
+%% Decode ASN.1's internal form of a termination id (a 'TerminationId'
+%% record) into the Megaco internal form of a termination id (a
+%% megaco_term_id record).
+%%-----------------------------------------------------------------
+
+decode_binary_term_id(Config, TermId) ->
+ megaco_binary_term_id:decode(Config, TermId).
+
+
+%%-----------------------------------------------------------------
+%% encode_sdp(SDP) ->
+%%
+%% {ok, PP} | {error, Reason}
+%%
+%% Encode a SDP construct into a property parm construct
+%%-----------------------------------------------------------------
+
+encode_sdp(SDP) ->
+ megaco_sdp:encode(SDP).
+
+
+%%-----------------------------------------------------------------
+%% decode_sdp(PP) ->
+%%
+%% {ok, SDP} | {error, Reason}
+%%
+%% Decode a property parm construct into a SDP construct
+%%-----------------------------------------------------------------
+
+decode_sdp(PP) ->
+ megaco_sdp:decode(PP).
+
+
+%%-----------------------------------------------------------------
+%% {ok, Vs} = megaco:versions1(), megaco:format_versions(Vs).
+
+print_version_info() ->
+ {ok, Versions} = megaco:versions1(),
+ print_version_info(Versions).
+
+print_version_info(Versions) when is_list(Versions) ->
+ print_sys_info(Versions),
+ print_os_info(Versions),
+ print_mods_info(Versions);
+print_version_info(BadVersions) ->
+ {error, {bad_versions, BadVersions}}.
+
+format_versions(Versions) ->
+ print_version_info(Versions).
+
+print_sys_info(Versions) ->
+ case key1search(sys_info, Versions) of
+ {value, SysInfo} when is_list(SysInfo) ->
+ {value, Arch} = key1search(arch, SysInfo, "Not found"),
+ {value, Ver} = key1search(ver, SysInfo, "Not found"),
+ io:format("System info: "
+ "~n Arch: ~s"
+ "~n Ver: ~s"
+ "~n", [Arch, Ver]),
+ ok;
+ _ ->
+ io:format("System info: Not found~n", []),
+ not_found
+ end.
+
+print_os_info(Versions) ->
+ case key1search(os_info, Versions) of
+ {value, OsInfo} when is_list(OsInfo) ->
+ Fam =
+ case key1search(fam, OsInfo, "Not found") of
+ {value, F} when is_atom(F) ->
+ atom_to_list(F);
+ {value, LF} when is_list(LF) ->
+ LF;
+ {value, XF} ->
+ lists:flatten(io_lib:format("~p", [XF]))
+ end,
+ Name =
+ case key1search(name, OsInfo) of
+ {value, N} when is_atom(N) ->
+ "[" ++ atom_to_list(N) ++ "]";
+ {value, LN} when is_list(LN) ->
+ "[" ++ LN ++ "]";
+ not_found ->
+ ""
+ end,
+ Ver =
+ case key1search(ver, OsInfo, "Not found") of
+ {value, T} when is_tuple(T) ->
+ tversion(T);
+ {value, LV} when is_list(LV) ->
+ LV;
+ {value, XV} ->
+ lists:flatten(io_lib:format("~p", [XV]))
+ end,
+ io:format("OS info: "
+ "~n Family: ~s ~s"
+ "~n Ver: ~s"
+ "~n", [Fam, Name, Ver]),
+ ok;
+ _ ->
+ io:format("OS info: Not found~n", []),
+ not_found
+ end.
+
+%% tversion({A, B, C}) ->
+%% lists:flatten(io_lib:format("~w.~w.~w", [A, B, C]));
+tversion(T) ->
+ L = tuple_to_list(T),
+ lversion(L).
+
+lversion([]) ->
+ "";
+lversion([A]) ->
+ integer_to_list(A);
+lversion([A|R]) ->
+ integer_to_list(A) ++ "." ++ lversion(R).
+
+print_mods_info(Versions) ->
+ case key1search(mod_info, Versions) of
+ {value, ModsInfo} when is_list(ModsInfo) ->
+ io:format("Module info: ~n", []),
+ lists:foreach(fun print_mod_info/1, ModsInfo);
+ _ ->
+ io:format("Module info: Not found~n", []),
+ not_found
+ end.
+
+print_mod_info({Module, Info}) ->
+ % Maybe a asn1 generated module
+ Asn1Vsn =
+ case (catch Module:info()) of
+ AI when is_list(AI) ->
+ case (catch key1search(vsn, AI)) of
+ {value, V} when is_atom(V) ->
+ atom_to_list(V);
+ _ ->
+ "-"
+ end;
+ _ ->
+ "-"
+ end,
+ Vsn =
+ case key1search(vsn, Info) of
+ {value, I} when is_integer(I) ->
+ integer_to_list(I);
+ _ ->
+ "Not found"
+ end,
+ AppVsn =
+ case key1search(app_vsn, Info) of
+ {value, S1} when is_list(S1) ->
+ S1;
+ _ ->
+ "Not found"
+ end,
+ CompVer =
+ case key1search(compiler_version, Info) of
+ {value, S2} when is_list(S2) ->
+ S2;
+ _ ->
+ "Not found"
+ end,
+ CompDate =
+ case key1search(compile_time, Info) of
+ {value, {Year, Month, Day, Hour, Min, Sec}} ->
+ lists:flatten(
+ io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
+ [Year, Month, Day, Hour, Min, Sec]));
+ _ ->
+ "Not found"
+ end,
+ io:format(" ~w:~n"
+ " Vsn: ~s~n"
+ " App vsn: ~s~n"
+ " ASN.1 vsn: ~s~n"
+ " Compiler ver: ~s~n"
+ " Compile time: ~s~n",
+ [Module, Vsn, AppVsn, Asn1Vsn, CompVer, CompDate]),
+ ok.
+
+
+
+key1search(Key, Vals) ->
+ case lists:keysearch(Key, 1, Vals) of
+ {value, {Key, Val}} ->
+ {value, Val};
+ false ->
+ not_found
+ end.
+
+key1search(Key, Vals, Def) ->
+ case key1search(Key, Vals) of
+ not_found ->
+ {value, Def};
+ Value ->
+ Value
+ end.
+
+
+%%-----------------------------------------------------------------
+
+versions1() ->
+ case ms1() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+versions2() ->
+ case ms2() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+version_info(Mods) ->
+ SysInfo = sys_info(),
+ OsInfo = os_info(),
+ ModInfo = [mod_version_info(Mod) || Mod <- Mods],
+ [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
+
+mod_version_info(Mod) ->
+ Info = Mod:module_info(),
+ {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info),
+ {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr),
+ {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr),
+ {value, {compile, Comp}} = lists:keysearch(compile, 1, Info),
+ {value, {version, Ver}} = lists:keysearch(version, 1, Comp),
+ {value, {time, Time}} = lists:keysearch(time, 1, Comp),
+ {Mod, [{vsn, Vsn},
+ {app_vsn, AppVsn},
+ {compiler_version, Ver},
+ {compile_time, Time}]}.
+
+sys_info() ->
+ SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
+ SysVer = string:strip(erlang:system_info(system_version),right,$\n),
+ [{arch, SysArch}, {ver, SysVer}].
+
+os_info() ->
+ V = os:version(),
+ case os:type() of
+ {OsFam, OsName} ->
+ [{fam, OsFam}, {name, OsName}, {ver, V}];
+ OsFam ->
+ [{fam, OsFam}, {ver, V}]
+ end.
+
+ms() ->
+ ms1().
+
+ms1() ->
+ App = ?APPLICATION,
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ case lists:keysearch(modules, 1, AppFile) of
+ {value, {modules, Mods}} ->
+ {ok, Mods};
+ _ ->
+ {error, {invalid_format, modules}}
+ end;
+ Error ->
+ {error, {invalid_format, Error}}
+ end.
+
+ms2() ->
+ application:get_key(?APPLICATION, modules).
+
+nc() ->
+ {ok, Mods} = ms(),
+ nc(Mods).
+
+nc(all) ->
+ application:load(?APPLICATION),
+ case application:get_key(?APPLICATION, modules) of
+ {ok, Mods} ->
+ application:unload(?APPLICATION),
+ nc(Mods);
+ _ ->
+ {error, not_found}
+ end;
+nc(Mods) when is_list(Mods) ->
+ [Mod || Mod <- Mods, ok /= load(Mod, compile)].
+
+ni() ->
+ case ms() of
+ {ok, Mods} ->
+ ni(Mods);
+ Error ->
+ Error
+ end.
+
+ni(all) ->
+ application:load(?APPLICATION),
+ case application:get_key(?APPLICATION, modules) of
+ {ok, Mods} ->
+ application:unload(?APPLICATION),
+ ni(Mods);
+ _ ->
+ {error, not_found}
+ end;
+ni(Mods) when is_list(Mods) ->
+ [Mod || Mod <- Mods, ok /= load(Mod, interpret)].
+
+load(Mod, How) when is_atom(Mod) ->
+ case try_load(Mod, How) of
+ ok ->
+ ok;
+ _ ->
+ io:format( "~n RETRY ~p FROM: ", [Mod]),
+ ModString = atom_to_list(Mod) ++ ".erl",
+ LibDir = code:lib_dir(?APPLICATION),
+ case find_file([LibDir], ModString) of
+ {ok, Abs} ->
+ load(Abs, How);
+ {error, Reason} ->
+ io:format( " *** ERROR *** ~p~n", [Reason]),
+ {error, Reason}
+ end
+ end;
+load(Abs, How) ->
+ case try_load(Abs, How) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ io:format( " *** ERROR *** ~p~n", [Reason]),
+ {error, Reason}
+ end.
+
+try_load(Mod, How) ->
+ io:format( " ~p ", [Mod]),
+ Flags = [{d, debug}],
+ case How of
+ compile ->
+ case catch c:nc(Mod, Flags) of
+ {ok, _} -> ok;
+ Other -> {error, Other}
+ end;
+ interpret ->
+ case catch int:ni(Mod, Flags) of
+ {module, _} -> ok;
+ Other -> {error, Other}
+ end
+ end.
+
+find_file([Dir | Dirs], File) ->
+ case file:list_dir(Dir) of
+ {ok, List} ->
+ case lists:member(File, List) of
+ true ->
+ {ok, filename:join([Dir, File])};
+ false ->
+ SubDirs = [filename:join([Dir, Sub]) || Sub <- List],
+ case find_file(SubDirs, File) of
+ {ok, Abs} ->
+ {ok, Abs};
+ {error, _Reason} ->
+ find_file(Dirs, File)
+ end
+ end;
+ {error, _Reason} ->
+ find_file(Dirs, File)
+ end;
+find_file([], File) ->
+ {error, {no_such_file, File}}.
+
+
+%%-----------------------------------------------------------------
+
+%% -----------------------------
+%% These functions can be used instead of the et tool for
+%% managing trace of the megaco application.
+
+%%-----------------------------------------------------------------
+%% enable_trace(Level, Destination) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%% Destination -> File | Port | io | {io, Verbosity} | HandlerSpec
+%% File -> string()
+%% Port -> integer()
+%% Verbosity -> true | false
+%% HandlerSpec = {function(), Data}
+%% Data = term()
+%%
+%% Description:
+%% This function is used to start tracing at level Level and send
+%% the result either to the file File or the port Port. Note that
+%% it starts a tracer server.
+%% When Destination is the atom io (or the tuple {io, Verbosity}),
+%% all (printable) megaco trace events (trace_ts events which has
+%% Severity withing Limit) will be written to stdout using io:format.
+%%
+%%-----------------------------------------------------------------
+enable_trace(Level, File) when is_list(File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ HandleSpec = {fun handle_trace/2, Fd},
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level);
+ Err ->
+ Err
+ end;
+enable_trace(Level, Port) when is_integer(Port) ->
+ dbg:tracer(port, dbg:trace_port(ip, Port)),
+ set_trace(Level);
+enable_trace(Level, io) ->
+ HandleSpec = {fun handle_trace/2, standard_io},
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level);
+enable_trace(Level, {Fun, _Data} = HandleSpec) when is_function(Fun) ->
+ dbg:tracer(process, HandleSpec),
+ set_trace(Level).
+
+
+%%-----------------------------------------------------------------
+%% disable_trace() -> void()
+%%
+%% Description:
+%% This function is used to stop tracing.
+%%-----------------------------------------------------------------
+disable_trace() ->
+ %% This is to make handle_trace/2 close the output file (if the
+ %% event gets there before dbg closes)
+ report_event(stop_trace, stop_trace, stop_trace, stop_trace, stop_trace),
+ dbg:stop().
+
+
+%%-----------------------------------------------------------------
+%% set_trace(Level) -> void()
+%%
+%% Parameters:
+%% Level -> max | min | integer()
+%%
+%% Description:
+%% This function is used to change the trace level when tracing has
+%% already been started.
+%%-----------------------------------------------------------------
+set_trace(Level) ->
+ Pat = et_selector:make_pattern({?MODULE, Level}),
+ et_selector:change_pattern(Pat).
+
+report_event(DetailLevel, FromTo, Label, Contents) ->
+ %% N.B External call
+ ?MODULE:report_event(DetailLevel, FromTo, FromTo, Label, Contents).
+
+report_event(_DetailLevel, _From, _To, _Label, _Contents) ->
+ hopefully_traced.
+
+
+%% ----------------------------------------------------------------------
+%% handle_trace(Event, Verbosity) -> Verbosity
+%%
+%% Parameters:
+%% Event -> The trace event (only megaco 'trace_ts' events are printed)
+%% Verbosity -> max | min | integer() (see Level above)
+%%
+%% Description:
+%% This function is "receive" and print the trace events.
+%% Events are printed if:
+%% - Verbosity is max
+%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40)
+%% Events are not printed if:
+%% - Verbosity is min
+%% - Severity is > Verbosity
+%%-----------------------------------------------------------------
+
+handle_trace(_, closed_file = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [stop_trace, stop_trace, stop_trace, stop_trace, stop_trace]},
+ _Timestamp},
+ standard_io = Fd) ->
+ Fd;
+handle_trace({trace_ts, _Who, call,
+ {?MODULE, report_event,
+ [stop_trace, stop_trace, stop_trace, stop_trace, stop_trace]},
+ Timestamp},
+ Fd) ->
+ (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])),
+ (catch file:close(Fd)),
+ closed_file;
+handle_trace({trace_ts, Who, call,
+ {?MODULE, report_event,
+ [Sev, From, To, Label, Content]}, Timestamp},
+ Fd) ->
+ (catch print_megaco_trace(Fd, Sev, Who, Timestamp, Label, From, To, Content)),
+ Fd;
+handle_trace(Event, Fd) ->
+ (catch print_trace(Fd, Event)),
+ Fd.
+
+
+print_megaco_trace(Fd, Sev, Who, Timestamp, Label, From, To, Content) ->
+ Ts = format_timestamp(Timestamp),
+ io:format(Fd, "[megaco trace ~w ~w ~s] ~s "
+ "~n From: ~p"
+ "~n To: ~p"
+ "~n Content: ~p"
+ "~n",
+ [Sev, Who, Ts, Label, From, To, Content]).
+
+print_trace(Fd, {trace, Who, What, Where}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Who, What, Where]);
+
+print_trace(Fd, {trace, Who, What, Where, Extra}) ->
+ io:format(Fd, "[trace]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Who, What, Where, Extra]);
+
+print_trace(Fd, {trace_ts, Who, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, Who, What, Where]);
+
+print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[trace ~s]"
+ "~n Who: ~p"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n Extra: ~p"
+ "~n", [Ts, Who, What, Where, Extra]);
+
+print_trace(Fd, {seq_trace, What, Where}) ->
+ io:format(Fd, "[seq trace]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [What, Where]);
+
+print_trace(Fd, {seq_trace, What, Where, When}) ->
+ Ts = format_timestamp(When),
+ io:format(Fd, "[seq trace ~s]"
+ "~n What: ~p"
+ "~n Where: ~p"
+ "~n", [Ts, What, Where]);
+
+print_trace(Fd, {drop, Num}) ->
+ io:format(Fd, "[drop trace] ~p~n", [Num]);
+
+print_trace(Fd, Trace) ->
+ io:format(Fd, "[trace] "
+ "~n ~p"
+ "~n", [Trace]).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
+
diff --git a/lib/megaco/src/app/megaco.mk b/lib/megaco/src/app/megaco.mk
new file mode 100644
index 0000000000..7bc276d26d
--- /dev/null
+++ b/lib/megaco/src/app/megaco.mk
@@ -0,0 +1,56 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+ifeq ($(MEGACO_TRACE), io)
+ERL_COMPILE_FLAGS += -Dmegaco_trace_io
+endif
+
+ifeq ($(MEGACO_EXTENDED_TRACE), true)
+ERL_COMPILE_FLAGS += -Dmegaco_extended_trace
+endif
+
+ifeq ($(USE_MEGACO_TEST_CODE), true)
+ERL_COMPILE_FLAGS += -DMEGACO_TEST_CODE=mona_lisa_spelar_doom
+endif
+
+ifeq ($(MEGACO_DEBUG), true)
+ERL_COMPILE_FLAGS += -Dmegaco_debug
+endif
+
+ifneq ($(MEGACO_PARSER_INLINE), false)
+ERL_COMPILE_FLAGS += -Dmegaco_parser_inline
+endif
+
+ifeq ($(USE_MEGACO_HIPE), true)
+ERL_COMPILE_FLAGS += +native
+endif
+
+ifeq ($(WARN_UNUSED_WARS), true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+MEGACO_APP_VSN_COMPILE_FLAGS = \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}'
+
+MEGACO_ERL_COMPILE_FLAGS += \
+ -pa $(ERL_TOP)/lib/et/ebin \
+ -pa $(ERL_TOP)/lib/megaco/ebin \
+ $(MEGACO_APP_VSN_COMPILE_FLAGS)
+
diff --git a/lib/megaco/src/app/megaco_internal.hrl b/lib/megaco/src/app/megaco_internal.hrl
new file mode 100644
index 0000000000..adbaacacef
--- /dev/null
+++ b/lib/megaco/src/app/megaco_internal.hrl
@@ -0,0 +1,183 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define internal data structures and error codes
+%%----------------------------------------------------------------------
+
+-define(APPLICATION, megaco).
+
+%% -define(debug, true).
+
+%% N.B. Update megaco_config when a new field is added
+-record(conn_data,
+ {
+ conn_handle,
+ serial,
+ max_serial,
+ request_timer,
+ long_request_timer,
+
+ %% Auto send of ack: false | true
+ %% (if true, and if trans_ack is false or trans_timer
+ %% is zero (0), then acks will be sent immediatly)
+ auto_ack,
+
+ %% ------
+ %% Accumulate trans acks/requests and send them "all" later
+ %% in one bigger message.
+ %% For this to take effekt, trans_timer has to be > 0
+ %% trans_ack and/or trans_req has to be true.
+ %% Accumulate transactions, and send them later, either
+ %% when the timer expires, when maxcount number of
+ %% transactions has been accumulated or in the case
+ %% requests, when the maxsize number of bytes has been
+ %% accumulated (whichever happens first).
+ %% (Note that, for acks, this is only valid if auto_ack
+ %% is true)
+
+ trans_ack, % false
+ trans_ack_maxcount, % 10
+
+ trans_req, % false
+ trans_req_maxcount, % 10
+ trans_req_maxsize, % 2048
+
+ trans_timer, % 0 (don't accumulate transactions)
+ trans_sender, % The trans sender process ref, or undefined
+
+ pending_timer,
+
+ %% ------
+ %% These counter's are used for the MGCOriginatedPendingLimit
+ %% and MGOriginatedPendingLimit counters (of the root package).
+ %% If the user is an MGC, then
+ %% sent_pending_limit - represent MGCOriginatedPendingLimit
+ %% recv_pending_limit - represent MGOriginatedPendingLimit
+ %% If the user is an MG, then
+ %% sent_pending_limit - represent MGOriginatedPendingLimit
+ %% recv_pending_limit - represent MGCOriginatedPendingLimit
+ sent_pending_limit, % infinity | integer() > 0
+ recv_pending_limit, % infinity | integer() > 0
+
+ reply_timer,
+ control_pid,
+ monitor_ref,
+ send_mod,
+ send_handle,
+ encoding_mod,
+ encoding_config,
+ protocol_version,
+ auth_data,
+ user_mod,
+ user_args,
+ reply_action, % call | cast
+ reply_data, % term()
+ threaded, % boolean(), false
+ strict_version, % boolean(), true
+ long_request_resend, % boolean(), false
+ call_proxy_gc_timeout, % integer() > 0
+
+ %% This flag is used when a connection is being cancelled.
+ %% The purpuse is to avoid raise conditions with replies
+ %% during the cancellation.
+ cancel, % boolean(), false
+ resend_indication, % boolean(), false
+
+ %% -------
+ %% Defined in the Segmentation Package (extends the root package)
+ %%
+ segment_reply_ind, % boolean(), false
+ segment_recv_acc, % bool()
+ segment_recv_timer, % megaco_timer() | integer() > 0 | infinity
+ segment_send, % none | infinity | integer() > 0
+ segment_send_timer, % megaco_timer() | integer() > 0 | infinity
+ max_pdu_size, % infinity | integer() > 0
+
+ request_keep_alive_timeout % plain | integer() >= 0
+ }).
+
+
+%% N.B. Update megaco_config when a new field is added
+-record(remote_conn_data,
+ {conn_handle,
+ user_node,
+ monitor_ref}).
+
+
+%%%----------------------------------------------------------------------
+%%% Error/warning/info message macro(s)
+%%%----------------------------------------------------------------------
+
+-define(megaco_info(F, A),
+ (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+-define(megaco_warning(F, A),
+ (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+-define(megaco_error(F, A),
+ (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n",
+ [?APPLICATION, ?MODULE, self()|A]))).
+
+
+%%%----------------------------------------------------------------------
+%%% Default (ignore) value of the Extra argument to the
+%%% megaco:receive_message/5 and process_received_message functions/5.
+%%%----------------------------------------------------------------------
+
+-define(default_user_callback_extra, ignore_extra).
+
+
+%%%----------------------------------------------------------------------
+%%% Event Trace
+%%%----------------------------------------------------------------------
+
+-ifdef(megaco_trace_io).
+-define(report(Level, C, Label, Contents),
+ io:format("*** [~s] ~p ~p *** "
+ "~n ~p[~p] " ++ Label ++
+ "~n ~p"
+ "~n ~p"
+ "~n",
+ [megaco:format_timestamp(now()),
+ self(), Level, ?MODULE, ?LINE, C, Contents])).
+-else.
+-define(report(Level, C, Label, Contents),
+ megaco:report_event(Level, ?APPLICATION, Label,
+ [{line, ?MODULE, ?LINE}, C | Contents])).
+-endif.
+
+-define(report_important(C, Label, Contents), ?report(20, C, Label, Contents)).
+-define(report_verbose( C, Label, Contents), ?report(40, C, Label, Contents)).
+-define(report_debug( C, Label, Contents), ?report(60, C, Label, Contents)).
+-define(report_trace( C, Label, Contents), ?report(80, C, Label, Contents)).
+
+
+%%%----------------------------------------------------------------------
+%%% Debug
+%%%----------------------------------------------------------------------
+
+-ifdef(megaco_debug).
+-define(d(F,A), io:format("~w: " ++ F ++ "~n",[?MODULE|A])).
+-else.
+-define(d(F,A), ok).
+-endif.
diff --git a/lib/megaco/src/app/modules.mk b/lib/megaco/src/app/modules.mk
new file mode 100644
index 0000000000..42a2e94752
--- /dev/null
+++ b/lib/megaco/src/app/modules.mk
@@ -0,0 +1,36 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco
+
+EXTERNAL_HRL_FILES = \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl \
+ ../../include/megaco_message_v2.hrl \
+ ../../include/megaco_message_prev3a.hrl \
+ ../../include/megaco_message_prev3b.hrl \
+ ../../include/megaco_message_prev3c.hrl \
+ ../../include/megaco_message_v3.hrl \
+ ../../include/megaco_sdp.hrl
+
+INTERNAL_HRL_FILES = \
+ megaco_internal.hrl
+
+
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn
new file mode 100644
index 0000000000..083f7e8271
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3a.asn
@@ -0,0 +1,1001 @@
+MEDIA-GATEWAY-CONTROL-prev3a
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepsCallind BOOLEAN OPTIONAL, -- Fixed
+ contextProp SEQUENCE OF PropertyParm OPTIONAL
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepsCallind NULL OPTIONAL, -- Fixed
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn
new file mode 100644
index 0000000000..1fb4d8fff2
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3b.asn
@@ -0,0 +1,1001 @@
+MEDIA-GATEWAY-CONTROL-prev3b
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn
new file mode 100644
index 0000000000..cb6940e8b0
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-prev3c.asn
@@ -0,0 +1,1073 @@
+MEDIA-GATEWAY-CONTROL-prev3c
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ -- segmentReply SegmentReply
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ -- Erlang Note: NOT REALLY PART OF THIS IMPLEMENTATION
+ -- Erlang Note: The only reason why we need to include
+ -- Erlang Note: these definitions in this version is
+ -- Erlang Note: that we cannot distinguish between v3
+ -- Erlang Note: versions in the megaco_messenger module
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+-- SegmentReply ::= SEQUENCE
+-- {
+-- transactionId TransactionId,
+-- segmentNumber SegmentNumber,
+-- segmentationComplete NULL OPTIONAL,
+-- ...
+-- }
+--
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL,
+ contextList SEQUENCE OF ContextID OPTIONAL
+ }
+-- When returning a contextList, the contextId in the ActionReply
+-- construct will return the contextId from the associated ActionRequest.
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL,
+
+ selectpriority INTEGER(0..15) OPTIONAL,
+ -- to select given priority
+
+ selectemergency BOOLEAN OPTIONAL,
+ -- to select if emergency set/not set (T/F)
+
+ selectiepscallind BOOLEAN OPTIONAL,
+ -- to select if IEPS set/not set (T/F)
+
+ selectLogic SelectLogic OPTIONAL -- default is AND
+ }
+
+SelectLogic ::= CHOICE
+ {
+ andAUDITSelect NULL, -- all selection conditions satisfied
+ orAUDITSelect NULL, -- at least one selection condition satisfied
+ ...
+ }
+
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL,
+ topologyDirectionExtension ENUMERATED
+ {
+ onewayexternal(0),
+ onewayboth(1),
+ ...
+ } OPTIONAL
+ -- This is not according to the standard, but without it
+ -- the TopologyRequest will be useless since topologyDirection
+ -- and topologyDirectionExtension are contradictory.
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...,
+ terminationIDList TerminationIDList OPTIONAL
+ }
+-- terminationID shall contain the first termination in the
+-- list when using the terminationIDList construct in AuditRequest
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...,
+ auditResultTermList TermListAuditResult
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+TermListAuditResult ::= SEQUENCE
+ {
+ terminationIDList TerminationIDList,
+ terminationAuditResult TerminationAudit,
+ ...
+ }
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...,
+ streamModeSel StreamMode OPTIONAL
+ -- must not have both streamMode and streamModeSel
+ -- if both are present only streamModeSel shall be honoured
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...,
+ propertyParms PropertyParm OPTIONAL
+ }
+-- to select based on property values
+-- AND/OR selection logic is specified at context level
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...,
+ serviceStateSel ServiceState OPTIONAL
+ -- must not have both serviceState and serviceStateSel
+ -- if both are present only serviceStateSel shall be honoured
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...,
+ signalRequestID RequestID OPTIONAL
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RegulatedEmbeddedDescriptor ::= SEQUENCE
+ {
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyBehaviour ::= CHOICE
+ {
+ notifyImmediate NULL,
+ notifyRegulated RegulatedEmbeddedDescriptor,
+ neverNotify NULL,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL,
+ intersigDelay INTEGER (0..65535) OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+-- If statistic consists of a sub-list there will be more than one
+-- octetstring in statValue.
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn
new file mode 100644
index 0000000000..717517938f
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v1.asn
@@ -0,0 +1,982 @@
+-- This ASN.1 spec has been extracted from the Megaco/H.248 spec
+-- http://www.ietf.org/internet-drafts/draft-ietf-megaco-merged-01.txt
+--
+-- o Removed stuff named nonStandard
+-- o Major enhancements of the indentation has been performed.
+--
+-- Hakan Mattsson <[email protected]>
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- ANNEX A: BINARY ENCODING OF THE PROTOCOL (NORMATIVE)
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- This Annex specifies the syntax of messages using the notation
+-- defined in ASN.1 [ITU-T Recommendation X.680 (1997): Information
+-- Technology - Abstract Syntax Notation One (ASN.1) - Specification of
+-- basic notation.]. Messages shall be encoded for transmission by
+-- applying the basic encoding rules specified in [ITU-T Recommendation
+-- X.690(1994) Information Technology - ASN.1 Encoding Rules:
+-- Specification of Basic Encoding Rules (BER)].
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- A.1 Coding of wildcards
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- The use of wildcards ALL and CHOOSE is allowed in the protocol.
+-- This allows a MGC to partially specify Termination IDs and let the
+-- MG choose from the values that conform to the partial specification.
+-- Termination IDs may encode a hierarchy of names. This hierarchy is
+-- provisioned. For instance, a TerminationID may consist of a trunk
+-- group, a trunk within the group and a circuit. Wildcarding must be
+-- possible at all levels. The following paragraphs explain how this
+-- is achieved.
+--
+-- The ASN.1 description uses octet strings of up to 8 octets in length
+-- for Termination IDs. This means that Termination IDs consist of at
+-- most 64 bits. A fully specified Termination ID may be preceded by a
+-- sequence of wildcarding fields. A wildcarding field is one octet in
+-- length. Bit 7 (the most significant bit) of this octet specifies
+-- what type of wildcarding is invoked: if the bit value equals 1,
+-- then the ALL wildcard is used; if the bit value if 0, then the
+-- CHOOSE wildcard is used. Bit 6 of the wildcarding field specifies
+-- whether the wildcarding pertains to one level in the hierarchical
+-- naming scheme (bit value 0) or to the level of the hierarchy
+-- specified in the wildcarding field plus all lower levels (bit value
+-- 1). Bits 0 through 5 of the wildcarding field specify the bit
+-- position in the Termination ID at which the starts.
+--
+-- We illustrate this scheme with some examples. In these examples,
+-- the most significant bit in a string of bits appears on the left
+-- hand side.
+--
+-- Assume that Termination IDs are three octets long and that each
+-- octet represents a level in a hierarchical naming scheme. A valid
+-- Termination ID is
+-- 00000001 00011110 01010101.
+--
+-- Addressing ALL names with prefix 00000001 00011110 is done as
+-- follows:
+-- wildcarding field: 10000111
+-- Termination ID: 00000001 00011110 xxxxxxxx.
+--
+-- The values of the bits labeled "x" is irrelevant and shall be
+-- ignored by the receiver.
+--
+-- Indicating to the receiver that is must choose a name with 00011110
+-- as the second octet is done as follows:
+-- wildcarding fields: 00010111 followed by 00000111
+-- Termination ID: xxxxxxxx 00011110 xxxxxxxx.
+--
+-- The first wildcard field indicates a CHOOSE wildcard for the level
+-- in the naming hierarchy starting at bit 23, the highest level in our
+-- assumed naming scheme. The second wildcard field indicates a CHOOSE
+-- wildcard for the level in the naming hierarchy starting at bit 7,
+-- the lowest level in our assumed naming scheme.
+--
+-- Finally, a CHOOSE-wildcarded name with the highest level of the name
+-- equal to 00000001 is specified as follows:
+-- wildcard field: 01001111
+-- Termination ID: 0000001 xxxxxxxx xxxxxxxx .
+--
+-- Bit value 1 at bit position 6 of the first octet of the wildcard
+-- field indicates that the wildcarding pertains to the specified level
+-- in the naming hierarchy and all lower levels.
+--
+-- Context IDs may also be wildcarded. In the case of Context IDs,
+-- however, specifying partial names is not allowed. Context ID 0x0
+-- SHALL be used to indicate the NULL Context, Context ID 0xFFFFFFFE
+-- SHALL be used to indicate a CHOOSE wildcard, and Context ID
+-- 0xFFFFFFFF SHALL be used to indicate an ALL wildcard.
+--
+-- TerminationID 0xFFFFFFFFFFFFFFFF SHALL be used to indicate the ROOT
+-- Termination.
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- Digit maps and path names
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- From a syntactic viewpoint, digit maps are strings with syntactic
+-- restrictions imposed upon them. The syntax of valid digit maps is
+-- specified in ABNF [RFC 2234]. The syntax for digit maps presented
+-- in this section is for illustrative purposes only. The definition of
+-- digitMap in Annex B takes precedence in the case of differences
+-- between the two.
+--
+-- digitMap = (digitString / LWSP "(" LWSP digitStringList LWSP ")"
+-- LWSP)
+-- digitStringList = digitString *( LWSP "/" LWSP digitString )
+-- digitString = 1*(digitStringElement)
+-- digitStringElement = digitPosition [DOT]
+-- digitPosition = digitMapLetter / digitMapRange
+-- digitMapRange = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)
+-- digitLetter = *((DIGIT "-" DIGIT) /digitMapLetter)
+-- digitMapLetter = DIGIT ;digits 0-9
+-- / %x41-4B / %x61-6B ;a-k and A-K
+-- / "L" / "S" ;Inter-event timers
+-- ;(long, short)
+-- / "Z" ;Long duration event
+-- DOT = %x2E ; "."
+-- LWSP = *(WSP / COMMENT / EOL)
+-- WSP = SP / HTAB
+-- COMMENT = ";" *(SafeChar / RestChar / WSP) EOL
+-- EOL = (CR [LF]) / LF
+-- SP = %x20
+-- HTAB = %x09
+-- CR = %x0D
+-- LF = %x0A
+-- SafeChar = DIGIT / ALPHA / "+" / "-" / "&" / "!" / "_" / "/" /
+-- "'" / "?" / "@" / "^" / "`" / "~" / "*" / "$" / "\" /
+-- "(" / ")" / "%" / "."
+-- RestChar = ";" / "[" / "]" / "{" / "}" / ":" / "," / "#" /
+-- "<" / ">" / "=" / %x22
+-- DIGIT = %x30-39 ; digits 0 through 9
+-- ALPHA = %x41-5A / %x61-7A ; A-Z, a-z
+-- A path name is also a string with syntactic restrictions imposed
+-- upon it. The ABNF production defining it is copied from Annex B.
+--
+-- PathName = NAME *(["/"] ["*"] ["@"] (ALPHA / DIGIT)) ["*"]
+-- NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+-- A.2 ASN.1 syntax specification
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- This section contains the ASN.1 specification of the H.248 protocol
+-- syntax.
+--
+-- NOTE - In case a transport mechanism is used that employs
+-- application level framing, the definition of Transaction below
+-- changes. Refer to the annex defining the transport mechanism for
+-- the definition that applies in that case.
+--
+-- NOTE - The ASN.1 specification below contains a clause defining
+-- TerminationIDList as a sequence of TerminationIDs. The length of
+-- this sequence SHALL be one, except possibly when used in
+-- contextAuditResult.
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+MEDIA-GATEWAY-CONTROL-v1
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+MegacoMessage ::= SEQUENCE
+{
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+}
+
+AuthenticationHeader ::= SEQUENCE
+{
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+}
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+{
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 1.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+}
+
+MId ::= CHOICE
+{
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 15 0
+ -- | PC | NI |
+ -- 14 bits 2 bits
+ ...
+}
+
+DomainName ::= SEQUENCE
+{
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+IP4Address ::= SEQUENCE
+{
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+IP6Address ::= SEQUENCE
+{
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+}
+
+PathName ::= IA5String(SIZE (1..64))
+-- See section A.3
+
+Transaction ::= CHOICE
+{
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+}
+
+TransactionId ::= INTEGER(0..4294967295) -- 32 bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+{
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+}
+
+TransactionPending ::= SEQUENCE
+{
+ transactionId TransactionId,
+ ...
+}
+
+TransactionReply ::= SEQUENCE
+{
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+}
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+
+TransactionAck ::= SEQUENCE
+{
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+}
+
+ErrorDescriptor ::= SEQUENCE
+{
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+}
+
+ErrorCode ::= INTEGER(0..65535)
+-- See section 13 for IANA considerations w.r.t. error codes
+
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+{
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+}
+
+ActionReply ::= SEQUENCE
+{
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+}
+
+ContextRequest ::= SEQUENCE
+{
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+}
+
+ContextAttrAuditRequest ::= SEQUENCE
+{
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+}
+
+CommandRequest ::= SEQUENCE
+{
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+}
+
+Command ::= CHOICE
+{
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+}
+
+CommandReply ::= CHOICE
+{
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+}
+
+TopologyRequest ::= SEQUENCE
+{
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ }
+}
+
+AmmRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+}
+
+AmmDescriptor ::= CHOICE
+{
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+...
+}
+
+AmmsReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+}
+
+SubtractRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+}
+
+AuditRequest ::= SEQUENCE
+{
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+}
+
+AuditReply ::= CHOICE
+{
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+}
+
+AuditResult ::= SEQUENCE
+{
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+}
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+{
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+}
+
+AuditDescriptor ::= SEQUENCE
+{
+ auditToken BIT STRING
+ {
+ muxToken(0),
+ modemToken(1),
+ mediaToken(2),
+ eventsToken(3),
+ signalsToken(4),
+ digitMapToken(5),
+ statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8),
+ eventBufferToken(9)
+ } OPTIONAL,
+ ...
+}
+
+NotifyRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+}
+
+NotifyReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+}
+
+ObservedEventsDescriptor ::= SEQUENCE
+{
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+}
+
+ObservedEvent ::= SEQUENCE
+{
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+}
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+{
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to propertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+ServiceChangeRequest ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+}
+
+ServiceChangeReply ::= SEQUENCE
+{
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+}
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+{
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+}
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+{
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+}
+-- See Section A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+{
+
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+}
+
+StreamDescriptor ::= SEQUENCE
+{
+ streamID StreamID,
+ streamParms StreamParms
+}
+
+StreamParms ::= SEQUENCE
+{
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+}
+
+LocalControlDescriptor ::= SEQUENCE
+{
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+}
+
+StreamMode ::= ENUMERATED
+{
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+}
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g., x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+{
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property Name (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- Wildcarding of Package Name is permitted only if Property Name is
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+{
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+}
+
+LocalRemoteDescriptor ::= SEQUENCE
+{
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+}
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+{
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+}
+
+EventBufferControl ::= ENUMERATED
+{
+ off(0),
+ lockStep(1),
+ ...
+}
+
+ServiceState ::= ENUMERATED
+{
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+}
+
+MuxDescriptor ::= SEQUENCE
+{
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+}
+
+MuxType ::= ENUMERATED
+{
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...
+}
+
+StreamID ::= INTEGER(0..65535) -- 16 bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+{
+ requestID RequestID,
+ -- IG 6.82 was withdrawn
+ -- requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+}
+
+RequestedEvent ::= SEQUENCE
+{
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+}
+
+RequestedActions ::= SEQUENCE
+{
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+}
+
+
+EventDM ::= CHOICE
+{
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+}
+
+SecondEventsDescriptor ::= SEQUENCE
+{
+ requestID RequestID,
+ -- IG 6.82 was withdrawn
+ -- requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList is non empty
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+}
+
+SecondRequestedEvent ::= SEQUENCE
+{
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+}
+
+SecondRequestedActions ::= SEQUENCE
+{
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+}
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+{
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+}
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+{
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+}
+
+SeqSigList ::= SEQUENCE
+{
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+}
+
+Signal ::= SEQUENCE
+{
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+}
+
+SignalType ::= ENUMERATED
+{
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+}
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+{
+ onTimeOut(0),
+ onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2),
+ otherReason(3)
+}
+
+SigParameter ::= SEQUENCE
+{
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to propertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+}
+
+RequestID ::= INTEGER(0..4294967295) -- 32 bit unsigned integer
+-- Request ALL Value: 4294967295 (0xFFFFFFFF)
+
+ModemDescriptor ::= SEQUENCE
+{
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+}
+
+ModemType ::= ENUMERATED
+{
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+}
+
+DigitMapDescriptor ::= SEQUENCE
+{
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+}
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+{
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- See Section A.3 for explanation of digit map syntax
+ ...
+}
+
+ServiceChangeParm ::= SEQUENCE
+{
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32 bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+}
+
+ServiceChangeAddress ::= CHOICE
+{
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+}
+
+ServiceChangeResParm ::= SEQUENCE
+{
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ ...
+}
+
+ServiceChangeMethod ::= ENUMERATED
+{
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+}
+
+ServiceChangeProfile ::= SEQUENCE
+{
+ profileName IA5String(SIZE (1..67))
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+}
+
+-- ServiceChangeProfile ::= SEQUENCE
+-- {
+-- profileName Name,
+-- version INTEGER(0..99)
+-- }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+{
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+}
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+{
+ statName PkgdName,
+ statValue Value OPTIONAL
+}
+
+NonStandardData ::= SEQUENCE
+{
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+}
+
+NonStandardIdentifier ::= CHOICE
+{
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters should be "X-" or "X+"
+ ...
+}
+
+H221NonStandard ::= SEQUENCE
+{
+ t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+}
+
+TimeNotation ::= SEQUENCE
+{
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+}
+
+Value ::= SEQUENCE OF OCTET STRING
+
+
+END
+
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn
new file mode 100644
index 0000000000..b75925b30e
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v2.asn
@@ -0,0 +1,966 @@
+MEDIA-GATEWAY-CONTROL-v2
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version2(2)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 2.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...
+ }
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...
+ }
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...
+ }
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...
+ }
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...
+ }
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn
new file mode 100644
index 0000000000..644a35ffee
--- /dev/null
+++ b/lib/megaco/src/binary/MEDIA-GATEWAY-CONTROL-v3.asn
@@ -0,0 +1,1068 @@
+MEDIA-GATEWAY-CONTROL-v3
+{itu-t(0) recommendation(0) h(8) h248(248)
+ modules(0) media-gateway-control(0) version3(3)}
+DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+
+MegacoMessage ::= SEQUENCE
+ {
+ authHeader AuthenticationHeader OPTIONAL,
+ mess Message
+ }
+
+AuthenticationHeader ::= SEQUENCE
+ {
+ secParmIndex SecurityParmIndex,
+ seqNum SequenceNum,
+ ad AuthData
+ }
+
+SecurityParmIndex ::= OCTET STRING(SIZE(4))
+
+SequenceNum ::= OCTET STRING(SIZE(4))
+
+AuthData ::= OCTET STRING (SIZE (12..32))
+
+Message ::= SEQUENCE
+ {
+ version INTEGER(0..99),
+ -- The version of the protocol defined here is equal to 3.
+ mId MId, -- Name/address of message originator
+ messageBody CHOICE
+ {
+ messageError ErrorDescriptor,
+ transactions SEQUENCE OF Transaction
+ },
+ ...
+ }
+
+MId ::= CHOICE
+ {
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ -- Addressing structure of mtpAddress:
+ -- 25 - 15 0
+ -- | PC | NI |
+ -- 24 - 14 bits 2 bits
+ -- Note: 14 bits are defined for international use.
+ -- Two national options exist where the point code is 16 or 24
+ -- bits.
+ -- To octet align the mtpAddress, the MSBs shall be encoded as 0s.
+ ...
+ }
+
+DomainName ::= SEQUENCE
+ {
+ name IA5String,
+ -- The name starts with an alphanumeric digit followed by a
+ -- sequence of alphanumeric digits, hyphens and dots. No two
+ -- dots shall occur consecutively.
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP4Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(4)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+IP6Address ::= SEQUENCE
+ {
+ address OCTET STRING (SIZE(16)),
+ portNumber INTEGER(0..65535) OPTIONAL
+ }
+
+PathName ::= IA5String(SIZE (1..64))
+-- See A.3
+
+Transaction ::= CHOICE
+ {
+ transactionRequest TransactionRequest,
+ transactionPending TransactionPending,
+ transactionReply TransactionReply,
+ transactionResponseAck TransactionResponseAck,
+ -- use of response acks is dependent on underlying transport
+ ...,
+ segmentReply SegmentReply
+ }
+
+TransactionId ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+TransactionRequest ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ actions SEQUENCE OF ActionRequest,
+ ...
+ }
+
+TransactionPending ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ ...
+ }
+
+TransactionReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ immAckRequired NULL OPTIONAL,
+ transactionResult CHOICE
+ {
+ transactionError ErrorDescriptor,
+ actionReplies SEQUENCE OF ActionReply
+ },
+ ...,
+ segmentNumber SegmentNumber OPTIONAL,
+ segmentationComplete NULL OPTIONAL
+ }
+
+SegmentReply ::= SEQUENCE
+ {
+ transactionId TransactionId,
+ segmentNumber SegmentNumber,
+ segmentationComplete NULL OPTIONAL,
+ ...
+ }
+
+SegmentNumber ::= INTEGER(0..65535)
+
+TransactionResponseAck ::= SEQUENCE OF TransactionAck
+TransactionAck ::= SEQUENCE
+ {
+ firstAck TransactionId,
+ lastAck TransactionId OPTIONAL
+ }
+
+ErrorDescriptor ::= SEQUENCE
+ {
+ errorCode ErrorCode,
+ errorText ErrorText OPTIONAL
+ }
+
+ErrorCode ::= INTEGER(0..65535)
+-- See clause 14 for IANA considerations with respect to error codes
+ErrorText ::= IA5String
+
+ContextID ::= INTEGER(0..4294967295)
+-- Context NULL Value: 0
+-- Context CHOOSE Value: 4294967294 (0xFFFFFFFE)
+-- Context ALL Value: 4294967295 (0xFFFFFFFF)
+
+
+ActionRequest ::= SEQUENCE
+ {
+ contextId ContextID,
+ contextRequest ContextRequest OPTIONAL,
+ contextAttrAuditReq ContextAttrAuditRequest OPTIONAL,
+ commandRequests SEQUENCE OF CommandRequest
+ }
+
+ActionReply ::= SEQUENCE
+ {
+ contextId ContextID,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ contextReply ContextRequest OPTIONAL,
+ commandReply SEQUENCE OF CommandReply
+ }
+
+ContextRequest ::= SEQUENCE
+ {
+ priority INTEGER(0..15) OPTIONAL,
+ emergency BOOLEAN OPTIONAL,
+ topologyReq SEQUENCE OF TopologyRequest OPTIONAL,
+ ...,
+ iepscallind BOOLEAN OPTIONAL,
+ contextProp SEQUENCE OF PropertyParm OPTIONAL,
+ contextList SEQUENCE OF ContextID OPTIONAL
+ }
+-- When returning a contextList, the contextId in the ActionReply
+-- construct will return the contextId from the associated ActionRequest.
+
+ContextAttrAuditRequest ::= SEQUENCE
+ {
+ topology NULL OPTIONAL,
+ emergency NULL OPTIONAL,
+ priority NULL OPTIONAL,
+ ...,
+ iepscallind NULL OPTIONAL,
+ contextPropAud SEQUENCE OF IndAudPropertyParm OPTIONAL,
+
+ selectpriority INTEGER(0..15) OPTIONAL,
+ -- to select given priority
+
+ selectemergency BOOLEAN OPTIONAL,
+ -- to select if emergency set/not set (T/F)
+
+ selectiepscallind BOOLEAN OPTIONAL,
+ -- to select if IEPS set/not set (T/F)
+
+ selectLogic SelectLogic OPTIONAL -- default is AND
+ }
+
+SelectLogic ::= CHOICE
+ {
+ andAUDITSelect NULL, -- all selection conditions satisfied
+ orAUDITSelect NULL, -- at least one selection condition satisfied
+ ...
+ }
+
+
+CommandRequest ::= SEQUENCE
+ {
+ command Command,
+ optional NULL OPTIONAL,
+ wildcardReturn NULL OPTIONAL,
+ ...
+ }
+
+Command ::= CHOICE
+ {
+ addReq AmmRequest,
+ moveReq AmmRequest,
+ modReq AmmRequest,
+ -- Add, Move, Modify requests have the same parameters
+ subtractReq SubtractRequest,
+ auditCapRequest AuditRequest,
+ auditValueRequest AuditRequest,
+ notifyReq NotifyRequest,
+ serviceChangeReq ServiceChangeRequest,
+ ...
+ }
+
+CommandReply ::= CHOICE
+ {
+ addReply AmmsReply,
+ moveReply AmmsReply,
+ modReply AmmsReply,
+ subtractReply AmmsReply,
+ -- Add, Move, Modify, Subtract replies have the same parameters
+ auditCapReply AuditReply,
+ auditValueReply AuditReply,
+ notifyReply NotifyReply,
+ serviceChangeReply ServiceChangeReply,
+ ...
+ }
+
+TopologyRequest ::= SEQUENCE
+ {
+ terminationFrom TerminationID,
+ terminationTo TerminationID,
+ topologyDirection ENUMERATED
+ {
+ bothway(0),
+ isolate(1),
+ oneway(2)
+ },
+ ...,
+ streamID StreamID OPTIONAL,
+ topologyDirectionExtension ENUMERATED
+ {
+ onewayexternal(0),
+ onewayboth(1),
+ ...
+ } OPTIONAL
+ -- This is not according to the standard, but without it
+ -- the TopologyRequest will be useless since topologyDirection
+ -- and topologyDirectionExtension are contradictory.
+ }
+
+AmmRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ descriptors SEQUENCE OF AmmDescriptor,
+ -- At most one descriptor of each type (see AmmDescriptor)
+ -- allowed in the sequence.
+ ...
+ }
+
+AmmDescriptor ::= CHOICE
+ {
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ auditDescriptor AuditDescriptor,
+ ...,
+ statisticsDescriptor StatisticsDescriptor
+ }
+
+
+AmmsReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ terminationAudit TerminationAudit OPTIONAL,
+ ...
+ }
+
+SubtractRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ auditDescriptor AuditDescriptor OPTIONAL,
+ ...
+ }
+
+AuditRequest ::= SEQUENCE
+ {
+ terminationID TerminationID,
+ auditDescriptor AuditDescriptor,
+ ...,
+ terminationIDList TerminationIDList OPTIONAL
+ }
+-- terminationID shall contain the first termination in the
+-- list when using the terminationIDList construct in AuditRequest
+
+AuditReply ::= CHOICE
+ {
+ contextAuditResult TerminationIDList,
+ error ErrorDescriptor,
+ auditResult AuditResult,
+ ...,
+ auditResultTermList TermListAuditResult
+ }
+
+AuditResult ::= SEQUENCE
+ {
+
+ terminationID TerminationID,
+ terminationAuditResult TerminationAudit
+ }
+
+TermListAuditResult ::= SEQUENCE
+ {
+ terminationIDList TerminationIDList,
+ terminationAuditResult TerminationAudit,
+ ...
+ }
+
+TerminationAudit ::= SEQUENCE OF AuditReturnParameter
+
+AuditReturnParameter ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ mediaDescriptor MediaDescriptor,
+ modemDescriptor ModemDescriptor,
+ muxDescriptor MuxDescriptor,
+ eventsDescriptor EventsDescriptor,
+ eventBufferDescriptor EventBufferDescriptor,
+ signalsDescriptor SignalsDescriptor,
+ digitMapDescriptor DigitMapDescriptor,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ statisticsDescriptor StatisticsDescriptor,
+ packagesDescriptor PackagesDescriptor,
+ emptyDescriptors AuditDescriptor,
+ ...
+ }
+
+AuditDescriptor ::= SEQUENCE
+ {
+ auditToken BIT STRING
+ {
+ muxToken(0), modemToken(1), mediaToken(2),
+ eventsToken(3), signalsToken(4),
+ digitMapToken(5), statsToken(6),
+ observedEventsToken(7),
+ packagesToken(8), eventBufferToken(9)
+ } OPTIONAL,
+ ...,
+ auditPropertyToken SEQUENCE OF IndAuditParameter OPTIONAL
+ }
+
+
+IndAuditParameter ::= CHOICE
+ {
+ -- Note that the lower/upper case letters of the tags have
+ -- been changed. The same changes has been made in text...
+ indAudMediaDescriptor IndAudMediaDescriptor,
+ indAudEventsDescriptor IndAudEventsDescriptor,
+ indAudEventBufferDescriptor IndAudEventBufferDescriptor,
+ indAudSignalsDescriptor IndAudSignalsDescriptor,
+ indAudDigitMapDescriptor IndAudDigitMapDescriptor,
+ indAudStatisticsDescriptor IndAudStatisticsDescriptor,
+ indAudPackagesDescriptor IndAudPackagesDescriptor,
+ ...
+ }
+
+IndAudMediaDescriptor ::= SEQUENCE
+ {
+
+ termStateDescr IndAudTerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream IndAudStreamParms,
+ multiStream SEQUENCE OF IndAudStreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+IndAudStreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms IndAudStreamParms
+ }
+
+IndAudStreamParms ::= SEQUENCE
+ {
+ localControlDescriptor IndAudLocalControlDescriptor OPTIONAL,
+ localDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor IndAudLocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor IndAudStatisticsDescriptor OPTIONAL
+ }
+
+IndAudLocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode NULL OPTIONAL,
+ reserveValue NULL OPTIONAL,
+ reserveGroup NULL OPTIONAL,
+ propertyParms SEQUENCE OF IndAudPropertyParm OPTIONAL,
+ ...,
+ streamModeSel StreamMode OPTIONAL
+ -- must not have both streamMode and streamModeSel
+ -- if both are present only streamModeSel shall be honoured
+ }
+
+IndAudPropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ ...,
+ propertyParms PropertyParm OPTIONAL
+ }
+-- to select based on property values
+-- AND/OR selection logic is specified at context level
+
+IndAudLocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGroupID INTEGER(0..65535) OPTIONAL,
+ propGrps IndAudPropertyGroup,
+ ...
+ }
+
+IndAudPropertyGroup ::= SEQUENCE OF IndAudPropertyParm
+
+IndAudTerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF IndAudPropertyParm,
+ eventBufferControl NULL OPTIONAL,
+ serviceState NULL OPTIONAL,
+ ...,
+ serviceStateSel ServiceState OPTIONAL
+ -- must not have both serviceState and serviceStateSel
+ -- if both are present only serviceStateSel shall be honoured
+ }
+
+IndAudEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudEventBufferDescriptor ::= SEQUENCE
+ {
+ eventName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...
+ }
+
+IndAudSignalsDescriptor ::=CHOICE
+ {
+ signal IndAudSignal,
+ seqSigList IndAudSeqSigList,
+ ...
+ }
+
+IndAudSeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList IndAudSignal OPTIONAL
+ }
+
+IndAudSignal ::= SEQUENCE
+ {
+ signalName PkgdName,
+ streamID StreamID OPTIONAL,
+ ...,
+ signalRequestID RequestID OPTIONAL
+ }
+
+IndAudDigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL
+ }
+
+IndAudStatisticsDescriptor ::= SEQUENCE
+ {
+ statName PkgdName
+ }
+
+IndAudPackagesDescriptor ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+NotifyRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ observedEventsDescriptor ObservedEventsDescriptor,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ errorDescriptor ErrorDescriptor OPTIONAL,
+ ...
+ }
+
+ObservedEventsDescriptor ::= SEQUENCE
+ {
+ requestId RequestID,
+ observedEventLst SEQUENCE OF ObservedEvent
+ }
+
+ObservedEvent ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ timeNotation TimeNotation OPTIONAL,
+ ...
+ }
+
+EventName ::= PkgdName
+
+EventParameter ::= SEQUENCE
+ {
+ eventParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+
+ }
+
+ServiceChangeRequest ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeParms ServiceChangeParm,
+ ...
+ }
+
+ServiceChangeReply ::= SEQUENCE
+ {
+ terminationID TerminationIDList,
+ serviceChangeResult ServiceChangeResult,
+ ...
+ }
+
+-- For ServiceChangeResult, no parameters are mandatory. Hence the
+-- distinction between ServiceChangeParm and ServiceChangeResParm.
+ServiceChangeResult ::= CHOICE
+ {
+ errorDescriptor ErrorDescriptor,
+ serviceChangeResParms ServiceChangeResParm
+ }
+
+WildcardField ::= OCTET STRING(SIZE(1))
+
+TerminationID ::= SEQUENCE
+ {
+ wildcard SEQUENCE OF WildcardField,
+ id OCTET STRING(SIZE(1..8)),
+ ...
+ }
+-- See A.1 for explanation of wildcarding mechanism.
+-- Termination ID 0xFFFFFFFFFFFFFFFF indicates the ROOT Termination.
+
+TerminationIDList ::= SEQUENCE OF TerminationID
+
+MediaDescriptor ::= SEQUENCE
+ {
+ termStateDescr TerminationStateDescriptor OPTIONAL,
+ streams CHOICE
+ {
+ oneStream StreamParms,
+ multiStream SEQUENCE OF StreamDescriptor
+ } OPTIONAL,
+ ...
+ }
+
+StreamDescriptor ::= SEQUENCE
+ {
+ streamID StreamID,
+ streamParms StreamParms
+ }
+
+StreamParms ::= SEQUENCE
+ {
+ localControlDescriptor LocalControlDescriptor OPTIONAL,
+ localDescriptor LocalRemoteDescriptor OPTIONAL,
+ remoteDescriptor LocalRemoteDescriptor OPTIONAL,
+ ...,
+ statisticsDescriptor StatisticsDescriptor OPTIONAL
+ }
+
+LocalControlDescriptor ::= SEQUENCE
+ {
+ streamMode StreamMode OPTIONAL,
+ reserveValue BOOLEAN OPTIONAL,
+ reserveGroup BOOLEAN OPTIONAL,
+ propertyParms SEQUENCE OF PropertyParm,
+ ...
+ }
+
+StreamMode ::= ENUMERATED
+ {
+ sendOnly(0),
+ recvOnly(1),
+ sendRecv(2),
+ inactive(3),
+ loopBack(4),
+ ...
+ }
+
+-- In PropertyParm, value is a SEQUENCE OF octet string. When sent
+-- by an MGC the interpretation is as follows:
+-- empty sequence means CHOOSE
+-- one element sequence specifies value
+-- If the sublist field is not selected, a longer sequence means
+-- "choose one of the values" (i.e. value1 OR value2 OR ...)
+-- If the sublist field is selected,
+-- a sequence with more than one element encodes the value of a
+-- list-valued property (i.e. value1 AND value2 AND ...).
+-- The relation field may only be selected if the value sequence
+-- has length 1. It indicates that the MG has to choose a value
+-- for the property. E.g. x > 3 (using the greaterThan
+-- value for relation) instructs the MG to choose any value larger
+-- than 3 for property x.
+-- The range field may only be selected if the value sequence
+-- has length 2. It indicates that the MG has to choose a value
+-- in the range between the first octet in the value sequence and
+-- the trailing octet in the value sequence, including the
+-- boundary values.
+-- When sent by the MG, only responses to an AuditCapability request
+-- may contain multiple values, a range, or a relation field.
+
+PropertyParm ::= SEQUENCE
+ {
+ name PkgdName,
+ value SEQUENCE OF OCTET STRING,
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+Name ::= OCTET STRING(SIZE(2))
+
+PkgdName ::= OCTET STRING(SIZE(4))
+-- represents Package Name (2 octets) plus Property, Event,
+-- Signal Names or Statistics ID. (2 octets)
+-- To wildcard a package use 0xFFFF for first two octets, choose
+-- is not allowed. To reference native property tag specified in
+-- Annex C, use 0x0000 as first two octets.
+-- To wildcard a Property, Event, Signal, or Statistics ID, use
+-- 0xFFFF for last two octets, choose is not allowed.
+-- Wildcarding of Package Name is permitted only if Property,
+-- Event, Signal, or Statistics ID are
+-- also wildcarded.
+
+Relation ::= ENUMERATED
+ {
+ greaterThan(0),
+ smallerThan(1),
+ unequalTo(2),
+ ...
+ }
+
+LocalRemoteDescriptor ::= SEQUENCE
+ {
+ propGrps SEQUENCE OF PropertyGroup,
+ ...
+ }
+
+PropertyGroup ::= SEQUENCE OF PropertyParm
+
+TerminationStateDescriptor ::= SEQUENCE
+ {
+ propertyParms SEQUENCE OF PropertyParm,
+ eventBufferControl EventBufferControl OPTIONAL,
+ serviceState ServiceState OPTIONAL,
+ ...
+ }
+
+EventBufferControl ::= ENUMERATED
+ {
+ off(0),
+ lockStep(1),
+ ...
+ }
+
+ServiceState ::= ENUMERATED
+ {
+ test(0),
+ outOfSvc(1),
+ inSvc(2),
+ ...
+ }
+
+MuxDescriptor ::= SEQUENCE
+ {
+ muxType MuxType,
+ termList SEQUENCE OF TerminationID,
+ nonStandardData NonStandardData OPTIONAL,
+ ...
+ }
+
+MuxType ::= ENUMERATED
+ {
+ h221(0),
+ h223(1),
+ h226(2),
+ v76(3),
+ ...,
+ nx64k(4)
+ }
+
+StreamID ::= INTEGER(0..65535) -- 16-bit unsigned integer
+
+EventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ -- RequestID must be present if eventList
+ -- is non empty
+ eventList SEQUENCE OF RequestedEvent,
+ ...
+ }
+
+RequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction RequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+RegulatedEmbeddedDescriptor ::= SEQUENCE
+ {
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...
+ }
+
+NotifyBehaviour ::= CHOICE
+ {
+ notifyImmediate NULL,
+ notifyRegulated RegulatedEmbeddedDescriptor,
+ neverNotify NULL,
+ ...
+ }
+
+RequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ secondEvent SecondEventsDescriptor OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventDM ::= CHOICE
+ {
+ digitMapName DigitMapName,
+ digitMapValue DigitMapValue
+ }
+
+SecondEventsDescriptor ::= SEQUENCE
+ {
+ requestID RequestID OPTIONAL,
+ eventList SEQUENCE OF SecondRequestedEvent,
+ ...
+ }
+
+SecondRequestedEvent ::= SEQUENCE
+ {
+ pkgdName PkgdName,
+ streamID StreamID OPTIONAL,
+ eventAction SecondRequestedActions OPTIONAL,
+ evParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+SecondRequestedActions ::= SEQUENCE
+ {
+ keepActive BOOLEAN OPTIONAL,
+ eventDM EventDM OPTIONAL,
+ signalsDescriptor SignalsDescriptor OPTIONAL,
+ ...,
+ notifyBehaviour NotifyBehaviour OPTIONAL,
+ resetEventsDescriptor NULL OPTIONAL
+ }
+
+EventBufferDescriptor ::= SEQUENCE OF EventSpec
+
+EventSpec ::= SEQUENCE
+ {
+ eventName EventName,
+ streamID StreamID OPTIONAL,
+ eventParList SEQUENCE OF EventParameter,
+ ...
+ }
+
+
+SignalsDescriptor ::= SEQUENCE OF SignalRequest
+
+SignalRequest ::= CHOICE
+ {
+ signal Signal,
+ seqSigList SeqSigList,
+ ...
+ }
+
+SeqSigList ::= SEQUENCE
+ {
+ id INTEGER(0..65535),
+ signalList SEQUENCE OF Signal
+ }
+
+Signal ::= SEQUENCE
+ {
+ signalName SignalName,
+ streamID StreamID OPTIONAL,
+ sigType SignalType OPTIONAL,
+ duration INTEGER (0..65535) OPTIONAL,
+ notifyCompletion NotifyCompletion OPTIONAL,
+ keepActive BOOLEAN OPTIONAL,
+ sigParList SEQUENCE OF SigParameter,
+ ...,
+ direction SignalDirection OPTIONAL,
+ requestID RequestID OPTIONAL,
+ intersigDelay INTEGER (0..65535) OPTIONAL
+ }
+
+SignalType ::= ENUMERATED
+ {
+ brief(0),
+ onOff(1),
+ timeOut(2),
+ ...
+ }
+
+SignalDirection ::= ENUMERATED
+ {
+ internal(0),
+ external(1),
+ both(3),
+ ...
+ }
+
+SignalName ::= PkgdName
+
+NotifyCompletion ::= BIT STRING
+ {
+ onTimeOut(0), onInterruptByEvent(1),
+ onInterruptByNewSignalDescr(2), otherReason(3), onIteration(4)
+ }
+
+SigParameter ::= SEQUENCE
+ {
+ sigParameterName Name,
+ value Value,
+ -- For use of extraInfo see the comment related to PropertyParm
+ extraInfo CHOICE
+ {
+ relation Relation,
+ range BOOLEAN,
+ sublist BOOLEAN
+ } OPTIONAL,
+ ...
+ }
+
+-- For an AuditCapReply with all events, the RequestID SHALL be ALL.
+-- ALL is represented by 0xffffffff.
+RequestID ::= INTEGER(0..4294967295) -- 32-bit unsigned integer
+
+ModemDescriptor ::= SEQUENCE
+ {
+ mtl SEQUENCE OF ModemType,
+ mpl SEQUENCE OF PropertyParm,
+ nonStandardData NonStandardData OPTIONAL
+ }
+
+ModemType ::= ENUMERATED
+ {
+ v18(0),
+ v22(1),
+ v22bis(2),
+ v32(3),
+ v32bis(4),
+ v34(5),
+ v90(6),
+ v91(7),
+ synchISDN(8),
+ ...
+ }
+
+DigitMapDescriptor ::= SEQUENCE
+ {
+ digitMapName DigitMapName OPTIONAL,
+ digitMapValue DigitMapValue OPTIONAL
+ }
+
+DigitMapName ::= Name
+
+DigitMapValue ::= SEQUENCE
+ {
+ startTimer INTEGER(0..99) OPTIONAL,
+ shortTimer INTEGER(0..99) OPTIONAL,
+ longTimer INTEGER(0..99) OPTIONAL,
+ digitMapBody IA5String,
+ -- Units are seconds for start, short and long timers, and
+ -- hundreds of milliseconds for duration timer. Thus start,
+ -- short, and long range from 1 to 99 seconds and duration
+ -- from 100 ms to 9.9 s
+ -- See A.3 for explanation of digit map syntax
+ ...,
+ durationTimer INTEGER (0..99) OPTIONAL
+ }
+
+ServiceChangeParm ::= SEQUENCE
+ {
+ serviceChangeMethod ServiceChangeMethod,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ serviceChangeReason Value,
+ -- A serviceChangeReason consists of a numeric reason code
+ -- and an optional text description.
+ -- The serviceChangeReason SHALL be a string consisting of
+ -- a decimal reason code, optionally followed by a single
+ -- space character and a textual description string.
+ -- This string is first BER-encoded as an IA5String.
+ -- The result of this BER-encoding is then encoded as
+ -- an ASN.1 OCTET STRING type, "double wrapping" the
+ -- value
+ -- as was done for package elements.
+ serviceChangeDelay INTEGER(0..4294967295) OPTIONAL,
+ -- 32-bit unsigned integer
+ serviceChangeMgcId MId OPTIONAL,
+ timeStamp TimeNotation OPTIONAL,
+ nonStandardData NonStandardData OPTIONAL,
+ ...,
+ serviceChangeInfo AuditDescriptor OPTIONAL,
+ serviceChangeIncompleteFlag NULL OPTIONAL
+ }
+
+ServiceChangeAddress ::= CHOICE
+ {
+ portNumber INTEGER(0..65535), -- TCP/UDP port number
+ ip4Address IP4Address,
+ ip6Address IP6Address,
+ domainName DomainName,
+ deviceName PathName,
+ mtpAddress OCTET STRING(SIZE(2..4)),
+ ...
+ }
+
+ServiceChangeResParm ::= SEQUENCE
+ {
+ serviceChangeMgcId MId OPTIONAL,
+ serviceChangeAddress ServiceChangeAddress OPTIONAL,
+ serviceChangeVersion INTEGER(0..99) OPTIONAL,
+ serviceChangeProfile ServiceChangeProfile OPTIONAL,
+ timestamp TimeNotation OPTIONAL,
+ ...
+ }
+
+ServiceChangeMethod ::= ENUMERATED
+ {
+ failover(0),
+ forced(1),
+ graceful(2),
+ restart(3),
+ disconnected(4),
+ handOff(5),
+ ...
+ }
+
+ServiceChangeProfile ::= SEQUENCE
+ {
+ profileName IA5String(SIZE (1..67))
+
+ -- 64 characters for name, 1 for "/", 2 for version to match ABNF
+ }
+
+PackagesDescriptor ::= SEQUENCE OF PackagesItem
+
+PackagesItem ::= SEQUENCE
+ {
+ packageName Name,
+ packageVersion INTEGER(0..99),
+ ...
+ }
+
+StatisticsDescriptor ::= SEQUENCE OF StatisticsParameter
+
+StatisticsParameter ::= SEQUENCE
+ {
+ statName PkgdName,
+ statValue Value OPTIONAL
+ }
+
+-- If statistic consists of a sub-list there will be more than one
+-- octetstring in statValue.
+
+NonStandardData ::= SEQUENCE
+ {
+ nonStandardIdentifier NonStandardIdentifier,
+ data OCTET STRING
+ }
+
+NonStandardIdentifier ::= CHOICE
+ {
+ object OBJECT IDENTIFIER,
+ h221NonStandard H221NonStandard,
+ experimental IA5String(SIZE(8)),
+ -- first two characters SHOULD be "X-" or "X+"
+ ...
+ }
+
+H221NonStandard ::= SEQUENCE
+ { t35CountryCode1 INTEGER(0..255),
+ t35CountryCode2 INTEGER(0..255), -- country, as per T.35
+ t35Extension INTEGER(0..255), -- assigned nationally
+ manufacturerCode INTEGER(0..65535), -- assigned nationally
+ ...
+ }
+
+TimeNotation ::= SEQUENCE
+ {
+ date IA5String(SIZE(8)), -- yyyymmdd format
+ time IA5String(SIZE(8)) -- hhmmssss format
+ -- per ISO 8601:1988
+ }
+
+Value ::= SEQUENCE OF OCTET STRING
+
+END
diff --git a/lib/megaco/src/binary/Makefile b/lib/megaco/src/binary/Makefile
new file mode 100644
index 0000000000..d594f34f43
--- /dev/null
+++ b/lib/megaco/src/binary/Makefile
@@ -0,0 +1,212 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+MEGACO_ENGINEDIR = ../engine
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ASN1_SPECS = $(ASN1_V1_SPEC) \
+ $(ASN1_V2_SPEC) \
+ $(ASN1_PREV3A_SPEC)
+ASN1_FILES = $(ASN1_SPECS:%=%.asn)
+
+V1_SPECS = $(BER_ASN1_V1_SPEC) \
+ $(BER_BIN_ASN1_V1_SPEC) \
+ $(BER_BIN_DRV_ASN1_V1_SPEC) \
+ $(PER_ASN1_V1_SPEC) \
+ $(PER_BIN_ASN1_V1_SPEC) \
+ $(PER_BIN_DRV_ASN1_V1_SPEC)
+
+V2_SPECS = $(BER_ASN1_V2_SPEC) \
+ $(BER_BIN_ASN1_V2_SPEC) \
+ $(BER_BIN_DRV_ASN1_V2_SPEC) \
+ $(PER_ASN1_V2_SPEC) \
+ $(PER_BIN_ASN1_V2_SPEC) \
+ $(PER_BIN_DRV_ASN1_V2_SPEC)
+
+PREV3A_SPECS = $(BER_ASN1_PREV3A_SPEC) \
+ $(BER_BIN_ASN1_PREV3A_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC) \
+ $(PER_ASN1_PREV3A_SPEC) \
+ $(PER_BIN_ASN1_PREV3A_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC)
+
+PREV3B_SPECS = $(BER_ASN1_PREV3B_SPEC) \
+ $(BER_BIN_ASN1_PREV3B_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC) \
+ $(PER_ASN1_PREV3B_SPEC) \
+ $(PER_BIN_ASN1_PREV3B_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC)
+
+PREV3C_SPECS = $(BER_ASN1_PREV3C_SPEC) \
+ $(BER_BIN_ASN1_PREV3C_SPEC) \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC) \
+ $(PER_ASN1_PREV3C_SPEC) \
+ $(PER_BIN_ASN1_PREV3C_SPEC) \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC)
+
+V3_SPECS = $(BER_ASN1_V3_SPEC) \
+ $(BER_BIN_ASN1_V3_SPEC) \
+ $(BER_BIN_DRV_ASN1_V3_SPEC) \
+ $(PER_ASN1_V3_SPEC) \
+ $(PER_BIN_ASN1_V3_SPEC) \
+ $(PER_BIN_DRV_ASN1_V3_SPEC) \
+ $(PREV3A_SPECS) $(PREV3B_SPECS) $(PREV3C_SPECS)
+
+SPECS = $(V1_SPECS) $(V2_SPECS) $(V3_SPECS)
+
+V1_SPEC_ASN1DB = $(V1_SPECS:%=%.asn1db)
+V2_SPEC_ASN1DB = $(V2_SPECS:%=%.asn1db)
+PREV3A_SPEC_ASN1DB = $(PREV3A_SPECS:%=%.asn1db)
+PREV3B_SPEC_ASN1DB = $(PREV3B_SPECS:%=%.asn1db)
+PREV3C_SPEC_ASN1DB = $(PREV3C_SPECS:%=%.asn1db)
+V3_SPEC_ASN1DB = $(V3_SPECS:%=%.asn1db) \
+ $(PREV3A_SPEC_ASN1DB) \
+ $(PREV3B_SPEC_ASN1DB) \
+ $(PREV3C_SPEC_ASN1DB)
+SPEC_ASN1DB = $(V1_SPEC_ASN1DB) \
+ $(V2_SPEC_ASN1DB)\
+ $(V3_SPEC_ASN1DB)
+
+V1_SPEC_BINS = $(V1_SPECS:%=%.erl) $(V1_SPECS:%=%.hrl)
+V2_SPEC_BINS = $(V2_SPECS:%=%.erl) $(V2_SPECS:%=%.hrl)
+PREV3A_SPEC_BINS = $(PREV3A_SPECS:%=%.erl) $(PREV3A_SPECS:%=%.hrl)
+PREV3B_SPEC_BINS = $(PREV3B_SPECS:%=%.erl) $(PREV3B_SPECS:%=%.hrl)
+PREV3C_SPEC_BINS = $(PREV3C_SPECS:%=%.erl) $(PREV3C_SPECS:%=%.hrl)
+V3_SPEC_BINS = $(V3_SPECS:%=%.erl) $(V3_SPECS:%=%.hrl) \
+ $(PREV3A_SPEC_BINS) \
+ $(PREV3B_SPEC_BINS) \
+ $(PREV3C_SPEC_BINS)
+SPEC_BINS = $(V1_SPEC_BINS) $(V2_SPEC_BINS) $(V3_SPEC_BINS)
+
+ERL_FILES = $(MODULES:%=%.erl)
+HRL_FILES = $(INTERNAL_HRL_FILES) \
+ $(V1_SPECS:%=%.hrl) \
+ $(V2_SPECS:%=%.hrl) \
+ $(V3_SPECS:%=%.hrl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: prebuild $(TARGET_FILES)
+
+prebuild: prebuild.skip
+
+prebuild.skip:
+ @echo "Building prebuild.skip\c"
+ @touch prebuild.skip
+ @for a in $(SPEC_ASN1DB); do \
+ echo $$a >> prebuild.skip; \
+ done
+ @echo ""
+
+v1: $(V2_SPEC_BINS)
+
+v2: $(V2_SPEC_BINS)
+
+v3: $(V3_SPEC_BINS)
+
+specs: v1 v2 v3
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f $(SPEC_BINS)
+ rm -f $(SPEC_ASN1DB)
+ rm -f prebuild.skip
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "MODULES: $(MODULES)"
+ @echo "ERL_FILES: $(ERL_FILES)"
+ @echo "HRL_FILES: $(HRL_FILES)"
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo "ASN1_SPECS: $(ASN1_SPECS)"
+ @echo "SPECS: $(SPECS)"
+ @echo "SPEC_BINS: $(SPEC_BINS)"
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/binary
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(ASN1_FILES) $(RELSYSDIR)/src/binary
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk
new file mode 100644
index 0000000000..5ec4977175
--- /dev/null
+++ b/lib/megaco/src/binary/depend.mk
@@ -0,0 +1,557 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+# Flag description:
+#
+# +optimize
+# For ber_bin this means "optimize" (whatever that is),
+# but for per_bin it means that a stage in the encode
+# is done in the asn1 driver.
+#
+# +driver
+# For ber_bin this means that part of the decode is done
+# in the asn1 driver.
+#
+# +asn1config
+# This is only used by the ber_bin, and means that
+# some partial decode functions will be created
+# (as described by the asn1config file).
+#
+# +inline
+# This means that the ASN.1 runtime library will be inlined.
+#
+
+ASN1_CT_OPTS += +noobj
+ifeq ($(MEGACO_INLINE_ASN1_RT),true)
+# We need atleast version 1.4.6 of the ANS.1 application
+ASN1_CT_OPTS += +inline
+endif
+
+BER_V1_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_V2_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_V3_FLAGS = $(ASN1_CT_OPTS)
+BER_BIN_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
+BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+PER_V1_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V1_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_V2_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V2_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +optimize
+PER_V3_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_V3_FLAGS = $(ASN1_CT_OPTS)
+PER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +optimize
+
+
+# --- Version 1 ---
+
+$(BER_ASN1_V1_SPEC).erl $(BER_ASN1_V1_SPEC).hrl: \
+ $(BER_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_ASN1_V1_SPEC):"
+ $(ERLC) -bber $(BER_V1_FLAGS) $(BER_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V1_SPEC).erl \
+ $(BER_ASN1_V1_SPEC).hrl
+
+$(BER_BIN_ASN1_V1_SPEC).erl $(BER_BIN_ASN1_V1_SPEC).hrl: \
+ $(BER_BIN_ASN1_V1_SPEC).set.asn \
+ $(BER_BIN_ASN1_V1_SPEC).asn1config \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V1_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V1_FLAGS) $(BER_BIN_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V1_SPEC).erl \
+ $(BER_BIN_ASN1_V1_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V1_SPEC).erl $(BER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).asn1config \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V1_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V1_FLAGS) $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V1_SPEC).hrl
+
+$(PER_ASN1_V1_SPEC).erl $(PER_ASN1_V1_SPEC).hrl: \
+ $(PER_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_ASN1_V1_SPEC):"
+ $(ERLC) -bper $(PER_V1_FLAGS) $(PER_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V1_SPEC).erl \
+ $(PER_ASN1_V1_SPEC).hrl
+
+$(PER_BIN_ASN1_V1_SPEC).erl $(PER_BIN_ASN1_V1_SPEC).hrl: \
+ $(PER_BIN_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V1_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V1_FLAGS) $(PER_BIN_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V1_SPEC).erl \
+ $(PER_BIN_ASN1_V1_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V1_SPEC).erl $(PER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn \
+ $(ASN1_V1_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V1_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V1_FLAGS) $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V1_SPEC).hrl
+
+
+# --- Version 2 ---
+
+$(BER_ASN1_V2_SPEC).erl $(BER_ASN1_V2_SPEC).hrl: \
+ $(BER_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_ASN1_V2_SPEC):"
+ $(ERLC) -bber $(BER_V2_FLAGS) $(BER_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V2_SPEC).erl \
+ $(BER_ASN1_V2_SPEC).hrl
+
+$(BER_BIN_ASN1_V2_SPEC).erl $(BER_BIN_ASN1_V2_SPEC).hrl: \
+ $(BER_BIN_ASN1_V2_SPEC).set.asn \
+ $(BER_BIN_ASN1_V2_SPEC).asn1config \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V2_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V2_FLAGS) $(BER_BIN_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V2_SPEC).erl \
+ $(BER_BIN_ASN1_V2_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V2_SPEC).erl $(BER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).asn1config \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V2_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V2_FLAGS) $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V2_SPEC).hrl
+
+$(PER_ASN1_V2_SPEC).erl $(PER_ASN1_V2_SPEC).hrl: \
+ $(PER_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_ASN1_V2_SPEC):"
+ $(ERLC) -bper $(PER_V2_FLAGS) $(PER_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V2_SPEC).erl \
+ $(PER_ASN1_V2_SPEC).hrl
+
+$(PER_BIN_ASN1_V2_SPEC).erl $(PER_BIN_ASN1_V2_SPEC).hrl: \
+ $(PER_BIN_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V2_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V2_FLAGS) $(PER_BIN_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V2_SPEC).erl \
+ $(PER_BIN_ASN1_V2_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V2_SPEC).erl $(PER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn \
+ $(ASN1_V2_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V2_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V2_FLAGS) $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V2_SPEC).hrl
+
+
+# --- Version 3 ---
+
+# -- (prev3a) --
+
+$(BER_ASN1_PREV3A_SPEC).erl $(BER_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber $(BER_PREV3A_FLAGS) $(BER_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3A_SPEC).erl \
+ $(BER_ASN1_PREV3A_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3A_SPEC).erl $(BER_BIN_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3A_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3A_SPEC).asn1config \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3A_FLAGS) $(BER_BIN_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3A_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3A_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).asn1config \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3A_FLAGS) $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+
+$(PER_ASN1_PREV3A_SPEC).erl $(PER_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper $(PER_PREV3A_FLAGS) $(PER_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3A_SPEC).erl \
+ $(PER_ASN1_PREV3A_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3A_SPEC).erl $(PER_BIN_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3A_FLAGS) $(PER_BIN_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3A_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3A_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
+ $(ASN1_PREV3A_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3A_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3A_FLAGS) $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+
+# -- (prev3b) --
+
+$(BER_ASN1_PREV3B_SPEC).erl $(BER_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber $(BER_PREV3B_FLAGS) $(BER_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3B_SPEC).erl \
+ $(BER_ASN1_PREV3B_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3B_SPEC).erl $(BER_BIN_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3B_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3B_SPEC).asn1config \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3B_FLAGS) $(BER_BIN_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3B_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3B_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).asn1config \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3B_FLAGS) $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+
+$(PER_ASN1_PREV3B_SPEC).erl $(PER_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper $(PER_PREV3B_FLAGS) $(PER_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3B_SPEC).erl \
+ $(PER_ASN1_PREV3B_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3B_SPEC).erl $(PER_BIN_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3B_FLAGS) $(PER_BIN_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3B_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3B_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
+ $(ASN1_PREV3B_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3B_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3B_FLAGS) $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+
+
+# -- (prev3c) --
+
+$(BER_ASN1_PREV3C_SPEC).erl $(BER_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber $(BER_PREV3C_FLAGS) $(BER_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_ASN1_PREV3C_SPEC).erl \
+ $(BER_ASN1_PREV3C_SPEC).hrl
+
+$(BER_BIN_ASN1_PREV3C_SPEC).erl $(BER_BIN_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_BIN_ASN1_PREV3C_SPEC).set.asn \
+ $(BER_BIN_ASN1_PREV3C_SPEC).asn1config \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_BIN_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_PREV3C_FLAGS) $(BER_BIN_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_PREV3C_SPEC).erl \
+ $(BER_BIN_ASN1_PREV3C_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).asn1config \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_PREV3C_FLAGS) $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+
+$(PER_ASN1_PREV3C_SPEC).erl $(PER_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper $(PER_PREV3C_FLAGS) $(PER_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_ASN1_PREV3C_SPEC).erl \
+ $(PER_ASN1_PREV3C_SPEC).hrl
+
+$(PER_BIN_ASN1_PREV3C_SPEC).erl $(PER_BIN_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_BIN_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_BIN_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_PREV3C_FLAGS) $(PER_BIN_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_PREV3C_SPEC).erl \
+ $(PER_BIN_ASN1_PREV3C_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
+ $(ASN1_PREV3C_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_PREV3C_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_PREV3C_FLAGS) $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+
+
+# -- (v3) --
+
+$(BER_ASN1_V3_SPEC).erl $(BER_ASN1_V3_SPEC).hrl: \
+ $(BER_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_ASN1_V3_SPEC):"
+ $(ERLC) -bber $(BER_V3_FLAGS) $(BER_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_ASN1_V3_SPEC).erl \
+ $(BER_ASN1_V3_SPEC).hrl
+
+$(BER_BIN_ASN1_V3_SPEC).erl $(BER_BIN_ASN1_V3_SPEC).hrl: \
+ $(BER_BIN_ASN1_V3_SPEC).set.asn \
+ $(BER_BIN_ASN1_V3_SPEC).asn1config \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_BIN_ASN1_V3_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_V3_FLAGS) $(BER_BIN_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_BIN_ASN1_V3_SPEC).erl \
+ $(BER_BIN_ASN1_V3_SPEC).hrl
+
+$(BER_BIN_DRV_ASN1_V3_SPEC).erl $(BER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).asn1config \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(BER_BIN_DRV_ASN1_V3_SPEC):"
+ $(ERLC) -bber_bin $(BER_BIN_DRV_V3_FLAGS) $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(BER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).erl \
+ $(BER_BIN_DRV_ASN1_V3_SPEC).hrl
+
+$(PER_ASN1_V3_SPEC).erl $(PER_ASN1_V3_SPEC).hrl: \
+ $(PER_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_ASN1_V3_SPEC):"
+ $(ERLC) -bper $(PER_V3_FLAGS) $(PER_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_ASN1_V3_SPEC).erl \
+ $(PER_ASN1_V3_SPEC).hrl
+
+$(PER_BIN_ASN1_V3_SPEC).erl $(PER_BIN_ASN1_V3_SPEC).hrl: \
+ $(PER_BIN_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_BIN_ASN1_V3_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_V3_FLAGS) $(PER_BIN_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_BIN_ASN1_V3_SPEC).erl \
+ $(PER_BIN_ASN1_V3_SPEC).hrl
+
+$(PER_BIN_DRV_ASN1_V3_SPEC).erl $(PER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn \
+ $(ASN1_V3_SPEC).asn
+ @echo "$(PER_BIN_DRV_ASN1_V3_SPEC):"
+ $(ERLC) -bper_bin $(PER_BIN_DRV_V3_FLAGS) $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn
+
+$(EBIN)/$(PER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).erl \
+ $(PER_BIN_DRV_ASN1_V3_SPEC).hrl
+
+
+# -------------
+
+$(EBIN)/megaco_ber_encoder.$(EMULATOR): megaco_ber_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_ber_bin_encoder.$(EMULATOR): megaco_ber_bin_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_per_encoder.$(EMULATOR): megaco_per_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_per_bin_encoder.$(EMULATOR): megaco_per_bin_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_encoder_lib.$(EMULATOR): megaco_binary_encoder_lib.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_encoder.$(EMULATOR): megaco_binary_encoder.erl \
+ $(MEGACO_ENGINEDIR)/megaco_message_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v1.$(EMULATOR): \
+ megaco_binary_name_resolver_v1.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v2.$(EMULATOR): \
+ megaco_binary_name_resolver_v2.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3a.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3a.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3b.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3b.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_prev3c.$(EMULATOR): \
+ megaco_binary_name_resolver_prev3c.erl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_binary_name_resolver_v3.$(EMULATOR): \
+ megaco_binary_name_resolver_v3.erl
+
+$(EBIN)/megaco_binary_term_id.$(EMULATOR): megaco_binary_term_id.erl
+
+$(EBIN)/megaco_binary_term_id_gen.$(EMULATOR): megaco_binary_term_id_gen.erl
+
+$(EBIN)/megaco_binary_transformer_v1.$(EMULATOR): \
+ megaco_binary_transformer_v1.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl
+
+$(EBIN)/megaco_binary_transformer_v2.$(EMULATOR): \
+ megaco_binary_transformer_v2.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3a.$(EMULATOR): \
+ megaco_binary_transformer_prev3a.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3b.$(EMULATOR): \
+ megaco_binary_transformer_prev3b.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl
+
+$(EBIN)/megaco_binary_transformer_prev3c.$(EMULATOR): \
+ megaco_binary_transformer_prev3c.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl
+
+$(EBIN)/megaco_binary_transformer_v3.$(EMULATOR): \
+ megaco_binary_transformer_v3.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl
+
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
new file mode 100644
index 0000000000..179473717d
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3a',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
new file mode 100644
index 0000000000..ceda97fbd1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3b',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
new file mode 100644
index 0000000000..d181ef44bd
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_prev3c',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config
new file mode 100644
index 0000000000..ea10a7d527
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.asn1config
@@ -0,0 +1,44 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v1',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
+
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
new file mode 100644
index 0000000000..3d0cb9a019
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v2',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
new file mode 100644
index 0000000000..cc662c0145
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_drv_media_gateway_control_v3',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_encoder.erl b/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
new file mode 100644
index 0000000000..bf9926c7e5
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_encoder.erl
@@ -0,0 +1,716 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_bin_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_bin_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_bin_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_bin_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_bin_media_gateway_control_prev3c).
+-define(V1_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD_DRV, megaco_ber_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% encode_transaction([] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%%encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list).
+%% encode_transaction([] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%%encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list).
+encode_transaction(_EC, _V, _Trans) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+%% encode_action_requests([] = EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([] = EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([] = EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([native] = EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests([driver|EC], 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%%encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_requests(_EC, V, _ActReqs) ->
+%% {error, {bad_version, V}}.
+encode_action_requests(_EC, _V, _ActReqs) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+%% encode_action_request([] = EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 1, ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([] = EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 2, ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([] = EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([native] = EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request([driver|EC], 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+%% encode_action_request(_EC, 3, ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+encode_action_request(_EC, _V, _ActReq) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% -- Dynamic version detection --
+
+%% Select from message
+decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD_DRV, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD_DRV, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD_DRV, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([driver|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD_DRV, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD_DRV, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD_DRV, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([driver|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD_DRV,
+ ?V2_ASN1_MOD_DRV,
+ ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config
new file mode 100644
index 0000000000..456ce750ad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3a',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config
new file mode 100644
index 0000000000..fa5cd80baf
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3b',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
new file mode 100644
index 0000000000..c74422b9a2
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_prev3c',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
new file mode 100644
index 0000000000..e815e90948
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.asn1config
@@ -0,0 +1,44 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v1',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config
new file mode 100644
index 0000000000..cc072b30ee
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v2',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config
new file mode 100644
index 0000000000..deeb2b2da9
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.asn1config
@@ -0,0 +1,43 @@
+{exclusive_decode,
+ {'megaco_ber_bin_media_gateway_control_v3',
+ [
+ {decode_message_trans_partial,
+ [
+ 'MegacoMessage',[{mess,[{messageBody,[{transactions,parts}]}]}]
+ ]
+ },
+ {decode_message_acts_partial,
+ ['Transaction',
+ [
+ {transactionRequest,
+ [
+ {actions,parts}
+ ]
+ },
+ {transactionReply,
+ [
+ {transactionResult, [{actionReplies,parts}]}
+ ]
+ }
+ ]
+ ]
+ },
+ {decode_message_version,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{mId,undecoded},{messageBody,undecoded}]}
+ ]
+ ]
+ },
+ {decode_message_mId,
+ ['MegacoMessage',
+ [
+ {authHeader,undecoded},
+ {mess,[{messageBody,undecoded}]}
+ ]
+ ]
+ }
+ ]
+ }
+}.
diff --git a/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_bin_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_ber_encoder.erl b/lib/megaco/src/binary/megaco_ber_encoder.erl
new file mode 100644
index 0000000000..ff65b5bf81
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_encoder.erl
@@ -0,0 +1,346 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% Not supported for this codec, revert to version 1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD,
+ ?V2_ASN1_MOD,
+ ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
+
+
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_ber_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_binary_encoder.erl b/lib/megaco/src/binary/megaco_binary_encoder.erl
new file mode 100644
index 0000000000..f825f91a45
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_encoder.erl
@@ -0,0 +1,588 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_encoder).
+
+-behaviour(megaco_encoder).
+
+%% API
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction([{version3,_}|EC], 1, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 1, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,_}|EC], 2, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 2, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,v3}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3c}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3b}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction([{version3,prev3a}|EC], 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list);
+encode_transaction(EC, 3, Trans) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([{version3,_}|EC], 1, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,_}|EC], 2, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,v3}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3c}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3b}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests([{version3,prev3a}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list);
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_requests(EC, ActReqs, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3,_}|EC], 1, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 1, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,_}|EC], 2, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 2, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,v3}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3c}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3b}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request([{version3,prev3a}|EC], 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list);
+encode_action_request(EC, 3, ActReq) ->
+ AsnMod = megaco_ber_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:encode_action_request(EC, ActReq, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3c],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3b],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3c],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3b],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+decode_message([{version3,v3},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3c},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3c,
+ megaco_binary_transformer_prev3c}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3b},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3b,
+ megaco_binary_transformer_prev3b}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3a},driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_prev3a,
+ megaco_binary_transformer_prev3a}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([driver|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3c,
+ megaco_binary_transformer_prev3c}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3b,
+ megaco_binary_transformer_prev3b}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_prev3a,
+ megaco_binary_transformer_prev3a}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+decode_message(EC, dynamic, Binary) ->
+ Decoders = [{megaco_ber_bin_media_gateway_control_v1,
+ megaco_binary_transformer_v1},
+ {megaco_ber_bin_media_gateway_control_v2,
+ megaco_binary_transformer_v2},
+ {megaco_ber_bin_media_gateway_control_v3,
+ megaco_binary_transformer_v3}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Decoders, binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 1, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ TransMod = megaco_binary_transformer_v1,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 2, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ TransMod = megaco_binary_transformer_v2,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ TransMod = megaco_binary_transformer_prev3c,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ TransMod = megaco_binary_transformer_prev3b,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ TransMod = megaco_binary_transformer_prev3a,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message(EC, 3, Binary) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ TransMod = megaco_binary_transformer_v3,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message([{version3,v3},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3c],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3b],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a},driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([driver|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3c],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3b],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_v3],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_},driver|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v1,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+
+decode_mini_message([{version3,_},driver|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v2,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+
+decode_mini_message([{version3,v3},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3c,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3b,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a},driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_prev3a,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([driver|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_drv_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3c,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3b,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_prev3a,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = megaco_ber_bin_media_gateway_control_v3,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
+
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_encoder_lib.erl b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
new file mode 100644
index 0000000000..842d6b70d1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_encoder_lib.erl
@@ -0,0 +1,317 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_encoder_lib).
+
+%% API
+-export([
+ version_of/4,
+ decode_message/5, decode_message_dynamic/4,
+ decode_mini_message/4, decode_mini_message_dynamic/4,
+ encode_message/5,
+ encode_transaction/5,
+ encode_action_requests/5,
+ encode_action_request/5,
+ encode_action_reply/5
+ ]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(_EC, Binary, dynamic, [AsnModV1|_AsnMods])
+ when is_binary(Binary) andalso is_atom(AsnModV1) ->
+ case (catch AsnModV1:decode_message_version(Binary)) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Error ->
+ Error
+ end;
+version_of(_EC, Binary, 1, AsnMods)
+ when is_binary(Binary) andalso is_list(AsnMods) ->
+ version_of(AsnMods, Binary, []);
+version_of(_EC, Binary, 2, [AsnModV1, AsnModV2, AsnModV3])
+ when is_binary(Binary) ->
+ version_of([AsnModV2, AsnModV1, AsnModV3], Binary, []);
+version_of(_EC, Binary, 3, [AsnModV1, AsnModV2, AsnModV3])
+ when is_binary(Binary) ->
+ version_of([AsnModV3, AsnModV1, AsnModV2], Binary, []).
+
+version_of([], _Binary, Err) ->
+ {error, {decode_failed, lists:reverse(Err)}};
+version_of([AsnMod|AsnMods], Binary, Errs) when is_atom(AsnMod) ->
+ case (catch asn1rt:decode(AsnMod, 'MegacoMessage', Binary)) of
+ {ok, M} ->
+ V = (M#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Err ->
+ version_of(AsnMods, Binary, [Err|Errs])
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message([native], MegaMsg, AsnMod, _TransMod, binary)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ asn1rt:encode(AsnMod, 'MegacoMessage', MegaMsg);
+encode_message(EC, MegaMsg, AsnMod, TransMod, binary)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch TransMod:tr_message(MegaMsg, encode, EC)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ MegaMsg2 ->
+ asn1rt:encode(AsnMod, 'MegacoMessage', MegaMsg2)
+ end;
+encode_message(EC, MegaMsg, AsnMod, TransMod, io_list) ->
+ case encode_message(EC, MegaMsg, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_message(EC, MegaMsg, _AsnMod, _TransMod, _Type)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EC}};
+encode_message(_EC, MegaMsg, _AsnMod, _TransMod, _Type) ->
+ {error, {no_megaco_message, MegaMsg}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Should handle encoding of all types of transactions:
+%% TransactionAck, TransactionPending, TransactionRequest
+%% and TransactionReply
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionResponseAck) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionPending) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionRequest) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+%% TransactionReply has been changed as of v3 so we cannot use
+%% the record definition in this common module.
+encode_transaction(EC, {Tag, _} = Trans, AsnMod, TransMod, Type)
+ when (Tag == transactionReply) ->
+ do_encode_transaction(EC, Trans, AsnMod, TransMod, Type);
+encode_transaction(_EC, T, _AsnMod, _TransMod, _Type) ->
+ {error, {no_megaco_transaction, T}}.
+
+do_encode_transaction([native], _Trans, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+do_encode_transaction(EC, _Trans, _AsnMod, _TransMod, binary)
+ when is_list(EC) ->
+ %% T2 = TransMod:tr_transaction(Trans, encode, EC),
+ %% asn1rt:encode(AsnMod, element(1, T), T2);
+ {error, not_implemented};
+do_encode_transaction(EC, Trans, AsnMod, TransMod, io_list) ->
+ case do_encode_transaction(EC, Trans, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+do_encode_transaction(EC, _Trans, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_requests(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_requests(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_requests(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_requests(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_request(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_request(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_request(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_request(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionReply record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply([native], _ARs, _AsnMod, _TransMod, binary) ->
+ %% asn1rt:encode(AsnMod, element(1, T), T);
+ {error, not_implemented};
+encode_action_reply(_EC, _ARs0, _AsnMod, _TransMod, binary) ->
+ {error, not_implemented};
+encode_action_reply(EC, ARs, AsnMod, TransMod, io_list) ->
+ case encode_action_reply(EC, ARs, AsnMod, TransMod, binary) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Bin};
+ {ok, DeepIoList} ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+encode_action_reply(EC, _ARs, _AsnMod, _TransMod, _Type) ->
+ {error, {bad_encoding_config, EC}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message_dynamic(EC, Bin,
+ [{AsnModV1, TransModV1},
+ {AsnModV2, TransModV2},
+ {AsnModV3, TransModV3}], Form)
+ when is_list(EC) andalso is_binary(Bin) ->
+ case AsnModV1:decode_message_version(Bin) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ case V of
+ 1 ->
+ decode_message(EC, Bin, AsnModV1, TransModV1, Form);
+ 2 ->
+ decode_message(EC, Bin, AsnModV2, TransModV2, Form);
+ 3 ->
+ decode_message(EC, Bin, AsnModV3, TransModV3, Form)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+decode_message_dynamic(EC, Bin, _Mods, _Type)
+ when is_binary(Bin) ->
+ {error, {bad_encoding_config, EC}};
+decode_message_dynamic(_EC, _BadBin, _Mods, _Type) ->
+ {error, no_binary}.
+
+
+decode_message(EC, Bin, AsnMod, TransMod, binary) ->
+ case asn1rt:decode(AsnMod, 'MegacoMessage', Bin) of
+ {ok, MegaMsg} ->
+ case EC of
+ [native] ->
+ {ok, MegaMsg};
+ _ ->
+ {ok, TransMod:tr_message(MegaMsg, decode, EC)}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+decode_message(EC, Bin, AsnMod, TransMod, io_list) ->
+ ShallowIoList = erlang:binary_to_list(Bin),
+ case asn1rt:decode(AsnMod, 'MegacoMessage', ShallowIoList) of
+ {ok, MegaMsg} ->
+ case EC of
+ [native] ->
+ {ok, MegaMsg};
+ _ ->
+ {ok, TransMod:tr_message(MegaMsg, decode, EC)}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a partial 'MegacoMessage' record
+%% I.e. only version and Mid is fully decoded.
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_mini_message(_, Bin, Mod, _) ->
+ case (catch Mod:decode_message_mId(Bin)) of
+ {ok, #'MegacoMessage'{mess = Mess} = MegaMsg} ->
+ Mess2 = Mess#'Message'{messageBody = undefined},
+ {ok, MegaMsg#'MegacoMessage'{mess = Mess2}};
+ Error ->
+ Error
+ end.
+
+
+decode_mini_message_dynamic(EC, Bin, [Mod1, Mod2, Mod3], Form) ->
+ case Mod1:decode_message_version(Bin) of
+ {ok, PartialMsg} ->
+ V = (PartialMsg#'MegacoMessage'.mess)#'Message'.version,
+ case V of
+ 1 ->
+ decode_mini_message(EC, Bin, Mod1, Form);
+ 2 ->
+ decode_mini_message(EC, Bin, Mod2, Form);
+ 3 ->
+ decode_mini_message(EC, Bin, Mod3, Form)
+ end;
+ Error ->
+ Error
+ end.
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
new file mode 100644
index 0000000000..72b3112053
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3a.erl
@@ -0,0 +1,2003 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3a).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
new file mode 100644
index 0000000000..12e673ac81
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3b.erl
@@ -0,0 +1,2003 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3b).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
new file mode 100644
index 0000000000..d08231caac
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_prev3c.erl
@@ -0,0 +1,2004 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_prev3c).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl
new file mode 100644
index 0000000000..a748a1d0cc
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v1.erl
@@ -0,0 +1,1613 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v1).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description:
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional):
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this
+%% PackageID when reporting packages.
+%%
+%% Extends (Optional): existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. An
+%% extended package shall not redefine or overload an identifier
+%% defined in the original package and packages it may have
+%% extended (multiple levels of extension). Hence, if package B
+%% version 1 extends package A version 1, version 2 of B will not
+%% be able to extend the A version 2 if A version 2 defines a name
+%% already in B version 1.
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description:
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list. The type of
+%% sub-list SHALL also be specified. The type shall be chosen
+%% from the types specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration. The
+%% encoding of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted. A default value (but not
+%% procedures) may be specified as provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream dependent properties.
+%% TerminationState is for stream independent properties. These
+%% are expected to be the most common cases, but it is possible
+%% for properties to be defined in other descriptors.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description:
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in
+%% replies to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a
+%% SignalsDescriptor
+%%
+%% Description
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE - SignalType may be defined such that it is dependent on the
+%% value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description:
+%%
+%% Units: unit of measure, e.g., milliseconds, packets
+%%
+%%
+%% 12.1.6 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining Parameters to Events and Signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of parameters
+%% to Events and Signals shall not start with "EPA" and "SPA",
+%% respectively. The textual ParameterID shall also not be "ST",
+%% "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+%% "DigitMap".
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%% Octet String: A number of octets. See Annex A and Annex B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported for
+%% statistics). The type of sub-list SHALL also be specified. The
+%% type shall be chosen from the types specified in this section
+%% (with the exception of sub-list). For example, Type: sub-list of
+%% enumeration. The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behavior when the value is
+%% omitted from its descriptor. For example, a package may specify
+%% that procedures related to the parameter are suspended when it
+%% value is omitted. A default value (but not procedures) may be
+%% specified as provisionable.
+%%
+%% Description:
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations
+%% may be defined in a list. It is recommended that the list be IANA
+%% registered so that packages that extend the list can be defined
+%% without concern for conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and
+%% consisting of alphanumeric characters and/or digits, and possibly
+%% including the special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons.
+%% See clause 13 for IANA Considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end
+ end.
+
+decode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl
new file mode 100644
index 0000000000..53891a26f2
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v2.erl
@@ -0,0 +1,1681 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v2).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, _Reason} ->
+ exit({bad_term_id, TermId})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description:
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. No deletions or
+%% modifications shall be allowed. A version is an integer in the range
+%% from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to be
+%% extended by others, not to be directly referenced. For example, the
+%% package may not have any function on its own or be nonsensical on its
+%% own. The MG SHOULD NOT publish this PackageID when reporting
+%% packages.
+%%
+%% Extends (Optional): existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the original
+%% package must be specified. When a package extends another package it
+%% shall only add additional Properties, Events, Signals, Statistics and
+%% new possible values for an existing parameter described in the
+%% original package. An extended package shall not redefine or overload
+%% an identifier defined in the original package and packages it may
+%% have extended (multiple levels of extension). Hence, if package B
+%% version 1 extends package A version 1, version 2 of B will not be
+%% able to extend the A version 2 if A version 2 defines a name already
+%% in B version 1.
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description:
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list. The type of
+%% sub-list SHALL also be specified. The type shall be chosen
+%% from the types specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration. The
+%% encoding of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value is
+%% omitted from its descriptor. For example, a package may specify that
+%% procedures related to the property are suspended when it value is
+%% omitted. A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in. LocalControl is
+%% for stream dependent properties. TerminationState is for stream
+%% independent properties. These are expected to be the most common
+%% cases, but it is possible for properties to be defined in other
+%% descriptors.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and if it
+%% is global. If Global is omitted, the property is not global. If a
+%% property is declared as global, the value of the property is shared
+%% by all Terminations realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description:
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in the
+%% EventsDescriptor. See 12.2.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies to
+%% command requests from the MGC that audit ObservedEventsDescriptor,
+%% and found in the ObservedEventsDescriptor. See 12.2.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a
+%% SignalsDescriptor
+%%
+%% Description
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE - SignalType may be defined such that it is dependent on the
+%% value of one or more parameters. The package MUST specify a default
+%% signal type. If the default type is TO, the package MUST specify a
+%% default duration which may be provisioned. A default duration is
+%% meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description:
+%%
+%% Type: One of:
+%% Boolean
+%% String: UTF-8 string
+%% Octet String: A number of octets. See Annex A and B.3 for encoding
+%% Integer: 4 byte signed integer
+%% Double: 8 byte signed integer
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%% Enumeration: One of a list of possible unique values (see 12.3)
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified
+%% in this clause (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in
+%% Annex A and B.3.
+%% Possible Values:
+%% A package must indicate the unit of measure, e.g.,
+%% milliseconds, packets, either here or along with the type
+%% above, as well as indicating any restriction on the range.
+%%
+%%
+%% 12.1.6 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining Parameters to Events and Signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "Keepactive", "EB", "Embed", "DM" or
+%% "DigitMap".
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and Annex B.3
+%% for encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in this
+%% section (with the exception of sub-list). For example, Type:
+%% sub-list of enumeration. The encoding of sub-lists is
+%% specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behavior when the value is
+%% omitted from its descriptor. For example, a package may specify that
+%% procedures related to the parameter are suspended when it value is
+%% omitted. A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Description:
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may
+%% be defined in a list. It is recommended that the list be IANA
+%% registered so that packages that extend the list can be defined
+%% without concern for conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and
+%% consisting of alphanumeric characters and/or digits, and possibly
+%% including the special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons.
+%% See clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end
+ end.
+
+decode_dg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
new file mode 100644
index 0000000000..c101aa15bc
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_name_resolver_v3.erl
@@ -0,0 +1,2016 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle meta data about packages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_name_resolver_v3).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+-export([packages/0,
+ capabilities/0,
+ capabilities/1,
+ decode_name/3,
+ encode_name/3
+ ]).
+
+encode_name(Config, term_id, TermId) ->
+ case megaco:encode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+encode_name(_Config, Scope, Item) ->
+ ?d("encode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ encode(Scope, Item).
+
+decode_name(Config, term_id, TermId) ->
+ case megaco:decode_binary_term_id(Config, TermId) of
+ {ok, TermId2} ->
+ TermId2;
+ {error, Reason} ->
+ exit({bad_term_id, TermId, Reason})
+ end;
+decode_name(_Config, Scope, Item) ->
+ ?d("decode_name(~p) -> entry with"
+ "~n Item: ~p", [Scope, Item]),
+ decode(Scope, Item).
+
+
+
+%%----------------------------------------------------------------------
+%% 12.1.1 Package
+%%
+%% Overall description of the package, specifying:
+%%
+%% Package Name: only descriptive
+%%
+%% PackageID: is an identifier
+%%
+%% Description: is a description of the package
+%%
+%% Version:
+%%
+%% A new version of a package can only add additional Properties,
+%% Events, Signals, Statistics and new possible values for an
+%% existing parameter described in the original package. No
+%% deletions or modifications shall be allowed. A version is an
+%% integer in the range from 1 to 99.
+%%
+%% Designed to be extended only (Optional): Yes
+%%
+%% This indicates that the package has been expressly designed to
+%% be extended by others, not to be directly referenced. For
+%% example, the package may not have any function on its own or be
+%% nonsensical on its own. The MG SHOULD NOT publish this PackageID
+%% when reporting packages.
+%%
+%% Extends: existing package Descriptor
+%%
+%% A package may extend an existing package. The version of the
+%% original package must be specified. When a package extends
+%% another package it shall only add additional Properties, Events,
+%% Signals, Statistics and new possible values for an existing
+%% parameter described in the original package. An extended package
+%% shall not redefine or overload an identifier defined in the
+%% original package and packages it may have extended (multiple
+%% levels of extension). Hence, if package B version 1 extends
+%% package A version 1, version 2 of B will not be able to extend
+%% the A version 2 if A version 2 defines a name already in B
+%% version 1. If the package does not extend another package, it
+%% shall specify "none".
+%%
+%%
+%% 12.1.2 Properties
+%%
+%% Properties defined by the package, specifying:
+%%
+%% Property Name: only descriptive
+%%
+%% PropertyID: is an identifier
+%%
+%% Description: is a description of the function of the property
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list). For
+%% example, Type: sub-list of enumeration. The encoding
+%% of sub-lists is specified in Annexes A and B.3.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST also
+%% specify a default value or the default behaviour when the value
+%% is omitted from its descriptor. For example, a package may
+%% specify that procedures related to the property are suspended
+%% when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%% Defined in:
+%%
+%% Which H.248.1 descriptor the property is defined in.
+%% LocalControl is for stream-dependent properties.
+%% TerminationState is for stream-independent properties.
+%% ContextAttribute is for properties that affect the context as
+%% a whole, i.e., mixing properties. These are expected to be the
+%% most common cases, but it is possible for properties to be
+%% defined in other descriptors. Context properties MUST be defined
+%% in the ContextAttribute descriptor.
+%%
+%% Characteristics: Read/Write or both, and (optionally), global:
+%%
+%% Indicates whether a property is read-only, or read-write, and
+%% if it is global. If Global is omitted, the property is not
+%% global. If a property is declared as global, the value of the
+%% property is shared by all Terminations realizing the package.
+%% If a context property is declared as global, the property is
+%% shared by all contexts realizing the package.
+%%
+%%
+%% 12.1.3 Events
+%%
+%% Events defined by the package, specifying:
+%%
+%% Event name: only descriptive
+%%
+%% EventID: is an identifier
+%%
+%% Description: a description of the function of the event
+%%
+%% EventsDescriptor Parameters:
+%%
+%% Parameters used by the MGC to configure the event, and found in
+%% the EventsDescriptor. See 12.2. If there are no parameters for
+%% the Events Descriptor, then "none" shall be specified.
+%%
+%% ObservedEventsDescriptor Parameters:
+%%
+%% Parameters returned to the MGC in Notify requests and in replies
+%% to command requests from the MGC that audit
+%% ObservedEventsDescriptor, and found in the
+%% ObservedEventsDescriptor. See 12.2. If there are no parameters
+%% for the ObservedEvents Descriptor, then �none� shall be specified.
+%%
+%%
+%% 12.1.4 Signals
+%%
+%% Signals defined by the package, specifying:
+%%
+%% Signal Name: only descriptive
+%%
+%% SignalID: is an identifier. SignalID is used in a SignalsDescriptor
+%%
+%% Description: a description of the function of the signal
+%%
+%% SignalType: one of:
+%%
+%% OO (On/Off)
+%%
+%% TO (TimeOut)
+%%
+%% BR (Brief)
+%%
+%% NOTE -�SignalType may be defined such that it is dependent on
+%% the value of one or more parameters. The package MUST specify a
+%% default signal type. If the default type is TO, the package MUST
+%% specify a default duration which may be provisioned. A default
+%% duration is meaningless for BR.
+%%
+%% Duration: in hundredths of seconds
+%%
+%% Additional Parameters: see 12.2
+%%
+%%
+%% 12.1.5 Statistics
+%%
+%% Statistics defined by the package, specifying:
+%%
+%% Statistic name: only descriptive
+%%
+%% StatisticID: is an identifier
+%%
+%% StatisticID is used in a StatisticsDescriptor
+%%
+%% Description: a description of the statistic
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 string
+%%
+%% Octet String: A number of octets.
+%% See Annex A and Annex B.3 for encoding
+%%
+%% Integer: 4 byte signed integer
+%%
+%% Double: 8 byte signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter.
+%% Could be more than one octet.
+%%
+%% Enumeration: One of a list of possible unique values (See 12.3)
+%%
+%% Sub-list: A list of several values from a list.
+%% The type of sub-list SHALL also be specified.
+%% The type shall be chosen from the types specified in
+%% this section (with the exception of sub-list).
+%% For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annexes A
+%% and B.3.
+%%
+%% Possible Values:
+%%
+%% A package must indicate the unit of measure, e.g. milliseconds,
+%% packets, either here or along with the type above, as well as
+%% indicating any restriction on the range.
+%%
+%% Level: Specify if the statistic can be kept at the Termination
+%% level, Stream level or Either.
+%%
+%%
+%% 12.1.6 Error Codes
+%%
+%% If the package does not define any error codes, this section may be omitted.
+%% Otherwise, it describes error codes defined by the package, specifying:
+%%
+%% Error Code #: The error code number.
+%%
+%% Name: Name of the error
+%%
+%% Definition: A description of the error code.
+%%
+%% Error Text in the Error Descriptor:
+%%
+%% A description of what text to return in the Error Descriptor.
+%%
+%% Comment: Any further comments on the use of the error code.
+%%
+%%
+%% 12.1.7 Procedures
+%%
+%% Additional guidance on the use of the package.
+%%
+%%
+%% 12.2 Guidelines to defining parameters to events and signals
+%%
+%% Parameter Name: only descriptive
+%%
+%% ParameterID: is an identifier. The textual ParameterID of
+%% parameters to Events and Signals shall not start with "EPA" and
+%% "SPA", respectively. The textual ParameterID shall also not be
+%% "ST", "Stream", "SY", "SignalType", "DR", "Duration", "NC",
+%% "NotifyCompletion", "KA", "KeepActive", "EB", "Embed", "DM",
+%% "DigitMap", "DI", "Direction", "RQ" or "RequestID".
+%%
+%% Description: a description of the function of the parameter.
+%%
+%% Type: One of:
+%%
+%% Boolean
+%%
+%% String: UTF-8 octet string
+%%
+%% Octet String: A number of octets. See Annex A and B.3 for
+%% encoding
+%%
+%% Integer: 4-octet signed integer
+%%
+%% Double: 8-octet signed integer
+%%
+%% Character: Unicode UTF-8 encoding of a single letter. Could be
+%% more than one octet.
+%%
+%% Enumeration: one of a list of possible unique values (see 12.3)
+%%
+%% Sub-list: a list of several values from a list (not supported
+%% for statistics). The type of sub-list SHALL also be
+%% specified The type shall be chosen from the types
+%% specified in this section (with the exception of
+%% sub-list). For example, Type: sub-list of enumeration.
+%% The encoding of sub-lists is specified in Annex A
+%% and B.3.
+%%
+%% Optional: Yes/No
+%%
+%% Describes if the parameter may be omitted from the signal or
+%% event.
+%%
+%% Possible values:
+%%
+%% A package MUST specify either a specific set of values or a
+%% description of how values are determined. A package MUST
+%% also specify a default value or the default behavior when the
+%% value is omitted from its descriptor. For example, a package
+%% may specify that procedures related to the parameter are
+%% suspended when its value is omitted.
+%%
+%% Default:
+%%
+%% A default value (but not procedures) may be specified as
+%% provisionable.
+%%
+%%
+%% 12.3 Lists
+%%
+%% Possible values for parameters include enumerations. Enumerations may be
+%% defined in a list. It is recommended that the list be IANA registered so
+%% that packages that extend the list can be defined without concern for
+%% conflicting names.
+%%
+%%
+%% 12.4 Identifiers
+%%
+%% Identifiers in text encoding shall be strings of up to 64 characters,
+%% containing no spaces, starting with an alphabetic character and consisting
+%% of alphanumeric characters and/or digits, and possibly including the
+%% special character underscore ("_").
+%%
+%% Identifiers in binary encoding are 2 octets long.
+%%
+%% Both text and binary values shall be specified for each identifier,
+%% including identifiers used as values in enumerated types.
+%%
+%%
+%% 12.5 Package registration
+%%
+%% A package can be registered with IANA for interoperability reasons. See
+%% clause 14 for IANA considerations.
+%%
+%%----------------------------------------------------------------------
+
+capabilities() ->
+ [{P, capabilities(P)} || P <- packages()].
+
+%% -record(property, {name, type, values, defined_in, characteristics}).
+
+%%----------------------------------------------------------------------
+%% List all known packages
+%% 'native' and 'all' are not real packages
+%%----------------------------------------------------------------------
+
+packages() ->
+ [
+ "g", % Generic
+ "root", % Base Root Package
+ "tonegen", % Tone Generator Package
+ "tonedet", % Tone Detection Package
+ "dg", % Basic DTMF Generator Package
+ "dd", % DTMF detection Package
+ "cg", % Call Progress Tones Generator Package
+ "cd", % Call Progress Tones Detection Package
+ "al", % Analog Line Supervision Package
+ "ct", % Basic Continuity Package
+ "nt", % Network Package
+ "rtp", % RTP Package
+ "swb", % SwitchBoard Package
+ "tdmc", % TDM Circuit Package
+ "" % Native pseudo package
+ ].
+
+%%----------------------------------------------------------------------
+%% List all matching capabilities
+%%----------------------------------------------------------------------
+
+capabilities(Package) ->
+ case Package of
+ "g" -> capabilities_g();
+ "root" -> capabilities_root();
+ "tonegen" -> capabilities_tonegen();
+ "tonedet" -> capabilities_tonedet();
+ "dg" -> capabilities_dg();
+ "dd" -> capabilities_dd();
+ "cg" -> capabilities_cg();
+ "cd" -> capabilities_cd();
+ "al" -> capabilities_al();
+ "ct" -> capabilities_ct();
+ "nt" -> capabilities_nt();
+ "rtp" -> capabilities_rtp();
+ "swb" -> capabilities_swb();
+ "tdmc" -> capabilities_tdmc();
+ "" -> capabilities_native()
+ end.
+
+%%----------------------------------------------------------------------
+%% Decode package name to internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+decode(mid, Package) ->
+ decode_mid(Package);
+decode(package, Package) ->
+ decode_package(Package);
+decode(profile, Package) ->
+ decode_profile(Package);
+decode(dialplan, Dialplan) ->
+ decode_dialplan(Dialplan);
+decode(Scope, [A, B | Item]) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p", [Scope, A, B, Item]),
+ case decode_package([A, B]) of
+ "" ->
+ ?d("decode -> \"no\" package",[]),
+ decode_item(Scope, [A, B], Item);
+ Package ->
+ ?d("decode -> Package: ~p", [Package]),
+ Package ++ "/" ++ decode_item(Scope, [A, B], Item)
+ end;
+decode({Scope, [A, B | Item]}, SubItem) when is_atom(Scope) ->
+ ?d("decode(~p) -> entry with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n Item: ~p"
+ "~n SubItem: ~p", [Scope, A, B, Item, SubItem]),
+ decode_item({Scope, Item}, [A, B], SubItem).
+
+decode_item(Scope, [A, B], Item) ->
+ ?d("decode_item -> entry",[]),
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> decode_g(Scope, Item);
+ 16#02 -> decode_root(Scope, Item);
+ 16#03 -> decode_tonegen(Scope, Item);
+ 16#04 -> decode_tonedet(Scope, Item);
+ 16#05 -> decode_dg(Scope, Item);
+ 16#06 -> decode_dd(Scope, Item);
+ 16#07 -> decode_cg(Scope, Item);
+ 16#08 -> decode_cd(Scope, Item);
+ 16#09 -> decode_al(Scope, Item);
+ 16#0a -> decode_ct(Scope, Item);
+ 16#0b -> decode_nt(Scope, Item);
+ 16#0c -> decode_rtp(Scope, Item);
+ 16#0d -> decode_tdmc(Scope, Item);
+ 16#00 -> decode_native(Scope, Item)
+ end;
+ 16#fe ->
+ case B of
+ %% Proprietary extension
+ 16#fe -> decode_swb(Scope, Item)
+ end;
+ 16#ff ->
+ case B of
+ 16#ff when Item =:= [16#ff, 16#ff] -> "*"
+ end
+ end.
+
+decode_package(Package) ->
+ ?d("decode_package -> entry with"
+ "~n Package: ~p", [Package]),
+ [A, B] = Package,
+ case A of
+ 16#00 ->
+ case B of
+ 16#01 -> "g";
+ 16#02 -> "root";
+ 16#03 -> "tonegen";
+ 16#04 -> "tonedet";
+ 16#05 -> "dg";
+ 16#06 -> "dd";
+ 16#07 -> "cg";
+ 16#08 -> "cd";
+ 16#09 -> "al";
+ 16#0a -> "ct";
+ 16#0b -> "nt";
+ 16#0c -> "rtp";
+ 16#0d -> "tdmc";
+ 16#00 -> ""
+ end;
+ 16#fe ->
+ case B of
+ 16#fe -> "swb"
+ end;
+ 16#ff ->
+ case B of
+ 16#ff -> "*"
+ end
+ end.
+
+decode_profile([A, B]) ->
+ case A of
+ 16#00 ->
+ case B of
+ 16#fe -> "resgw";
+ _ -> "profile" ++ [A + $0, B + $0]
+ end;
+ _ ->
+ "profile" ++ [A + $0, B + $0]
+ end.
+
+decode_dialplan([A, B]) ->
+ "dialplan" ++ [A + $0, B + $0].
+
+decode_mid(Mid) ->
+ case Mid of
+ {domainName, DN} ->
+ Lower = to_lower(DN#'DomainName'.name),
+ {domainName, DN#'DomainName'{name = Lower}};
+ {deviceName, PathName} ->
+ Lower = to_lower(PathName),
+ {deviceName, Lower};
+ Other ->
+ Other
+ end.
+
+to_lower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+%%----------------------------------------------------------------------
+%% Encode package name from internal form
+%% Scope ::= property | event | signal | statistics
+%%----------------------------------------------------------------------
+
+encode(mid, Package) ->
+ encode_mid(Package);
+encode(package, Package) ->
+ encode_package(Package);
+encode(profile, Profile) ->
+ encode_profile(Profile);
+encode(dialplan, Dialplan) ->
+ encode_dialplan(Dialplan);
+encode(Scope, PackageItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p", [Scope, PackageItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_package(Package) ++ encode_item(Scope, Package, Item);
+ [Item] ->
+ ?d("encode -> Item: ~p", [Item]),
+ [16#00, 16#00 | encode_native(Scope, Item)]
+ end;
+encode({Scope, PackageItem}, SubItem) when is_atom(Scope) ->
+ ?d("encode(~p) -> entry with"
+ "~n PackageItem: ~p"
+ "~n SubItem: ~p", [Scope, PackageItem, SubItem]),
+ case string:tokens(PackageItem, [$/]) of
+ [Package, Item] ->
+ ?d("encode -> "
+ "~n Package: ~p"
+ "~n Item: ~p", [Package, Item]),
+ encode_item({Scope, Item}, Package, SubItem);
+ [_Item] ->
+ ?d("encode -> _Item: ~p", [_Item]),
+ encode_native(Scope, SubItem)
+ end.
+
+encode_item(_Scope, _Package, "*") ->
+ [16#ff, 16#ff];
+encode_item(Scope, Package, Item) ->
+ ?d("encode_item(~s) -> entry", [Package]),
+ case Package of
+ "g" -> encode_g(Scope, Item);
+ "root" -> encode_root(Scope, Item);
+ "tonegen" -> encode_tonegen(Scope, Item);
+ "tonedet" -> encode_tonedet(Scope, Item);
+ "dg" -> encode_dg(Scope, Item);
+ "dd" -> encode_dd(Scope, Item);
+ "cg" -> encode_cg(Scope, Item);
+ "cd" -> encode_cd(Scope, Item);
+ "al" -> encode_al(Scope, Item);
+ "ct" -> encode_ct(Scope, Item);
+ "nt" -> encode_nt(Scope, Item);
+ "rtp" -> encode_rtp(Scope, Item);
+ "tdmc" -> encode_tdmc(Scope, Item);
+ "swb" -> encode_swb(Scope, Item)
+ end.
+
+encode_package(Package) ->
+ case Package of
+ "g" -> [16#00, 16#01];
+ "root" -> [16#00, 16#02];
+ "tonegen" -> [16#00, 16#03];
+ "tonedet" -> [16#00, 16#04];
+ "dg" -> [16#00, 16#05];
+ "dd" -> [16#00, 16#06];
+ "cg" -> [16#00, 16#07];
+ "cd" -> [16#00, 16#08];
+ "al" -> [16#00, 16#09];
+ "ct" -> [16#00, 16#0a];
+ "nt" -> [16#00, 16#0b];
+ "rtp" -> [16#00, 16#0c];
+ "tdmc" -> [16#00, 16#0d];
+ "" -> [16#00, 16#00];
+ "*" -> [16#ff, 16#ff];
+ "swb" -> [16#fe, 16#fe]
+ end.
+
+encode_profile(Profile) ->
+ case Profile of
+ "resgw" ->
+ [16#00, 16#fe];
+ [$p, $r, $o, $f, $i, $l, $e | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_dialplan(Dialplan) ->
+ case Dialplan of
+ [$d, $i, $a, $l, $p, $l, $a, $n | Name] ->
+ case Name of
+ [A, B] -> [A - $0, B - $0];
+ [B] -> [0, B - $0];
+ [] -> [0, 0]
+ end
+ end.
+
+encode_mid(Mid) ->
+ Mid.
+
+
+%%----------------------------------------------------------------------
+%% Name: g - Generic
+%% Version: 1
+%% Extends: None
+%% Purpose: Generic package for commonly encountered items
+%%----------------------------------------------------------------------
+
+capabilities_g() ->
+ [
+ {event, "cause"},
+ {event, "sc"}
+ ].
+
+encode_g(event, Item) ->
+ case Item of
+ "cause" -> [16#00, 16#01];
+ "sc" -> [16#00, 16#02]
+ end;
+
+encode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cause" ->
+ case SubItem of
+ "Generalcause" -> [16#00, 16#01];
+ "Failurecause" -> [16#00, 16#02]
+ end;
+ "sc" ->
+ case SubItem of
+ "SigID" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#02];
+ "SLID" -> [16#00, 16#03];
+ "RID" -> [16#00, 16#04]
+ end
+ end.
+
+decode_g(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "cause";
+ [16#00, 16#02] -> "sc"
+ end;
+
+decode_g({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: cause
+ case SubItem of
+ [16#00, 16#01] -> "Generalcause";
+ [16#00, 16#02] -> "Failurecause"
+ end;
+
+ [16#00, 16#02] -> % Event: sc
+ case SubItem of
+ [16#00, 16#01] -> "SigID";
+ [16#00, 16#02] -> "Meth";
+ [16#00, 16#03] -> "SLID";
+ [16#00, 16#04] -> "RID"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: root - Base Root Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines Gateway wide properties.
+%%----------------------------------------------------------------------
+
+capabilities_root() ->
+ [
+ {property, "maxNumberOfContexts"},
+ {property, "maxTerminationsPerContext"},
+ {property, "normalMGExecutionTime"},
+ {property, "normalMGCExecutionTime"},
+ {property, "MGProvisionalResponseTimerValue"},
+ {property, "MGCProvisionalResponseTimerValue"},
+ {property, "MGCOriginatedPendingLimit"},
+ {property, "MGOriginatedPendingLimit"},
+ {property, "MGSegmentationTimerValue"},
+ {property, "MGCSegmentationTimerValue"},
+ {property, "MGMaxPDUSize"},
+ {property, "MGCMaxPDUSize"}
+ ].
+
+encode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "maxNumberOfContexts" -> [16#00, 16#01];
+ "maxTerminationsPerContext" -> [16#00, 16#02];
+ "normalMGExecutionTime" -> [16#00, 16#03];
+ "normalMGCExecutionTime" -> [16#00, 16#04];
+ "MGProvisionalResponseTimerValue" -> [16#00, 16#05];
+ "MGCProvisionalResponseTimerValue" -> [16#00, 16#06];
+ "MGCOriginatedPendingLimit" -> [16#00, 16#07];
+ "MGOriginatedPendingLimit" -> [16#00, 16#08];
+ "MGSegmentationTimerValue" -> [16#00, 16#09];
+ "MGCSegmentationTimerValue" -> [16#00, 16#0a];
+ "MGMaxPDUSize" -> [16#00, 16#0b];
+ "MGCMaxPDUSize" -> [16#00, 16#0c]
+ end
+ end.
+
+decode_root(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#01] -> "maxNumberOfContexts";
+ [16#00, 16#02] -> "maxTerminationsPerContext";
+ [16#00, 16#03] -> "normalMGExecutionTime";
+ [16#00, 16#04] -> "normalMGCExecutionTime";
+ [16#00, 16#05] -> "MGProvisionalResponseTimerValue";
+ [16#00, 16#06] -> "MGCProvisionalResponseTimerValue";
+ [16#00, 16#07] -> "MGCOriginatedPendingLimit";
+ [16#00, 16#08] -> "MGOriginatedPendingLimit";
+ [16#00, 16#09] -> "MGSegmentationTimerValue";
+ [16#00, 16#0a] -> "MGCSegmentationTimerValue";
+ [16#00, 16#0b] -> "MGMaxPDUSize";
+ [16#00, 16#0c] -> "MGCMaxPDUSize"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonegen - Tone Generator Package
+%% Version: 2
+%% Extends: None
+%% Purpose: This package defines signals to generate audio tones.
+%% This package does not specify parameter values. It is
+%% intended to be extendable. Generally, tones are defined
+%% as an individual signal with a parameter, ind,
+%% representing "interdigit" time delay, and a tone id to
+%% be used with playtones. A tone id should be kept
+%% consistent with any tone generation for the same tone.
+%% MGs are expected to be provisioned with the characteristics
+%% of appropriate tones for the country in which the MG is located.
+%%----------------------------------------------------------------------
+
+capabilities_tonegen() ->
+ [
+ {signal, "pt"}
+ ].
+
+encode_tonegen(signal, Item) ->
+ case Item of
+ "pt" -> [16#00, 16#01]
+ end;
+
+encode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "pt" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "ind" -> [16#00, 16#02];
+ "btd" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonegen(signal, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pt"
+ end;
+
+decode_tonegen({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event: pt
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "ind";
+ [16#00, 16#03] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tonedet - Tone Detection Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This Package defines events for audio tone detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%----------------------------------------------------------------------
+
+capabilities_tonedet() ->
+ [
+ {event, "std"},
+ {event, "etd"},
+ {event, "ltd"}
+ ].
+
+encode_tonedet(event, Item) ->
+ case Item of
+ "std" -> [16#00, 16#01];
+ "etd" -> [16#00, 16#02];
+ "ltd" -> [16#00, 16#03]
+ end;
+
+encode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ "std" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03]
+ end;
+ "etd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "tid" -> [16#00, 16#03];
+ "dur" -> [16#00, 16#02]
+ end;
+ "ltd" ->
+ case SubItem of
+ "tl" -> [16#00, 16#01];
+ "dur" -> [16#00, 16#02];
+ "tid" -> [16#00, 16#03]
+ end
+ end.
+
+decode_tonedet(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "std";
+ [16#00, 16#02] -> "etd";
+ [16#00, 16#03] -> "ltd"
+ end;
+
+decode_tonedet({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event std
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid"
+ end;
+ [16#00, 16#02] -> % Event etd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#03] -> "tid";
+ [16#00, 16#02] -> "dur"
+ end;
+ [16#00, 16#03] -> % Event ltd
+ case SubItem of
+ [16#00, 16#01] -> "tl";
+ [16#00, 16#02] -> "dur";
+ [16#00, 16#03] -> "tid"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dg - Basic DTMF Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic DTMF tones as signals and
+%% extends the allowed values of parameter tl of playtone
+%% in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_dg() ->
+ [
+ {signal, "d0"},
+ {signal, "d1"},
+ {signal, "d2"},
+ {signal, "d3"},
+ {signal, "d4"},
+ {signal, "d5"},
+ {signal, "d6"},
+ {signal, "d7"},
+ {signal, "d8"},
+ {signal, "d9"},
+ {signal, "ds"},
+ {signal, "do"},
+ {signal, "da"},
+ {signal, "db"},
+ {signal, "dc"},
+ {signal, "dd"}
+ ].
+
+encode_dg(signal, Item) ->
+ case Item of
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dg(signal, Item) ->
+ case Item of
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dg({signal_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: dd - DTMF detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic DTMF tones detection.
+%% Tones are selected by name (tone id). MGs are expected
+%% to be provisioned with the characteristics of appropriate
+%% tones for the country in which the MG is located.
+%%
+%% This package does not specify parameter values.
+%% It is intended to be extendable.
+%%
+%% Additional tone id values are all tone ids described in package dg
+%% (basic DTMF generator package).
+%%
+%% The following table maps DTMF events to digit map symbols as described
+%% in section 7.1.14.
+%%
+%% _________________________________
+%% | DTMF Event | Symbol |
+%% | d0 | "0" |
+%% | d1 | "1" |
+%% | d2 | "2" |
+%% | d3 | "3" |
+%% | d4 | "4" |
+%% | d5 | "5" |
+%% | d6 | "6" |
+%% | d7 | "7" |
+%% | d8 | "8" |
+%% | d9 | "9" |
+%% | da | "A" or "a"|
+%% | db | "B" or "b"|
+%% | dc | "C" or "c"|
+%% | dd | "D" or "d"|
+%% | ds | "E" or "e"|
+%% | do | "F" or "f"|
+%% |___________________|____________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_dd() ->
+ [
+ {event, "ce"},
+ {event, "d0"},
+ {event, "d1"},
+ {event, "d2"},
+ {event, "d3"},
+ {event, "d4"},
+ {event, "d5"},
+ {event, "d6"},
+ {event, "d7"},
+ {event, "d8"},
+ {event, "d9"},
+ {event, "ds"},
+ {event, "do"},
+ {event, "da"},
+ {event, "db"},
+ {event, "dc"},
+ {event, "dd"}
+ ].
+
+encode_dd(event, Item) ->
+ case Item of
+ "ce" -> [16#00, 16#04];
+ "d0" -> [16#00, 16#10];
+ "d1" -> [16#00, 16#11];
+ "d2" -> [16#00, 16#12];
+ "d3" -> [16#00, 16#13];
+ "d4" -> [16#00, 16#14];
+ "d5" -> [16#00, 16#15];
+ "d6" -> [16#00, 16#16];
+ "d7" -> [16#00, 16#17];
+ "d8" -> [16#00, 16#18];
+ "d9" -> [16#00, 16#19];
+ "ds" -> [16#00, 16#20];
+ "do" -> [16#00, 16#21];
+ "da" -> [16#00, 16#1a];
+ "db" -> [16#00, 16#1b];
+ "dc" -> [16#00, 16#1c];
+ "dd" -> [16#00, 16#1d]
+ end;
+
+encode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ "ce" ->
+ case SubItem of
+ "ds" -> [16#00, 16#01];
+ "Meth" -> [16#00, 16#03]
+ end;
+ "d0" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d1" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d2" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d3" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d4" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d5" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d6" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d7" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d8" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "d9" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "ds" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "do" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "da" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "db" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dc" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end;
+ "dd" ->
+ case SubItem of
+ "btd" -> [16#00, 16#01]
+ end
+ end.
+
+decode_dd(event, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ce";
+ [16#00, 16#10] -> "d0";
+ [16#00, 16#11] -> "d1";
+ [16#00, 16#12] -> "d2";
+ [16#00, 16#13] -> "d3";
+ [16#00, 16#14] -> "d4";
+ [16#00, 16#15] -> "d5";
+ [16#00, 16#16] -> "d6";
+ [16#00, 16#17] -> "d7";
+ [16#00, 16#18] -> "d8";
+ [16#00, 16#19] -> "d9";
+ [16#00, 16#20] -> "ds";
+ [16#00, 16#21] -> "do";
+ [16#00, 16#1a] -> "da";
+ [16#00, 16#1b] -> "db";
+ [16#00, 16#1c] -> "dc";
+ [16#00, 16#1d] -> "dd"
+ end;
+
+decode_dd({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#04] -> % Event ce
+ case SubItem of
+ [16#00, 16#01] -> "ds";
+ [16#00, 16#03] -> "Meth"
+ end;
+ [16#00, 16#10] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#11] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#12] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#13] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#14] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#15] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#16] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#17] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#18] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#19] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#20] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#21] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1a] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1b] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1c] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end;
+ [16#00, 16#1d] ->
+ case SubItem of
+ [16#00, 16#01] -> "btd"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cg - Call Progress Tones Generator Package
+%% Version: 1
+%% Extends: tonegen version 1
+%% Purpose: This package defines the basic call progress tones as signals
+%% and extends the allowed values of the tl parameter of
+%% playtone in tonegen.
+%%----------------------------------------------------------------------
+
+capabilities_cg() ->
+ [
+ {signal, "dt"},
+ {signal, "rt"},
+ {signal, "bt"},
+ {signal, "ct"},
+ {signal, "sit"},
+ {signal, "wt"},
+ {signal, "prt"},
+ {signal, "cw"},
+ {signal, "cr"}
+ ].
+
+
+encode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit" -> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt" -> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cg(Scope, Item) ->
+ case Scope of
+ signal ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: cd - Call Progress Tones Detection Package
+%% Version: 1
+%% Extends: tonedet version 1
+%% Purpose: This package defines the basic call progress detection tones.
+%% This Package extends the possible values of tone id
+%% in the "start tone detected", "end tone detected" and
+%% "long tone detected" events.
+%% Additional values
+%% tone id values are defined for start tone detected,
+%% end tone detected and long tone detected with
+%% the same values as those in package cg (call
+%% progress tones generation package).
+%%
+%% The required set of tone ids corresponds to Recommendation E.180/Q.35
+%% [ITU-T Recommendation E.180/Q.35 (1998)]. See Recommendation E.180/Q.35
+%% for definition of the meanings of these tones.
+%%----------------------------------------------------------------------
+
+capabilities_cd() ->
+ [
+ {event, "dt"},
+ {event, "rt"},
+ {event, "bt"},
+ {event, "ct"},
+ {event, "sit"},
+ {event, "wt"},
+ {event, "prt"},
+ {event, "cw"},
+ {event, "cr"}
+ ].
+
+
+encode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ "dt" -> [16#00, 16#30];
+ "rt" -> [16#00, 16#31];
+ "bt" -> [16#00, 16#32];
+ "ct" -> [16#00, 16#33];
+ "sit"-> [16#00, 16#34];
+ "wt" -> [16#00, 16#35];
+ "prt"-> [16#00, 16#36];
+ "cw" -> [16#00, 16#37];
+ "cr" -> [16#00, 16#38]
+ end
+ end.
+
+decode_cd(Scope, Item) ->
+ case Scope of
+ event ->
+ case Item of
+ [16#00, 16#30] -> "dt";
+ [16#00, 16#31] -> "rt";
+ [16#00, 16#32] -> "bt";
+ [16#00, 16#33] -> "ct";
+ [16#00, 16#34] -> "sit";
+ [16#00, 16#35] -> "wt";
+ [16#00, 16#36] -> "prt";
+ [16#00, 16#37] -> "cw";
+ [16#00, 16#38] -> "cr"
+ end
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: al - Analog Line Supervision Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for an analog line.
+%%----------------------------------------------------------------------
+
+capabilities_al() ->
+ [
+ {event, "on"},
+ {event, "of"},
+ {event, "fl"},
+ {signal, "ri"}
+ ].
+
+encode_al(event, Item) ->
+ ?d("encode_al(event) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "on" -> [16#00, 16#04];
+ "of" -> [16#00, 16#05];
+ "fl" -> [16#00, 16#06]
+ end;
+
+encode_al({event_parameter, Item}, SubItem) ->
+ ?d("encode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "on" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "of" ->
+ case SubItem of
+ "strict" -> [16#00, 16#01];
+ "init" -> [16#00, 16#02]
+ end;
+ "fl" ->
+ case SubItem of
+ "mindur" -> [16#00, 16#04];
+ "maxdur" -> [16#00, 16#05]
+ end
+ end;
+
+encode_al(signal, Item) ->
+ ?d("encode_al(signal) -> entry with"
+ "~n Item: ~p", [Item]),
+ case Item of
+ "ri" -> [16#00, 16#02]
+ end;
+
+encode_al({signal_parameter, Item}, SubItem) ->
+ ?d("encode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ "ri" ->
+ case SubItem of
+ "cad" -> [16#00, 16#06];
+ "freq" -> [16#00, 16#07]
+ end
+ end.
+
+decode_al(event, SubItem) ->
+ ?d("decode_al(event) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#04] -> "on";
+ [16#00, 16#05] -> "of";
+ [16#00, 16#06] -> "fl"
+ end;
+
+decode_al({event_parameter, Item}, SubItem) ->
+ ?d("decode_al({event_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#04] -> %% Event: on
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#05] -> %% Event: of
+ case SubItem of
+ [16#00, 16#01] -> "strict";
+ [16#00, 16#02] -> "init"
+ end;
+ [16#00,16#06] -> %% Event: fl
+ case SubItem of
+ [16#00, 16#04] -> "mindur";
+ [16#00, 16#05] -> "maxdur"
+ end
+ end;
+
+decode_al(signal, SubItem) ->
+ ?d("decode_al(signal) -> entry with"
+ "~n SubItem: ~p", [SubItem]),
+ case SubItem of
+ [16#00, 16#02] -> "ri"
+ end;
+
+decode_al({signal_parameter, Item}, SubItem) ->
+ ?d("decode_al({signal_parameter,~p}) -> entry with"
+ "~n SubItem: ~p", [Item, SubItem]),
+ case Item of
+ [16#00,16#02] -> %% Event: ri
+ case SubItem of
+ [16#00, 16#06] -> "cad";
+ [16#00, 16#07] -> "freq"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: ct - Basic Continuity Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines events and signals for continuity test.
+%% The continuity test includes provision of either a loopback
+%% or transceiver functionality.
+%%----------------------------------------------------------------------
+
+capabilities_ct() ->
+ [
+ {event, "cmp"},
+ {signal, "ct"},
+ {signal, "rsp"}
+ ].
+
+encode_ct(event, Item) ->
+ case Item of
+ "cmp" -> [16#00, 16#05]
+ end;
+encode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ "cmp" ->
+ case SubItem of
+ "res" -> [16#00, 16#08]
+ end
+ end;
+encode_ct(signal, Item) ->
+ case Item of
+ "ct" -> [16#00, 16#03];
+ "rsp" -> [16#00, 16#04]
+ end.
+
+decode_ct(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "cmp"
+ end;
+decode_ct({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event cmp
+ case SubItem of
+ [16#00, 16#08] -> "res"
+ end
+ end;
+decode_ct(signal, Item) ->
+ case Item of
+ [16#00, 16#03] -> "ct";
+ [16#00, 16#04] -> "rsp"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: nt - Network Package
+%% Version: 1
+%% Extends: None
+%% Purpose: This package defines properties of network terminations
+%% independent of network type.
+%%----------------------------------------------------------------------
+
+capabilities_nt() ->
+ [
+ {property, "jit"},
+ {event, "netfail"},
+ {event, "qualert"},
+ {statistics, "dur"},
+ {statistics, "os"},
+ {statistics, "or"}
+ ].
+
+encode_nt(property, Item) ->
+ case Item of
+ "jit" -> [16#00, 16#07]
+ end;
+encode_nt(event, Item) ->
+ case Item of
+ "netfail" -> [16#00, 16#05];
+ "qualert" -> [16#00, 16#06]
+ end;
+encode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ "netfail" ->
+ case SubItem of
+ "cs" -> [16#00, 16#01]
+ end;
+ "qualert" ->
+ case SubItem of
+ "th" -> [16#00, 16#01]
+ end
+ end;
+encode_nt(statistics, Item) ->
+ case Item of
+ "dur" -> [16#00, 16#01];
+ "os" -> [16#00, 16#02];
+ "or" -> [16#00, 16#03]
+ end.
+
+decode_nt(property, Item) ->
+ case Item of
+ [16#00, 16#07] -> "jit"
+ end;
+decode_nt(event, Item) ->
+ case Item of
+ [16#00, 16#05] -> "netfail";
+ [16#00, 16#06] -> "qualert"
+ end;
+decode_nt({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#05] -> % Event netfail
+ case SubItem of
+ [16#00, 16#01] -> "cs"
+ end;
+ [16#00, 16#06] -> % Event qualert
+ case Item of
+ [16#00, 16#01] -> "th"
+ end
+ end;
+decode_nt(statistics, Item) ->
+ case Item of
+ [16#00, 16#01] -> "dur";
+ [16#00, 16#02] -> "os";
+ [16#00, 16#03] -> "or"
+ end.
+
+%%----------------------------------------------------------------------
+%% Name: rtp - RTP Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support packet based multimedia
+%% data transfer by means of the Real-time Transport Protocol
+%% (RTP) [RFC 1889].
+%%----------------------------------------------------------------------
+
+capabilities_rtp() ->
+ [
+ {event, "pltrans"},
+ {statistics, "ps"},
+ {statistics, "pr"},
+ {statistics, "pl"},
+ {statistics, "jit"},
+ {statistics, "delay"}
+ ].
+
+encode_rtp(event, Item) ->
+ case Item of
+ "pltrans" -> [16#00, 16#01]
+ end;
+encode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ "pltrans" ->
+ case SubItem of
+ "rtppltype" -> [16#00, 16#01]
+ end
+ end;
+encode_rtp(statistics, Item) ->
+ case Item of
+ "ps" -> [16#00, 16#04];
+ "pr" -> [16#00, 16#05];
+ "pl" -> [16#00, 16#06];
+ "jit" -> [16#00, 16#07];
+ "delay" -> [16#00, 16#08]
+ end.
+
+decode_rtp(event, Item) ->
+ case Item of
+ [16#00, 16#01] -> "pltrans"
+ end;
+decode_rtp({event_parameter, Item}, SubItem) ->
+ case Item of
+ [16#00, 16#01] -> % Event pltrans
+ case SubItem of
+ [16#00, 16#01] -> "rtppltype"
+ end
+ end;
+decode_rtp(statistics, Item) ->
+ case Item of
+ [16#00, 16#04] -> "ps";
+ [16#00, 16#05] -> "pr";
+ [16#00, 16#06] -> "pl";
+ [16#00, 16#07] -> "jit";
+ [16#00, 16#08] -> "delay"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: tdmc - TDM Circuit Package
+%% Version: 1
+%% Extends: nt version 1
+%% Purpose: This package is used to support TDM circuit terminations.
+%%----------------------------------------------------------------------
+
+capabilities_tdmc() ->
+ [
+ {property, "ec"},
+ {property, "gain"}
+ ].
+
+encode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ "ec" -> [16#00, 16#08];
+ "gain" -> [16#00, 16#0a]
+ end
+ end.
+
+decode_tdmc(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ [16#00, 16#08] -> "ec";
+ [16#00, 16#0a] -> "gain"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: swb - SwitchBoard Package
+%% Version: 1
+%% Extends: none
+%% Purpose: This package is used to support SwitchBoard specials
+%%----------------------------------------------------------------------
+
+capabilities_swb() ->
+ [
+ {statistics, "fs"}, % Free slots
+ {statistics, "as"} % Allocated slots
+ ].
+
+encode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ "fs" -> [16#00, 16#00];
+ "as" -> [16#00, 16#01]
+ end
+ end.
+
+decode_swb(Scope, Item) ->
+ case Scope of
+ statistics ->
+ case Item of
+ [16#00, 16#00] -> "fs";
+ [16#00, 16#01] -> "as"
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Name: native - Pseudo package
+%% Version: 1
+%% Extends: None
+%% Purpose: Native tags for media stream properties
+%%
+%% Parameters for Local descriptors and Remote descriptors are
+%% specified as tag-value pairs if binary encoding is used for the
+%% protocol. This annex contains the property names (PropertyID), the
+%% tags (Property Tag), type of the property (Type) and the values
+%% (Value).Values presented in the Value field when the field contains
+%% references shall be regarded as "information". The reference
+%% contains the normative values. If a value field does not contain a
+%% reference then the values in that field can be considered as
+%% "normative".
+%%
+%% Tags are given as hexadecimal numbers in this annex. When setting
+%% the value of a property, a MGC may underspecify the value according
+%% to one of the mechanisms specified in section 7.1.1.
+%%
+%% For type "enumeration" the value is represented by the value in brack-
+%% ets, e.g., Send(0), Receive(1).
+%%----------------------------------------------------------------------
+%%
+%% C.6. IP
+%%
+%% ________________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | IPv4 | 6001 | 32 BITS | Ipv4Address |
+%% | IPv6 | 6002 | 128 BITS | IPv6 Address |
+%% | Port | 6003 | Unsigned Int| Port |
+%% | Porttype | 6004 | Enumerated | TCP(0),UDP(1),SCTP(2)|
+%% |___________|____________|______________|_______________________|
+%%
+%%
+%% C.11. SDP Equivalents
+%%
+%% ______________________________________________________________
+%% | PropertyID| Tag | Type | Value |
+%% | SDP_V | B001| STRING| Protocol Version |
+%% | SDP_O | B002| STRING| Owner-creator and session ID |
+%% | SDP_S | B003| STRING| Sesson name |
+%% | SDP_I | B004| STRING| Session identifier |
+%% | SDP_U | B005| STRING| URI of descriptor |
+%% | SDC_E | B006| STRING| email address |
+%% | SDP_P | B007| STRING| phone number |
+%% | SDP_C | B008| STRING| Connection information |
+%% | SDP_B | B009| STRING| Bandwidth Information |
+%% | SDP_Z | B00A| STRING| time zone adjustment |
+%% | SDP_K | B00B| STRING| Encryption Key |
+%% | SDP_A | B00C| STRING| Zero or more session attributes|
+%% | SDP_T | B00D| STRING| Active Session Time |
+%% | SDP_R | B00E| STRING| Zero or more repeat times |
+%% | SDP_M | B00F| STRING| Media name and transport addr |
+%% | | | | Reference: IETF RFC 2327 |
+%% |___________|______|________|_________________________________|
+%%
+%%----------------------------------------------------------------------
+
+capabilities_native() ->
+ [
+ %% C.6. IP
+ {property, "IPv4"},
+ {property, "IPv6"},
+ {property, "Port"},
+ {property, "Porttype"},
+
+ %% C.11. SDP Equivalents
+ {property, "v"},
+ {property, "o"},
+ {property, "s"},
+ {property, "i"},
+ {property, "u"},
+ {property, "e"},
+ {property, "p"},
+ {property, "c"},
+ {property, "b"},
+ {property, "z"},
+ {property, "k"},
+ {property, "a"},
+ {property, "t"},
+ {property, "r"},
+ {property, "m"}
+ ].
+
+encode_native(Scope, Item) ->
+ case Scope of
+ property ->
+ case Item of
+ %% IP
+ "IPv4" -> [16#60, 16#01];
+ "IPv6" -> [16#60, 16#02];
+ "Port" -> [16#60, 16#03];
+ "Porttype" -> [16#60, 16#04];
+
+ %% SDP
+ "v" -> [16#b0, 16#01];
+ "o" -> [16#b0, 16#02];
+ "s" -> [16#b0, 16#03];
+ "i" -> [16#b0, 16#04];
+ "u" -> [16#b0, 16#05];
+ "e" -> [16#b0, 16#06];
+ "p" -> [16#b0, 16#07];
+ "c" -> [16#b0, 16#08];
+ "b" -> [16#b0, 16#09];
+ "z" -> [16#b0, 16#0a];
+ "k" -> [16#b0, 16#0b];
+ "a" -> [16#b0, 16#0c];
+ "t" -> [16#b0, 16#0d];
+ "r" -> [16#b0, 16#0e];
+ "m" -> [16#b0, 16#0f]
+ end
+ end.
+
+decode_native(Scope, [Type, Item]) ->
+ case Scope of
+ property ->
+ case Type of
+ 16#60 ->
+ case Item of
+ 16#01 -> "IPv4";
+ 16#02 -> "IPv6";
+ 16#03 -> "Port";
+ 16#04 -> "Porttype"
+ end;
+
+ 16#b0 ->
+ case Item of
+ 16#01 -> "v";
+ 16#02 -> "o";
+ 16#03 -> "s";
+ 16#04 -> "i";
+ 16#05 -> "u";
+ 16#06 -> "e";
+ 16#07 -> "p";
+ 16#08 -> "c";
+ 16#09 -> "b";
+ 16#0a -> "z";
+ 16#0b -> "k";
+ 16#0c -> "a";
+ 16#0d -> "t";
+ 16#0e -> "r";
+ 16#0f -> "m"
+ end
+ end
+ end.
+
+%% -------------------------------------------------------------------
+
+% error(Reason) ->
+% erlang:error(Reason).
+
diff --git a/lib/megaco/src/binary/megaco_binary_term_id.erl b/lib/megaco/src/binary/megaco_binary_term_id.erl
new file mode 100644
index 0000000000..f975c1ab53
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_term_id.erl
@@ -0,0 +1,187 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_term_id).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([encode/2, decode/2]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+-define(default_config, [8,8,8]).
+
+-define(asn_root_termination_id,
+ #'TerminationID'{wildcard = [],
+ id = [16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF]}).
+
+-define(megaco_all_wildcard_termination_id,
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_all]]}).
+-define(megaco_choose_wildcard_termination_id,
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]}).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'TerminationId' record into a ASN.1 termination id
+%% Return {ok, TermId} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode(_Config, TermId) when TermId =:= ?megaco_root_termination_id ->
+ {ok, ?asn_root_termination_id};
+encode(Config, TermId) when (TermId =:= ?megaco_all_wildcard_termination_id) andalso
+ (Config =:= ?default_config) ->
+ {ok, asn_all_tid()};
+encode(Config, TermId) when (TermId =:= ?megaco_choose_wildcard_termination_id) andalso
+ (Config =:= ?default_config) ->
+ {ok, asn_choose_tid()};
+encode(Config, #megaco_term_id{contains_wildcards = false, id = IDs}) ->
+ case (catch encode1(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ EncodedTid ->
+ {ok, EncodedTid}
+ end;
+encode(Config, #megaco_term_id{contains_wildcards = true, id = IDs}) ->
+ case (catch encode2(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ EncodedTid ->
+ {ok, EncodedTid}
+ end;
+encode(_Config, TermId) ->
+ {error, {bad_type, TermId}}.
+
+
+first_bit() ->
+ lists:sum(?default_config) - 1.
+asn_all_tid() ->
+ #'TerminationID'{wildcard = [[(2#11000000 + first_bit())]],
+ id = [0, 0, 0]}.
+asn_choose_tid() ->
+ #'TerminationID'{wildcard = [[(2#01000000 + first_bit())]],
+ id = [0, 0, 0]}.
+
+
+%%----------------------------------------------------------------------
+%% Encode without wildcards
+%%----------------------------------------------------------------------
+encode1(IDs,LevelConfig) when is_list(LevelConfig) ->
+ megaco_binary_term_id_gen:encode_without_wildcards(IDs, LevelConfig);
+
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+encode1(IDs,LevelConfig) when is_integer(LevelConfig) ->
+ %% megaco_binary_term_id_8lev:encode_without_wildcards(IDs, LevelConfig).
+ encode1(IDs,lists:duplicate(LevelConfig,8)).
+
+
+%%----------------------------------------------------------------------
+%% Encode with wildcards
+%%----------------------------------------------------------------------
+encode2(IDs,LevelConfig) when is_list(LevelConfig) ->
+ megaco_binary_term_id_gen:encode_with_wildcards(IDs, LevelConfig);
+
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+encode2(IDs,LevelConfig) when is_integer(LevelConfig) ->
+ %% megaco_binary_term_id_8lev:encode_with_wildcards(IDs, LevelConfig).
+ encode2(IDs,lists:duplicate(LevelConfig,8)).
+
+
+%%----------------------------------------------------------------------
+%% Convert a ASN.1 termination id into a 'TerminationId' record
+%% Return {ok, TerminationId} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode(_Config, TermId) when (TermId =:= ?asn_root_termination_id) ->
+ {ok, ?megaco_root_termination_id};
+decode(Config, #'TerminationID'{wildcard = [], id = IDs}) ->
+ case (catch decode1(IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ MegacoTid ->
+ {ok,MegacoTid}
+ end;
+decode(Config, #'TerminationID'{wildcard = Wildcards, id = IDs}) ->
+ case (catch decode2(Wildcards,IDs,Config)) of
+ {'EXIT',Reason} ->
+ {error,Reason};
+ MegacoTid ->
+ {ok,MegacoTid}
+ end;
+decode(_Config, TermId) ->
+ {error, {bad_type, TermId}}.
+
+
+%%----------------------------------------------------------------------
+%% Decode without wildcards
+%%----------------------------------------------------------------------
+decode1(IDs, Lc) when is_list(Lc) ->
+ megaco_binary_term_id_gen:decode_without_wildcards(IDs, Lc);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+decode1(IDs, Lc) when is_integer(Lc) ->
+ %% megaco_binary_term_id_8lev:decode_without_wildcards(IDs, Lc).
+ decode1(IDs,lists:duplicate(Lc,8)).
+
+
+%%----------------------------------------------------------------------
+%% Decode with wildcards
+%%----------------------------------------------------------------------
+decode2(Wildcards, IDs, Lc) when is_list(Lc) ->
+ megaco_binary_term_id_gen:decode_with_wildcards(Wildcards, IDs, Lc);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented
+decode2(Wildcards, IDs, Lc) when is_integer(Lc) ->
+ %% megaco_binary_term_id_8lev:decode_with_wildcards(Wildcards, IDs, Lc);
+ decode2(Wildcards, IDs, lists:duplicate(Lc,8)).
+
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_term_id_gen.erl b/lib/megaco/src/binary/megaco_binary_term_id_gen.erl
new file mode 100644
index 0000000000..c8192c79b6
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_term_id_gen.erl
@@ -0,0 +1,436 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_term_id_gen).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([encode_without_wildcards/2, encode_with_wildcards/2,
+ decode_without_wildcards/2, decode_with_wildcards/3]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+-define(asn_choose, ?megaco_choose).
+-define(asn_all, ?megaco_all).
+
+
+%%----------------------------------------------------------------------
+%% Encode without wildcards
+%%----------------------------------------------------------------------
+encode_without_wildcards(IDs,LevelConfig) when is_list(LevelConfig) ->
+ EncodedIDs = encode_ids(false,IDs,LevelConfig),
+ #'TerminationID'{wildcard = [], id = EncodedIDs}.
+
+%%----------------------------------------------------------------------
+%% Encode with wildcards
+%%----------------------------------------------------------------------
+encode_with_wildcards(IDs,LevelConfig) when is_list(LevelConfig) ->
+ Wildcards = encode_wildcards(IDs,LevelConfig),
+ EncodedIDs = encode_ids(true,IDs,LevelConfig),
+ #'TerminationID'{wildcard = Wildcards, id = EncodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Decode without wildcards
+%%----------------------------------------------------------------------
+decode_without_wildcards(IDs,Lc) ->
+ DecodedIDs = decode_ids(IDs,Lc),
+ #megaco_term_id{contains_wildcards = false,
+ id = DecodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Decode with wildcards
+%%----------------------------------------------------------------------
+decode_with_wildcards(Wildcards,IDs,Lc) ->
+ DecodedIDs = decode_ids(Wildcards,IDs,Lc),
+ #megaco_term_id{contains_wildcards = true,
+ id = DecodedIDs}.
+
+
+%%----------------------------------------------------------------------
+%% Convert an internal TermId to an external
+%%----------------------------------------------------------------------
+
+encode_wildcards(IDs,LevelConfig) ->
+ case (catch encode_wildcards1(IDs,LevelConfig)) of
+ {'EXIT',id_config_mismatch} ->
+ exit({id_config_mismatch,IDs,LevelConfig});
+ {'EXIT',Reason} ->
+ exit(Reason);
+ Wildcards ->
+ encode_wildcards2(Wildcards)
+ end.
+
+encode_wildcards1(IDs,LevelConfig) ->
+ encode_wildcards3(IDs,LevelConfig).
+
+encode_wildcards2(Ws) ->
+ F = fun(no_wildcard) -> false; (_) -> true end,
+ lists:filter(F,Ws).
+
+
+
+encode_wildcards3(IDs,LevelConfig) ->
+ encode_wildcards3(IDs,LevelConfig,1,lists:sum(LevelConfig)).
+
+encode_wildcards3([],[],_,_) ->
+ [];
+encode_wildcards3([Level|Levels],[BitsInLevel|BitsRest],LevelNo,TotSize) ->
+ case (catch encode_wildcard(Level,BitsInLevel,TotSize-BitsInLevel,
+ length(Levels))) of
+ {'EXIT',{Reason,Info}} ->
+ exit({Reason,{LevelNo,Info}});
+
+ no_wildcard ->
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel);
+
+ {level,Wl} ->
+ [Wl|
+ encode_wildcards3(Levels,BitsRest,LevelNo+1,TotSize-BitsInLevel)];
+
+ {recursive,Wr} ->
+ [Wr];
+
+ Else ->
+ exit({wildcard_decode_error,Else})
+ end;
+encode_wildcards3(Levels,[],LevelNo,TotSize) ->
+ exit({id_config_mismatch,{Levels,LevelNo,TotSize}});
+encode_wildcards3(L,B,N,S) ->
+ exit({wildcard_encode_error,{L,B,N,S}}).
+
+
+encode_wildcard([],0,_TotBits,_RemainingIdLevels) ->
+ no_wildcard;
+encode_wildcard([],More,_TotBits,_RemainingIdLevels) ->
+ exit({to_few_bits_in_level,More});
+encode_wildcard(More,0,_TotBits,_RemainingIdLevels) ->
+ exit({to_many_bits_in_level,More});
+encode_wildcard([$0|R],Pos,TotBits,RemainingIdLevels) ->
+ encode_wildcard(R,Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([$1|R],Pos,TotBits,RemainingIdLevels) ->
+ encode_wildcard(R,Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([?asn_choose],Pos,TotBits,RemainingIdLevels) ->
+ encode_choose(Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([?asn_all],Pos,TotBits,RemainingIdLevels) ->
+ encode_all(Pos-1,TotBits,RemainingIdLevels);
+encode_wildcard([Val|_Rest],Pos,_TotBits,_RemainingIdLevels) ->
+ exit({invalid_level_content,{Pos-1,Val}}).
+
+%% This is the last level specified in the id list.
+%% Therefor it is a 'recursive' wildcard, i.e. the 'choose'
+%% apply to this level and all remaining levels.
+encode_choose(BitPosInLevel,BitsInRemainingConfigLevels,0)
+ when BitsInRemainingConfigLevels > 0 ->
+ {recursive,[16#40 + BitPosInLevel + BitsInRemainingConfigLevels]};
+
+%% The fact that there is no more bits in the level config
+%% means that this is actually the last level.
+%% It should not be a 'recursive' case but a 'level' case.
+%% Although it is (propably) correct with both.
+encode_choose(BitPosInLevel,0,0) ->
+ {recursive,[16#00 + BitPosInLevel]};
+
+%% There are more levels specified in the id list.
+%% Therefor it is a 'level' wildcard, i.e. the 'choose'
+%% apply to this level only.
+encode_choose(BitPosInLevel,BitsInRemainingConfigLevels,RemainingIdLevels)
+ when RemainingIdLevels > 0 ->
+ {level,[16#00 + BitPosInLevel + BitsInRemainingConfigLevels]}.
+
+%% This is the last level specified in the id list.
+%% Therefor it is a 'recursive' wildcard, i.e. the 'all'
+%% apply to this level and all remaining levels.
+encode_all(BitPosInLevel,BitsInRemainingConfigLevels,0)
+ when BitsInRemainingConfigLevels > 0 ->
+ {recursive,[16#c0 + BitPosInLevel + BitsInRemainingConfigLevels]};
+
+%% The fact that there is no more bits in the level config
+%% means that this is actually the last level.
+%% It should not be a 'recursive' case but a 'level' case.
+%% Although it is (propably) correct with both.
+encode_all(BitPosInLevel,0,0) ->
+ {recursive,[16#80 + BitPosInLevel]};
+
+%% There are more levels specified in the id list.
+%% Therefor it is a 'level' wildcard, i.e. the 'all'
+%% apply to this level only.
+encode_all(BitPosInLevel,BitsInRemainingConfigLevels,RemainingIdLevels)
+ when RemainingIdLevels > 0 ->
+ {level,[16#80 + BitPosInLevel + BitsInRemainingConfigLevels]}.
+
+
+encode_ids(W,IDs,Config) ->
+ encode_ids(W,IDs,Config,8,[0],false).
+
+encode_ids(_,[],[],8,[0|EncodedIDs],_) ->
+ lists:reverse(EncodedIDs);
+encode_ids(W,IDs,Config,0,EncodedIDs,Wf) ->
+ encode_ids(W,IDs,Config,8,[0|EncodedIDs],Wf);
+encode_ids(W,[L|Ls],[C|Cs],R,E,_) ->
+ case (catch encode_id_level(W,L,C,R,E)) of
+ {'EXIT',Reason} ->
+ exit(Reason);
+ {true,R1,E1} when (length(Ls) =:= 0) ->
+ encode_ids2(Cs,encode_ids1(R1,E1));
+ {WildcardFound1,R1,E1} ->
+ encode_ids(W,Ls,Cs,R1,E1,WildcardFound1);
+ {true,E2} when (length(Ls) =:= 0) ->
+ encode_ids2(Cs,E2);
+ {WildcardFound2,E2} ->
+ encode_ids(W,Ls,Cs,8,[0|E2],WildcardFound2)
+ end;
+encode_ids(W,[[]],C,R,E,Wf) when length(C) > 0 ->
+ exit({empty_last_level,{W,C,R,E,Wf}});
+encode_ids(W,[],C,R,E,false) when length(C) > 0 ->
+ exit({unexpected_eof_data,{W,C,R,E}}).
+
+encode_ids1(_R,[0|Es]) ->
+ [0|Es];
+encode_ids1(R,[E|Es]) ->
+ [(E bsl R)|Es].
+
+encode_ids2([],Es) ->
+ lists:reverse(Es);
+encode_ids2(Cs,Es) ->
+ Fill = lists:duplicate(lists:sum(Cs) div 8,0),
+ lists:reverse(Fill ++ Es).
+
+
+encode_id_level(W,L,C,R,[E|Es]) ->
+ case encode_id_level1(W,L,C,R,E) of
+ %% End Of Byte (more bits in level)
+ {eob,_WildcardFound,L1,C1,E1} ->
+ encode_id_level(W,L1,C1,8,[0,E1|Es]);
+
+ %% End Of Level (more room in byte)
+ {eol,WildcardFound,R1,E1} ->
+ {WildcardFound,R1,[E1|Es]};
+
+ %% Done; Level used up all of the byte
+ {done,WildcardFound,E1} ->
+ {WildcardFound,[E1|Es]}
+ end.
+
+
+encode_id_level1(_W,[],0,0,E) ->
+ {done,false,E};
+encode_id_level1(_W,[],0,R,E) ->
+ {eol,false,R,E};
+encode_id_level1(_W,L,C,0,E) ->
+ {eob,false,L,C,E};
+encode_id_level1(W,[$0|L],C,R,E) ->
+ encode_id_level1(W,L,C-1,R-1,E bsl 1);
+encode_id_level1(W,[$1|L],C,R,E) ->
+ encode_id_level1(W,L,C-1,R-1,(E bsl 1) + 1);
+encode_id_level1(true,[$$],C,R,E) ->
+ encode_id_level2(C,R,E,$$);
+encode_id_level1(true,[$*],C,R,E) ->
+ encode_id_level2(C,R,E,$*);
+encode_id_level1(false,[$$],C,R,_E) ->
+ exit({wildcard_error,{$$,C,R}});
+encode_id_level1(false,[$*],C,R,_E) ->
+ exit({wildcard_error,{$*,C,R}});
+encode_id_level1(_W,[L|_Ls],C,R,_E) ->
+ exit({invalid_level_content,{C,R,L}}).
+
+encode_id_level2(C,C,E,_W) ->
+ {done,true,E bsl C};
+encode_id_level2(C,R,E,W) when C > R ->
+ {eob,true,[W],C-R,E bsl R};
+encode_id_level2(C,R,E,_W) ->
+ {eol,true,R-C,E bsl C}.
+
+
+%%----------------------------------------------------------------------
+%% Convert an external TermId to an internal
+%%----------------------------------------------------------------------
+
+%% Decode ID with wildcards
+decode_ids(Ws,IDs,Config) when is_list(Config) ->
+ IDs1 = decode_ids(IDs,Config),
+ Ws1 = decode_wildcards(Ws,(length(IDs)*8) - 1),
+ decode_ids1(Ws1,IDs1);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented.
+%% This is the case when each level is 8 bits = 1 byte and the config
+%% simply indicates the number of (1 byte) levels
+decode_ids(Ws,IDs,Config) when is_integer(Config) ->
+ decode_ids(Ws,IDs,lists:duplicate(Config,8)).
+
+
+%% Decode ID without wildcards
+decode_ids(E,Config) when is_list(Config) ->
+ decode_ids(0,E,Config,[]);
+
+%% This is only temporary. Eventually a proper encoder for this case
+%% should be implemented.
+%% This is the case when each level is 8 bits = 1 byte and the config
+%% simply indicates the number of (1 byte) levels
+decode_ids(E,Config) when is_integer(Config) ->
+ decode_ids(E,lists:duplicate(Config,8)).
+
+
+%% The [0] is the result of all the bits of the byte has been shifted out.
+decode_ids(_B,[0],[],Acc) ->
+ lists:reverse(Acc);
+decode_ids(_B,[E],[],Acc) ->
+ exit({id_config_mismatch,{two_much_data,E,Acc}});
+decode_ids(_B,E,[],Acc) ->
+ exit({id_config_mismatch,{two_much_data,E,Acc}});
+decode_ids(B,E,[L|Ls],Acc) ->
+ case (catch decode_id_level(B,E,L,[])) of
+ {Level,E1,B1} ->
+ decode_ids(B1,E1,Ls,[Level|Acc]);
+ {'EXIT',{id_config_mismatch,{Bx,Ex,Lx,Accx}}} ->
+ exit({id_level_mismatch,{B,Bx,E,Ex,L,Ls,Lx,Acc,Accx}})
+ end.
+
+
+decode_wildcards(Ws,NofBits) ->
+ lists:keysort(3,[decode_wildcard(W,NofBits) || W <- Ws]).
+
+
+%% ----------------------------------------------------------------------
+%% A decoded wildcard is a three tuple:
+%% {wildcard_type(), wildcard_level(), wildcard_offset()}
+%% wildcard_type() -> $ | *
+%% wildcard_level() -> level | recursive
+%% wildcard_offset() -> integer()
+%%
+%% The "raw" wildcard offset is measured from the end of the id bytes:
+%%
+%% 0 1 2 3 4 5 6 7
+%% -----------------
+%% | | | | | | | | |
+%% -----------------
+%%
+%% |<--------|
+%% 5
+%%
+%% The decoded wildcard offset in contrast is measured from the start
+%% of the id field:
+%%
+%% 0 1 2 3 4 5 6 7
+%% -----------------
+%% | | | | | | | | |
+%% -----------------
+%%
+%% |---->|
+%% 3
+%%
+
+decode_wildcard([W],NofBits) ->
+ {decode_wildcard_t(W band 16#80),
+ decode_wildcard_l(W band 16#40),
+ NofBits - (W band 16#3F)}.
+
+decode_wildcard_t(16#80) -> ?asn_all;
+decode_wildcard_t(16#00) -> ?asn_choose.
+
+decode_wildcard_l(16#00) -> level;
+decode_wildcard_l(16#40) -> recursive.
+
+
+decode_ids1(W,IDs) ->
+ lists:reverse(decode_ids1(W,IDs,0,[])).
+
+decode_ids1([],IDs,_,Acc) ->
+ lists:reverse(IDs) ++ Acc;
+decode_ids1([{Type,recursive,Offset}],IDs,Bp,Acc) ->
+ decode_ids2(Type,Offset,IDs,Bp,Acc);
+decode_ids1([{Type,level,Offset}|Ws],IDs,Bp,Acc) ->
+ {IDs1,IDs2,Bp1} = decode_ids3(Type,Offset,IDs,Bp,[]),
+ decode_ids1(Ws,IDs2,Bp1,IDs1++Acc);
+decode_ids1(Ws,_,_,_) ->
+ exit({invalid_wildcards,Ws}).
+
+
+%% Called when recursive wildcard found
+decode_ids2(Type,Offset,[ID|IDs],Bp,Acc) ->
+ LevelSz = length(ID),
+ Bp1 = Offset-Bp,
+ case Bp1 >= LevelSz of
+ true ->
+ decode_ids2(Type,Offset,IDs,Bp+LevelSz,[ID|Acc]);
+ false ->
+ [decode_ids4(Type,Bp1,ID)|Acc]
+ end.
+
+
+decode_ids3(Type,Offset,[ID|IDs],Bp,Acc) ->
+ LevelSz = length(ID),
+ Bp1 = Offset-Bp,
+ case Bp1 > LevelSz of
+ true ->
+ decode_ids3(Type,Offset,IDs,Bp+LevelSz,[ID|Acc]);
+ false ->
+ A1 = decode_ids4(Type,Bp1,ID),
+ {[A1|Acc],IDs,Bp+LevelSz}
+ end.
+
+
+decode_ids4(Type,0,_ID) ->
+ [Type];
+decode_ids4(Type,O,[H|T]) ->
+ [H|decode_ids4(Type,O-1,T)].
+
+
+%% E: Encoded bits -> [byte()]
+%% L: Number of nits in level
+decode_id_level(B,E,0,Acc) ->
+ {lists:reverse(Acc),E,B};
+decode_id_level(8,[_H|T],L,Acc) ->
+ decode_id_level(0,T,L,Acc);
+decode_id_level(B,[H|T],L,Acc) ->
+ Acc1 = [decode_id_level1(H band 16#80) | Acc],
+ decode_id_level(B+1,[((H bsl 1) band 16#FF) |T],L-1,Acc1);
+decode_id_level(B,E,L,Acc) ->
+ exit({id_config_mismatch,{B,E,L,Acc}}).
+
+decode_id_level1(16#80) -> $1;
+decode_id_level1(16#00) -> $0.
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl
new file mode 100644
index 0000000000..609947c933
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3a.erl
@@ -0,0 +1,1629 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3a).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3a).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepsCallind = Ind,
+ contextProp = Props},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ Props2 =
+ case Props of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepsCallind = Ind2,
+ contextProp = Props2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepsCallind = Ind,
+ contextPropAud = Props},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepsCallind = Ind2,
+ contextPropAud = Props2}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_duration(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl
new file mode 100644
index 0000000000..baca84bbfe
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3b.erl
@@ -0,0 +1,1629 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3b).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3b).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = Props},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ Props2 =
+ case Props of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = Props2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_duration(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl b/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl
new file mode 100644
index 0000000000..8d2f9eea38
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_prev3c.erl
@@ -0,0 +1,1756 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_prev3c).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_prev3c).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE};
+tr_TransactionReply(TR, _State) ->
+ error({unsupported_TransactionReply, TR}).
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = CtxProps,
+ contextList = CtxList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ CtxProps2 =
+ case CtxProps of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- CtxProps]
+ end,
+ CtxList2 =
+ case CtxList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_ContextID(Id, State) || Id <- CtxList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = CtxProps2,
+ contextList = CtxList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SInd,
+ selectLogic = SLog},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ SPrio2 =
+ case SPrio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(SPrio, State, 0, 15)
+ end,
+ SEm2 =
+ case SEm of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SInd2 =
+ case SInd of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SLog2 =
+ case SLog of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_SelectLogic(SLog, State)
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2,
+ selectpriority = SPrio2,
+ selectemergency = SEm2,
+ selectiepscallind = SInd2,
+ selectLogic = SLog2}.
+
+tr_SelectLogic({andAUDITSelect, 'NULL'} = Val, _State) ->
+ Val;
+tr_SelectLogic({orAUDITSelect, 'NULL'} = Val, _State) ->
+ Val.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID,
+ topologyDirectionExtension = TDE},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ TDE2 =
+ case TDE of
+ onewayexternal -> onewayexternal;
+ onewayboth -> onewayboth;
+ asn1_NOVALUE -> asn1_NOVALUE
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2,
+ streamID = tr_opt_StreamID(SID, State),
+ topologyDirectionExtension = TDE2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc,
+ terminationIDList = TIDList},
+ State) ->
+ TIDList2 =
+ case TIDList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TerminationID(TID, State) || TID <- TIDList]
+ end,
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State),
+ terminationIDList = TIDList2}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State);
+ auditResultTermList ->
+ tr_TermListAuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR},
+ State) ->
+ TIDList2 = [tr_TerminationID(TID, State) || TID <- TIDList],
+ TAR2 = tr_TerminationAudit(TAR, State),
+ #'TermListAuditResult'{terminationIDList = TIDList2,
+ terminationAuditResult = TAR2}.
+
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ SSS2 = tr_opt_ServiceState(SSS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P,
+ streamModeSel = SMS} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ SMS2 = tr_opt_StreamMode(SMS, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2,
+ streamModeSel = SMS2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0,
+ propertyParms = Prop0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ Prop =
+ case Prop0 of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_PropertyParm(Prop0, State)
+ end,
+ #'IndAudPropertyParm'{name = Name,
+ propertyParms = Prop}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID,
+ signalRequestID = RID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State),
+ signalRequestID = tr_opt_RequestID(RID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}.
+
+tr_opt_NotifyBehaviour(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyBehaviour(NB, State) ->
+ tr_NotifyBehaviour(NB, State).
+
+tr_NotifyBehaviour({notifyImmediate, 'NULL'} = NB, _State) ->
+ NB;
+tr_NotifyBehaviour({notifyRegulated = Tag, Val}, State) ->
+ {Tag, tr_RegulatedEmbeddedDescriptor(Val, State)};
+tr_NotifyBehaviour({neverNotify, 'NULL'} = NB, _State) ->
+ NB.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = DM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = DM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_UINT16(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ ID2 = tr_opt_UINT16(ID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ID2}.
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason;
+ onIteration -> onIteration
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v1.erl b/lib/megaco/src/binary/megaco_binary_transformer_v1.erl
new file mode 100644
index 0000000000..7236c0a9e1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v1.erl
@@ -0,0 +1,1261 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v1).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER,megaco_binary_name_resolver_v1).
+-define(error(R), erlang:error({error, R})).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ %% i("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ %% i("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ %% i("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ %% i("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ ?error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ State) ->
+ #'ContextAttrAuditRequest'{topology = tr_opt_null(Top, State),
+ emergency = tr_opt_null(Em, State),
+ priority = tr_opt_null(Prio, State)}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = [tr_ammDescriptor(Desc, State) ||
+ Desc <- DescList]}.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ [tr_AuditReturnParameter(Parm, State) || Parm <- ParmList].
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = Control,
+ localDescriptor = Local,
+ remoteDescriptor = Remote},
+ State) ->
+ #'StreamParms'{localControlDescriptor = tr_opt_LocalControlDescriptor(Control, State),
+ localDescriptor = tr_opt_LocalRemoteDescriptor(Local, State),
+ remoteDescriptor = tr_opt_LocalRemoteDescriptor(Remote, State)}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = Id,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms},
+ State) ->
+ #'Signal'{signalName = tr_SignalName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ sigType = tr_opt_SignalType(Type, State),
+ duration = tr_opt_duration(Dur, State),
+ notifyCompletion = tr_opt_NotifyCompletion(Compl, State),
+ keepActive = tr_opt_keepActive(Keep, State),
+ sigParList = [tr_SigParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(#'ModemDescriptor'{mtl = Types,
+ mpl = Props},
+ State) when is_list(Types) andalso is_list(Props) ->
+ %% BUGBUG: Does not handle extensionParameter
+ #'ModemDescriptor'{mtl = [tr_ModemType(T, State) || T <- Types],
+ mpl = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_ModemType(Type, _State) ->
+ %% BUGBUG: Does not handle extensionParameter
+ case Type of
+ v18 -> v18;
+ v22 -> v22;
+ v22bis -> v22bis;
+ v32 -> v32;
+ v32bis -> v32bis;
+ v34 -> v34;
+ v90 -> v90;
+ v91 -> v91;
+ synchISDN -> synchISDN
+ end.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeParm'{serviceChangeMethod = tr_ServiceChangeMethod(Method, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ serviceChangeReason = tr_serviceChangeReason(Reason, State),
+ serviceChangeDelay = tr_opt_serviceChangeDelay(Delay, State),
+ serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ ?error({count_too_large, Count, Max})
+ end;
+ true ->
+ ?error({count_too_small, Count, Min})
+ end;
+ true ->
+ ?error({count_not_an_integer, Count})
+ end.
+
+
+% i(F,A) ->
+% %% i(true,F,A).
+% i(get(dbg),F,A).
+
+% i(true,F,A) ->
+% S1 = io_lib:format("TRANSF-v1: " ++ F ++ "~n",A),
+% S2 = lists:flatten(S1),
+% io:format("~s",[S2]);
+% i(_,_F,_A) ->
+% ok.
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v2.erl b/lib/megaco/src/binary/megaco_binary_transformer_v2.erl
new file mode 100644
index 0000000000..686e384a29
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v2.erl
@@ -0,0 +1,1544 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v2).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER,megaco_binary_name_resolver_v2).
+-define(error(R), erlang:error({error, R})).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ %% i("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ %% i("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ %% i("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ %% i("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+% i("tr_MegacoMessage -> entry with"
+% "~n Auth: ~p"
+% "~n Mess: ~p"
+% "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ ?error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ State) ->
+ #'ContextAttrAuditRequest'{topology = tr_opt_null(Top, State),
+ emergency = tr_opt_null(Em, State),
+ priority = tr_opt_null(Prio, State)}.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ ?error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc},
+ State) ->
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State)}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ #'IndAudPropertyParm'{name = Name}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n N: ~p"
+% "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+% i("tr_indAudEventBufferDescriptor -> entry with"
+% "~n N: ~p"
+% "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+% i("tr_indAudPackagesDescriptor -> entry with"
+% "~n N: ~p"
+% "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+% i("tr_indAudPackagesDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ ?error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list(Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = Control,
+ localDescriptor = Local,
+ remoteDescriptor = Remote},
+ State) ->
+ #'StreamParms'{localControlDescriptor = tr_opt_LocalControlDescriptor(Control, State),
+ localDescriptor = tr_opt_LocalRemoteDescriptor(Local, State),
+ remoteDescriptor = tr_opt_LocalRemoteDescriptor(Remote, State)}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ secondEvent = Event,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'RequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ secondEvent = tr_opt_SecondEventsDescriptor(Event, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(#'SecondRequestedActions'{keepActive = Keep,
+ eventDM = DM,
+ signalsDescriptor = SigDesc},
+ State) ->
+ #'SecondRequestedActions'{keepActive = tr_opt_keepActive(Keep, State),
+ eventDM = tr_opt_EventDM(DM, State),
+ signalsDescriptor = tr_opt_SignalsDescriptor(SigDesc, State)}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = Id,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms},
+ State) ->
+ #'Signal'{signalName = tr_SignalName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ sigType = tr_opt_SignalType(Type, State),
+ duration = tr_opt_duration(Dur, State),
+ notifyCompletion = tr_opt_NotifyCompletion(Compl, State),
+ keepActive = tr_opt_keepActive(Keep, State),
+ sigParList = [tr_SigParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_duration(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_duration(Dur, State) ->
+ tr_UINT16(Dur, State).
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason
+ end.
+
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+% tr_ModemDescriptor(#'ModemDescriptor'{mtl = Types,
+% mpl = Props},
+% State) when list(Types), list(Props) ->
+% %% BUGBUG: Does not handle extensionParameter
+% #'ModemDescriptor'{mtl = [tr_ModemType(T, State) || T <- Types],
+% mpl = [tr_PropertyParm(P, State) || P <- Props]}.
+
+% tr_ModemType(Type, _State) ->
+% %% BUGBUG: Does not handle extensionParameter
+% case Type of
+% v18 -> v18;
+% v22 -> v22;
+% v22bis -> v22bis;
+% v32 -> v32;
+% v32bis -> v32bis;
+% v34 -> v34;
+% v90 -> v90;
+% v91 -> v91;
+% synchISDN -> synchISDN
+% end.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info},
+ State) ->
+ #'ServiceChangeParm'{serviceChangeMethod = tr_ServiceChangeMethod(Method, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ serviceChangeReason = tr_serviceChangeReason(Reason, State),
+ serviceChangeDelay = tr_opt_serviceChangeDelay(Delay, State),
+ serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ timeStamp = tr_opt_TimeNotation(Time, State),
+ serviceChangeInfo = tr_opt_AuditDescriptor(Info, State)}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ ?error({count_too_large, Count, Max})
+ end;
+ true ->
+ ?error({count_too_small, Count, Min})
+ end;
+ true ->
+ ?error({count_not_an_integer, Count})
+ end.
+
+
+% i(F,A) ->
+% S1 = io_lib:format("TRANSF-v2: " ++ F ++ "~n",A),
+% S2 = lists:flatten(S1),
+% io:format("~s",[S2]).
diff --git a/lib/megaco/src/binary/megaco_binary_transformer_v3.erl b/lib/megaco/src/binary/megaco_binary_transformer_v3.erl
new file mode 100644
index 0000000000..cef49b03fd
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_binary_transformer_v3.erl
@@ -0,0 +1,1763 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transform internal form of Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_transformer_v3).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-export([tr_message/3, tr_transaction/3]).
+
+-define(DEFAULT_NAME_RESOLVER, megaco_binary_name_resolver_v3).
+
+-record(state, {mode, % verify | encode | decode
+ resolver_module, %
+ resolver_options}).
+
+resolve(Type, Item, State, Constraint) ->
+ case State#state.mode of
+ verify ->
+ Item;
+ encode ->
+ ?d("resolve(encode) -> encode: ~p",[Item]),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ EncodedItem = Mod:encode_name(Opt, Type, Item),
+ ?d("resolve -> verify contraint for ~p",[EncodedItem]),
+ verify_constraint(EncodedItem, Constraint);
+ decode ->
+ ?d("resolve(decode) -> verify contraint for ~p",[Item]),
+ DecodedItem = verify_constraint(Item, Constraint),
+ Mod = State#state.resolver_module,
+ Opt = State#state.resolver_options,
+ ?d("resolve(decode) -> decode: ~p",[DecodedItem]),
+ Mod:decode_name(Opt, Type, DecodedItem)
+ end.
+
+verify_constraint(Item, valid) ->
+ Item;
+verify_constraint(Item, Constraint) when is_function(Constraint) ->
+ Constraint(Item).
+
+tr_message(MegaMsg, Mode, Config) ->
+ case Config of
+ [native] ->
+ MegaMsg;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_MegacoMessage(MegaMsg, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_MegacoMessage(MegaMsg, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_MegacoMessage(MegaMsg, State)
+ end.
+
+tr_transaction(Trans, Mode, Config) ->
+ case Config of
+ [native] ->
+ Trans;
+ [verify] ->
+ State = #state{mode = verify},
+ tr_Transaction(Trans, State);
+ [] ->
+ State = #state{mode = Mode,
+ resolver_module = ?DEFAULT_NAME_RESOLVER,
+ resolver_options = [8, 8, 8]},
+ tr_Transaction(Trans, State);
+ [{binary_name_resolver, {Module, Options}}] when is_atom(Module) ->
+ State = #state{mode = Mode,
+ resolver_module = Module,
+ resolver_options = Options},
+ tr_Transaction(Trans, State)
+ end.
+
+tr_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess},
+ State) ->
+ ?d("tr_MegacoMessage -> entry with"
+ "~n Auth: ~p"
+ "~n Mess: ~p"
+ "~n State: ~p", [Auth, Mess, State]),
+ #'MegacoMessage'{authHeader = tr_opt_AuthenticationHeader(Auth, State),
+ mess = tr_Message(Mess, State)}.
+
+tr_opt_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AuthData},
+ State) ->
+ #'AuthenticationHeader'{secParmIndex = tr_SecurityParmIndex(SPI, State),
+ seqNum = tr_SequenceNum(SN, State),
+ ad = tr_AuthData(AuthData, State)}.
+
+tr_SecurityParmIndex(SPI, State) ->
+ tr_HEXDIG(SPI, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_SequenceNum(SN, State) ->
+ tr_HEXDIG(SN, State, 4, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_AuthData(AuthData, State) ->
+ tr_HEXDIG(AuthData, State, 12, 32). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_Message(#'Message'{version = Version,
+ mId = MID,
+ messageBody = Body},
+ State) ->
+ #'Message'{version = tr_version(Version, State),
+ mId = tr_MId(MID, State),
+ messageBody = tr_Message_messageBody(Body, State)}.
+
+tr_version(Version, State) ->
+ tr_DIGIT(Version, State, 0, 99).
+
+tr_Message_messageBody({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ messageError -> tr_ErrorDescriptor(Val, State);
+ transactions when is_list(Val) -> [tr_Transaction(T, State) || T <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_MId({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_mtpAddress(MtpAddr, State) ->
+ tr_OCTET_STRING(MtpAddr, State, 2, 4). % BUGBUG: Mismatch between ASN.1 and ABNF
+
+tr_DomainName(#'DomainName'{name = Name,
+ portNumber = Port},
+ State) ->
+ Domain = #'DomainName'{name = tr_STRING(Name, State), % BUGBUG: Mismatch between ASN.1 and ABNF
+ portNumber = tr_opt_portNumber(Port, State)},
+ {domainName, Domain2} = resolve(mid, {domainName, Domain}, State, valid),
+ Domain2.
+
+tr_IP4Address(#'IP4Address'{address = [A1, A2, A3, A4],
+ portNumber = Port},
+ State) ->
+ #'IP4Address'{address = [tr_V4hex(A1, State),
+ tr_V4hex(A2, State),
+ tr_V4hex(A3, State),
+ tr_V4hex(A4, State)],
+ portNumber = tr_opt_portNumber(Port, State)}.
+
+tr_V4hex(Val, State) ->
+ tr_DIGIT(Val, State, 0, 255).
+
+tr_IP6Address(_Val, _State) ->
+ error(ipv6_not_supported). %% BUGBUG: nyi
+
+tr_PathName(Path, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ Constraint = fun({deviceName, Item}) -> tr_STRING(Item, State, 1, 64) end,
+ resolve(mid, {deviceName, Path}, State, Constraint).
+
+tr_Transaction({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionRequest -> tr_TransactionRequest(Val, State);
+ transactionPending -> tr_TransactionPending(Val, State);
+ transactionReply -> tr_TransactionReply(Val, State);
+ transactionResponseAck -> [tr_TransactionAck(T, State) || T <- Val];
+ segmentReply -> tr_SegmentReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TransactionAck(#'TransactionAck'{firstAck = First,
+ lastAck = Last},
+ State) ->
+ #'TransactionAck'{firstAck = tr_TransactionId(First, State),
+ lastAck = tr_opt_TransactionId(Last, State)}.
+
+tr_opt_TransactionId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TransactionId(Id, State) ->
+ tr_TransactionId(Id, State).
+
+tr_TransactionId(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_TransactionRequest(#'TransactionRequest'{transactionId = Id,
+ actions = Actions},
+ State) when is_list(Actions) ->
+
+ #'TransactionRequest'{transactionId = tr_TransactionId(Id, State),
+ actions = [tr_ActionRequest(ActReq, State) || ActReq <- Actions]}.
+
+tr_TransactionPending(#'TransactionPending'{transactionId = Id},
+ State) ->
+ #'TransactionPending'{transactionId = tr_TransactionId(Id, State)}.
+
+tr_TransactionReply(#'TransactionReply'{transactionId = Id,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = SC},
+ State) ->
+ #'TransactionReply'{transactionId = tr_TransactionId(Id, State),
+ immAckRequired = tr_opt_null(ImmAck, State),
+ transactionResult = tr_TransactionReply_transactionResult(TransRes, State),
+ segmentNumber = tr_opt_SegmentNumber(SN, State),
+ segmentationComplete = tr_opt_null(SC, State)}.
+
+tr_opt_null(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_null('NULL', _State) -> 'NULL'.
+
+tr_SegmentNumber(Num, State) ->
+ tr_UINT16(Num, State).
+
+tr_opt_SegmentNumber(Num, State) ->
+ tr_opt_UINT16(Num, State).
+
+tr_SegmentReply(#'SegmentReply'{transactionId = TID,
+ segmentNumber = SN,
+ segmentationComplete = SC}, State) ->
+ #'SegmentReply'{transactionId = tr_TransactionId(TID, State),
+ segmentNumber = tr_SegmentNumber(SN, State),
+ segmentationComplete = tr_opt_null(SC, State)}.
+
+tr_TransactionReply_transactionResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ transactionError ->
+ tr_ErrorDescriptor(Val, State);
+ actionReplies when is_list(Val) andalso (Val =/= []) ->
+ [tr_ActionReply(ActRep, State) || ActRep <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_opt_ErrorDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorDescriptor(ErrDesc, State) ->
+ tr_ErrorDescriptor(ErrDesc, State).
+
+tr_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ State) ->
+ #'ErrorDescriptor'{errorCode = tr_ErrorCode(Code, State),
+ errorText = tr_opt_ErrorText(Text, State)}.
+
+tr_ErrorCode(Code, State) ->
+ tr_DIGIT(Code, State, 0, 999).
+
+tr_opt_ErrorText(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ErrorText(Text, State) ->
+ tr_QUOTED_STRING(Text, State).
+
+tr_ContextID(CtxId, State) ->
+ case CtxId of
+ ?megaco_all_context_id -> ?megaco_all_context_id;
+ ?megaco_null_context_id -> ?megaco_null_context_id;
+ ?megaco_choose_context_id -> ?megaco_choose_context_id;
+ Int when is_integer(Int) -> tr_UINT32(Int, State)
+ end.
+
+tr_ActionRequest(#'ActionRequest'{contextId = CtxId,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAuditReq,
+ commandRequests = CmdReqList},
+ State) ->
+ #'ActionRequest'{contextId = tr_ContextID(CtxId, State),
+ contextRequest = tr_opt_ContextRequest(CtxReq, State),
+ contextAttrAuditReq = tr_opt_ContextAttrAuditRequest(CtxAuditReq, State),
+ commandRequests = [tr_CommandRequest(CmdReq, State) || CmdReq <- CmdReqList]}.
+
+tr_ActionReply(#'ActionReply'{contextId = CtxId,
+ errorDescriptor = ErrDesc,
+ contextReply = CtxRep,
+ commandReply = CmdRepList},
+ State) ->
+ CmdRepList2 = [tr_CommandReply(CmdRep, State) || CmdRep <- CmdRepList],
+ #'ActionReply'{contextId = tr_ContextID(CtxId, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State),
+ contextReply = tr_opt_ContextRequest(CtxRep, State),
+ commandReply = CmdRepList2}.
+
+tr_opt_ContextRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextRequest(CR, State) ->
+ tr_ContextRequest(CR, State).
+
+tr_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReqList,
+ iepscallind = Ind,
+ contextProp = CtxProps,
+ contextList = CtxList},
+ State) ->
+ Prio2 =
+ case Prio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(Prio, State, 0, 15)
+ end,
+ Em2 =
+ case Em of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ TopReqList2 =
+ case TopReqList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TopologyRequest(TopReq, State) ||
+ TopReq <- TopReqList]
+ end,
+ Ind2 =
+ case Ind of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ CtxProps2 =
+ case CtxProps of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_PropertyParm(Prop, State) || Prop <- CtxProps]
+ end,
+ CtxList2 =
+ case CtxList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_ContextID(Id, State) || Id <- CtxList]
+ end,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReqList2,
+ iepscallind = Ind2,
+ contextProp = CtxProps2,
+ contextList = CtxList2}.
+
+tr_opt_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ContextAttrAuditRequest(CAAR, State) ->
+ tr_ContextAttrAuditRequest(CAAR, State).
+
+tr_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ind,
+ contextPropAud = Props,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SInd,
+ selectLogic = SLog},
+ State) ->
+ Top2 = tr_opt_null(Top, State),
+ Em2 = tr_opt_null(Em, State),
+ Prio2 = tr_opt_null(Prio, State),
+ Ind2 = tr_opt_null(Ind, State),
+ Props2 =
+ case Props of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAudPropertyParm(Prop, State) || Prop <- Props]
+ end,
+ SPrio2 =
+ case SPrio of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_integer(SPrio, State, 0, 15)
+ end,
+ SEm2 =
+ case SEm of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SInd2 =
+ case SInd of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ false -> false;
+ true -> true
+ end,
+ SLog2 =
+ case SLog of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_SelectLogic(SLog, State)
+ end,
+ #'ContextAttrAuditRequest'{topology = Top2,
+ emergency = Em2,
+ priority = Prio2,
+ iepscallind = Ind2,
+ contextPropAud = Props2,
+ selectpriority = SPrio2,
+ selectemergency = SEm2,
+ selectiepscallind = SInd2,
+ selectLogic = SLog2}.
+
+tr_SelectLogic({andAUDITSelect, 'NULL'} = Val, _State) ->
+ Val;
+tr_SelectLogic({orAUDITSelect, 'NULL'} = Val, _State) ->
+ Val.
+
+tr_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = Wild},
+ State) ->
+ #'CommandRequest'{optional = tr_opt_null(Opt, State),
+ wildcardReturn = tr_opt_null(Wild, State),
+ command = tr_Command(Cmd, State)}.
+
+tr_Command({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReq -> tr_AmmRequest(Val, State);
+ moveReq -> tr_AmmRequest(Val, State);
+ modReq -> tr_AmmRequest(Val, State);
+ subtractReq -> tr_SubtractRequest(Val, State);
+ auditCapRequest -> tr_AuditRequest(Val, State);
+ auditValueRequest -> tr_AuditRequest(Val, State);
+ notifyReq -> tr_NotifyRequest(Val, State);
+ serviceChangeReq -> tr_ServiceChangeRequest(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_CommandReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ addReply -> tr_AmmsReply(Val, State);
+ moveReply -> tr_AmmsReply(Val, State);
+ modReply -> tr_AmmsReply(Val, State);
+ subtractReply -> tr_AmmsReply(Val, State);
+ auditCapReply -> tr_AuditReply(Val, State);
+ auditValueReply -> tr_AuditReply(Val, State);
+ notifyReply -> tr_NotifyReply(Val, State);
+ serviceChangeReply -> tr_ServiceChangeReply(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID,
+ topologyDirectionExtension = TDE},
+ State) ->
+ Dir2 =
+ case Dir of
+ bothway -> bothway;
+ isolate -> isolate;
+ oneway -> oneway
+ end,
+ TDE2 =
+ case TDE of
+ onewayexternal -> onewayexternal;
+ onewayboth -> onewayboth;
+ asn1_NOVALUE -> asn1_NOVALUE
+ end,
+ #'TopologyRequest'{terminationFrom = tr_TerminationID(From, State),
+ terminationTo = tr_TerminationID(To, State),
+ topologyDirection = Dir2,
+ streamID = tr_opt_StreamID(SID, State),
+ topologyDirectionExtension = TDE2}.
+
+tr_AmmRequest(#'AmmRequest'{terminationID = IdList,
+ descriptors = DescList},
+ State) ->
+ #'AmmRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ descriptors = tr_ammDescriptors(DescList, [], State)}.
+
+tr_ammDescriptors([], Acc, _State) ->
+ lists:reverse(Acc);
+tr_ammDescriptors([Desc|Descs], Acc, State) ->
+ case tr_ammDescriptor(Desc, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Desc});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ tr_ammDescriptors(Descs, Acc, State);
+ NewDesc ->
+ tr_ammDescriptors(Descs, [NewDesc|Acc], State)
+ end.
+
+tr_ammDescriptor({Tag, Desc}, State) ->
+ Desc2 =
+ case Tag of
+ mediaDescriptor -> tr_MediaDescriptor(Desc, State);
+ modemDescriptor -> tr_ModemDescriptor(Desc, State);
+ muxDescriptor -> tr_MuxDescriptor(Desc, State);
+ eventsDescriptor -> tr_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> tr_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> tr_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> tr_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> tr_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> tr_StatisticsDescriptor(Desc, State)
+ end,
+ {Tag, Desc2}.
+
+tr_AmmsReply(#'AmmsReply'{terminationID = IdList,
+ terminationAudit = TermAudit},
+ State) ->
+ TermAudit2 =
+ case TermAudit of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_TerminationAudit(TermAudit, State)
+ end,
+ #'AmmsReply'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ terminationAudit = TermAudit2}.
+
+tr_SubtractRequest(#'SubtractRequest'{terminationID = IdList,
+ auditDescriptor = Desc},
+ State) ->
+ #'SubtractRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ auditDescriptor = tr_opt_AuditDescriptor(Desc, State)}.
+
+tr_AuditRequest(#'AuditRequest'{terminationID = Id,
+ auditDescriptor = Desc,
+ terminationIDList = TIDList},
+ State) ->
+ TIDList2 =
+ case TIDList of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_TerminationID(TID, State) || TID <- TIDList]
+ end,
+ #'AuditRequest'{terminationID = tr_TerminationID(Id, State),
+ auditDescriptor = tr_AuditDescriptor(Desc, State),
+ terminationIDList = TIDList2}.
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+
+tr_AuditReply({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ contextAuditResult ->
+ [tr_TerminationID(Id, State) || Id <- Val];
+ error ->
+ tr_ErrorDescriptor(Val, State);
+ auditResult ->
+ tr_AuditResult(Val, State);
+ auditResultTermList ->
+ tr_TermListAuditResult(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_AuditResult(#'AuditResult'{terminationID = Id,
+ terminationAuditResult = AuditRes},
+ State) ->
+ #'AuditResult'{terminationID = tr_TerminationID(Id, State),
+ terminationAuditResult = tr_TerminationAudit(AuditRes, State)}.
+
+tr_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR},
+ State) ->
+ TIDList2 = [tr_TerminationID(TID, State) || TID <- TIDList],
+ TAR2 = tr_TerminationAudit(TAR, State),
+ #'TermListAuditResult'{terminationIDList = TIDList2,
+ terminationAuditResult = TAR2}.
+
+
+tr_opt_AuditDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_AuditDescriptor(Desc, State) ->
+ tr_AuditDescriptor(Desc, State).
+
+%% BUGBUG BUGBUG BUGBUG
+%% With this construction it is possible to have both auditToken
+%% and auditPropertyToken, but it is actually valid?
+tr_AuditDescriptor(#'AuditDescriptor'{auditToken = Tokens,
+ auditPropertyToken = APTs},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ %% v2
+ APTs2 =
+ case APTs of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ [tr_indAuditParameter(APT, State) || APT <- APTs]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2,
+ auditPropertyToken = APTs2}.
+
+tr_auditItem(Token, _State) ->
+ case Token of
+ muxToken -> muxToken;
+ modemToken -> modemToken;
+ mediaToken -> mediaToken;
+ eventsToken -> eventsToken;
+ signalsToken -> signalsToken;
+ digitMapToken -> digitMapToken;
+ statsToken -> statsToken;
+ observedEventsToken -> observedEventsToken;
+ packagesToken -> packagesToken;
+ eventBufferToken -> eventBufferToken
+ end.
+
+%% --- v2 begin ---
+
+tr_indAuditParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ indAudMediaDescriptor ->
+ tr_indAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ tr_indAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ tr_indAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ tr_indAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ tr_indAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ tr_indAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ tr_indAudPackagesDescriptor(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+%% -
+
+tr_indAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S},
+ State) ->
+ TSD2 =
+ case TSD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudTerminationStateDescriptor(TSD, State)
+ end,
+ S2 =
+ case S of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ {oneStream, OS} ->
+ {oneStream, tr_indAudStreamParms(OS, State)};
+ {multiStream, MS} ->
+ MS2 = [tr_indAudStreamDescriptor(MS1, State) || MS1 <- MS],
+ {multiStream, MS2}
+ end,
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}.
+
+tr_indAudTerminationStateDescriptor(Val, State)
+ when is_record(Val, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS} = Val,
+ Parms2 = [tr_indAudPropertyParm(Parm, State) || Parm <- Parms],
+ EBC2 = tr_opt_null(EBC, State),
+ SS2 = tr_opt_null(SS, State),
+ SSS2 = tr_opt_ServiceState(SSS, State),
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}.
+
+
+tr_indAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 =
+ case LCD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalControlDescriptor(LCD, State)
+ end,
+ LD2 =
+ case LD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(LD, State)
+ end,
+ RD2 =
+ case RD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudLocalRemoteDescriptor(RD, State)
+ end,
+ SD2 =
+ case SD of
+ asn1_NOVALUE ->
+ asn1_NOVALUE;
+ _ ->
+ tr_indAudStatisticsDescriptor(SD, State)
+ end,
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_indAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ #'IndAudLocalControlDescriptor'{streamMode = M,
+ reserveValue = V,
+ reserveGroup = G,
+ propertyParms = P,
+ streamModeSel = SMS} = Val,
+ M2 = tr_opt_null(M, State),
+ V2 = tr_opt_null(V, State),
+ G2 = tr_opt_null(G, State),
+ P2 = tr_indAudLocalControlDescriptor_propertyParms(P, State),
+ SMS2 = tr_opt_StreamMode(SMS, State),
+ #'IndAudLocalControlDescriptor'{streamMode = M2,
+ reserveValue = V2,
+ reserveGroup = G2,
+ propertyParms = P2,
+ streamModeSel = SMS2}.
+
+tr_indAudLocalControlDescriptor_propertyParms(Parms, State)
+ when is_list(Parms) andalso (length(Parms) > 0) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Parms];
+tr_indAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE.
+
+tr_indAudLocalRemoteDescriptor(#'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps},
+ State) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = tr_opt_UINT16(ID, State),
+ propGrps = tr_indAudPropertyGroup(Grps,
+ State)}.
+
+tr_indAudPropertyGroup(Grps, State) when is_list(Grps) ->
+ [tr_indAudPropertyParm(Parm, State) || Parm <- Grps].
+
+tr_indAudPropertyParm(#'IndAudPropertyParm'{name = Name0,
+ propertyParms = Prop0}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(property, Name0, State, Constraint),
+ Prop =
+ case Prop0 of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> tr_PropertyParm(Prop0, State)
+ end,
+ #'IndAudPropertyParm'{name = Name,
+ propertyParms = Prop}.
+
+
+tr_indAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = ID,
+ streamParms = Parms},
+ State) ->
+ #'IndAudStreamDescriptor'{streamID = tr_StreamID(ID, State),
+ streamParms = tr_indAudStreamParms(Parms,
+ State)}.
+
+
+%% -
+
+tr_indAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name0,
+ streamID = SID},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, Name0, State, Constraint),
+ #'IndAudEventsDescriptor'{requestID = tr_opt_RequestID(RID, State),
+ pkgdName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+
+%% -
+
+tr_indAudSignalsDescriptor({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ {signal, tr_indAudSignal(Val, State)};
+ seqSigList ->
+ {seqSigList, tr_indAudSeqSigList(Val, State)}
+ end.
+
+tr_opt_indAudSignal(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_indAudSignal(Val, State) ->
+ tr_indAudSignal(Val, State).
+
+tr_indAudSignal(#'IndAudSignal'{signalName = Name0,
+ streamID = SID,
+ signalRequestID = RID}, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(signal, Name0, State, Constraint),
+ #'IndAudSignal'{signalName = Name,
+ streamID = tr_opt_StreamID(SID, State),
+ signalRequestID = tr_opt_RequestID(RID, State)}.
+
+tr_indAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SigList}, State) ->
+ #'IndAudSeqSigList'{id = tr_integer(ID, State, 0, 65535),
+ signalList = tr_opt_indAudSignal(SigList, State)}.
+
+%% -
+
+tr_indAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ #'IndAudDigitMapDescriptor'{digitMapName =
+ tr_opt_DigitMapName(Name, State)}.
+
+
+%% -
+
+tr_indAudEventBufferDescriptor(#'IndAudEventBufferDescriptor'{eventName = N,
+ streamID = SID},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p", [N, SID]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(event, N, State, Constraint),
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = tr_opt_StreamID(SID, State)}.
+
+%% -
+
+tr_indAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = N},
+ State) ->
+ ?d("tr_indAudEventBufferDescriptor -> entry with"
+ "~n N: ~p", [N]),
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ Name = resolve(statistics, N, State, Constraint),
+ #'IndAudStatisticsDescriptor'{statName = Name}.
+
+
+%% -
+
+tr_indAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n N: ~p"
+ "~n V: ~p", [N, V]),
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ Name = resolve(package, N, State, Constraint),
+ ?d("tr_indAudPackagesDescriptor -> entry with"
+ "~n Name: ~p", [Name]),
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = tr_integer(V, State, 0, 99)}.
+
+%% -- v2 end --
+
+
+tr_TerminationAudit(ParmList, State) when is_list(ParmList) ->
+ do_tr_TerminationAudit(ParmList, [], State).
+
+do_tr_TerminationAudit([], Acc, _State) ->
+ lists:reverse(Acc);
+do_tr_TerminationAudit([Parm|ParmList], Acc, State) ->
+ case tr_AuditReturnParameter(Parm, State) of
+ {_, deprecated} when State#state.mode =:= encode ->
+ error({deprecated, Parm});
+ {_, deprecated} when State#state.mode =:= decode ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ {_, deprecated} ->
+ %% SKIP
+ do_tr_TerminationAudit(ParmList, Acc, State);
+ NewParm ->
+ do_tr_TerminationAudit(ParmList, [NewParm|Acc], State)
+ end.
+
+tr_AuditReturnParameter({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor ->
+ tr_ErrorDescriptor(Val, State);
+ mediaDescriptor ->
+ tr_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ tr_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ tr_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ tr_EventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ tr_EventBufferDescriptor(Val, State);
+ signalsDescriptor ->
+ tr_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ tr_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ tr_ObservedEventsDescriptor(Val, State);
+ statisticsDescriptor ->
+ tr_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ tr_PackagesDescriptor(Val, State);
+ emptyDescriptors ->
+ tr_EmptyDescriptors(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_EmptyDescriptors(#'AuditDescriptor'{auditToken = Tokens},
+ State) ->
+ Tokens2 =
+ case Tokens of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ _ -> [tr_auditItem(Token, State) || Token <- Tokens]
+ end,
+ #'AuditDescriptor'{auditToken = Tokens2}.
+
+tr_NotifyRequest(#'NotifyRequest'{terminationID = IdList,
+ observedEventsDescriptor = ObsDesc,
+ errorDescriptor = ErrDesc},
+ State) ->
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ #'NotifyRequest'{terminationID = [tr_TerminationID(Id, State) ||
+ Id <- IdList],
+ observedEventsDescriptor = tr_ObservedEventsDescriptor(ObsDesc, State),
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_NotifyReply(#'NotifyReply'{terminationID = IdList,
+ errorDescriptor = ErrDesc},
+ State) ->
+ #'NotifyReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ errorDescriptor = tr_opt_ErrorDescriptor(ErrDesc, State)}.
+
+tr_ObservedEventsDescriptor(#'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = Events},
+ State) when is_list (Events) ->
+ #'ObservedEventsDescriptor'{requestId = tr_RequestID(Id, State),
+ observedEventLst = [tr_ObservedEvent(E, State) || E <- Events]}.
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+
+tr_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms,
+ timeNotation = Time},
+ State) ->
+ #'ObservedEvent'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms],
+ timeNotation = tr_opt_TimeNotation(Time, State)}.
+
+tr_EventName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(event, Name, State, Constraint).
+
+tr_EventParameter(#'EventParameter'{eventParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ EventName,
+ State) ->
+ %% BUGBUG: event parameter name
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({event_parameter, EventName}, ParName, State, Constraint),
+ #'EventParameter'{eventParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = IdList,
+ serviceChangeParms = Parms},
+ State) ->
+ #'ServiceChangeRequest'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeParms = tr_ServiceChangeParm(Parms, State)}.
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+tr_ServiceChangeReply(#'ServiceChangeReply'{terminationID = IdList,
+ serviceChangeResult = Res},
+ State) ->
+ #'ServiceChangeReply'{terminationID = [tr_TerminationID(Id, State) || Id <- IdList],
+ serviceChangeResult = tr_ServiceChangeResult(Res, State)}.
+
+tr_ServiceChangeResult({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ errorDescriptor -> tr_ErrorDescriptor(Val, State);
+ serviceChangeResParms -> tr_ServiceChangeResParm(Val, State)
+ end,
+ {Tag, Val2}.
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+
+tr_TerminationID(TermId, State) when State#state.mode =/= verify ->
+ resolve(term_id, TermId, State, valid);
+tr_TerminationID(#'TerminationID'{wildcard = Wild,
+ id = Id},
+ _State) ->
+ #'TerminationID'{wildcard = Wild,
+ id = Id};
+tr_TerminationID(#megaco_term_id{contains_wildcards = IsWild,
+ id = Id},
+ State) ->
+ #megaco_term_id{contains_wildcards = tr_bool(IsWild, State),
+ id = [tr_term_id_component(Sub, State) || Sub <- Id]}.
+
+tr_opt_bool(asn1_NOVALUE, _State) -> asn1_NOVALUE;
+tr_opt_bool(Bool, State) -> tr_bool(Bool, State).
+
+tr_bool(true, _State) -> true;
+tr_bool(false, _State) -> false.
+
+tr_term_id_component(Sub, _State) ->
+ case Sub of
+ all -> all;
+ choose -> choose;
+ Char when is_integer(Char) -> Char
+ end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+tr_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TermState,
+ streams = Streams},
+ State) ->
+ #'MediaDescriptor'{termStateDescr = tr_opt_TerminationStateDescriptor(TermState, State),
+ streams = tr_opt_streams(Streams, State)}.
+
+tr_opt_streams(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_streams({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ oneStream -> tr_StreamParms(Val, State);
+ multiStream -> [tr_StreamDescriptor(SD, State) || SD <- Val]
+ end,
+ {Tag, Val2}.
+
+tr_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD},
+ State) ->
+ LCD2 = tr_opt_LocalControlDescriptor(LCD, State),
+ LD2 = tr_opt_LocalRemoteDescriptor(LD, State),
+ RD2 = tr_opt_LocalRemoteDescriptor(RD, State),
+ SD2 = tr_opt_StatisticsDescriptor(SD, State),
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}.
+
+tr_StreamDescriptor(#'StreamDescriptor'{streamID = Id,
+ streamParms = Parms},
+ State) ->
+ #'StreamDescriptor'{streamID = tr_StreamID(Id, State),
+ streamParms = tr_StreamParms(Parms, State)}.
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+tr_opt_LocalControlDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = Mode,
+ reserveGroup = Group,
+ reserveValue = Value,
+ propertyParms = Props},
+ State) ->
+ #'LocalControlDescriptor'{streamMode = tr_opt_StreamMode(Mode, State),
+ reserveGroup = tr_opt_bool(Group, State),
+ reserveValue = tr_opt_bool(Value, State),
+ propertyParms = [tr_PropertyParm(P, State) || P <- Props]}.
+
+tr_opt_StreamMode(Mode, _State) ->
+ case Mode of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ sendOnly -> sendOnly;
+ recvOnly -> recvOnly;
+ sendRecv -> sendRecv;
+ inactive -> inactive;
+ loopBack -> loopBack
+ end.
+
+tr_Name(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ tr_STRING(Name, State, 2, 2).
+
+tr_PkgdName(Name, State) ->
+ %% BUGBUG: transform
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ tr_OCTET_STRING(Name, State, 4, 4).
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+tr_opt_LocalRemoteDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = Groups},
+ State) ->
+ #'LocalRemoteDescriptor'{propGrps = [tr_PropertyGroup(G, State) || G <- Groups]}.
+
+tr_PropertyGroup(Props, State) ->
+ [tr_PropertyGroupParm(P, State) || P <- Props].
+
+tr_PropertyGroupParm(#'PropertyParm'{name = Name,
+ value = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_OCTET_STRING(Value, State, 0, infinity)}.
+
+tr_PropertyParm(#'PropertyParm'{name = Name,
+ value = Value,
+ extraInfo = Extra},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'PropertyParm'{name = resolve(property, Name, State, Constraint),
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_extraInfo(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_extraInfo({relation, Rel}, _State) ->
+ Rel2 =
+ case Rel of
+ greaterThan -> greaterThan;
+ smallerThan -> smallerThan;
+ unequalTo -> unequalTo
+ end,
+ {relation, Rel2};
+tr_opt_extraInfo({range, Range}, State) ->
+ Range2 = tr_bool(Range, State),
+ {range, Range2};
+tr_opt_extraInfo({sublist, Sub}, State) ->
+ Sub2 = tr_bool(Sub, State),
+ {sublist, Sub2}.
+
+tr_opt_TerminationStateDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TerminationStateDescriptor(#'TerminationStateDescriptor'{propertyParms = Props,
+ eventBufferControl = Control,
+ serviceState = Service},
+ State) ->
+ #'TerminationStateDescriptor'{propertyParms = [tr_PropertyParm(P, State) || P <- Props],
+ eventBufferControl = tr_opt_EventBufferControl(Control, State),
+ serviceState = tr_opt_ServiceState(Service, State)}.
+
+tr_opt_EventBufferControl(Control, _State) ->
+ case Control of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ off -> off;
+ lockStep -> lockStep
+ end.
+
+tr_opt_ServiceState(Service, _State) ->
+ case Service of
+ asn1_NOVALUE -> asn1_NOVALUE;
+ test -> test;
+ outOfSvc -> outOfSvc;
+ inSvc -> inSvc
+ end.
+
+tr_MuxDescriptor(#'MuxDescriptor'{muxType = Type,
+ termList = IdList},
+ State) ->
+ #'MuxDescriptor'{muxType = tr_MuxType(Type, State),
+ termList = [tr_TerminationID(Id, State) || Id <- IdList]}.
+
+tr_MuxType(Type, _State) ->
+ case Type of
+ h221 -> h221;
+ h223 -> h223;
+ h226 -> h226;
+ v76 -> v76
+ end.
+
+tr_opt_StreamID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StreamID(Id, State) ->
+ tr_StreamID(Id, State).
+
+tr_StreamID(Id, State) ->
+ tr_UINT16(Id, State).
+
+tr_EventsDescriptor(#'EventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'EventsDescriptor'{requestID = tr_opt_RequestID(Id, State),
+ eventList = [tr_RequestedEvent(E, State) || E <- Events]}.
+
+tr_RequestedEvent(#'RequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'RequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_RequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}.
+
+tr_opt_NotifyBehaviour(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyBehaviour(NB, State) ->
+ tr_NotifyBehaviour(NB, State).
+
+tr_NotifyBehaviour({notifyImmediate, 'NULL'} = NB, _State) ->
+ NB;
+tr_NotifyBehaviour({notifyRegulated = Tag, Val}, State) ->
+ {Tag, tr_RegulatedEmbeddedDescriptor(Val, State)};
+tr_NotifyBehaviour({neverNotify, 'NULL'} = NB, _State) ->
+ NB.
+
+tr_opt_RequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = DM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SE2 = tr_opt_SecondEventsDescriptor(SE, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_opt_keepActive(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_keepActive(Keep, State) ->
+ tr_bool(Keep, State).
+
+tr_opt_EventDM(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_EventDM({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ digitMapName -> tr_DigitMapName(Val, State);
+ digitMapValue -> tr_DigitMapValue(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_SecondEventsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = Id,
+ eventList = Events},
+ State) ->
+ #'SecondEventsDescriptor'{requestID = tr_RequestID(Id, State), %% IG v6 6.8 withdrawn
+ eventList = [tr_SecondRequestedEvent(E, State) || E <- Events]}.
+
+tr_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = Name,
+ streamID = Id,
+ evParList = Parms,
+ eventAction = Actions},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'SecondRequestedEvent'{pkgdName = resolve(event, Name, State, Constraint),
+ streamID = tr_opt_StreamID(Id, State),
+ eventAction = tr_opt_SecondRequestedActions(Actions, State),
+ evParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+
+tr_opt_SecondRequestedActions(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = DM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RSD},
+ State) ->
+ KA2 = tr_opt_keepActive(KA, State),
+ DM2 = tr_opt_EventDM(DM, State),
+ SD2 = tr_opt_SignalsDescriptor(SD, State),
+ NB2 = tr_opt_NotifyBehaviour(NB, State),
+ RSD2 = tr_opt_null(RSD, State),
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = DM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RSD2}.
+
+tr_EventBufferDescriptor(EventSpecs, State) ->
+ [tr_EventSpec(ES, State) || ES <- EventSpecs].
+
+tr_EventSpec(#'EventSpec'{eventName = Name,
+ streamID = Id,
+ eventParList = Parms},
+ State) ->
+ #'EventSpec'{eventName = tr_EventName(Name, State),
+ streamID = tr_opt_StreamID(Id, State),
+ eventParList = [tr_EventParameter(P, Name, State) || P <- Parms]}.
+
+tr_opt_SignalsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_SignalsDescriptor(SigDesc, State) ->
+ tr_SignalsDescriptor(SigDesc, State).
+
+tr_SignalsDescriptor(SigDesc, State) when is_list(SigDesc) ->
+ [tr_SignalRequest(SigReq, State) || SigReq <- SigDesc].
+
+tr_SignalRequest({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ signal -> tr_Signal(Val, State);
+ seqSigList -> tr_SeqSigList(Val, State)
+ end,
+ {Tag, Val2}.
+
+
+tr_SeqSigList(#'SeqSigList'{id = Id,
+ signalList = SigList},
+ State) when is_list(SigList) ->
+ #'SeqSigList'{id = tr_UINT16(Id, State),
+ signalList = [tr_Signal(Sig, State) || Sig <- SigList]}.
+
+tr_Signal(#'Signal'{signalName = Name,
+ streamID = SID,
+ sigType = Type,
+ duration = Dur,
+ notifyCompletion = Compl,
+ keepActive = Keep,
+ sigParList = Parms,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ID},
+ State) ->
+ Name2 = tr_SignalName(Name, State),
+ SID2 = tr_opt_StreamID(SID, State),
+ Type2 = tr_opt_SignalType(Type, State),
+ Dur2 = tr_opt_UINT16(Dur, State),
+ Compl2 = tr_opt_NotifyCompletion(Compl, State),
+ Keep2 = tr_opt_keepActive(Keep, State),
+ Parms2 = [tr_SigParameter(P, Name, State) || P <- Parms],
+ Dir2 = tr_opt_SignalDirection(Dir, State),
+ RID2 = tr_opt_RequestID(RID, State),
+ ID2 = tr_opt_UINT16(ID, State),
+ #'Signal'{signalName = Name2,
+ streamID = SID2,
+ sigType = Type2,
+ duration = Dur2,
+ notifyCompletion = Compl2,
+ keepActive = Keep2,
+ sigParList = Parms2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ID2}.
+
+tr_opt_NotifyCompletion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_NotifyCompletion(Items, State) when is_list(Items) ->
+ [tr_notifyCompletionItem(I, State) || I <- Items].
+
+tr_notifyCompletionItem(Item, _State) ->
+ case Item of
+ onTimeOut -> onTimeOut;
+ onInterruptByEvent -> onInterruptByEvent;
+ onInterruptByNewSignalDescr -> onInterruptByNewSignalDescr;
+ otherReason -> otherReason;
+ onIteration -> onIteration
+ end.
+
+tr_opt_SignalType(asn1_NOVALUE = Type, _State) ->
+ Type;
+tr_opt_SignalType(Type, _State) ->
+ case Type of
+ brief -> brief;
+ onOff -> onOff;
+ timeOut -> timeOut
+ end.
+
+tr_opt_SignalDirection(asn1_NOVALUE = SD, _State) ->
+ SD;
+tr_opt_SignalDirection(SD, _State) ->
+ case SD of
+ internal -> internal;
+ external -> external;
+ both -> both
+ end.
+
+tr_SignalName(Name, State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ resolve(signal, Name, State, Constraint).
+
+tr_SigParameter(#'SigParameter'{sigParameterName = ParName,
+ value = Value,
+ extraInfo = Extra},
+ SigName,
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ N = resolve({signal_parameter, SigName}, ParName, State, Constraint),
+ #'SigParameter'{sigParameterName = N,
+ value = tr_Value(Value, State),
+ extraInfo = tr_opt_extraInfo(Extra, State)}.
+
+tr_opt_RequestID(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_RequestID(Id, State) ->
+ tr_RequestID(Id, State).
+
+tr_RequestID(Id, _State) when Id =:= ?megaco_all_request_id ->
+ ?megaco_all_request_id;
+tr_RequestID(Id, State) ->
+ tr_UINT32(Id, State).
+
+tr_ModemDescriptor(_MD, _State) ->
+ deprecated.
+
+tr_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State) ->
+ #'DigitMapDescriptor'{digitMapName = tr_opt_DigitMapName(Name, State),
+ digitMapValue = tr_opt_DigitMapValue(Value, State)}.
+
+tr_opt_DigitMapName(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapName(Name, State) ->
+ tr_DigitMapName(Name, State).
+
+tr_DigitMapName(Name, State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ resolve(dialplan, Name, State, Constraint).
+
+tr_opt_DigitMapValue(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_DigitMapValue(Value, State) ->
+ tr_DigitMapValue(Value, State).
+
+tr_DigitMapValue(#'DigitMapValue'{digitMapBody = Body,
+ startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long},
+ State) ->
+ #'DigitMapValue'{startTimer = tr_opt_timer(Start, State),
+ shortTimer = tr_opt_timer(Short, State),
+ longTimer = tr_opt_timer(Long, State),
+ digitMapBody = tr_STRING(Body, State)}. %% BUGBUG: digitMapBody not handled at all
+
+tr_opt_timer(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_timer(Timer, State) ->
+ tr_DIGIT(Timer, State, 0, 99).
+
+tr_ServiceChangeParm(
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = Reason,
+ serviceChangeDelay = Delay,
+ serviceChangeMgcId = MgcId,
+ timeStamp = Time,
+ serviceChangeInfo = Info,
+ serviceChangeIncompleteFlag = Incomplete},
+ State) ->
+ Method2 = tr_ServiceChangeMethod(Method, State),
+ Addr2 = tr_opt_ServiceChangeAddress(Addr, State),
+ Version2 = tr_opt_serviceChangeVersion(Version, State),
+ Profile2 = tr_opt_ServiceChangeProfile(Profile, State),
+ Reason2 = tr_serviceChangeReason(Reason, State),
+ Delay2 = tr_opt_serviceChangeDelay(Delay, State),
+ MgcId2 = tr_opt_serviceChangeMgcId(MgcId, State),
+ Time2 = tr_opt_TimeNotation(Time, State),
+ Info2 = tr_opt_AuditDescriptor(Info, State),
+ Incomplete2 = tr_opt_null(Incomplete, State),
+ #'ServiceChangeParm'{serviceChangeMethod = Method2,
+ serviceChangeAddress = Addr2,
+ serviceChangeVersion = Version2,
+ serviceChangeProfile = Profile2,
+ serviceChangeReason = Reason2,
+ serviceChangeDelay = Delay2,
+ serviceChangeMgcId = MgcId2,
+ timeStamp = Time2,
+ serviceChangeInfo = Info2,
+ serviceChangeIncompleteFlag = Incomplete2}.
+
+tr_ServiceChangeMethod(Method, _State) ->
+ case Method of
+ failover -> failover;
+ forced -> forced;
+ graceful -> graceful;
+ restart -> restart;
+ disconnected -> disconnected;
+ handOff -> handOff
+ end. %% BUGBUG: extension
+
+tr_opt_ServiceChangeAddress(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_ServiceChangeAddress({Tag, Val}, State) ->
+ Val2 =
+ case Tag of
+ portNumber -> tr_portNumber(Val, State);
+ ip4Address -> tr_IP4Address(Val, State);
+ ip6Address -> tr_IP6Address(Val, State);
+ domainName -> tr_DomainName(Val, State);
+ deviceName -> tr_PathName(Val, State);
+ mtpAddress -> tr_mtpAddress(Val, State)
+ end,
+ {Tag, Val2}.
+
+tr_opt_serviceChangeVersion(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeVersion(Version, State) ->
+ tr_version(Version, State).
+
+tr_opt_ServiceChangeProfile(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+%% Decode
+tr_opt_ServiceChangeProfile({'ServiceChangeProfile', ProfileName}, State) ->
+ case string:tokens(ProfileName, "/") of
+ [Name0, Version0] ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(list_to_integer(Version0), State),
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version}
+ end;
+%% Encode
+tr_opt_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name0,
+ version = Version0},
+ State) ->
+ Name = tr_STRING(Name0, State, 1, 64),
+ Version = tr_version(Version0, State),
+ ProfileName = lists:flatten(io_lib:format("~s/~w", [Name, Version])),
+ {'ServiceChangeProfile', ProfileName}.
+
+tr_serviceChangeReason([_] = Reason, State) ->
+ tr_Value(Reason, State).
+
+tr_opt_serviceChangeDelay(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeDelay(Delay, State) ->
+ tr_UINT32(Delay, State).
+
+tr_opt_serviceChangeMgcId(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_serviceChangeMgcId(MgcId, State) ->
+ tr_MId(MgcId, State).
+
+tr_opt_portNumber(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_portNumber(Port, State) ->
+ tr_portNumber(Port, State).
+
+tr_portNumber(Port, State) when is_integer(Port) andalso (Port >= 0) ->
+ tr_UINT16(Port, State).
+
+tr_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = MgcId,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Version,
+ serviceChangeProfile = Profile,
+ timeStamp = Time},
+ State) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = tr_opt_serviceChangeMgcId(MgcId, State),
+ serviceChangeAddress = tr_opt_ServiceChangeAddress(Addr, State),
+ serviceChangeVersion = tr_opt_serviceChangeVersion(Version, State),
+ serviceChangeProfile = tr_opt_ServiceChangeProfile(Profile, State),
+ timeStamp = tr_opt_TimeNotation(Time, State)}.
+
+tr_PackagesDescriptor(Items, State) when is_list(Items) ->
+ [tr_PackagesItem(I, State) || I <- Items].
+
+tr_PackagesItem(#'PackagesItem'{packageName = Name,
+ packageVersion = Version},
+ State) ->
+ Constraint = fun(Item) -> tr_Name(Item, State) end,
+ #'PackagesItem'{packageName = resolve(package, Name, State, Constraint),
+ packageVersion = tr_UINT16(Version, State)}.
+
+tr_opt_StatisticsDescriptor(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_StatisticsDescriptor(Parms, State) ->
+ tr_StatisticsDescriptor(Parms, State).
+
+tr_StatisticsDescriptor(Parms, State) when is_list(Parms) ->
+ [tr_StatisticsParameter(P, State) || P <- Parms].
+
+tr_StatisticsParameter(#'StatisticsParameter'{statName = Name,
+ statValue = Value},
+ State) ->
+ Constraint = fun(Item) -> tr_PkgdName(Item, State) end,
+ #'StatisticsParameter'{statName = resolve(statistics, Name, State, Constraint),
+ statValue = tr_opt_Value(Value, State)}.
+
+tr_opt_TimeNotation(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_TimeNotation(#'TimeNotation'{date = Date,
+ time = Time},
+ State) ->
+ #'TimeNotation'{date = tr_STRING(Date, State, 8, 8), % "yyyymmdd"
+ time = tr_STRING(Time, State, 8, 8)}.% "hhmmssss"
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+
+tr_opt_Value(asn1_NOVALUE, _State) ->
+ asn1_NOVALUE;
+tr_opt_Value(Value, State) ->
+ tr_Value(Value, State).
+
+tr_Value(Strings, _State) when is_list(Strings) ->
+ [[Char || Char <- String] || String <- Strings].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+tr_OCTET_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_QUOTED_STRING(String, _State) when is_list(String) ->
+ verify_count(length(String), 1, infinity),
+ String.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+tr_HEXDIG(Octets, _State, Min, Max) when is_list(Octets) ->
+ verify_count(length(Octets), Min, Max),
+ Octets.
+
+tr_DIGIT(Val, State, Min, Max) ->
+ tr_integer(Val, State, Min, Max).
+
+tr_STRING(String, _State) when is_list(String) ->
+ String.
+
+tr_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+tr_opt_UINT16(Val, State) ->
+ tr_opt_integer(Val, State, 0, 65535).
+
+tr_UINT16(Val, State) ->
+ tr_integer(Val, State, 0, 65535).
+
+tr_UINT32(Val, State) ->
+ tr_integer(Val, State, 0, 4294967295).
+
+tr_opt_integer(asn1_NOVALUE, _State, _Min, _Max) ->
+ asn1_NOVALUE;
+tr_opt_integer(Int, State, Min, Max) ->
+ tr_integer(Int, State, Min, Max).
+
+tr_integer(Int, _State, Min, Max) ->
+ verify_count(Int, Min, Max),
+ Int.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_drv_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_encoder.erl b/lib/megaco/src/binary/megaco_per_bin_encoder.erl
new file mode 100644
index 0000000000..f7280f4e04
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_encoder.erl
@@ -0,0 +1,447 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_bin_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_bin_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_bin_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_bin_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_bin_media_gateway_control_prev3c).
+-define(V1_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD_DRV, megaco_per_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3C_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3B_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a},driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?PREV3A_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([driver|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD_DRV, ?V2_ASN1_MOD_DRV, ?V3_ASN1_MOD_DRV],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3, _},driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_},driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a},driver|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([driver|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% encode_transaction([] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 1, Trans) ->
+%% AsnMod = ?V1_ASN1_MOD_DRV,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 1, _Trans) ->
+ %% AsnMod = ?V1_ASN1_MOD,
+ %% TransMod = ?V1_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+ %% io_list);
+ {error, not_implemented};
+
+%% encode_transaction([] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 2, Trans) ->
+%% AsnMod = ?V2_ASN1_MOD_DRV,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 2, _Trans) ->
+ %% AsnMod = ?V2_ASN1_MOD,
+ %% TransMod = ?V2_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+ %% io_list).
+ {error, not_implemented};
+
+%% encode_transaction([] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([native] = EC, 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+%% encode_transaction([driver|EC], 3, Trans) ->
+%% AsnMod = ?V3_ASN1_MOD_DRV,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+encode_transaction(_EC, 3, _Trans) ->
+ %% AsnMod = ?V3_ASN1_MOD,
+ %% TransMod = ?V3_TRANS_MOD,
+ %% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod, %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_},driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD_DRV,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 2 --
+
+decode_message([{version3,_},driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD_DRV,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+%% -- Version 3 --
+
+decode_message([{version3,v3},driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD_DRV,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD_DRV,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a},driver|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD_DRV,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([driver|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD_DRV,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+%% All values we need to take (special) care of has been delt with,
+%% so just pass the rest on
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_bin_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/megaco_per_encoder.erl b/lib/megaco/src/binary/megaco_per_encoder.erl
new file mode 100644
index 0000000000..596e621c65
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_encoder.erl
@@ -0,0 +1,291 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check/get) message version
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+
+%% -- Version 1 --
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 2 --
+
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+
+
+%% -- Version 3 --
+
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:encode_message(EC, MegaMsg, AsnMod, TransMod, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 3, _Trans) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_transaction(EC, Trans, AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 3, ActReqs) when is_list(ActReqs) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+%% AsnMod = ?V1_ASN1_MOD,
+%% TransMod = ?V1_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+%% AsnMod = ?V2_ASN1_MOD,
+%% TransMod = ?V2_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 3, _ActReq) ->
+%% AsnMod = ?V3_ASN1_MOD,
+%% TransMod = ?V3_TRANS_MOD,
+%% ?BIN_LIB:encode_action_request(EC, ActReq,
+%% AsnMod, TransMod,
+%% io_list);
+ {error, not_implemented}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+
+%% -- Version 1 --
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+
+%% -- Version 2 --
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+
+%% -- Version 3 --
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, io_list).
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn
new file mode 100644
index 0000000000..b9ba7ffdb4
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3a.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3a.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn
new file mode 100644
index 0000000000..0437bde310
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3b.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3b.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn
new file mode 100644
index 0000000000..e78055fbad
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_prev3c.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-prev3c.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn
new file mode 100644
index 0000000000..0f5a92dba1
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v1.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v1.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn
new file mode 100644
index 0000000000..7fc82b127f
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v2.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v2.asn
diff --git a/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn b/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn
new file mode 100644
index 0000000000..1d7950a283
--- /dev/null
+++ b/lib/megaco/src/binary/megaco_per_media_gateway_control_v3.set.asn
@@ -0,0 +1 @@
+MEDIA-GATEWAY-CONTROL-v3.asn
diff --git a/lib/megaco/src/binary/modules.mk b/lib/megaco/src/binary/modules.mk
new file mode 100644
index 0000000000..a86ce2aecc
--- /dev/null
+++ b/lib/megaco/src/binary/modules.mk
@@ -0,0 +1,128 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco_binary_encoder \
+ megaco_binary_encoder_lib \
+ megaco_ber_encoder \
+ megaco_ber_media_gateway_control_v1 \
+ megaco_ber_media_gateway_control_v2 \
+ megaco_ber_media_gateway_control_prev3a \
+ megaco_ber_media_gateway_control_prev3b \
+ megaco_ber_media_gateway_control_prev3c \
+ megaco_ber_media_gateway_control_v3 \
+ megaco_ber_bin_encoder \
+ megaco_ber_bin_media_gateway_control_v1 \
+ megaco_ber_bin_media_gateway_control_v2 \
+ megaco_ber_bin_media_gateway_control_prev3a \
+ megaco_ber_bin_media_gateway_control_prev3b \
+ megaco_ber_bin_media_gateway_control_prev3c \
+ megaco_ber_bin_media_gateway_control_v3 \
+ megaco_ber_bin_drv_media_gateway_control_v1 \
+ megaco_ber_bin_drv_media_gateway_control_v2 \
+ megaco_ber_bin_drv_media_gateway_control_prev3a \
+ megaco_ber_bin_drv_media_gateway_control_prev3b \
+ megaco_ber_bin_drv_media_gateway_control_prev3c \
+ megaco_ber_bin_drv_media_gateway_control_v3 \
+ megaco_per_encoder \
+ megaco_per_media_gateway_control_v1 \
+ megaco_per_media_gateway_control_v2 \
+ megaco_per_media_gateway_control_prev3a \
+ megaco_per_media_gateway_control_prev3b \
+ megaco_per_media_gateway_control_prev3c \
+ megaco_per_media_gateway_control_v3 \
+ megaco_per_bin_encoder \
+ megaco_per_bin_media_gateway_control_v1 \
+ megaco_per_bin_media_gateway_control_v2 \
+ megaco_per_bin_media_gateway_control_prev3a \
+ megaco_per_bin_media_gateway_control_prev3b \
+ megaco_per_bin_media_gateway_control_prev3c \
+ megaco_per_bin_media_gateway_control_v3 \
+ megaco_per_bin_drv_media_gateway_control_v1 \
+ megaco_per_bin_drv_media_gateway_control_v2 \
+ megaco_per_bin_drv_media_gateway_control_prev3a \
+ megaco_per_bin_drv_media_gateway_control_prev3b \
+ megaco_per_bin_drv_media_gateway_control_prev3c \
+ megaco_per_bin_drv_media_gateway_control_v3 \
+ megaco_binary_name_resolver_v1 \
+ megaco_binary_name_resolver_v2 \
+ megaco_binary_name_resolver_prev3a \
+ megaco_binary_name_resolver_prev3b \
+ megaco_binary_name_resolver_prev3c \
+ megaco_binary_name_resolver_v3 \
+ megaco_binary_term_id \
+ megaco_binary_term_id_gen \
+ megaco_binary_transformer_v1 \
+ megaco_binary_transformer_v2 \
+ megaco_binary_transformer_prev3a \
+ megaco_binary_transformer_prev3b \
+ megaco_binary_transformer_prev3c \
+ megaco_binary_transformer_v3
+
+INTERNAL_HRL_FILES =
+
+ASN1_V1_SPEC = MEDIA-GATEWAY-CONTROL-v1
+ASN1_V2_SPEC = MEDIA-GATEWAY-CONTROL-v2
+ASN1_PREV3A_SPEC = MEDIA-GATEWAY-CONTROL-prev3a
+ASN1_PREV3B_SPEC = MEDIA-GATEWAY-CONTROL-prev3b
+ASN1_PREV3C_SPEC = MEDIA-GATEWAY-CONTROL-prev3c
+ASN1_V3_SPEC = MEDIA-GATEWAY-CONTROL-v3
+
+BER_ASN1_V1_SPEC = megaco_ber_media_gateway_control_v1
+BER_BIN_ASN1_V1_SPEC = megaco_ber_bin_media_gateway_control_v1
+BER_BIN_DRV_ASN1_V1_SPEC = megaco_ber_bin_drv_media_gateway_control_v1
+PER_ASN1_V1_SPEC = megaco_per_media_gateway_control_v1
+PER_BIN_ASN1_V1_SPEC = megaco_per_bin_media_gateway_control_v1
+PER_BIN_DRV_ASN1_V1_SPEC = megaco_per_bin_drv_media_gateway_control_v1
+
+BER_ASN1_V2_SPEC = megaco_ber_media_gateway_control_v2
+BER_BIN_ASN1_V2_SPEC = megaco_ber_bin_media_gateway_control_v2
+BER_BIN_DRV_ASN1_V2_SPEC = megaco_ber_bin_drv_media_gateway_control_v2
+PER_ASN1_V2_SPEC = megaco_per_media_gateway_control_v2
+PER_BIN_ASN1_V2_SPEC = megaco_per_bin_media_gateway_control_v2
+PER_BIN_DRV_ASN1_V2_SPEC = megaco_per_bin_drv_media_gateway_control_v2
+
+BER_ASN1_PREV3A_SPEC = megaco_ber_media_gateway_control_prev3a
+BER_BIN_ASN1_PREV3A_SPEC = megaco_ber_bin_media_gateway_control_prev3a
+BER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3a
+PER_ASN1_PREV3A_SPEC = megaco_per_media_gateway_control_prev3a
+PER_BIN_ASN1_PREV3A_SPEC = megaco_per_bin_media_gateway_control_prev3a
+PER_BIN_DRV_ASN1_PREV3A_SPEC = megaco_per_bin_drv_media_gateway_control_prev3a
+
+BER_ASN1_PREV3B_SPEC = megaco_ber_media_gateway_control_prev3b
+BER_BIN_ASN1_PREV3B_SPEC = megaco_ber_bin_media_gateway_control_prev3b
+BER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3b
+PER_ASN1_PREV3B_SPEC = megaco_per_media_gateway_control_prev3b
+PER_BIN_ASN1_PREV3B_SPEC = megaco_per_bin_media_gateway_control_prev3b
+PER_BIN_DRV_ASN1_PREV3B_SPEC = megaco_per_bin_drv_media_gateway_control_prev3b
+
+BER_ASN1_PREV3C_SPEC = megaco_ber_media_gateway_control_prev3c
+BER_BIN_ASN1_PREV3C_SPEC = megaco_ber_bin_media_gateway_control_prev3c
+BER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_ber_bin_drv_media_gateway_control_prev3c
+PER_ASN1_PREV3C_SPEC = megaco_per_media_gateway_control_prev3c
+PER_BIN_ASN1_PREV3C_SPEC = megaco_per_bin_media_gateway_control_prev3c
+PER_BIN_DRV_ASN1_PREV3C_SPEC = megaco_per_bin_drv_media_gateway_control_prev3c
+
+BER_ASN1_V3_SPEC = megaco_ber_media_gateway_control_v3
+BER_BIN_ASN1_V3_SPEC = megaco_ber_bin_media_gateway_control_v3
+BER_BIN_DRV_ASN1_V3_SPEC = megaco_ber_bin_drv_media_gateway_control_v3
+PER_ASN1_V3_SPEC = megaco_per_media_gateway_control_v3
+PER_BIN_ASN1_V3_SPEC = megaco_per_bin_media_gateway_control_v3
+PER_BIN_DRV_ASN1_V3_SPEC = megaco_per_bin_drv_media_gateway_control_v3
+
diff --git a/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl b/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl
new file mode 100644
index 0000000000..a9217940a1
--- /dev/null
+++ b/lib/megaco/src/binary/old/megaco_ber_bin_drv_encoder.erl
@@ -0,0 +1,319 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 BER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_ber_bin_drv_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+%% Backward compatible functions:
+-export([encode_message/2, decode_message/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_ber_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_v3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, dynamic, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(EC, 1, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_transaction(EC, 2, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, 3, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(EC, 1, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(EC, 2, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(EC, 3, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% Select from message
+%% This does not work at the moment so, we use version 1 for this
+decode_message([{version3,v3}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3c}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3b}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message([{version3,prev3a}|EC], dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+decode_message(EC, dynamic, Binary) ->
+ Mods = [{?V1_ASN1_MOD, ?V1_TRANS_MOD},
+ {?V2_ASN1_MOD, ?V2_TRANS_MOD},
+ {?V3_ASN1_MOD, ?V3_TRANS_MOD}],
+ ?BIN_LIB:decode_message_dynamic(EC, Binary, Mods, binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+
+decode_mini_message([{version3,v3}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3c}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3b}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message([{version3,prev3a}|EC], dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+decode_mini_message(EC, dynamic, Bin) ->
+ Mods = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:decode_mini_message_dynamic(EC, Bin, Mods, binary);
+
+decode_mini_message([{version3,_}|EC], 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 1, Bin) ->
+ AsnMod = ?V1_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,_}|EC], 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 2, Bin) ->
+ AsnMod = ?V2_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,v3}|EC], 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3c}|EC], 3, Bin) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3b}|EC], 3, Bin) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message([{version3,prev3a}|EC], 3, Bin) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary);
+decode_mini_message(EC, 3, Bin) ->
+ AsnMod = ?V3_ASN1_MOD,
+ ?BIN_LIB:decode_mini_message(EC, Bin, AsnMod, binary).
diff --git a/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl b/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl
new file mode 100644
index 0000000000..0afe6d9f36
--- /dev/null
+++ b/lib/megaco/src/binary/old/megaco_per_bin_drv_encoder.erl
@@ -0,0 +1,255 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Handle ASN.1 PER encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_per_bin_drv_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/2, decode_message/2,
+ encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_action_reply/3,
+
+ version_of/2]).
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v1).
+-define(V2_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v2).
+-define(V3_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_v3).
+-define(PREV3A_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3a).
+-define(PREV3B_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3b).
+-define(PREV3C_ASN1_MOD, megaco_per_bin_drv_media_gateway_control_prev3c).
+
+-define(V1_TRANS_MOD, megaco_binary_transformer_v1).
+-define(V2_TRANS_MOD, megaco_binary_transformer_v2).
+-define(V3_TRANS_MOD, megaco_binary_transformer_V3).
+-define(PREV3A_TRANS_MOD, megaco_binary_transformer_prev3a).
+-define(PREV3B_TRANS_MOD, megaco_binary_transformer_prev3b).
+-define(PREV3C_TRANS_MOD, megaco_binary_transformer_prev3c).
+
+-define(BIN_LIB, megaco_binary_encoder_lib).
+
+
+%%----------------------------------------------------------------------
+%% Detect (check) which version a message is
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of([{version3,v3}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3c}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3C_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3b}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3B_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of([{version3,prev3a}|EC], Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?PREV3A_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders);
+version_of(EC, Binary) ->
+ Decoders = [?V1_ASN1_MOD, ?V2_ASN1_MOD, ?V3_ASN1_MOD],
+ ?BIN_LIB:version_of(EC, Binary, 1, Decoders).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EC, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message(EC, 1, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V1_ASN1_MOD, ?V1_TRANS_MOD, io_list);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message(EC, 2, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V2_ASN1_MOD, ?V2_TRANS_MOD, io_list);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3C_ASN1_MOD, ?PREV3C_TRANS_MOD, io_list);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3B_ASN1_MOD, ?PREV3B_TRANS_MOD, io_list);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg,
+ ?PREV3A_ASN1_MOD, ?PREV3A_TRANS_MOD, io_list);
+encode_message(EC, 3, MegaMsg) ->
+ ?BIN_LIB:encode_message(EC, MegaMsg, ?V3_ASN1_MOD, ?V3_TRANS_MOD, io_list).
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction (or transactions in the case of ack) record(s)
+%% into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction(_EC, 1, _Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC,
+ %% Trans,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_transaction(_EC, 2, _Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC,
+ %% Trans,
+ %% ?V2_ASN1_MOD,
+ %% ?V2_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, prev3a, Trans) ->
+ %% ?BIN_LIB:encode_transaction(EC, Trans,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_transaction(EC, 3, Trans) ->
+ encode_transaction(EC, prev3a, Trans).
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, 1, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_requests(_EC, 2, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ %% ?BIN_LIB:encode_action_requests(EC, ActReqs,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, 1, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list);
+ {error, not_implemented};
+encode_action_request(_EC, 2, _ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V1_ASN1_MOD,
+ %% ?V1_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented};
+encode_action_request(EC, 3, ActReq) ->
+ %% ?BIN_LIB:encode_action_request(EC, ActReq,
+ %% ?V3_ASN1_MOD,
+ %% ?V3_TRANS_MOD,
+ %% io_list).
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Not yest supported by this binary codec!
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_action_reply(_EC, _V, _AcionReply) ->
+ {error, not_implemented}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+%% Old decode function
+decode_message(EC, Binary) ->
+ decode_message(EC, 1, Binary).
+
+%% PER does not support partial decode, so this means V1
+decode_message(EC, dynamic, Binary) ->
+ decode_message(EC, 1, Binary);
+
+decode_message([{version3,_}|EC], 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 1, Binary) ->
+ AsnMod = ?V1_ASN1_MOD,
+ TransMod = ?V1_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,_}|EC], 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 2, Binary) ->
+ AsnMod = ?V2_ASN1_MOD,
+ TransMod = ?V2_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+
+decode_message([{version3,v3}|EC], 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3c}|EC], 3, Binary) ->
+ AsnMod = ?PREV3C_ASN1_MOD,
+ TransMod = ?PREV3C_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3b}|EC], 3, Binary) ->
+ AsnMod = ?PREV3B_ASN1_MOD,
+ TransMod = ?PREV3B_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message([{version3,prev3a}|EC], 3, Binary) ->
+ AsnMod = ?PREV3A_ASN1_MOD,
+ TransMod = ?PREV3A_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary);
+decode_message(EC, 3, Binary) ->
+ AsnMod = ?V3_ASN1_MOD,
+ TransMod = ?V3_TRANS_MOD,
+ ?BIN_LIB:decode_message(EC, Binary, AsnMod, TransMod, binary).
+
+decode_mini_message(_EC, _Vsn, _Bin) ->
+ {error, not_implemented}.
+
diff --git a/lib/megaco/src/engine/Makefile b/lib/megaco/src/engine/Makefile
new file mode 100644
index 0000000000..3943f4b957
--- /dev/null
+++ b/lib/megaco/src/engine/Makefile
@@ -0,0 +1,107 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/engine
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/engine
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/engine/depend.mk b/lib/megaco/src/engine/depend.mk
new file mode 100644
index 0000000000..8d8c83e923
--- /dev/null
+++ b/lib/megaco/src/engine/depend.mk
@@ -0,0 +1,81 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+$(EBIN)/megaco_config.$(EMULATOR): megaco_config.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_digit_map.$(EMULATOR): megaco_digit_map.erl \
+ megaco_message_internal.hrl \
+ ../text/megaco_text_tokens.hrl
+
+$(EBIN)/megaco_encoder.$(EMULATOR): megaco_encoder.erl
+
+$(EBIN)/megaco_edist_compress.$(EMULATOR): megaco_edist_compress.erl
+
+$(EBIN)/megaco_erl_dist_encoder.$(EMULATOR): megaco_erl_dist_encoder.erl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_erl_dist_encoder_mc.$(EMULATOR): megaco_erl_dist_encoder_mc.erl \
+ megaco_message_internal.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_filter.$(EMULATOR): megaco_filter.erl \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl \
+ ../app/megaco_internal.hrl
+
+$(EBIN)/megaco_messenger.$(EMULATOR): megaco_messenger.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_messenger_misc.$(EMULATOR): megaco_messenger_misc.erl \
+ ../../include/megaco.hrl \
+ ../app/megaco_internal.hrl \
+ megaco_message_internal.hrl
+
+$(EBIN)/megaco_misc_sup.$(EMULATOR): megaco_misc_sup.erl
+
+$(EBIN)/megaco_monitor.$(EMULATOR): megaco_monitor.erl
+
+$(EBIN)/megaco_sdp.$(EMULATOR): \
+ megaco_sdp.erl \
+ ../../include/megaco_sdp.hrl
+
+$(EBIN)/megaco_stats.$(EMULATOR): megaco_stats.erl
+
+$(EBIN)/megaco_sup.$(EMULATOR): megaco_sup.erl
+
+$(EBIN)/megaco_timer.$(EMULATOR): \
+ megaco_timer.erl \
+ ../../include/megaco.hrl
+
+$(EBIN)/megaco_trans_sender.$(EMULATOR): megaco_trans_sender.erl
+
+$(EBIN)/megaco_trans_sup.$(EMULATOR): megaco_trans_sup.erl
+
+$(EBIN)/megaco_transport.$(EMULATOR): megaco_transport.erl
+
+$(EBIN)/megaco_user.$(EMULATOR): megaco_user.erl
+
+$(EBIN)/megaco_user_default.$(EMULATOR): megaco_user_default.erl \
+ ../../include/megaco.hrl \
+ ../../include/megaco_message_v1.hrl
+
diff --git a/lib/megaco/src/engine/megaco_config.erl b/lib/megaco/src/engine/megaco_config.erl
new file mode 100644
index 0000000000..2058c53973
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_config.erl
@@ -0,0 +1,2113 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle configuration of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_config).
+
+-behaviour(gen_server).
+
+%% Application internal exports
+-export([
+ start_link/0,
+ stop/0,
+
+ start_user/2,
+ stop_user/1,
+
+ user_info/2,
+ update_user_info/3,
+ conn_info/2,
+ update_conn_info/3,
+ system_info/1,
+
+ %% incr_counter/2,
+ incr_trans_id_counter/1,
+ incr_trans_id_counter/2,
+
+ %% Verification functions
+ verify_val/2,
+ verify_strict_uint/1,
+ verify_strict_int/1, verify_strict_int/2,
+ verify_uint/1,
+ verify_int/1, verify_int/2,
+
+
+ %% Reply limit counter
+ cre_reply_counter/2,
+ get_reply_counter/2,
+ incr_reply_counter/2,
+ del_reply_counter/2,
+
+ %% Pending limit counter
+ cre_pending_counter/3,
+ get_pending_counter/2,
+ incr_pending_counter/2,
+ del_pending_counter/2,
+ %% Backward compatibillity functions (to be removed in later versions)
+ cre_pending_counter/1,
+ get_pending_counter/1,
+ incr_pending_counter/1,
+ del_pending_counter/1,
+
+ lookup_local_conn/1,
+ connect/4, finish_connect/4,
+ autoconnect/4,
+ disconnect/1,
+ connect_remote/3,
+ disconnect_remote/2,
+ init_conn_data/4,
+
+ trans_sender_exit/2
+
+ ]).
+
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-record(state, {parent_pid}).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-ifdef(MEGACO_TEST_CODE).
+-define(megaco_test_init(),
+ (catch ets:new(megaco_test_data, [set, public, named_table]))).
+-else.
+-define(megaco_test_init(),
+ ok).
+-endif.
+
+-define(TID_CNT(LMID), {LMID, trans_id_counter}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start_link() ->
+ ?d("start_link -> entry", []),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], []).
+
+stop() ->
+ ?d("stop -> entry", []),
+ call({stop, self()}).
+
+start_user(UserMid, Config) ->
+ call({start_user, UserMid, Config}).
+
+stop_user(UserMid) ->
+ call({stop_user, UserMid}).
+
+user_info(UserMid, all) ->
+ All0 = ets:match_object(megaco_config, {{UserMid, '_'}, '_'}),
+ All1 = [{Item, Val} || {{_, Item}, Val} <- All0, Item /= trans_sender],
+ case lists:keysearch(trans_id_counter, 1, All1) of
+ {value, {_, Val}} ->
+ lists:keyreplace(trans_id_counter, 1, All1, {trans_id, Val});
+ false when UserMid /= default ->
+ [{trans_id, undefined_serial}|All1];
+ false ->
+ All1
+ end;
+user_info(UserMid, receive_handle) ->
+ case call({receive_handle, UserMid}) of
+ {ok, RH} ->
+ RH;
+ {error, Reason} ->
+ exit(Reason)
+ end;
+user_info(UserMid, conn_data) ->
+ HandlePat = #megaco_conn_handle{local_mid = UserMid, remote_mid = '_'},
+ Pat = #conn_data{conn_handle = HandlePat,
+ serial = '_',
+ max_serial = '_',
+ request_timer = '_',
+ long_request_timer = '_',
+
+ auto_ack = '_',
+
+ trans_ack = '_',
+ trans_ack_maxcount = '_',
+
+ trans_req = '_',
+ trans_req_maxcount = '_',
+ trans_req_maxsize = '_',
+
+ trans_timer = '_',
+ trans_sender = '_',
+
+ pending_timer = '_',
+ sent_pending_limit = '_',
+ recv_pending_limit = '_',
+ reply_timer = '_',
+ control_pid = '_',
+ monitor_ref = '_',
+ send_mod = '_',
+ send_handle = '_',
+ encoding_mod = '_',
+ encoding_config = '_',
+ protocol_version = '_',
+ auth_data = '_',
+ user_mod = '_',
+ user_args = '_',
+ reply_action = '_',
+ reply_data = '_',
+ threaded = '_',
+ strict_version = '_',
+ long_request_resend = '_',
+ call_proxy_gc_timeout = '_',
+ cancel = '_',
+ resend_indication = '_',
+ segment_reply_ind = '_',
+ segment_recv_acc = '_',
+ segment_recv_timer = '_',
+ segment_send = '_',
+ segment_send_timer = '_',
+ max_pdu_size = '_',
+ request_keep_alive_timeout = '_'
+ },
+ %% ok = io:format("PATTERN: ~p~n", [Pat]),
+ ets:match_object(megaco_local_conn, Pat);
+user_info(UserMid, connections) ->
+ [C#conn_data.conn_handle || C <- user_info(UserMid, conn_data)];
+user_info(UserMid, mid) ->
+ ets:lookup_element(megaco_config, {UserMid, mid}, 2);
+user_info(UserMid, orig_pending_limit) ->
+ user_info(UserMid, sent_pending_limit);
+user_info(UserMid, trans_id) ->
+ case (catch user_info(UserMid, trans_id_counter)) of
+ {'EXIT', _} ->
+ %% There is only two cases where this can occure:
+ %% 1) The user does not exist
+ %% 2) Called before the first message is sent, use
+ %% undefined_serial, since there is no
+ %% "current transaction id"
+ case (catch user_info(UserMid, mid)) of
+ {'EXIT', _} ->
+ %% case 1:
+ exit({no_such_user, UserMid});
+ _ ->
+ undefined_serial
+ end;
+ Else ->
+ Else
+ end;
+user_info(UserMid, Item) ->
+ ets:lookup_element(megaco_config, {UserMid, Item}, 2).
+
+update_user_info(UserMid, orig_pending_limit, Val) ->
+ update_user_info(UserMid, sent_pending_limit, Val);
+update_user_info(UserMid, Item, Val) ->
+ call({update_user_info, UserMid, Item, Val}).
+
+conn_info(CH, Item)
+ when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) ->
+ case Item of
+ conn_handle ->
+ CH;
+ mid ->
+ CH#megaco_conn_handle.local_mid;
+ local_mid ->
+ CH#megaco_conn_handle.local_mid;
+ remote_mid ->
+ CH#megaco_conn_handle.remote_mid;
+ conn_data ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ ConnData
+ end;
+ _ ->
+ case lookup_local_conn(CH) of
+ [] ->
+ exit({no_such_connection, CH});
+ [ConnData] ->
+ conn_info(ConnData, Item)
+ end
+ end;
+conn_info(#conn_data{conn_handle = CH}, cancel) ->
+ %% To minimise raise-condition propabillity,
+ %% we always look in the table instead of
+ %% in the record for this one
+ ets:lookup_element(megaco_local_conn, CH, #conn_data.cancel);
+
+conn_info(CD, Item) when is_record(CD, conn_data) ->
+ case Item of
+ all ->
+ Tags0 = record_info(fields, conn_data),
+ Tags1 = replace(serial, trans_id, Tags0),
+ Tags = [mid, local_mid, remote_mid] ++
+ replace(max_serial, max_trans_id, Tags1),
+ [{Tag, conn_info(CD,Tag)} || Tag <- Tags,
+ Tag /= conn_data,
+ Tag /= trans_sender,
+ Tag /= cancel];
+ conn_data -> CD;
+ conn_handle -> CD#conn_data.conn_handle;
+ mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
+ local_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid;
+ remote_mid -> (CD#conn_data.conn_handle)#megaco_conn_handle.remote_mid;
+ trans_id -> CH = CD#conn_data.conn_handle,
+ LocalMid = CH#megaco_conn_handle.local_mid,
+ Item2 = {LocalMid, trans_id_counter},
+ case (catch ets:lookup(megaco_config, Item2)) of
+ {'EXIT', _} ->
+ undefined_serial;
+ [] ->
+ user_info(LocalMid, min_trans_id);
+ [{_, Serial}] ->
+ Max = CD#conn_data.max_serial,
+ if
+ ((Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial < 4294967295)) ->
+ Serial + 1;
+ (Max =:= infinity) andalso
+ is_integer(Serial) andalso
+ (Serial =:= 4294967295) ->
+ user_info(LocalMid,
+ min_trans_id);
+ Serial < Max ->
+ Serial + 1;
+ Serial =:= Max ->
+ user_info(LocalMid,
+ min_trans_id);
+ Serial =:= 4294967295 ->
+ user_info(LocalMid,
+ min_trans_id);
+ true ->
+ undefined_serial
+ end
+ end;
+ max_trans_id -> CD#conn_data.max_serial;
+ request_timer -> CD#conn_data.request_timer;
+ long_request_timer -> CD#conn_data.long_request_timer;
+
+ auto_ack -> CD#conn_data.auto_ack;
+
+ trans_ack -> CD#conn_data.trans_ack;
+ trans_ack_maxcount -> CD#conn_data.trans_ack_maxcount;
+
+ trans_req -> CD#conn_data.trans_req;
+ trans_req_maxcount -> CD#conn_data.trans_req_maxcount;
+ trans_req_maxsize -> CD#conn_data.trans_req_maxsize;
+
+ trans_timer -> CD#conn_data.trans_timer;
+
+ pending_timer -> CD#conn_data.pending_timer;
+ orig_pending_limit -> CD#conn_data.sent_pending_limit;
+ sent_pending_limit -> CD#conn_data.sent_pending_limit;
+ recv_pending_limit -> CD#conn_data.recv_pending_limit;
+ reply_timer -> CD#conn_data.reply_timer;
+ control_pid -> CD#conn_data.control_pid;
+ monitor_ref -> CD#conn_data.monitor_ref;
+ send_mod -> CD#conn_data.send_mod;
+ send_handle -> CD#conn_data.send_handle;
+ encoding_mod -> CD#conn_data.encoding_mod;
+ encoding_config -> CD#conn_data.encoding_config;
+ protocol_version -> CD#conn_data.protocol_version;
+ auth_data -> CD#conn_data.auth_data;
+ user_mod -> CD#conn_data.user_mod;
+ user_args -> CD#conn_data.user_args;
+ reply_action -> CD#conn_data.reply_action;
+ reply_data -> CD#conn_data.reply_data;
+ threaded -> CD#conn_data.threaded;
+ strict_version -> CD#conn_data.strict_version;
+ long_request_resend -> CD#conn_data.long_request_resend;
+ call_proxy_gc_timeout -> CD#conn_data.call_proxy_gc_timeout;
+ cancel -> CD#conn_data.cancel;
+ resend_indication -> CD#conn_data.resend_indication;
+ segment_reply_ind -> CD#conn_data.segment_reply_ind;
+ segment_recv_acc -> CD#conn_data.segment_recv_acc;
+ segment_recv_timer -> CD#conn_data.segment_recv_timer;
+ segment_send -> CD#conn_data.segment_send;
+ segment_send_timer -> CD#conn_data.segment_send_timer;
+ max_pdu_size -> CD#conn_data.max_pdu_size;
+ request_keep_alive_timeout -> CD#conn_data.request_keep_alive_timeout;
+ receive_handle ->
+ LocalMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ #megaco_receive_handle{local_mid = LocalMid,
+ encoding_mod = CD#conn_data.encoding_mod,
+ encoding_config = CD#conn_data.encoding_config,
+ send_mod = CD#conn_data.send_mod};
+ _ ->
+ exit({no_such_item, Item})
+ end;
+conn_info(BadHandle, _Item) ->
+ {error, {no_such_connection, BadHandle}}.
+
+replace(_, _, []) ->
+ [];
+replace(Item, WithItem, [Item|List]) ->
+ [WithItem|List];
+replace(Item, WithItem, [OtherItem|List]) ->
+ [OtherItem | replace(Item, WithItem, List)].
+
+
+update_conn_info(#conn_data{conn_handle = CH}, Item, Val) ->
+ do_update_conn_info(CH, Item, Val);
+update_conn_info(CH, Item, Val)
+ when is_record(CH, megaco_conn_handle) andalso (Item /= cancel) ->
+ do_update_conn_info(CH, Item, Val);
+update_conn_info(BadHandle, _Item, _Val) ->
+ {error, {no_such_connection, BadHandle}}.
+
+do_update_conn_info(CH, orig_pending_limit, Val) ->
+ do_update_conn_info(CH, sent_pending_limit, Val);
+do_update_conn_info(CH, Item, Val) ->
+ call({update_conn_data, CH, Item, Val}).
+
+
+system_info(all) ->
+ AllItems = [n_active_requests,
+ n_active_replies,
+ n_active_connections,
+ users,
+ connections,
+ text_config,
+ reply_counters,
+ pending_counters],
+ [{Item, system_info(Item)} || Item <- AllItems];
+system_info(Item) ->
+ case Item of
+ n_active_requests ->
+ ets:info(megaco_requests, size);
+ n_active_replies ->
+ ets:info(megaco_replies, size);
+ n_active_connections ->
+ ets:info(megaco_local_conn, size);
+ users ->
+ Pat = {{'_', mid}, '_'},
+ [Mid || {_, Mid} <- ets:match_object(megaco_config, Pat)];
+ connections ->
+ [C#conn_data.conn_handle || C <- ets:tab2list(megaco_local_conn)];
+ text_config ->
+ case ets:lookup(megaco_config, text_config) of
+ [] ->
+ [];
+ [{text_config, Conf}] ->
+ [Conf]
+ end;
+
+ reply_counters ->
+ reply_counters();
+
+ pending_counters ->
+ pending_counters();
+
+ recv_pending_counters ->
+ pending_counters(recv);
+
+ sent_pending_counters ->
+ pending_counters(sent);
+
+ BadItem ->
+ exit({no_such_item, BadItem})
+
+ end.
+
+
+get_env(Env, Default) ->
+ case application:get_env(megaco, Env) of
+ {ok, Val} -> Val;
+ undefined -> Default
+ end.
+
+lookup_local_conn(Handle) ->
+ ets:lookup(megaco_local_conn, Handle).
+
+
+autoconnect(RH, RemoteMid, SendHandle, ControlPid) ->
+ ?d("autoconnect -> entry with "
+ "~n RH: ~p"
+ "~n RemoteMid: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]),
+ case RemoteMid of
+ {MidType, _MidValue} when is_atom(MidType) ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid, auto});
+ preliminary_mid ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid, auto});
+ BadMid ->
+ {error, {bad_remote_mid, BadMid}}
+ end.
+
+connect(RH, RemoteMid, SendHandle, ControlPid) ->
+ ?d("connect -> entry with "
+ "~n RH: ~p"
+ "~n RemoteMid: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p", [RH, RemoteMid, SendHandle, ControlPid]),
+ case RemoteMid of
+ {MidType, _MidValue} when is_atom(MidType) ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid,
+ {plain, self()}});
+ preliminary_mid ->
+ call({connect, RH, RemoteMid, SendHandle, ControlPid,
+ {plain, self()}});
+ BadMid ->
+ {error, {bad_remote_mid, BadMid}}
+ end.
+
+finish_connect(ConnHandle, SendHandle, ControlPid, MFA) ->
+ ?d("finish_connect -> entry with "
+ "~n ConnHandle: ~p"
+ "~n SendHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n MFA: ~p", [ConnHandle, SendHandle, ControlPid, MFA]),
+ call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA}).
+
+connect_remote(ConnHandle, UserNode, Ref) ->
+ call({connect_remote, ConnHandle, UserNode, Ref}).
+
+disconnect(ConnHandle) ->
+ call({disconnect, ConnHandle}).
+
+disconnect_remote(ConnHandle, UserNode) ->
+ call({disconnect_remote, ConnHandle, UserNode}).
+
+
+incr_counter(Item, Incr) ->
+ try
+ begin
+ ets:update_counter(megaco_config, Item, Incr)
+ end
+ catch
+ error:_ ->
+ try
+ begin
+ cre_counter(Item, Incr)
+ end
+ catch
+ exit:_ ->
+ %% Ok, some other process got there before us,
+ %% so try again
+ ets:update_counter(megaco_config, Item, Incr)
+ end
+ end.
+%% incr_counter(Item, Incr) ->
+%% case (catch ets:update_counter(megaco_config, Item, Incr)) of
+%% {'EXIT', _} ->
+%% case (catch cre_counter(Item, Incr)) of
+%% {'EXIT', _} ->
+%% %% Ok, some other process got there before us,
+%% %% so try again
+%% ets:update_counter(megaco_config, Item, Incr);
+%% NewVal ->
+%% NewVal
+%% end;
+%% NewVal ->
+%% NewVal
+%% end.
+
+cre_counter(Item, Initial) ->
+ case whereis(?SERVER) =:= self() of
+ false ->
+ case call({cre_counter, Item, Initial}) of
+ {ok, Value} ->
+ Value;
+ Error ->
+ exit(Error)
+ end;
+ true ->
+ %% Check that the counter does not already exists
+ %% so we don't overwrite an already existing counter
+ case ets:lookup(megaco_config, Item) of
+ [] ->
+ ets:insert(megaco_config, {Item, Initial}),
+ {ok, Initial};
+ [_] ->
+ %% Ouch, now what?
+ {error, already_exists}
+
+ end
+ end.
+
+
+cre_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ Initial = 1,
+ cre_counter(Counter, Initial).
+
+incr_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ incr_counter(Counter, 1).
+
+get_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ [{Counter, Val}] = ets:lookup(megaco_config, Counter),
+ Val.
+
+del_reply_counter(ConnHandle, TransId) ->
+ Counter = {reply_counter, ConnHandle, TransId},
+ ets:delete(megaco_config, Counter).
+
+reply_counters() ->
+ Pattern = {{reply_counter, '_', '_'}, '_'},
+ Counters1 = ets:match_object(megaco_config, Pattern),
+ [{ConnHandle, TransId, CounterVal} ||
+ {{reply_counter, ConnHandle, TransId}, CounterVal} <- Counters1].
+
+
+cre_pending_counter(TransId) ->
+ cre_pending_counter(sent, TransId, 0).
+
+cre_pending_counter(Direction, TransId, Initial) ->
+ Counter = {pending_counter, Direction, TransId},
+ cre_counter(Counter, Initial).
+
+incr_pending_counter(TransId) ->
+ incr_pending_counter(sent, TransId).
+
+incr_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ incr_counter(Counter, 1).
+
+get_pending_counter(TransId) ->
+ get_pending_counter(sent, TransId).
+
+get_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ [{Counter, Val}] = ets:lookup(megaco_config, Counter),
+ Val.
+
+del_pending_counter(TransId) ->
+ del_pending_counter(sent, TransId).
+
+del_pending_counter(Direction, TransId) ->
+ Counter = {pending_counter, Direction, TransId},
+ ets:delete(megaco_config, Counter).
+
+
+pending_counters() ->
+ Pattern = {{pending_counter, '_', '_'}, '_'},
+ Counters1 = ets:match_object(megaco_config, Pattern),
+ Counters2 = [{Direction, TransId, CounterVal} ||
+ {{pending_counter, Direction, TransId}, CounterVal} <-
+ Counters1],
+ RecvCounters = [{TransId, CounterVal} ||
+ {recv, TransId, CounterVal} <- Counters2],
+ SentCounters = [{TransId, CounterVal} ||
+ {sent, TransId, CounterVal} <- Counters2],
+ [{recv, RecvCounters}, {sent, SentCounters}].
+
+
+pending_counters(Direction)
+ when ((Direction =:= sent) orelse (Direction =:= recv)) ->
+ Pattern = {{pending_counter, Direction, '_'}, '_'},
+ Counters = ets:match_object(megaco_config, Pattern),
+ [{TransId, CounterVal} ||
+ {{pending_counter, D, TransId}, CounterVal} <-
+ Counters, (Direction == D)].
+
+%% A wrapping transaction id counter
+incr_trans_id_counter(ConnHandle) ->
+ incr_trans_id_counter(ConnHandle, 1).
+incr_trans_id_counter(ConnHandle, Incr)
+ when is_integer(Incr) andalso (Incr > 0) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ Min = user_info(LocalMid, min_trans_id),
+ Max =
+ case ConnData#conn_data.max_serial of
+ infinity ->
+ 4294967295;
+ MS ->
+ MS
+ end,
+ Item = ?TID_CNT(LocalMid),
+ do_incr_trans_id_counter(ConnData, Item, Min, Max, Incr, -1)
+ end.
+
+do_incr_trans_id_counter(ConnData, _Item, _Min, _Max, 0, Serial) ->
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ {ok, ConnData2};
+do_incr_trans_id_counter(ConnData, Item, Min, Max, N, _) ->
+ case (catch ets:update_counter(megaco_config, Item, {2, 1, Max, Min})) of
+ {'EXIT', _} ->
+ %% This can only happen for the first ever increment,
+ %% in which case N is equal to (the initial) Incr
+ ConnHandle = ConnData#conn_data.conn_handle,
+ init_trans_id_counter(ConnHandle, Item, N);
+ Serial ->
+ do_incr_trans_id_counter(ConnData, Item, Min, Max, N-1, Serial)
+ end.
+
+init_trans_id_counter(ConnHandle, Item, Incr) ->
+ case whereis(?SERVER) == self() of
+ false ->
+ call({init_trans_id_counter, ConnHandle, Item, Incr});
+ true ->
+ do_init_trans_id_counter(ConnHandle, Item, Incr)
+ end.
+
+do_init_trans_id_counter(ConnHandle, Item, Incr) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ %% Make sure that the counter still does not exist
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ Min = user_info(LocalMid, min_trans_id),
+ Max =
+ case ConnData#conn_data.max_serial of
+ infinity ->
+ 4294967295;
+ MS ->
+ MS
+ end,
+ Item = ?TID_CNT(LocalMid),
+ Incr2 = {2, Incr, Max, Min},
+ case (catch ets:update_counter(megaco_config, Item, Incr2)) of
+ {'EXIT', _} ->
+ %% Yep, we are the first one here
+ Serial1 = Min + (Incr-1),
+ ets:insert(megaco_config, {Item, Serial1}),
+ ConnData2 = ConnData#conn_data{serial = Serial1},
+ {ok, ConnData2};
+ Serial2 ->
+ %% No, someone got there before we did
+ ConnData2 = ConnData#conn_data{serial = Serial2},
+ {ok, ConnData2}
+ end
+ end.
+
+%% For backward compatibillity (during code upgrade)
+reset_trans_id_counter(ConnHandle, Item, Serial) ->
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [] ->
+ {error, {no_such_connection, ConnHandle}};
+ [ConnData] ->
+ do_reset_trans_id_counter(ConnData, LocalMid,
+ Item, Serial)
+ end.
+
+do_reset_trans_id_counter(ConnData, LocalMid, Item, Serial)
+ when is_integer(Serial) ->
+ Max = ConnData#conn_data.max_serial,
+ Overflow =
+ if
+ (Max == infinity) ->
+ Serial - 4294967295;
+
+ is_integer(Max) ->
+ Serial - Max
+ end,
+ NewSerial = user_info(LocalMid, min_trans_id) + (Overflow-1),
+ ConnData2 = ConnData#conn_data{serial = NewSerial},
+ ets:insert(megaco_config, {Item, NewSerial}),
+ {ok, ConnData2}.
+
+
+trans_sender_exit(Reason, CH) ->
+ ?d("trans_sender_exit -> entry with"
+ "~n Reason: ~p"
+ "~n CH: ~p", [Reason, CH]),
+ cast({trans_sender_exit, Reason, CH}).
+
+
+call(Request) ->
+ case (catch gen_server:call(?SERVER, Request, infinity)) of
+ {'EXIT', _} ->
+ {error, megaco_not_started};
+ Res ->
+ Res
+ end.
+
+
+cast(Msg) ->
+ case (catch gen_server:cast(?SERVER, Msg)) of
+ {'EXIT', _} ->
+ {error, megaco_not_started};
+ Res ->
+ Res
+ end.
+
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+
+init([Parent]) ->
+ ?d("init -> entry with "
+ "~n Parent: ~p", [Parent]),
+ process_flag(trap_exit, true),
+ case (catch do_init()) of
+ ok ->
+ ?d("init -> init ok", []),
+ {ok, #state{parent_pid = Parent}};
+ Else ->
+ ?d("init -> init error: "
+ "~n ~p", [Else]),
+ {stop, Else}
+ end.
+
+do_init() ->
+ ?megaco_test_init(),
+ ets:new(megaco_config, [public, named_table, {keypos, 1}]),
+ ets:new(megaco_local_conn, [public, named_table, {keypos, 2}]),
+ ets:new(megaco_remote_conn, [public, named_table, {keypos, 2}, bag]),
+ megaco_stats:init(megaco_stats, global_snmp_counters()),
+ init_scanner(),
+ init_user_defaults(),
+ init_users().
+
+
+
+init_scanner() ->
+ case get_env(scanner, undefined) of
+ undefined ->
+ Key = text_config,
+ Data = [],
+ ets:insert(megaco_config, {Key, Data});
+ flex ->
+ start_scanner(megaco_flex_scanner_handler,
+ start_link, [], [gen_server]);
+ {flex, Opts} when is_list(Opts) -> % For future use
+ start_scanner(megaco_flex_scanner_handler,
+ start_link, [Opts], [gen_server]);
+ {M, F, A, Mods} when is_atom(M) andalso
+ is_atom(F) andalso
+ is_list(A) andalso
+ is_list(Mods) ->
+ start_scanner(M, F, A, Mods)
+ end.
+
+start_scanner(M, F, A, Mods) ->
+ case megaco_misc_sup:start_permanent_worker(M, F, A, Mods) of
+ {ok, Pid, Conf} when is_pid(Pid) ->
+ Key = text_config,
+ Data = [Conf],
+ ets:insert(megaco_config, {Key, Data});
+ Else ->
+ throw({scanner_start_failed, Else})
+ end.
+
+init_user_defaults() ->
+ init_user_default(min_trans_id, 1),
+ init_user_default(max_trans_id, infinity),
+ init_user_default(request_timer, #megaco_incr_timer{}),
+ init_user_default(long_request_timer, timer:seconds(60)),
+
+ init_user_default(auto_ack, false),
+
+ init_user_default(trans_ack, false),
+ init_user_default(trans_ack_maxcount, 10),
+
+ init_user_default(trans_req, false),
+ init_user_default(trans_req_maxcount, 10),
+ init_user_default(trans_req_maxsize, 2048),
+
+ init_user_default(trans_timer, 0),
+ init_user_default(trans_sender, undefined),
+
+ init_user_default(pending_timer, timer:seconds(30)),
+ init_user_default(sent_pending_limit, infinity),
+ init_user_default(recv_pending_limit, infinity),
+ init_user_default(reply_timer, timer:seconds(30)),
+ init_user_default(send_mod, megaco_tcp),
+ init_user_default(encoding_mod, megaco_pretty_text_encoder),
+ init_user_default(protocol_version, 1),
+ init_user_default(auth_data, asn1_NOVALUE),
+ init_user_default(encoding_config, []),
+ init_user_default(user_mod, megaco_user_default),
+ init_user_default(user_args, []),
+ init_user_default(reply_data, undefined),
+ init_user_default(threaded, false),
+ init_user_default(strict_version, true),
+ init_user_default(long_request_resend, false),
+ init_user_default(call_proxy_gc_timeout, timer:seconds(5)),
+ init_user_default(cancel, false),
+ init_user_default(resend_indication, false),
+ init_user_default(segment_reply_ind, false),
+ init_user_default(segment_recv_acc, false),
+ init_user_default(segment_recv_timer, timer:seconds(10)),
+ init_user_default(segment_send, none),
+ init_user_default(segment_send_timer, timer:seconds(5)),
+ init_user_default(max_pdu_size, infinity),
+ init_user_default(request_keep_alive_timeout, plain).
+
+init_user_default(Item, Default) when Item /= mid ->
+ Val = get_env(Item, Default),
+ case do_update_user(default, Item, Val) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ throw(Reason)
+ end.
+
+init_users() ->
+ Users = get_env(users, []),
+ init_users(Users).
+
+init_users([]) ->
+ ok;
+init_users([{UserMid, Config} | Rest]) ->
+ case handle_start_user(UserMid, Config) of
+ ok ->
+ init_users(Rest);
+ Else ->
+ throw({bad_user, UserMid, Else})
+ end;
+init_users(BadConfig) ->
+ throw({bad_config, users, BadConfig}).
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_call({cre_counter, Item, Incr}, _From, S) ->
+ Reply = cre_counter(Item, Incr),
+ {reply, Reply, S};
+
+handle_call({del_counter, Item, Incr}, _From, S) ->
+ Reply = cre_counter(Item, Incr),
+ {reply, Reply, S};
+
+%% For backward compatibillity (code upgrade)
+handle_call({incr_trans_id_counter, ConnHandle}, _From, S) ->
+ Reply = incr_trans_id_counter(ConnHandle),
+ {reply, Reply, S};
+
+handle_call({init_trans_id_counter, ConnHandle, Item, Incr}, _From, S) ->
+ Reply = do_init_trans_id_counter(ConnHandle, Item, Incr),
+ {reply, Reply, S};
+
+%% For backward compatibillity (code upgrade)
+handle_call({reset_trans_id_counter, ConnHandle, Item, Serial}, _From, S) ->
+ Reply = reset_trans_id_counter(ConnHandle, Item, Serial),
+ {reply, Reply, S};
+
+handle_call({receive_handle, UserMid}, _From, S) ->
+ case catch make_receive_handle(UserMid) of
+ {'EXIT', _} ->
+ {reply, {error, {no_receive_handle, UserMid}}, S};
+ RH ->
+ {reply, {ok, RH}, S}
+ end;
+handle_call({connect, RH, RemoteMid, SendHandle, ControlPid}, _From, S) ->
+ Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, auto),
+ {reply, Reply, S};
+handle_call({connect, RH, RemoteMid, SendHandle, ControlPid, Auto}, _From, S) ->
+ Reply = handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto),
+ {reply, Reply, S};
+
+handle_call({finish_connect, ConnHandle, SendHandle, ControlPid, MFA},
+ _From, S) ->
+ Reply = handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA),
+ {reply, Reply, S};
+
+handle_call({connect_remote, CH, UserNode, Ref}, _From, S) ->
+ Reply = handle_connect_remote(CH, UserNode, Ref),
+ {reply, Reply, S};
+
+handle_call({disconnect, ConnHandle}, _From, S) ->
+ Reply = handle_disconnect(ConnHandle),
+ {reply, Reply, S};
+handle_call({disconnect_remote, CH, UserNode}, _From, S) ->
+ Reply = handle_disconnect_remote(CH, UserNode),
+ {reply, Reply, S};
+
+handle_call({start_user, UserMid, Config}, _From, S) ->
+ Reply = handle_start_user(UserMid, Config),
+ {reply, Reply, S};
+handle_call({stop_user, UserMid}, _From, S) ->
+ Reply = handle_stop_user(UserMid),
+ {reply, Reply, S};
+handle_call({update_conn_data, CH, Item, Val}, _From, S) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ {reply, {error, {no_such_connection, CH}}, S};
+ [CD] ->
+ Reply = handle_update_conn_data(CD, Item, Val),
+ {reply, Reply, S}
+ end;
+handle_call({update_user_info, UserMid, Item, Val}, _From, S) ->
+ case catch user_info(UserMid, mid) of
+ {'EXIT', _} ->
+ {reply, {error, {no_such_user, UserMid}}, S};
+ _ ->
+ Reply = do_update_user(UserMid, Item, Val),
+ {reply, Reply, S}
+ end;
+
+handle_call({stop, ParentPid}, _From, #state{parent_pid = ParentPid} = S) ->
+ Reason = normal,
+ Reply = ok,
+ {stop, Reason, Reply, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {bad_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_cast({trans_sender_exit, Reason, CH}, S) ->
+ warning_msg("transaction sender [~p] restarting: "
+ "~n~p", [CH, Reason]),
+ case lookup_local_conn(CH) of
+ [] ->
+ error_msg("connection data not found for ~p~n"
+ "when restarting transaction sender", [CH]);
+ [CD] ->
+ CD2 = trans_sender_start(CD#conn_data{trans_sender = undefined}),
+ ets:insert(megaco_local_conn, CD2)
+ end,
+ {noreply, S};
+
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_info({'EXIT', Pid, Reason}, S) when Pid =:= S#state.parent_pid ->
+ {stop, Reason, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unknown info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change(_Vsn, S, upgrade_from_pre_3_12) ->
+ upgrade_user_info_from_pre_3_12(),
+ upgrade_conn_data_from_pre_3_12(),
+ {ok, S};
+
+code_change(_Vsn, S, downgrade_to_pre_3_12) ->
+ downgrade_user_info_to_pre_3_12(),
+ downgrade_conn_data_to_pre_3_12(),
+ {ok, S};
+
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+%% -- Upgrade user info --
+
+upgrade_user_info_from_pre_3_12() ->
+ NewValues = [{request_keep_alive_timeout, plain}],
+ upgrade_user_info(NewValues).
+
+%% upgrade_user_info_from_pre_3_7() ->
+%% NewValues = [{segment_reply_ind, false},
+%% {segment_recv_acc, false},
+%% {segment_recv_timer, #megaco_incr_timer{}},
+%% {segment_send, none},
+%% {segment_send_timer, infinity},
+%% {max_pdu_size, infinity}],
+%% upgrade_user_info(NewValues).
+
+upgrade_user_info(NewValues) ->
+ Users = [default|system_info(users)],
+ F = fun({Item, Val}) ->
+ upgrade_user_info(Users, Item, Val)
+ end,
+ lists:foreach(F, NewValues),
+ ok.
+
+upgrade_user_info(Users, Item, Val) ->
+ F = fun(User) -> do_update_user(User, Item, Val) end,
+ lists:foreach(F, Users),
+ ok.
+
+
+%% %% -- Downgrade user info --
+
+downgrade_user_info_to_pre_3_12() ->
+ NewItems = [
+ request_keep_alive_timeout
+ ],
+ downgrade_user_info(NewItems).
+
+%% downgrade_user_info_to_pre_3_7() ->
+%% NewItems = [
+%% segment_reply_ind,
+%% segment_recv_acc,
+%% segment_recv_timer,
+%% segment_send,
+%% segment_send_timer,
+%% max_pdu_size
+%% ],
+%% downgrade_user_info(NewItems).
+
+downgrade_user_info(NewItems) ->
+ Users = [default|system_info(users)],
+ F = fun(Item) ->
+ downgrade_user_info(Users, Item)
+ end,
+ lists:foreach(F, NewItems),
+ ok.
+
+downgrade_user_info(Users, Item) ->
+ F = fun(User) -> do_downgrade_user_info(User, Item) end,
+ lists:foreach(F, Users),
+ ok.
+
+do_downgrade_user_info(User, Item) ->
+ ets:delete(megaco_config, {User, Item}).
+
+
+%% %% -- Upgrade conn data --
+
+upgrade_conn_data_from_pre_3_12() ->
+ Conns = system_info(connections),
+ Defaults = [{request_keep_alive_timeout, plain}],
+ upgrade_conn_data(Conns, Defaults).
+
+%% upgrade_conn_data_from_pre_3_7() ->
+%% Conns = system_info(connections),
+%% Defaults = [{segment_reply_ind, false},
+%% {segment_recv_acc, false},
+%% {segment_recv_timer, #megaco_incr_timer{}},
+%% {segment_send, false},
+%% {segment_send_timer, #megaco_incr_timer{}},
+%% {max_pdu_size, infinity}],
+%% upgrade_conn_data(Conns, Defaults).
+
+upgrade_conn_data(Conns, Defaults) ->
+ F = fun(CH) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ ok;
+ [CD] ->
+ do_upgrade_conn_data(CD, Defaults)
+ end
+ end,
+ lists:foreach(F, Conns),
+ ok.
+
+do_upgrade_conn_data(OldStyleCD, Defaults) ->
+ NewStyleCD = new_conn_data(OldStyleCD, Defaults),
+ ets:insert(megaco_local_conn, NewStyleCD).
+
+%% Pre 3.12
+new_conn_data({conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr,
+ AutoAck,
+ TransAck, TransAckMaxCnt,
+ TransReq, TransReqMaxCnt, TransReqMaxSz,
+ TransTmr, TransSndr,
+
+ PendingTmr,
+ SentPendingLimit,
+ RecvPendingLimit,
+ ReplyTmr, CtrPid, MonRef,
+ Sendmod, SendHandle,
+ EncodeMod, EncodeConf,
+ ProtV, AuthData,
+ UserMod, UserArgs, ReplyAction, ReplyData,
+ Threaded,
+ StrictVersion,
+ LongReqResend,
+ Cancel,
+ ResendIndication,
+ SegmentReplyInd,
+ SegmentRecvAcc,
+ SegmentRecvTimer,
+ SegmentSend,
+ SegmentSendTimer,
+ MaxPDUSize
+ %% RequestKeepAliveTimerDefault - New values
+ },
+ Defaults) ->
+ #conn_data{conn_handle = CH,
+ serial = Serial,
+ max_serial = MaxSerial,
+ request_timer = ReqTmr,
+ long_request_timer = LongReqTmr,
+
+ auto_ack = AutoAck,
+
+ trans_ack = TransAck,
+ trans_ack_maxcount = TransAckMaxCnt,
+
+ trans_req = TransReq,
+ trans_req_maxcount = TransReqMaxCnt,
+ trans_req_maxsize = TransReqMaxSz,
+
+ trans_timer = TransTmr,
+ trans_sender = TransSndr,
+
+ pending_timer = PendingTmr,
+ sent_pending_limit = SentPendingLimit,
+ recv_pending_limit = RecvPendingLimit,
+
+ reply_timer = ReplyTmr,
+ control_pid = CtrPid,
+ monitor_ref = MonRef,
+ send_mod = Sendmod,
+ send_handle = SendHandle,
+ encoding_mod = EncodeMod,
+ encoding_config = EncodeConf,
+ protocol_version = ProtV,
+ auth_data = AuthData,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = ReplyAction,
+ reply_data = ReplyData,
+ threaded = Threaded,
+ strict_version = StrictVersion,
+ long_request_resend = LongReqResend,
+ cancel = Cancel,
+ resend_indication = ResendIndication,
+ segment_reply_ind = SegmentReplyInd,
+ segment_recv_acc = SegmentRecvAcc,
+ segment_recv_timer = SegmentRecvTimer,
+ segment_send = SegmentSend,
+ segment_send_timer = SegmentSendTimer,
+ max_pdu_size = MaxPDUSize,
+ request_keep_alive_timeout = get_default(request_keep_alive_timeout, Defaults)
+ }.
+
+
+get_default(Key, Defaults) ->
+ {value, {Key, Default}} = lists:keysearch(Key, 1, Defaults),
+ Default.
+
+
+%% %% -- Downgrade conn data --
+
+downgrade_conn_data_to_pre_3_12() ->
+ Conns = system_info(connections),
+ Downgrade = fun(NewCD) -> old_conn_data_to_pre_3_12(NewCD) end,
+ downgrade_conn_data(Downgrade, Conns).
+
+downgrade_conn_data(Downgrade, Conns) ->
+ F = fun(CH) ->
+ case lookup_local_conn(CH) of
+ [] ->
+ ok;
+ [CD] ->
+ do_downgrade_conn_data(Downgrade, CD)
+ end
+ end,
+ lists:foreach(F, Conns).
+
+do_downgrade_conn_data(Downgrade, NewStyleCD) ->
+ OldStyleCD = Downgrade(NewStyleCD),
+ ets:insert(megaco_local_conn, OldStyleCD).
+
+old_conn_data_to_pre_3_12(
+ #conn_data{conn_handle = CH,
+ serial = Serial,
+ max_serial = MaxSerial,
+ request_timer = ReqTmr,
+ long_request_timer = LongReqTmr,
+
+ auto_ack = AutoAck,
+
+ trans_ack = TransAck,
+ trans_ack_maxcount = TransAckMaxCnt,
+
+ trans_req = TransReq,
+ trans_req_maxcount = TransReqMaxCnt,
+ trans_req_maxsize = TransReqMaxSz,
+
+ trans_timer = TransTmr,
+ trans_sender = TransSndr,
+
+ pending_timer = PendingTmr,
+ sent_pending_limit = SentPendingLimit,
+ recv_pending_limit = RecvPendingLimit,
+
+ reply_timer = ReplyTmr,
+ control_pid = CtrPid,
+ monitor_ref = MonRef,
+ send_mod = Sendmod,
+ send_handle = SendHandle,
+ encoding_mod = EncodeMod,
+ encoding_config = EncodeConf,
+ protocol_version = ProtV,
+ auth_data = AuthData,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = ReplyAction,
+ reply_data = ReplyData,
+ threaded = Threaded,
+ strict_version = StrictVersion,
+ long_request_resend = LongReqResend,
+ cancel = Cancel,
+ resend_indication = ResendIndication,
+ segment_reply_ind = SegmentRecvAcc,
+ segment_recv_acc = SegmentRecvAcc,
+ segment_recv_timer = SegmentRecvTimer,
+ segment_send = SegmentSend,
+ segment_send_timer = SegmentSendTimer,
+ max_pdu_size = MaxPDUSize
+ %% request_keep_alive_timeout = RequestKeepAliveTimeout
+ }) ->
+ {conn_data, CH, Serial, MaxSerial, ReqTmr, LongReqTmr,
+ AutoAck,
+ TransAck, TransAckMaxCnt,
+ TransReq, TransReqMaxCnt, TransReqMaxSz,
+ TransTmr, TransSndr,
+ PendingTmr,
+ SentPendingLimit,
+ RecvPendingLimit,
+ ReplyTmr, CtrPid, MonRef,
+ Sendmod, SendHandle,
+ EncodeMod, EncodeConf,
+ ProtV, AuthData,
+ UserMod, UserArgs, ReplyAction, ReplyData,
+ Threaded,
+ StrictVersion,
+ LongReqResend,
+ Cancel,
+ ResendIndication,
+ SegmentRecvAcc,
+ SegmentRecvAcc,
+ SegmentRecvTimer,
+ SegmentSend,
+ SegmentSendTimer,
+ MaxPDUSize}.
+
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+handle_start_user(default, _Config) ->
+ {error, bad_user_mid};
+handle_start_user(Mid, Config) ->
+ case catch user_info(Mid, mid) of
+ {'EXIT', _} ->
+ DefaultConfig = user_info(default, all),
+ do_handle_start_user(Mid, DefaultConfig),
+ do_handle_start_user(Mid, Config);
+ _LocalMid ->
+ {error, {user_already_exists, Mid}}
+ end.
+
+do_handle_start_user(UserMid, [{Item, Val} | Rest]) ->
+ case do_update_user(UserMid, Item, Val) of
+ ok ->
+ do_handle_start_user(UserMid, Rest);
+ {error, Reason} ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ {error, Reason}
+ end;
+do_handle_start_user(UserMid, []) ->
+ do_update_user(UserMid, mid, UserMid),
+ ok;
+do_handle_start_user(UserMid, BadConfig) ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ {error, {bad_user_config, UserMid, BadConfig}}.
+
+do_update_user(UserMid, Item, Val) ->
+ case verify_val(Item, Val) of
+ true ->
+ ets:insert(megaco_config, {{UserMid, Item}, Val}),
+ ok;
+ false ->
+ {error, {bad_user_val, UserMid, Item, Val}}
+ end.
+
+verify_val(Item, Val) ->
+ case Item of
+ mid -> true;
+ local_mid -> true;
+ remote_mid -> true;
+ min_trans_id -> verify_strict_uint(Val, 4294967295); % uint32
+ max_trans_id -> verify_uint(Val, 4294967295); % uint32
+ request_timer -> verify_timer(Val);
+ long_request_timer -> verify_timer(Val);
+
+ auto_ack -> verify_bool(Val);
+
+ trans_ack -> verify_bool(Val);
+ trans_ack_maxcount -> verify_uint(Val);
+
+ trans_req -> verify_bool(Val);
+ trans_req_maxcount -> verify_uint(Val);
+ trans_req_maxsize -> verify_uint(Val);
+
+ trans_timer -> verify_timer(Val) and (Val >= 0);
+ trans_sender when Val == undefined -> true;
+
+ pending_timer -> verify_timer(Val);
+ sent_pending_limit -> verify_uint(Val) andalso
+ (Val > 0);
+ recv_pending_limit -> verify_uint(Val) andalso
+ (Val > 0);
+ reply_timer -> verify_timer(Val);
+ control_pid when is_pid(Val) -> true;
+ monitor_ref -> true; % Internal usage only
+ send_mod when is_atom(Val) -> true;
+ send_handle -> true;
+ encoding_mod when is_atom(Val) -> true;
+ encoding_config when is_list(Val) -> true;
+ protocol_version -> verify_strict_uint(Val);
+ auth_data -> true;
+ user_mod when is_atom(Val) -> true;
+ user_args when is_list(Val) -> true;
+ reply_data -> true;
+ threaded -> verify_bool(Val);
+ strict_version -> verify_bool(Val);
+ long_request_resend -> verify_bool(Val);
+ call_proxy_gc_timeout -> verify_strict_uint(Val);
+ cancel -> verify_bool(Val);
+ resend_indication -> verify_resend_indication(Val);
+
+ segment_reply_ind -> verify_bool(Val);
+ segment_recv_acc -> verify_bool(Val);
+ segment_recv_timer -> verify_timer(Val);
+ segment_send -> verify_segmentation_window(Val);
+ segment_send_timer -> verify_timer(Val);
+ max_pdu_size -> verify_int(Val) andalso (Val > 0);
+ request_keep_alive_timeout ->
+ (verify_int(Val) andalso (Val >= 0)) orelse (Val =:= plain);
+
+ _ -> false
+ end.
+
+
+
+verify_bool(true) -> true;
+verify_bool(false) -> true;
+verify_bool(_) -> false.
+
+verify_resend_indication(flag) -> true;
+verify_resend_indication(Val) -> verify_bool(Val).
+
+-spec verify_strict_int(Int :: integer()) -> boolean().
+verify_strict_int(Int) when is_integer(Int) -> true;
+verify_strict_int(_) -> false.
+
+-spec verify_strict_int(Int :: integer(),
+ Max :: integer() | 'infinity') -> boolean().
+verify_strict_int(Int, infinity) ->
+ verify_strict_int(Int);
+verify_strict_int(Int, Max) ->
+ verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max).
+
+-spec verify_strict_uint(Int :: non_neg_integer()) -> boolean().
+verify_strict_uint(Int) when is_integer(Int) andalso (Int >= 0) -> true;
+verify_strict_uint(_) -> false.
+
+-spec verify_strict_uint(Int :: non_neg_integer(),
+ Max :: non_neg_integer() | 'infinity') -> boolean().
+verify_strict_uint(Int, infinity) ->
+ verify_strict_uint(Int);
+verify_strict_uint(Int, Max) ->
+ verify_strict_int(Int, 0, Max).
+
+-spec verify_uint(Val :: non_neg_integer() | 'infinity') -> boolean().
+verify_uint(infinity) -> true;
+verify_uint(Val) -> verify_strict_uint(Val).
+
+-spec verify_int(Val :: integer() | 'infinity') -> boolean().
+verify_int(infinity) -> true;
+verify_int(Val) -> verify_strict_int(Val).
+
+-spec verify_int(Int :: integer() | 'infinity',
+ Max :: integer() | 'infinity') -> boolean().
+verify_int(Int, infinity) ->
+ verify_int(Int);
+verify_int(infinity, _Max) ->
+ true;
+verify_int(Int, Max) ->
+ verify_strict_int(Int) andalso verify_strict_int(Max) andalso (Int =< Max).
+
+-spec verify_uint(Int :: non_neg_integer() | 'infinity',
+ Max :: non_neg_integer() | 'infinity') -> boolean().
+verify_uint(Int, infinity) ->
+ verify_uint(Int);
+verify_uint(infinity, _Max) ->
+ true;
+verify_uint(Int, Max) ->
+ verify_strict_int(Int, 0, Max).
+
+-spec verify_strict_int(Int :: integer(),
+ Min :: integer(),
+ Max :: integer()) -> boolean().
+verify_strict_int(Val, Min, Max)
+ when (is_integer(Val) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Val >= Min) andalso
+ (Val =< Max)) ->
+ true;
+verify_strict_int(_Val, _Min, _Max) ->
+ false.
+
+-spec verify_int(Val :: integer() | 'infinity',
+ Min :: integer(),
+ Max :: integer() | 'infinity') -> boolean().
+verify_int(infinity, Min, infinity) ->
+ verify_strict_int(Min);
+verify_int(Val, Min, infinity) ->
+ verify_strict_int(Val) andalso
+ verify_strict_int(Min) andalso (Val >= Min);
+verify_int(Int, Min, Max) ->
+ verify_strict_int(Int, Min, Max).
+
+verify_timer(Timer) ->
+ megaco_timer:verify(Timer).
+
+verify_segmentation_window(none) ->
+ true;
+verify_segmentation_window(K) ->
+ verify_int(K, 1, infinity).
+
+handle_stop_user(UserMid) ->
+ case catch user_info(UserMid, mid) of
+ {'EXIT', _} ->
+ {error, {no_such_user, UserMid}};
+ _ ->
+ case catch user_info(UserMid, connections) of
+ [] ->
+ ets:match_delete(megaco_config, {{UserMid, '_'}, '_'}),
+ ok;
+ {'EXIT', _} ->
+ {error, {no_such_user, UserMid}};
+ _Else ->
+ {error, {active_connections, UserMid}}
+ end
+ end.
+
+handle_update_conn_data(CD, Item = receive_handle, RH) ->
+ UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ if
+ is_record(RH, megaco_receive_handle) andalso
+ is_atom(RH#megaco_receive_handle.encoding_mod) andalso
+ is_list(RH#megaco_receive_handle.encoding_config) andalso
+ is_atom(RH#megaco_receive_handle.send_mod) andalso
+ (RH#megaco_receive_handle.local_mid /= UserMid) ->
+ CD2 = CD#conn_data{
+ encoding_mod = RH#megaco_receive_handle.encoding_mod,
+ encoding_config = RH#megaco_receive_handle.encoding_config,
+ send_mod = RH#megaco_receive_handle.send_mod},
+ ets:insert(megaco_local_conn, CD2),
+ ok;
+ true ->
+ {error, {bad_user_val, UserMid, Item, RH}}
+ end;
+handle_update_conn_data(CD, Item, Val) ->
+ case verify_val(Item, Val) of
+ true ->
+ CD2 = replace_conn_data(CD, Item, Val),
+ ets:insert(megaco_local_conn, CD2),
+ ok;
+ false ->
+ UserMid = (CD#conn_data.conn_handle)#megaco_conn_handle.local_mid,
+ {error, {bad_user_val, UserMid, Item, Val}}
+ end.
+
+replace_conn_data(CD, Item, Val) ->
+ case Item of
+ trans_id -> CD#conn_data{serial = Val};
+ max_trans_id -> CD#conn_data{max_serial = Val};
+ request_timer -> CD#conn_data{request_timer = Val};
+ long_request_timer -> CD#conn_data{long_request_timer = Val};
+
+ auto_ack -> update_auto_ack(CD, Val);
+
+ %% Accumulate trans ack before sending
+ trans_ack -> update_trans_ack(CD, Val);
+ trans_ack_maxcount -> update_trans_ack_maxcount(CD, Val);
+
+ %% Accumulate trans req before sending
+ trans_req -> update_trans_req(CD, Val);
+ trans_req_maxcount -> update_trans_req_maxcount(CD, Val);
+ trans_req_maxsize -> update_trans_req_maxsize(CD, Val);
+
+ trans_timer -> update_trans_timer(CD, Val);
+ %% trans_sender - Automagically updated by
+ %% update_auto_ack & update_trans_timer &
+ %% update_trans_ack & update_trans_req
+
+ pending_timer -> CD#conn_data{pending_timer = Val};
+ sent_pending_limit -> CD#conn_data{sent_pending_limit = Val};
+ recv_pending_limit -> CD#conn_data{recv_pending_limit = Val};
+ reply_timer -> CD#conn_data{reply_timer = Val};
+ control_pid -> CD#conn_data{control_pid = Val};
+ monitor_ref -> CD#conn_data{monitor_ref = Val};
+ send_mod -> CD#conn_data{send_mod = Val};
+ send_handle -> CD#conn_data{send_handle = Val};
+ encoding_mod -> CD#conn_data{encoding_mod = Val};
+ encoding_config -> CD#conn_data{encoding_config = Val};
+ protocol_version -> CD#conn_data{protocol_version = Val};
+ auth_data -> CD#conn_data{auth_data = Val};
+ user_mod -> CD#conn_data{user_mod = Val};
+ user_args -> CD#conn_data{user_args = Val};
+ reply_action -> CD#conn_data{reply_action = Val};
+ reply_data -> CD#conn_data{reply_data = Val};
+ threaded -> CD#conn_data{threaded = Val};
+ strict_version -> CD#conn_data{strict_version = Val};
+ long_request_resend -> CD#conn_data{long_request_resend = Val};
+ call_proxy_gc_timeout -> CD#conn_data{call_proxy_gc_timeout = Val};
+ cancel -> CD#conn_data{cancel = Val};
+ resend_indication -> CD#conn_data{resend_indication = Val};
+ segment_reply_ind -> CD#conn_data{segment_reply_ind = Val};
+ segment_recv_acc -> CD#conn_data{segment_recv_acc = Val};
+ segment_recv_timer -> CD#conn_data{segment_recv_timer = Val};
+ segment_send -> CD#conn_data{segment_send = Val};
+ segment_send_timer -> CD#conn_data{segment_send_timer = Val};
+ max_pdu_size -> CD#conn_data{max_pdu_size = Val};
+ request_keep_alive_timeout -> CD#conn_data{request_keep_alive_timeout = Val}
+ end.
+
+%% update auto_ack
+update_auto_ack(#conn_data{trans_sender = Pid,
+ trans_req = false} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{auto_ack = false, trans_sender = undefined};
+
+update_auto_ack(#conn_data{trans_timer = To,
+ trans_ack = true,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{auto_ack = true, trans_sender = Pid};
+
+update_auto_ack(CD, Val) ->
+ ?d("update_auto_ack -> entry with ~p", [Val]),
+ CD#conn_data{auto_ack = Val}.
+
+%% update trans_ack
+update_trans_ack(#conn_data{auto_ack = true,
+ trans_req = false,
+ trans_sender = Pid} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_ack = false, trans_sender = undefined};
+
+update_trans_ack(#conn_data{trans_timer = To,
+ auto_ack = true,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_ack = true, trans_sender = Pid};
+
+update_trans_ack(CD, Val) ->
+ ?d("update_trans_ack -> entry with ~p", [Val]),
+ CD#conn_data{trans_ack = Val}.
+
+%% update trans_req
+update_trans_req(#conn_data{trans_ack = false,
+ trans_sender = Pid} = CD,
+ false) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_req = false, trans_sender = undefined};
+
+update_trans_req(#conn_data{trans_timer = To,
+ trans_sender = undefined} = CD,
+ true) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_req = true, trans_sender = Pid};
+
+update_trans_req(CD, Val) ->
+ ?d("update_trans_req -> entry with ~p", [Val]),
+ CD#conn_data{trans_req = Val}.
+
+%% update trans_timer
+update_trans_timer(#conn_data{auto_ack = true,
+ trans_ack = true,
+ trans_sender = undefined} = CD,
+ To) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_timer = To, trans_sender = Pid};
+
+update_trans_timer(#conn_data{trans_req = true,
+ trans_sender = undefined} = CD,
+ To) when To > 0 ->
+ #conn_data{conn_handle = CH,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz} = CD,
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_timer = To, trans_sender = Pid};
+
+update_trans_timer(#conn_data{trans_sender = Pid} = CD, 0) when is_pid(Pid) ->
+ megaco_trans_sender:stop(Pid),
+ CD#conn_data{trans_timer = 0, trans_sender = undefined};
+
+update_trans_timer(#conn_data{trans_sender = Pid} = CD, To)
+ when is_pid(Pid) and (To > 0) ->
+ megaco_trans_sender:timeout(Pid, To),
+ CD#conn_data{trans_timer = To};
+
+update_trans_timer(CD, To) when To > 0 ->
+ CD#conn_data{trans_timer = To}.
+
+%% update trans_ack_maxcount
+update_trans_ack_maxcount(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:ack_maxcount(Pid, Max),
+ CD#conn_data{trans_ack_maxcount = Max};
+
+update_trans_ack_maxcount(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_ack_maxcount -> entry with ~p", [Max]),
+ CD#conn_data{trans_ack_maxcount = Max}.
+
+%% update trans_req_maxcount
+update_trans_req_maxcount(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:req_maxcount(Pid, Max),
+ CD#conn_data{trans_req_maxcount = Max};
+
+update_trans_req_maxcount(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_req_maxcount -> entry with ~p", [Max]),
+ CD#conn_data{trans_req_maxcount = Max}.
+
+%% update trans_req_maxsize
+update_trans_req_maxsize(#conn_data{trans_sender = Pid} = CD, Max)
+ when is_pid(Pid) and (Max > 0) ->
+ megaco_trans_sender:req_maxsize(Pid, Max),
+ CD#conn_data{trans_req_maxsize = Max};
+
+update_trans_req_maxsize(CD, Max)
+ when Max > 0 ->
+ ?d("update_trans_req_maxsize -> entry with ~p", [Max]),
+ CD#conn_data{trans_req_maxsize = Max}.
+
+
+
+handle_connect(RH, RemoteMid, SendHandle, ControlPid, Auto) ->
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ ConnHandle = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ ?d("handle_connect -> entry with"
+ "~n ConnHandle: ~p", [ConnHandle]),
+ case ets:lookup(megaco_local_conn, ConnHandle) of
+ [] ->
+ PrelMid = preliminary_mid,
+ PrelHandle = ConnHandle#megaco_conn_handle{remote_mid = PrelMid},
+ case ets:lookup(megaco_local_conn, PrelHandle) of
+ [] ->
+ case (catch init_conn_data(RH,
+ RemoteMid, SendHandle,
+ ControlPid, Auto)) of
+ {'EXIT', _Reason} ->
+ ?d("handle_connect -> init conn data failed: "
+ "~n ~p",[_Reason]),
+ {error, {no_such_user, LocalMid}};
+ ConnData ->
+ ?d("handle_connect -> new connection"
+ "~n ConnData: ~p", [ConnData]),
+ %% Brand new connection, use
+ %% When is the preliminary_mid used?
+ create_snmp_counters(ConnHandle),
+ %% Maybe start transaction sender
+ ConnData2 = trans_sender_start(ConnData),
+ ets:insert(megaco_local_conn, ConnData2),
+ {ok, ConnData2}
+ end;
+ [PrelData] ->
+ ?d("handle_connect -> connection upgrade"
+ "~n PrelData: ~p", [PrelData]),
+ %% OK, we need to fix the snmp counters. Used
+ %% with the temporary (preliminary_mid) conn_handle.
+ create_snmp_counters(ConnHandle),
+ ConnData = PrelData#conn_data{conn_handle = ConnHandle},
+ trans_sender_upgrade(ConnData),
+ ets:insert(megaco_local_conn, ConnData),
+ ets:delete(megaco_local_conn, PrelHandle),
+ update_snmp_counters(ConnHandle, PrelHandle),
+ TH = ConnHandle#megaco_conn_handle{local_mid = PrelMid,
+ remote_mid = RemoteMid},
+ TD = ConnData#conn_data{conn_handle = TH},
+ ?report_debug(TD,
+ "Upgrade preliminary_mid to "
+ "actual remote_mid",
+ [{preliminary_mid, preliminary_mid},
+ {local_mid, LocalMid},
+ {remote_mid, RemoteMid}]),
+ {ok, ConnData}
+ end;
+ [_ConnData] ->
+ {error, {already_connected, ConnHandle}}
+ end.
+
+handle_finish_connect(ConnHandle, SendHandle, ControlPid, MFA) ->
+ case (catch ets:lookup(megaco_local_conn, ConnHandle)) of
+ [#conn_data{monitor_ref = connected} = CD] ->
+ {M, F, A} = MFA,
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlPid),
+ ConnData2 = CD#conn_data{monitor_ref = Ref,
+ control_pid = ControlPid,
+ send_handle = SendHandle},
+ ets:insert(megaco_local_conn, ConnData2),
+ {ok, Ref};
+ [#conn_data{monitor_ref = Ref}] ->
+ {ok, Ref};
+ [] ->
+ {error, {no_such_connection, ConnHandle}}
+ end.
+
+
+%% also trans_req == true
+trans_sender_start(#conn_data{conn_handle = CH,
+ auto_ack = true,
+ trans_ack = true,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz,
+ trans_timer = To,
+ trans_sender = undefined} = CD)
+ when To > 0 ->
+
+ ?d("trans_sender_start(ack) -> entry when"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n AcksMax: ~p"
+ "~n ReqsMax: ~p"
+ "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ ?d("trans_sender_start(ack) -> Pid: ~p", [Pid]),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_sender = Pid};
+
+trans_sender_start(#conn_data{conn_handle = CH,
+ trans_req = true,
+ trans_ack_maxcount = AcksMax,
+ trans_req_maxcount = ReqsMax,
+ trans_req_maxsize = ReqsMaxSz,
+ trans_timer = To,
+ trans_sender = undefined} = CD)
+ when To > 0 ->
+
+ ?d("trans_sender_start(req) -> entry when"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n AcksMax: ~p"
+ "~n ReqsMax: ~p"
+ "~n ReqsMaxSz: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+
+ {ok, Pid} = megaco_trans_sup:start_trans_sender(CH, To, ReqsMaxSz,
+ ReqsMax, AcksMax),
+
+ ?d("trans_sender_start(req) -> Pid: ~p", [Pid]),
+
+ %% Make sure we are notified when/if the transaction
+ %% sender goes down.
+ %% Do we need to store the ref? Will we ever need to
+ %% cancel this (apply_at_exit)?
+ megaco_monitor:apply_at_exit(?MODULE, trans_sender_exit, [CH], Pid),
+
+ CD#conn_data{trans_sender = Pid};
+
+trans_sender_start(CD) ->
+ ?d("trans_sender_start -> undefined", []),
+ CD#conn_data{trans_sender = undefined}.
+
+trans_sender_upgrade(#conn_data{conn_handle = CH,
+ trans_sender = Pid})
+ when is_pid(Pid) ->
+ ?d("trans_sende_upgrade -> entry when"
+ "~n CH: ~p"
+ "~n Pid: ~p", [CH, Pid]),
+ megaco_trans_sender:upgrade(Pid, CH);
+trans_sender_upgrade(_CD) ->
+ ok.
+
+
+handle_connect_remote(ConnHandle, UserNode, Ref) ->
+ Pat = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = '_'},
+ case ets:match_object(megaco_remote_conn, Pat) of
+ [] ->
+ RCD = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = Ref},
+ ets:insert(megaco_remote_conn, RCD),
+ ok;
+ _ ->
+ {error, {already_connected, ConnHandle, UserNode}}
+ end.
+
+init_conn_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ init_conn_data(RH, RemoteMid, SendHandle, ControlPid, auto).
+init_conn_data(RH, RemoteMid, SendHandle, ControlPid, Auto) ->
+ Mid = RH#megaco_receive_handle.local_mid,
+ ConnHandle = #megaco_conn_handle{local_mid = Mid,
+ remote_mid = RemoteMid},
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ SendMod = RH#megaco_receive_handle.send_mod,
+ MonitorRef =
+ case Auto of
+ auto ->
+ undefined_auto_monitor_ref;
+ {plain, ConnectorPid} ->
+ {connecting, ConnectorPid}
+ end,
+ #conn_data{conn_handle = ConnHandle,
+ serial = undefined_serial,
+ max_serial = user_info(Mid, max_trans_id),
+ request_timer = user_info(Mid, request_timer),
+ long_request_timer = user_info(Mid, long_request_timer),
+
+ auto_ack = user_info(Mid, auto_ack),
+ trans_ack = user_info(Mid, trans_req),
+ trans_req = user_info(Mid, trans_req),
+
+ trans_timer = user_info(Mid, trans_timer),
+ trans_req_maxsize = user_info(Mid, trans_req_maxsize),
+ trans_req_maxcount = user_info(Mid, trans_req_maxcount),
+ trans_ack_maxcount = user_info(Mid, trans_ack_maxcount),
+
+ pending_timer = user_info(Mid, pending_timer),
+ sent_pending_limit = user_info(Mid, sent_pending_limit),
+ recv_pending_limit = user_info(Mid, recv_pending_limit),
+ reply_timer = user_info(Mid, reply_timer),
+ control_pid = ControlPid,
+ monitor_ref = MonitorRef,
+ send_mod = SendMod,
+ send_handle = SendHandle,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig,
+ protocol_version = user_info(Mid, protocol_version),
+ auth_data = user_info(Mid, auth_data),
+ user_mod = user_info(Mid, user_mod),
+ user_args = user_info(Mid, user_args),
+ reply_action = undefined,
+ reply_data = user_info(Mid, reply_data),
+ threaded = user_info(Mid, threaded),
+ strict_version = user_info(Mid, strict_version),
+ long_request_resend = user_info(Mid, long_request_resend),
+ call_proxy_gc_timeout = user_info(Mid, call_proxy_gc_timeout),
+ cancel = false,
+ resend_indication = user_info(Mid, resend_indication),
+ segment_reply_ind = user_info(Mid, segment_reply_ind),
+ segment_recv_acc = user_info(Mid, segment_recv_acc),
+ segment_recv_timer = user_info(Mid, segment_recv_timer),
+ segment_send = user_info(Mid, segment_send),
+ segment_send_timer = user_info(Mid, segment_send_timer),
+ max_pdu_size = user_info(Mid, max_pdu_size),
+ request_keep_alive_timeout = user_info(Mid, request_keep_alive_timeout)
+ }.
+
+handle_disconnect(ConnHandle) when is_record(ConnHandle, megaco_conn_handle) ->
+ case ets:lookup(megaco_local_conn, ConnHandle) of
+ [ConnData] ->
+ ets:delete(megaco_local_conn, ConnHandle),
+ RemoteConnData = handle_disconnect_remote(ConnHandle, '_'),
+ {ok, ConnData, RemoteConnData};
+ [] ->
+ {error, {already_disconnected, ConnHandle}}
+ end.
+
+handle_disconnect_remote(ConnHandle, UserNode) ->
+ Pat = #remote_conn_data{conn_handle = ConnHandle,
+ user_node = UserNode,
+ monitor_ref = '_'},
+ RemoteConnData = ets:match_object(megaco_remote_conn, Pat),
+ ets:match_delete(megaco_remote_conn, Pat),
+ RemoteConnData.
+
+make_receive_handle(UserMid) ->
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = user_info(UserMid, encoding_mod),
+ encoding_config = user_info(UserMid, encoding_config),
+ send_mod = user_info(UserMid, send_mod)}.
+
+
+%%-----------------------------------------------------------------
+%% Func: create_snmp_counters/1, update_snmp_counters/2
+%% Description: create/update all the SNMP statistic counters
+%%-----------------------------------------------------------------
+
+create_snmp_counters(CH) ->
+ create_snmp_counters(CH, snmp_counters()).
+
+% create_snmp_counters(CH, []) ->
+% ok;
+% create_snmp_counters(CH, [Counter|Counters]) ->
+% Key = {CH, Counter},
+% ets:insert(megaco_stats, {Key, 0}),
+% create_snmp_counters(CH, Counters).
+
+create_snmp_counters(CH, Counters) ->
+ F = fun(Counter) ->
+ Key = {CH, Counter},
+ ets:insert(megaco_stats, {Key, 0})
+ end,
+ lists:foreach(F, Counters).
+
+
+update_snmp_counters(CH, PrelCH) ->
+ update_snmp_counters(CH, PrelCH, snmp_counters()).
+
+update_snmp_counters(_CH, _PrelCH, []) ->
+ ok;
+update_snmp_counters(CH, PrelCH, [Counter|Counters]) ->
+ PrelKey = {PrelCH, Counter},
+ Key = {CH, Counter},
+ [{PrelKey,PrelVal}] = ets:lookup(megaco_stats, PrelKey),
+ ets:update_counter(megaco_stats, Key, PrelVal),
+ ets:delete(megaco_stats, PrelKey),
+ update_snmp_counters(CH, PrelCH, Counters).
+
+
+global_snmp_counters() ->
+ [medGwyGatewayNumErrors].
+
+snmp_counters() ->
+ [medGwyGatewayNumTimerRecovery,
+ medGwyGatewayNumErrors].
+
+
+
+%%-----------------------------------------------------------------
+
+%% Time in milli seconds
+%% t() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+
+%%-----------------------------------------------------------------
+
+warning_msg(F, A) ->
+ ?megaco_warning("Config server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Config server: " ++ F, A).
+
diff --git a/lib/megaco/src/engine/megaco_digit_map.erl b/lib/megaco/src/engine/megaco_digit_map.erl
new file mode 100644
index 0000000000..de28686d6d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_digit_map.erl
@@ -0,0 +1,856 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Parse and evaluate digit maps
+%%----------------------------------------------------------------------
+%%
+%% digitMap = digitString
+%% / LWSP "(" LWSP digitStringList LWSP ")" LWSP
+%% digitStringList = digitString *( LWSP "|" LWSP digitString )
+%% digitString = 1*(digitStringElement)
+%% digitStringElement = digitPosition [DOT]
+%% digitPosition = digitMapLetter / digitMapRange
+%% digitMapRange = ("x" / LWSP "[" LWSP digitLetter LWSP "]" LWSP)
+%% digitLetter = *((DIGIT "-" DIGIT ) / digitMapLetter)
+%% digitMapLetter = DIGIT ; Basic event symbols
+%% / %x41-4B ; a-k
+%% / %x61-6B ; A-K
+%% / "T" ; Start inter-event timers
+%% / "S" ; Short inter-event timers
+%% / "L" ; Long inter-event timers, e.g. 16 sec
+%% / "Z" ; Long duration modifier
+%% DIGIT = %x30-39 ; 0-9
+%%
+%%----------------------------------------------------------------------
+%% Example of a digit map:
+%%
+%% (0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)
+%%
+%% DM = "(0| 00|[1-7]xxx|8xxxxxxx|Fxxxxxxx|Exx|91xxxxxxxxxx|9011x.)".
+%% DM = "xxx | xxL3 | xxS4".
+%% megaco:parse_digit_map(DM).
+%% megaco:test_digit_event(DM, "1234").
+%% megaco:test_digit_event(DM, "12ssss3").
+%% megaco:test_digit_event(DM, "12ssss4").
+%% megaco:test_digit_event(DM, "12ssss5").
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_digit_map).
+
+-export([parse/1, eval/1, eval/2, report/2, test/2]). % Public
+-export([test_eval/2]). % Internal
+
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/text/megaco_text_tokens.hrl").
+
+-record(state_transition, {mode, next, cont}).
+
+-record(timers, {mode = state_dependent,
+ start = 0,
+ short = timer_to_millis(3),
+ long = timer_to_millis(9),
+ duration = 100, % (not used) 100 ms <-> 9.9 sec
+ unexpected = reject}). % ignore | reject
+
+
+%%----------------------------------------------------------------------
+%% Parses a digit map body, represented as a list of chars,
+%% into a list of state transitions.
+%%
+%% Returns {ok, StateTransitionList} | {error, Reason}
+%%
+%%----------------------------------------------------------------------
+
+parse(DigitMapBody) when is_list(DigitMapBody) ->
+ ?d("parse -> entry with"
+ "~n DigitMapBody: ~p", [DigitMapBody]),
+ case parse_digit_map(DigitMapBody) of
+ {ok, STL} ->
+ {ok, duration_cleanup(STL, [])};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+parse(_DigitMapBody) ->
+ {error, not_a_digit_map_body}.
+
+duration_cleanup([], Acc) ->
+ Acc;
+duration_cleanup([STL|T], Acc) ->
+ #state_transition{cont = Events} = STL,
+ Events2 = duration_events_cleanup(Events, []),
+ duration_cleanup(T, [STL#state_transition{cont = Events2}|Acc]).
+
+duration_events_cleanup([], Acc) ->
+ lists:reverse(Acc);
+duration_events_cleanup([duration_event, Event|Events], Acc) ->
+ duration_events_cleanup(Events, [{duration_event, Event}|Acc]);
+duration_events_cleanup([Event|Events], Acc) ->
+ duration_events_cleanup(Events, [Event|Acc]).
+
+parse_digit_map(Chars) ->
+ parse_digit_map(Chars, 1, [], []).
+
+parse_digit_map(Chars, Line, DS, STL) ->
+ ?d("parse_digit_map -> entry with"
+ "~n Chars: ~p"
+ "~n DS: ~p", [Chars, DS]),
+ case megaco_text_scanner:skip_sep_chars(Chars, Line) of
+ {[], _Line2} when (DS =/= []) ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ STL2 = lists:reverse([ST | STL]),
+ {ok, STL2};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {[Char | Chars2], Line2} ->
+ case Char of
+ $( when (DS =:= []) andalso (STL =:= []) ->
+ parse_digit_map(Chars2, Line2, DS, STL);
+ $) when (DS =/= []) ->
+ case megaco_text_scanner:skip_sep_chars(Chars2, Line2) of
+ {[], _Line3} ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ STL2 = lists:reverse([ST | STL]),
+ {ok, STL2};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {Chars3, Line3} ->
+ Trash = lists:reverse(Chars3),
+ {error, {round_bracket_mismatch, Trash, Line3}}
+ end;
+ $| when (DS =/= []) ->
+ case parse_digit_string(DS) of
+ {ok, DS2} ->
+ ST = #state_transition{mode = state_dependent,
+ next = start,
+ cont = DS2},
+ parse_digit_map(Chars2, Line2, [], [ST | STL]);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ _ when ( Char =/= $( ) andalso
+ ( Char =/= $| ) andalso
+ ( Char =/= $) ) ->
+ parse_digit_map(Chars2, Line2, [Char | DS], STL);
+ _ ->
+ {error, {round_bracket_mismatch, Line2}}
+ end;
+ {[], Line2} ->
+ {error, {digit_string_expected, Line2}}
+ end.
+
+parse_digit_string(Chars) ->
+ ?d("parse_digit_string -> entry with"
+ "~n Chars: ~p", [Chars]),
+ parse_digit_string(Chars, []).
+
+parse_digit_string([Char | Chars], DS) ->
+ ?d("parse_digit_string -> entry with"
+ "~n Char: ~p"
+ "~n Chars: ~p"
+ "~n DS: ~p", [[Char], Chars, DS]),
+ case Char of
+ $] ->
+ parse_digit_letter(Chars, [], DS);
+ $[ ->
+ {error, square_bracket_mismatch};
+ $x ->
+ parse_digit_string(Chars, [{range, $0, $9} | DS]);
+ $. ->
+ parse_digit_string(Chars, [zero_or_more | DS]);
+
+ I when (I >= $0) andalso (I =< $9) ->
+ parse_digit_string(Chars, [{single, I} | DS]);
+
+ A when (A >= $a) andalso (A =< $k) ->
+ parse_digit_string(Chars, [{single, A} | DS]);
+ A when (A >= $A) andalso (A =< $K) ->
+ parse_digit_string(Chars, [{single, A} | DS]);
+
+ $S ->
+ parse_digit_string(Chars, [use_short_timer | DS]);
+ $s ->
+ parse_digit_string(Chars, [use_short_timer | DS]);
+
+ $L ->
+ parse_digit_string(Chars, [use_long_timer | DS]);
+ $l ->
+ parse_digit_string(Chars, [use_long_timer | DS]);
+
+ $Z when length(Chars) > 0 ->
+ parse_digit_string(Chars, [duration_event | DS]);
+ $z when length(Chars) > 0 ->
+ parse_digit_string(Chars, [duration_event | DS]);
+
+ $Z ->
+ {error, duration_not_allowed_as_last_char};
+ $z ->
+ {error, duration_not_allowed_as_last_char};
+
+ BadChar ->
+ {error, {illegal_char_in_digit_string, BadChar}}
+ end;
+parse_digit_string([], DM) ->
+ ?d("parse_digit_string -> entry when done with"
+ "~n DM: ~p", [DM]),
+ {ok, DM}.
+
+
+parse_digit_letter([Char | Chars], DL, DS) ->
+ ?d("parse_digit_letter -> entry with"
+ "~n Char: ~p"
+ "~n Chars: ~p"
+ "~n DL: ~p"
+ "~n DS: ~p", [[Char], Chars, DL, DS]),
+ case Char of
+ $[ ->
+ parse_digit_string(Chars, [{letter, DL} | DS]);
+ $] ->
+ {error, square_bracket_mismatch};
+ To when (To >= $0) andalso (To =< $9) ->
+ case Chars of
+ [$-, From | Chars2] when (From >= $0) andalso (From =< $9) ->
+ parse_digit_letter(Chars2, [{range, From, To} | DL], DS);
+ _ ->
+ parse_digit_letter(Chars, [{single, To} | DL], DS)
+ end;
+
+ A when (A >= $a) andalso (A =< $k) ->
+ parse_digit_letter(Chars, [{single, A} | DL], DS);
+ A when (A >= $A) andalso (A =< $K) ->
+ parse_digit_letter(Chars, [{single, A} | DL], DS);
+
+ $S ->
+ parse_digit_letter(Chars, [use_short_timer | DL], DS);
+ $s ->
+ parse_digit_letter(Chars, [use_short_timer | DL], DS);
+
+ $L ->
+ parse_digit_letter(Chars, [use_long_timer | DL], DS);
+ $l ->
+ parse_digit_letter(Chars, [use_long_timer | DL], DS);
+
+ $Z ->
+ parse_digit_letter(Chars, [duration_event | DL], DS);
+ $z ->
+ parse_digit_letter(Chars, [duration_event | DL], DS);
+
+ BadChar ->
+ {error, {illegal_char_between_square_brackets, BadChar}}
+ end;
+parse_digit_letter([], _DL, _DS) ->
+ {error, square_bracket_mismatch}.
+
+
+%%----------------------------------------------------------------------
+%% Collect digit map letters according to digit map
+%% Returns {ok, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+
+eval(DMV) when is_record(DMV, 'DigitMapValue') ->
+ case parse(DMV#'DigitMapValue'.digitMapBody) of
+ {ok, DigitMapBody} ->
+ eval(DigitMapBody, DMV);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+eval(STL) when is_list(STL) ->
+ eval(STL, #timers{}).
+
+eval(STL, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration)},
+ eval(STL, Timers);
+eval(STL, {ignore, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration),
+ unexpected = ignore},
+ eval(STL, Timers);
+eval(STL, {reject, #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ durationTimer = Duration}}) ->
+ Timers = #timers{start = timer_to_millis(Start),
+ short = timer_to_millis(Short),
+ long = timer_to_millis(Long),
+ duration = duration_to_millis(Duration),
+ unexpected = reject},
+ eval(STL, Timers);
+eval(STL, Timers) when is_list(STL) andalso
+ is_record(hd(STL), state_transition) andalso
+ is_record(Timers, timers) ->
+ ?d("eval -> entry with"
+ "~n STL: ~p"
+ "~n Timers: ~p", [STL, Timers]),
+ case collect(start, mandatory_event, Timers, lists:reverse(STL), []) of
+ {error, _} = Error ->
+ ?d("eval -> error:"
+ "~n Error: ~p", [Error]),
+ Error;
+ OK ->
+ ?d("eval -> ok:"
+ "~n OK: ~p", [OK]),
+ OK
+ end;
+eval(DigitMapBody, ignore) ->
+ eval(DigitMapBody, #timers{unexpected = ignore});
+eval(DigitMapBody, reject) ->
+ eval(DigitMapBody, #timers{unexpected = reject});
+eval(DigitMapBody, Timers) ->
+ case parse(DigitMapBody) of
+ {ok, STL} ->
+ eval(STL, Timers);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%% full | unambiguous
+
+collect(Event, State, Timers, STL, Letters) ->
+ ?d("collect -> entry with"
+ "~n Event: ~p"
+ "~n State: ~p"
+ "~n Timers: ~p"
+ "~n STL: ~p", [Event, State, Timers, STL]),
+ case handle_event(Event, State, Timers, STL, Letters) of
+ {completed_full, _Timers2, _STL2, Letters2} ->
+ completed(full, Letters2);
+ {completed, _Timers2, _STL2, Letters2} ->
+ completed(unambiguous, Letters2);
+ {State2, Timers2, STL2, Letters2} ->
+ ?d("collect -> "
+ "~n State2: ~p"
+ "~n Timers2: ~p"
+ "~n Letters2: ~p", [State2, Timers2, Letters2]),
+ MaxWait = choose_timer(State2, Event, Timers2),
+ ?d("collect -> Timer choosen: "
+ "~n MaxWait: ~p", [MaxWait]),
+ receive
+ {?MODULE, _FromPid, Event2} ->
+ ?d("collect -> Got event: "
+ "~n ~p", [Event2]),
+ collect(Event2, State2, Timers2, STL2, Letters2)
+ after MaxWait ->
+ ?d("collect -> timeout after ~w", [MaxWait]),
+ collect(inter_event_timeout,
+ State2, Timers2, STL2, Letters2)
+ end;
+
+ {error, Reason} ->
+ ?d("collect -> error: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+choose_timer(_State, start, #timers{start = 0}) ->
+ ?d("choose_timer(start) -> entry", []),
+ infinity;
+choose_timer(_State, start, #timers{start = T}) ->
+ ?d("choose_timer(start) -> entry with"
+ "~n T: ~p", [T]),
+ T;
+choose_timer(State, _Event, T) ->
+ ?d("choose_timer(~p) -> entry with"
+ "~n State: ~p"
+ "~n T: ~p", [_Event, State, T]),
+ do_choose_timer(State, T).
+
+do_choose_timer(mandatory_event, #timers{mode = state_dependent, long = T}) ->
+ T;
+do_choose_timer(optional_event, #timers{mode = state_dependent, short = T}) ->
+ T;
+do_choose_timer(_State, #timers{mode = use_short_timer, short = T}) ->
+ T;
+do_choose_timer(_State, #timers{mode = use_long_timer, long = T}) ->
+ T.
+
+timer_to_millis(asn1_NOVALUE) -> infinity;
+timer_to_millis(infinity) -> infinity;
+timer_to_millis(Seconds) -> timer:seconds(Seconds).
+
+%% Time for duration is in hundreds of milliseconds
+duration_to_millis(asn1_NOVALUE) -> 100;
+duration_to_millis(Time) when is_integer(Time) -> Time*100.
+
+completed(Kind, {Letters, Event}) when is_list(Letters) ->
+ ?d("completed -> entry with"
+ "~n Kind: ~p"
+ "~n Event: ~s", [Kind, [Event]]),
+ {ok, {Kind, duration_letter_cleanup(Letters, []), Event}};
+completed(Kind, Letters) when is_list(Letters) ->
+ ?d("completed -> entry with"
+ "~n Kind: ~p", [Kind]),
+ {ok, {Kind, duration_letter_cleanup(Letters, [])}}.
+
+duration_letter_cleanup([], Acc) ->
+ Acc;
+duration_letter_cleanup([{long, Letter}|Letters], Acc) ->
+ duration_letter_cleanup(Letters, [$Z,Letter|Acc]);
+duration_letter_cleanup([Letter|Letters], Acc) ->
+ duration_letter_cleanup(Letters, [Letter|Acc]).
+
+unexpected_event(Event, STL, Letters) ->
+ Expected = [Next || #state_transition{next = Next} <- STL],
+ SoFar = lists:reverse(Letters),
+ Reason = {unexpected_event, Event, SoFar, Expected},
+ {error, Reason}.
+
+
+%%----------------------------------------------------------------------
+%% Handles a received event according to digit map
+%% State ::= optional_event | mandatory_event
+%%
+%% Returns {State, NewSTL, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+handle_event(inter_event_timeout, optional_event, Timers, STL, Letters) ->
+ {completed_full, Timers, STL, Letters}; % 7.1.14.5 2
+handle_event(cancel, _State, _Timers, STL, Letters) ->
+ unexpected_event(cancel, STL, Letters);
+handle_event(start, _State, Timers, STL, Letters) ->
+ {State2, Timers2, STL2} = compute(Timers, STL),
+ {State2, Timers2, STL2, Letters};
+handle_event(Event, State, Timers, STL, Letters) ->
+ ?d("handle_event -> entry when"
+ "~n Event: ~p"
+ "~n State: ~p"
+ "~n Timers: ~p"
+ "~n Letters: ~p", [Event, State, Timers, Letters]),
+ {STL2, Collect, KeepDur} = match_event(Event, STL),
+ ?d("handle_event -> match event result: "
+ "~n Collect: ~p"
+ "~n KeepDur: ~p"
+ "~n STL2: ~p", [Collect, KeepDur, STL2]),
+ case STL2 of
+ [] when (State =:= optional_event) -> % 7.1.14.5 5
+ ?d("handle_event -> complete-full with event - 7.1.14.5 5", []),
+ {completed_full, Timers, [], {Letters, Event}};
+ [] when (Timers#timers.unexpected =:= ignore) ->
+ ok = io:format("<WARNING> Ignoring unexpected event: ~p~n"
+ "Expected: ~p~n",
+ [Event, STL]),
+ {State, Timers, STL, Letters};
+ [] when (Timers#timers.unexpected =:= reject) ->
+ ?d("handle_event -> unexpected (reject)", []),
+ unexpected_event(Event, STL, Letters);
+ _ ->
+ {State3, Timers2, STL3} = compute(Timers, STL2),
+ ?d("handle_event -> computed: "
+ "~n State3: ~p"
+ "~n Timers2: ~p"
+ "~n STL3: ~p", [State3, Timers2, STL3]),
+ case Collect of
+ true when (KeepDur =:= true) ->
+ {State3, Timers2, STL3, [Event | Letters]};
+ true ->
+ case Event of
+ {long, ActualEvent} ->
+ {State3, Timers2, STL3, [ActualEvent | Letters]};
+ _ ->
+ {State3, Timers2, STL3, [Event | Letters]}
+ end;
+ false ->
+ {State3, Timers2, STL3, Letters}
+ end
+ end.
+
+match_event(Event, STL) ->
+ MatchingDuration = matching_duration_event(Event, STL),
+ match_event(Event, STL, [], false, false, MatchingDuration).
+
+match_event(Event, [ST | OldSTL], NewSTL, Collect, KeepDur, MatchingDuration)
+ when is_record(ST, state_transition) ->
+ ?d("match_event -> entry with"
+ "~n Event: ~p"
+ "~n ST: ~p"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur: ~p"
+ "~n MatchingDuration: ~p",
+ [Event, ST, NewSTL, Collect, KeepDur, MatchingDuration]),
+ case ST#state_transition.next of
+ {single, Event} ->
+ ?d("match_event -> keep ST (1)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {single, Single} when (Event =:= {long, Single}) andalso
+ (MatchingDuration =:= false) ->
+ %% Chap 7.1.14.5 point 4
+ ?d("match_event -> keep ST - change to ordinary event (2)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {range, From, To} when (Event >= From) andalso (Event =< To) ->
+ ?d("match_event -> keep ST (3)", []),
+ ST2 = ST#state_transition{next = {single, Event}},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,
+ MatchingDuration);
+
+ {range, From, To} ->
+ case Event of
+ {long, R} when (R >= From) andalso
+ (R =< To) andalso
+ (MatchingDuration =:= false) ->
+ ?d("match_event -> keep ST (4)", []),
+ ST2 = ST#state_transition{next = {single, R}},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, true,
+ MatchingDuration);
+ _ ->
+ ?d("match_event -> drop ST - "
+ "change to ordinary event (5)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ {duration_event, {single, Single}} when (Event =:= {long, Single}) ->
+ ?d("match_event -> keep ST (5)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, true,
+ MatchingDuration);
+
+ {duration_event, {range, From, To}} ->
+ case Event of
+ {long, R} when (R >= From) andalso (R =< To) ->
+ ?d("match_event -> keep ST (6)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, true,
+ MatchingDuration);
+ _ ->
+ ?d("match_event -> drop ST (7)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ Event ->
+ ?d("match_event -> keep ST (8)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], Collect, KeepDur,
+ MatchingDuration);
+
+ {letter, Letters} ->
+ case match_letter(Event, Letters, MatchingDuration) of
+ {true, ChangedEvent} ->
+ ?d("match_event -> keep ST (9)", []),
+ ST2 = ST#state_transition{next = ChangedEvent},
+ match_event(Event, OldSTL, [ST2 | NewSTL], true, KeepDur,
+ MatchingDuration);
+ true ->
+ ?d("match_event -> keep ST (10)", []),
+ match_event(Event, OldSTL, [ST | NewSTL], true, KeepDur,
+ MatchingDuration);
+ false ->
+ ?d("match_event -> drop ST (11)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+
+ _ ->
+ ?d("match_event -> drop ST (12)", []),
+ match_event(Event, OldSTL, NewSTL, Collect, KeepDur,
+ MatchingDuration)
+ end;
+match_event(Event, [H | T], NewSTL, Collect, KeepDur0, MatchingDuration)
+ when is_list(H) ->
+ ?d("match_event -> entry with"
+ "~n Event: ~p"
+ "~n H: ~p"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur0: ~p"
+ "~n MatchingDuration: ~p",
+ [Event, H, NewSTL, Collect, KeepDur0, MatchingDuration]),
+ {NewSTL2, _Letters, KeepDur} =
+ match_event(Event, H, NewSTL, Collect, KeepDur0, MatchingDuration),
+ ?d("match_event -> "
+ "~n NewSTLs: ~p", [NewSTL2]),
+ match_event(Event, T, NewSTL2, Collect, KeepDur,
+ MatchingDuration);
+match_event(_Event, [], NewSTL, Collect, KeepDur, _MatchingDuration) ->
+ ?d("match_event -> entry with"
+ "~n NewSTL: ~p"
+ "~n Collect: ~p"
+ "~n KeepDur: ~p", [NewSTL, Collect, KeepDur]),
+ {lists:reverse(NewSTL), Collect, KeepDur}.
+
+
+match_letter(_Event, [], _MatchingDuration) ->
+ false;
+match_letter(Event, [Letter | Letters], MatchingDuration) ->
+ ?d("match_letter -> entry with"
+ "~n Event: ~p"
+ "~n Letter: ~p",
+ [Event, Letter]),
+ case Letter of
+ {single, Event} ->
+ ?d("match_letter -> keep ST (1)", []),
+ true;
+
+ {single, Single} when (Event =:= {long, Single}) andalso
+ (MatchingDuration =:= false) ->
+ %% Chap 7.1.14.5 point 4
+ ?d("match_letter -> keep ST - change to ordinary event (2)", []),
+ true;
+
+ {range, From, To} when (Event >= From) andalso (Event =< To) ->
+ ?d("match_letter -> keep ST (3)", []),
+ {true, {single, Event}};
+
+ {range, From, To} ->
+ case Event of
+ {long, R} when (R >= From) andalso
+ (R =< To) andalso
+ (MatchingDuration =:= false) ->
+ ?d("match_letter -> keep ST (4)", []),
+ {true, {single, R}};
+ _ ->
+ ?d("match_letter -> drop ST - "
+ "change to ordinary event (5)", []),
+ match_letter(Event, Letters, MatchingDuration)
+ end;
+
+ {duration_event, {single, Single}} when (Event =:= {long, Single}) ->
+ ?d("match_letter -> keep ST (5)", []),
+ true;
+
+ {duration_event, {range, From, To}} ->
+ case Event of
+ {long, R} when (R >= From) andalso (R =< To) ->
+ ?d("match_letter -> keep ST (6)", []),
+ true;
+ _ ->
+ ?d("match_letter -> drop ST (7)", []),
+ match_letter(Event, Letters, MatchingDuration)
+ end;
+
+ _ ->
+ ?d("match_letter -> drop ST (8)", []),
+ match_letter(Event, Letters, MatchingDuration)
+
+ end.
+
+
+
+
+matching_duration_event({long, Event}, STL) ->
+ Nexts = [Next || #state_transition{next = Next} <- STL],
+ mde(Event, Nexts);
+matching_duration_event(_Event, _STL) ->
+ false.
+
+
+mde(_, []) ->
+ false;
+mde(Event, [{duration_event, {single, Event}}|_]) ->
+ true;
+mde(Event, [{duration_event, {range, From, To}}|_])
+ when Event >= From, Event =< To ->
+ true;
+mde(Event, [_|Nexts]) ->
+ mde(Event, Nexts).
+
+
+%%----------------------------------------------------------------------
+%% Compute new state transitions
+%% Returns {State, Timers, NewSTL}
+%%----------------------------------------------------------------------
+compute(Timers, OldSTL) ->
+ ?d("compute -> entry with"
+ "~n Timers: ~p"
+ "~n OldSTL: ~p", [Timers, OldSTL]),
+ {State, GlobalMode, NewSTL} =
+ compute(mandatory_event, state_dependent, OldSTL, []),
+ ?d("compute -> "
+ "~n State: ~p"
+ "~n GlobalMode: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
+ Timers2 = Timers#timers{mode = GlobalMode},
+ ?d("compute -> "
+ "~n Timers2: ~p", [Timers2]),
+ {State, Timers2, NewSTL}.
+
+compute(State, GlobalMode, [ST | OldSTL], NewSTL)
+ when is_record(ST, state_transition) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n ST: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, ST, NewSTL]),
+ Cont = ST#state_transition.cont,
+ Mode = ST#state_transition.mode,
+ {State2, GlobalMode2, NewSTL2} =
+ compute_cont(Cont, Mode, GlobalMode, State, NewSTL),
+ compute(State2, GlobalMode2, OldSTL, NewSTL2);
+compute(State, GlobalMode, [H | T], NewSTL) when is_list(H) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n H: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, H, NewSTL]),
+ {State2, GlobalMode2, NewSTL2} = compute(State, GlobalMode, H, NewSTL),
+ compute(State2, GlobalMode2, T, NewSTL2);
+compute(State, GlobalMode, [], NewSTL) ->
+ ?d("compute(~w) -> entry with"
+ "~n GlobalMode: ~p"
+ "~n NewSTL: ~p", [State, GlobalMode, NewSTL]),
+ case NewSTL of
+ [] -> {completed, GlobalMode, NewSTL};
+ _ -> {State, GlobalMode, NewSTL}
+ end.
+
+compute_cont([Next | Cont] = All, Mode, GlobalMode, State, STL) ->
+ ?d("compute_cont -> entry with"
+ "~n Next: ~p"
+ "~n Mode: ~p"
+ "~n GlobalMode: ~p", [Next, Mode, GlobalMode]),
+ case Next of
+ %% Retain long timer if that has already been choosen
+ use_short_timer when GlobalMode =:= use_long_timer ->
+ compute_cont(Cont, Mode, GlobalMode, State, STL);
+ use_short_timer ->
+ Mode2 = use_short_timer,
+ compute_cont(Cont, Mode2, GlobalMode, State, STL);
+ use_long_timer ->
+ Mode2 = use_long_timer,
+ compute_cont(Cont, Mode2, GlobalMode, State, STL);
+ [] ->
+ %% Skip empty list
+ case Cont of
+ [zero_or_more | Cont2] ->
+ compute_cont(Cont2, Mode, GlobalMode, State, STL);
+ _ ->
+ compute_cont(Cont, Mode, GlobalMode, State, STL)
+ end;
+ _ ->
+ GlobalMode2 =
+ case Mode of
+ state_dependent -> GlobalMode;
+ _ -> Mode
+ end,
+ case Cont of
+ [zero_or_more | Cont2] ->
+ ST = make_cont(Mode, Next, All),
+ compute_cont(Cont2, Mode, GlobalMode2, State, [ST | STL]);
+ _ ->
+ ST = make_cont(Mode, Next, Cont),
+ {State, GlobalMode2, [ST | STL]}
+ end
+ end;
+compute_cont([], GlobalMode, _Mode, _State, STL) ->
+ {optional_event, GlobalMode, STL}.
+
+make_cont(Mode, [Next | Cont2], Cont) ->
+ #state_transition{mode = Mode, next = Next, cont = [Cont2 | Cont]};
+make_cont(Mode, Next, Cont) ->
+ #state_transition{mode = Mode, next = Next, cont = Cont}.
+
+
+%%----------------------------------------------------------------------
+%% Send one or more events to event collector process
+%%
+%% Events ::= Event* | Event
+%% Event ::= $0-$9 | $a-$k | $A-$K | $S | $L | $Z
+%% $S means sleep one second
+%% $L means sleep ten seconds
+%% $Z means cancel
+%% Returns ok | {error, Reason}
+%%----------------------------------------------------------------------
+
+report(Pid, [H | T])->
+ case report(Pid, H) of
+ ok ->
+ report(Pid, T);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+report(_Pid, [])->
+ ok;
+report(Pid, Event) when is_pid(Pid) ->
+ case Event of
+ I when I >= $0, I =< $9 -> cast(Pid, Event);
+ A when A >= $a, A =< $k -> cast(Pid, Event);
+ A when A >= $A, A =< $K -> cast(Pid, Event);
+ cancel -> cast(Pid, Event);
+ $Z -> cast(Pid, cancel);
+ $z -> cast(Pid, cancel);
+ $R -> timer:sleep(100); % 100 ms
+ $r -> timer:sleep(100); % 100 ms
+ $S -> sleep(1); % 1 sec (1000 ms)
+ $s -> sleep(1); % 1 sec (1000 ms)
+ $L -> sleep(10); % 10 sec (10000 ms)
+ $l -> sleep(10); % 10 sec (10000 ms)
+ {long, I} when (I >= $0) and (I =< $9) -> cast(Pid, {long, I});
+ {long, A} when (A >= $a) and (A =< $k) -> cast(Pid, {long, A});
+ {long, A} when (A >= $A) and (A =< $K) -> cast(Pid, {long, A});
+%% {long, I} when (I >= $0) and (I =< $9) -> long(Pid, I);
+%% {long, A} when (A >= $a) and (A =< $k) -> long(Pid, A);
+%% {long, A} when (A >= $A) and (A =< $K) -> long(Pid, A);
+ _ -> {error, {illegal_event, Event}}
+ end.
+
+%% long(Pid, Event) ->
+%% cast(Pid, long),
+%% cast(Pid, Event).
+%%
+sleep(Sec) ->
+ timer:sleep(timer:seconds(Sec)),
+ ok.
+
+cast(Pid, Event) ->
+ Pid ! {?MODULE, self(), Event},
+ ok.
+
+%%----------------------------------------------------------------------
+%% Feed digit map collector with events
+%% Returns: {ok, Letters} | {error, Reason}
+%%----------------------------------------------------------------------
+
+test(DigitMap, Events) ->
+ Self = self(),
+ Pid = spawn_link(?MODULE, test_eval, [DigitMap, Self]),
+ report(Pid, Events),
+ receive
+ {Self, Pid, Res} ->
+ Res;
+ {'EXIT', Pid, Reason} ->
+ {error, {'EXIT', Reason}}
+ end.
+
+test_eval(DigitMap, Parent) ->
+ Res = eval(DigitMap),
+ unlink(Parent),
+ Parent ! {Parent, self(), Res},
+ exit(normal).
diff --git a/lib/megaco/src/engine/megaco_edist_compress.erl b/lib/megaco/src/engine/megaco_edist_compress.erl
new file mode 100644
index 0000000000..544e3b8ff0
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_edist_compress.erl
@@ -0,0 +1,33 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Megaco erlang dist compress behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_edist_compress).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{encode,2},
+ {decode,2}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_encoder.erl b/lib/megaco/src/engine/megaco_encoder.erl
new file mode 100644
index 0000000000..a07ee1a6bc
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_encoder.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Megaco encoder behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_encoder).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{encode_message, 3},
+ {decode_message, 3},
+ {decode_mini_message, 3},
+ {encode_transaction, 3},
+ {encode_action_requests, 3},
+ {encode_action_reply, 3}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_erl_dist_encoder.erl b/lib/megaco/src/engine/megaco_erl_dist_encoder.erl
new file mode 100644
index 0000000000..e8ade615df
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_erl_dist_encoder.erl
@@ -0,0 +1,275 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Externalize/internalize Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_erl_dist_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_command_request/3,
+ encode_action_reply/3
+ ]).
+-export([version_of/2]).
+
+%% Backward compatible funcs:
+-export([encode_message/2, decode_message/2]).
+
+
+-include("megaco_message_internal.hrl").
+
+-define(MC_MOD, megaco_erl_dist_encoder_mc).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(Config,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(Config, V, MegaMsg).
+
+encode_message([{version3, _}|EC], Vsn, MegaMsg) ->
+ encode_message(EC, Vsn, MegaMsg);
+encode_message([megaco_compressed|Config], Vsn, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(MegaMsg, Vsn), Config)};
+encode_message([{megaco_compressed, Mod}|Config], Vsn, MegaMsg)
+ when is_atom(Mod) and is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(Mod:encode(MegaMsg, Vsn), Config)};
+encode_message(Config, _Vsn, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, erlang:term_to_binary(MegaMsg, Config)};
+encode_message(_Config, _Vsn, _MegaMsg) ->
+ {error, not_a_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a binary
+%% Return {ok, Bin} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_transaction([{version3, _}|EC], Vsn, Trans) ->
+ encode_transaction(EC, Vsn, Trans);
+encode_transaction([megaco_compressed|Config], _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(Trans), Config)};
+encode_transaction([{megaco_compressed, Mod}|Config], _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(Mod:encode(Trans), Config)};
+encode_transaction(Config, _Vsn, Trans) ->
+ {ok, erlang:term_to_binary(Trans, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([{version3, _}|EC], Vsn, ActReqs) ->
+ encode_action_requests(EC, Vsn, ActReqs);
+encode_action_requests([megaco_compressed|Config], Vsn, ActReqs0)
+ when is_list(ActReqs0) ->
+ ActReqs = [?MC_MOD:encode(AR, Vsn) || AR <- ActReqs0],
+ {ok, erlang:term_to_binary(ActReqs, Config)};
+encode_action_requests([{megaco_compressed, Mod}|Config], Vsn, ActReqs0)
+ when is_list(ActReqs0) ->
+ ActReqs = [Mod:encode(AR, Vsn) || AR <- ActReqs0],
+ {ok, erlang:term_to_binary(ActReqs, Config)};
+encode_action_requests(Config, _Vsn, ActReqs)
+ when is_list(ActReqs) ->
+ {ok, erlang:term_to_binary(ActReqs, Config)}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, Binary} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3, _}|EC], Vsn, ActReq) ->
+ encode_action_request(EC, Vsn, ActReq);
+encode_action_request([megaco_compressed|Config], Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(ActReq, Vsn), Config)};
+encode_action_request([{megaco_compressed, Mod}|Config], Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(Mod:encode(ActReq, Vsn), Config)};
+encode_action_request(Config, _Vsn, ActReq)
+ when is_tuple(ActReq) ->
+ {ok, erlang:term_to_binary(ActReq, Config)}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request([{version3, _}|EC], Vsn, CmdReq) ->
+ encode_command_request(EC, Vsn, CmdReq);
+encode_command_request([megaco_compressed|Config], Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(CmdReq, Vsn), Config)};
+encode_command_request([{megaco_compressed, Mod}|Config], Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(Mod:encode(CmdReq, Vsn), Config)};
+encode_command_request(Config, _Vsn, CmdReq)
+ when is_tuple(CmdReq) ->
+ {ok, erlang:term_to_binary(CmdReq, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply([{version3, _}|EC], Vsn, ActRep) ->
+ encode_action_reply(EC, Vsn, ActRep);
+encode_action_reply([megaco_compressed|Config], Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(?MC_MOD:encode(ActRep, Vsn), Config)};
+encode_action_reply([{megaco_compressed, Mod}|Config], Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(Mod:encode(ActRep, Vsn), Config)};
+encode_action_reply(Config, _Vsn, ActRep)
+ when is_tuple(ActRep) ->
+ {ok, erlang:term_to_binary(ActRep, Config)}.
+
+
+%%----------------------------------------------------------------------
+%% Get the megaco version of the message
+%% Return {ok, Version} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(Config, Bin) when is_binary(Bin) ->
+ case decode_message(Config, 1, Bin) of
+ {ok, M} ->
+ V = (M#'MegacoMessage'.mess)#'Message'.version,
+ {ok, V};
+ Error ->
+ Error
+ end.
+
+decode_message(Config, Bin) ->
+ decode_message(Config, 1, Bin).
+
+decode_message([{version3, _}|EC], V, Bin) ->
+ decode_message(EC, V, Bin);
+decode_message([megaco_compressed = MC|_Config], Vsn, Bin) ->
+ case catch erlang:binary_to_term(Bin) of
+ Msg when is_tuple(Msg) ->
+ case (?MC_MOD:decode(Msg, Vsn)) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, MC, Vsn)};
+ _ ->
+ {error, {bad_message, Msg}}
+ end;
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end;
+decode_message([{megaco_compressed, Mod} = MC|_Config], Vsn, Bin)
+ when is_atom(Mod) ->
+ case catch erlang:binary_to_term(Bin) of
+ Msg when is_tuple(Msg) ->
+ case (Mod:decode(Msg, Vsn)) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, MC, Vsn)};
+ _ ->
+ {error, {bad_message, Msg}}
+ end;
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end;
+decode_message(_Config, Vsn, Bin) ->
+ case catch erlang:binary_to_term(Bin) of
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ {ok, dm(MegaMsg, undefined, Vsn)};
+ {'EXIT', _Reason} ->
+ {error, bad_binary}
+ end.
+
+
+decode_mini_message(EC, Vsn, Bin) when is_binary(Bin) ->
+ decode_message(EC, Vsn, Bin).
+
+
+%% This crap is because the transactions or the action-requests
+%% might have been encoded separetely
+
+dm(#'MegacoMessage'{mess = Mess} = M, MC, Vsn) ->
+ #'Message'{messageBody = Body} = Mess,
+ case Body of
+ {transactions, Transactions} ->
+ Body2 = {transactions, dmt(Transactions, [], MC, Vsn)},
+ Mess2 = Mess#'Message'{messageBody = Body2},
+ M#'MegacoMessage'{mess = Mess2};
+ _ ->
+ M
+ end.
+
+dmt([], Acc, _, _Vsn) ->
+ lists:reverse(Acc);
+dmt([Trans0|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
+ Trans1 = erlang:binary_to_term(Trans0),
+ Trans2 = dmt1(Trans1, MC, Vsn),
+ dmt(Transactions, [Trans2|Acc], MC, Vsn);
+dmt([{Tag, Trans0}|Transactions], Acc, MC, Vsn) when is_binary(Trans0) ->
+ Trans1 = erlang:binary_to_term(Trans0),
+ Trans2 = dmt1(Trans1, MC, Vsn),
+ dmt(Transactions, [{Tag, Trans2}|Acc], MC, Vsn);
+dmt([{transactionRequest,
+ #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
+ Acc, MC, Vsn)
+ when is_binary(Acts0) ->
+ Acts1 = erlang:binary_to_term(Acts0),
+ Acts2 = dmt1(Acts1, MC, Vsn),
+ TR1 = TR0#'TransactionRequest'{actions = Acts2},
+ dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
+dmt([{transactionRequest,
+ #'TransactionRequest'{actions = Acts0} = TR0}|Transactions],
+ Acc, MC, Vsn) ->
+ Acts2 = [dmt2(AR, MC, Vsn) || AR <- Acts0],
+ TR1 = TR0#'TransactionRequest'{actions = Acts2},
+ dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn);
+dmt([Trans|Transactions], Acc, MC, Vsn) ->
+ dmt(Transactions, [Trans|Acc], MC, Vsn).
+
+dmt1(L, megaco_compressed, Vsn) when is_list(L) ->
+ [?MC_MOD:decode(E, Vsn) || E <- L];
+dmt1(L, {megaco_compressed, Mod}, Vsn) when is_list(L) ->
+ [Mod:decode(E, Vsn) || E <- L];
+dmt1(T, megaco_compressed, Vsn) when is_tuple(T) ->
+ ?MC_MOD:decode(T, Vsn);
+dmt1(T, {megaco_compressed, Mod}, Vsn) when is_tuple(T) ->
+ Mod:decode(T, Vsn);
+dmt1(Else, _, _Vsn) ->
+ Else.
+
+dmt2(Bin, MC, Vsn) when is_binary(Bin) ->
+ AR = erlang:binary_to_term(Bin),
+ dmt1(AR, MC, Vsn);
+dmt2(AR, _MC, _Vsn) ->
+ AR.
+
+
diff --git a/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl b/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl
new file mode 100644
index 0000000000..52395ae516
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_erl_dist_encoder_mc.erl
@@ -0,0 +1,1894 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Externalize/internalize Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_erl_dist_encoder_mc).
+
+-behaviour(megaco_edist_compress).
+
+-export([
+ encode/1, encode/2,
+ decode/1, decode/2
+ ]).
+
+
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Megaco compress a Megaco record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode(M) ->
+ e(M, 1).
+
+encode(M, Vsn) ->
+ ?d("encode -> entry with"
+ "~n M: ~p"
+ "~n Vsn: ~p", [M, Vsn]),
+ Result = e(M, Vsn),
+ ?d("encode -> "
+ "~n Result: ~p", [Result]),
+ Result.
+
+decode(M) ->
+ d(M, 1).
+
+decode(M, Vsn) ->
+ ?d("decode -> entry with"
+ "~n M: ~p"
+ "~n Vsn: ~p", [M, Vsn]),
+ Result = d(M, Vsn),
+ ?d("decode -> "
+ "~n Result: ~p", [Result]),
+ Result.
+
+
+el(L, V) when is_list(L) -> [e(T, V) || T <- L];
+el(L, _V) -> L.
+dl(L, V) when is_list(L) -> [d(T, V) || T <- L];
+dl(L, _V) -> L.
+
+ell(L, V) when is_list(L) -> [el(T, V) || T <- L];
+ell(L, _V) -> L.
+dll(L, V) when is_list(L) -> [dl(T, V) || T <- L];
+dll(L, _V) -> L.
+
+e(asn1_NOVALUE, _) ->
+ {1};
+e('NULL', _V) ->
+ {2};
+e(sendRecv, _V) ->
+ {3};
+e(recvOnly, _V) ->
+ {4};
+e(restart, _V) ->
+ {5};
+e(mediaToken, _V) ->
+ {6};
+e(eventsToken, _V) ->
+ {7};
+e(signalsToken, _V) ->
+ {8};
+e(digitMapToken, _V) ->
+ {9};
+e(statsToken, _V) ->
+ {10};
+e(packagesToken, _V) ->
+ {11};
+e(h221, _V) ->
+ {12};
+e(h223, _V) ->
+ {13};
+e(h226, _V) ->
+ {14};
+e(v76, _V) ->
+ {15};
+
+e({'MegacoMessage', asn1_NOVALUE, {'Message', 1 = V, Mid, Body}}, _) ->
+ {20, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', asn1_NOVALUE, {'Message', 2 = V, Mid, Body}}, _) ->
+ {21, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', asn1_NOVALUE, {'Message', V, Mid, Body}}, _) ->
+ {22, V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', 1 = V, Mid, Body}}, _) ->
+ {23, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', 2 = V, Mid, Body}}, _) ->
+ {24, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, {'Message', V, Mid, Body}}, _) ->
+ {25, V, e(AuthHeader, V), V, e(Mid, V), e(Body, V)};
+e({'MegacoMessage', AuthHeader, Mess}, V) ->
+ {26, e(AuthHeader, V), e(Mess, V)};
+e({'Message', V, Mid, Body}, _) ->
+ {27, V, e(Mid, V), e(Body, V)};
+
+e({domainName, {'DomainName', Name, asn1_NOVALUE}}, _V) ->
+ {30, Name};
+e({domainName, {'DomainName', Name, PortNumber}}, _V) ->
+ {31, Name, PortNumber};
+e({domainName, N}, V) ->
+ {32, e(N, V)};
+e({'DomainName', Name, asn1_NOVALUE}, _V) ->
+ {33, Name};
+e({'DomainName', Name, PortNumber}, _V) ->
+ {34, Name, PortNumber};
+e({ip4Address, {'IP4Address', Addr, asn1_NOVALUE}}, _V) ->
+ {35, Addr};
+e({ip4Address, {'IP4Address', Addr, PortNumber}}, _V) ->
+ {36, Addr, PortNumber};
+e({ip4Address, A}, V) ->
+ {37, e(A, V)};
+e({'IP4Address', Addr, asn1_NOVALUE}, _V) ->
+ {38, Addr};
+e({'IP4Address', Addr, PortNumber}, _V) ->
+ {39, Addr, PortNumber};
+e({ip6Address, {'IP6Address', Addr, asn1_NOVALUE}}, _V) ->
+ {40, Addr};
+e({ip6Address, {'IP6Address', Addr, PortNumber}}, _V) ->
+ {41, Addr, PortNumber};
+e({ip6Address, A}, V) ->
+ {42, e(A, V)};
+e({'IP6Address', Addr, asn1_NOVALUE}, _V) ->
+ {43, Addr};
+e({'IP6Address', Addr, PortNumber}, _V) ->
+ {44, Addr, PortNumber};
+
+e({transactions, [Transaction]}, V) ->
+ {50, e(Transaction, V)};
+e({transactions, Transactions}, V) ->
+ {51, el(Transactions, V)};
+e({messageError, {'ErrorDescriptor', EC, asn1_NOVALUE}}, _V) ->
+ {52, EC};
+e({messageError, {'ErrorDescriptor', EC, ET}}, _V) ->
+ {53, EC, ET};
+e({messageError, Error}, V) ->
+ {54, e(Error, V)};
+e({transactionRequest, {'TransactionRequest', TransId, Actions}}, V) ->
+ {55, TransId, el(Actions, V)};
+e({transactionPending, {'TransactionPending', TransId}}, _V) ->
+ {56, TransId};
+e({transactionReply, {'TransactionReply', TransId, asn1_NOVALUE, TransRes}}, V) ->
+ {57, TransId, e(TransRes, V)};
+e({transactionReply, {'TransactionReply', TransId, 'NULL', TransRes}}, V) ->
+ {58, TransId, e(TransRes, V)};
+e({transactionReply, {'TransactionReply', TransId, ImmAckReq, TransRes}}, V) ->
+ {59, TransId, e(ImmAckReq, V), e(TransRes, V)};
+e({transactionResponseAck, T}, V) ->
+ {60, el(T, V)};
+e({'TransactionAck', FirstAck, asn1_NOVALUE}, _V) ->
+ {61, FirstAck};
+e({'TransactionAck', FirstAck, LastAck}, _V) ->
+ {62, FirstAck, LastAck};
+
+e({'ErrorDescriptor', EC, asn1_NOVALUE}, _V) ->
+ {70, EC};
+e({'ErrorDescriptor', EC, ET}, _V) ->
+ {71, EC, ET};
+
+e({'ActionRequest', Cid, CtxReq, CtxAAR, [CmdReq]}, V) ->
+ {80, Cid, e(CtxReq, V), e(CtxAAR, V), e(CmdReq, V)};
+e({'ActionRequest', Cid, CtxReq, CtxAAR, CmdReqs}, V) ->
+ {81, Cid, e(CtxReq, V), e(CtxAAR, V), el(CmdReqs, V)};
+
+e({'ContextRequest', P, E, T}, V) when V < 3 ->
+ {90, e(P, V), e(E, V), el(T, V)};
+e({'ContextRequest', P, E, T, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {91, e(P, V), e(E, V), el(T, V)};
+e({'ContextRequest', P, E, T, IC, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {92, e(P, V), e(E, V), el(T, V), e(IC, V)};
+e({'ContextRequest', P, E, T, IC, CP, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {93, e(P, V), e(E, V), el(T, V), e(IC, V), el(CP, V)};
+e({'ContextRequest', P, E, T, IC, CP, CL}, V)
+ when V >= 3 ->
+ {94, e(P, V), e(E, V), el(T, V), e(IC, V), el(CP, V), el(CL, V)};
+
+e({'ContextAttrAuditRequest', P, E, T}, V) when V < 3 ->
+ {100, e(P, V), e(E, V), e(T, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {101, e(P, V), e(E, V), e(T, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {102, e(P, V), e(E, V), e(T, V),
+ e(IC, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {103, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {104, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {105, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, SIC, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {106, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V), e(SIC, V)};
+e({'ContextAttrAuditRequest', P, E, T,
+ IC, CPA, SP, SE, SIC, SL}, V)
+ when V >= 3 ->
+ {107, e(P, V), e(E, V), e(T, V),
+ e(IC, V), el(CPA, V), e(SP, V), e(SE, V), e(SIC, V), e(SL, V)};
+
+e({'CommandRequest', Cmd, asn1_NOVALUE, asn1_NOVALUE}, V) ->
+ {110, e(Cmd, V)};
+e({'CommandRequest', Cmd, 'NULL', asn1_NOVALUE}, V) ->
+ {111, e(Cmd, V)};
+e({'CommandRequest', Cmd, asn1_NOVALUE, 'NULL'}, V) ->
+ {112, e(Cmd, V)};
+e({'CommandRequest', Cmd, 'NULL', 'NULL'}, V) ->
+ {113, e(Cmd, V)};
+e({'CommandRequest', Cmd, Opt, WR}, V) ->
+ {114, e(Cmd, V), e(Opt, V), e(WR, V)};
+
+e({'TopologyRequest', From, To, Dir}, 1 = V) ->
+ {120, e(From, V), e(To, V), e(Dir, V)};
+e({'TopologyRequest', From, To, Dir, SID}, 2 = V) ->
+ {121, e(From, V), e(To, V), e(Dir, V), e(SID, V)};
+e({'TopologyRequest', From, To, Dir, SID, asn1_NOVALUE}, V) when (V >= 3) ->
+ {122, e(From, V), e(To, V), e(Dir, V), e(SID, V)};
+e({'TopologyRequest', From, To, Dir, SID, TDE}, V) when (V >= 3) ->
+ {123, e(From, V), e(To, V), e(Dir, V), e(SID, V), e(TDE, V)};
+
+e({modReq, {'AmmRequest', TID, []}}, V) ->
+ {130, el(TID, V)};
+e({modReq, {'AmmRequest', TID, [Desc]}}, V) ->
+ {131, el(TID, V), e(Desc, V)};
+e({modReq, {'AmmRequest', TID, Descs}}, V) ->
+ {132, el(TID, V), el(Descs, V)};
+e({addReq, {'AmmRequest', TID, []}}, V) ->
+ {133, el(TID, V)};
+e({addReq, {'AmmRequest', TID, [Desc]}}, V) ->
+ {134, el(TID, V), e(Desc, V)};
+e({addReq, {'AmmRequest', TID, Descs}}, V) ->
+ {135, el(TID, V), el(Descs, V)};
+e({'AmmRequest', TID, Descs}, V) ->
+ {136, el(TID, V), el(Descs, V)};
+
+e({subtractReq, {'SubtractRequest', TID, asn1_NOVALUE}}, V) ->
+ {140, el(TID, V)};
+e({subtractReq, {'SubtractRequest', TID, AudDesc}}, V) ->
+ {141, el(TID, V), e(AudDesc, V)};
+e({'SubtractRequest', TID, asn1_NOVALUE}, V) ->
+ {142, el(TID, V)};
+e({'SubtractRequest', TID, AudDesc}, V) ->
+ {143, el(TID, V), e(AudDesc, V)};
+
+e({auditValueRequest, AR}, V) ->
+ {150, e(AR, V)};
+
+e({'AuditRequest', TID, AudDesc}, V) when V < 3 ->
+ {160, e(TID, V), e(AudDesc, V)};
+e({'AuditRequest', TID, AudDesc, asn1_NOVALUE}, V) when V >= 3 ->
+ {161, e(TID, V), e(AudDesc, V)};
+e({'AuditRequest', TID, AudDesc, TIDs}, V) when V >= 3 ->
+ {162, e(TID, V), e(AudDesc, V), el(TIDs, V)};
+
+e({actionReplies, [AR]}, V) ->
+ {170, e(AR, V)};
+e({actionReplies, ARs}, V) ->
+ {171, el(ARs, V)};
+
+e({'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, [CmdRep]}, V) ->
+ {180, CID, e(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, CmdRep}, V) ->
+ {181, CID, el(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, CtxRep, [CmdRep]}, V) ->
+ {182, CID, e(CtxRep, V), e(CmdRep, V)};
+e({'ActionReply', CID, asn1_NOVALUE, CtxRep, CmdRep}, V) ->
+ {183, CID, e(CtxRep, V), el(CmdRep, V)};
+e({'ActionReply', CID, ED, asn1_NOVALUE, [CmdRep]}, V) ->
+ {184, CID, e(ED, V), e(CmdRep, V)};
+e({'ActionReply', CID, ED, asn1_NOVALUE, CmdRep}, V) ->
+ {185, CID, e(ED, V), el(CmdRep, V)};
+e({'ActionReply', CID, ED, CtxRep, [CmdRep]}, V) ->
+ {186, CID, e(ED, V), e(CtxRep, V), e(CmdRep, V)};
+e({'ActionReply', CID, ED, CtxRep, CmdRep}, V) ->
+ {187, CID, e(ED, V), e(CtxRep, V), el(CmdRep, V)};
+
+e({'AuditDescriptor', asn1_NOVALUE}, 1 = _V) ->
+ {190};
+e({'AuditDescriptor', AT}, 1 = V) ->
+ {191, el(AT, V)};
+e({'AuditDescriptor', asn1_NOVALUE, asn1_NOVALUE}, V) when V >= 2 ->
+ {192};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(AT) andalso is_list(APT) andalso (V >= 2) ->
+ {193, el(AT, V), el(APT, V)};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(APT) andalso (V >= 2) ->
+ {194, e(AT, V), el(APT, V)};
+e({'AuditDescriptor', AT, APT}, V)
+ when is_list(AT) andalso (V >= 2) ->
+ {195, el(AT, V), e(APT, V)};
+e({'AuditDescriptor', AT, APT}, V) when (V >= 2) ->
+ {196, e(AT, V), e(APT, V)};
+
+e({notifyReq, {'NotifyRequest', TID, OED, asn1_NOVALUE}}, V) ->
+ {200, el(TID, V), e(OED, V)};
+e({notifyReq, {'NotifyRequest', TID, OED, ED}}, V) ->
+ {201, el(TID, V), e(OED, V), e(ED, V)};
+e({'NotifyRequest', TID, OED}, V) ->
+ {202, el(TID, V), e(OED, V)};
+e({'NotifyRequest', TID, OED, ED}, V) ->
+ {203, el(TID, V), e(OED, V), e(ED, V)};
+
+e({'ObservedEventsDescriptor', RID, OEL}, V) ->
+ {210, RID, el(OEL, V)};
+
+e({'ObservedEvent', EN, SID, EPL, TN}, V) ->
+ {220, EN, e(SID, V), el(EPL, V), e(TN, V)};
+
+e({'EventParameter', "type", ["est"], asn1_NOVALUE}, _V) ->
+ {230};
+e({'EventParameter', "type", [Val], asn1_NOVALUE}, _V) ->
+ {231, Val};
+e({'EventParameter', "type", Val, asn1_NOVALUE}, _V) ->
+ {232, Val};
+e({'EventParameter', "Generalcause", ["NR"], asn1_NOVALUE}, _V) ->
+ {233};
+e({'EventParameter', "Generalcause", ["UR"], asn1_NOVALUE}, _V) ->
+ {234};
+e({'EventParameter', "Generalcause", ["FT"], asn1_NOVALUE}, _V) ->
+ {235};
+e({'EventParameter', "Generalcause", ["FP"], asn1_NOVALUE}, _V) ->
+ {236};
+e({'EventParameter', "Generalcause", ["IW"], asn1_NOVALUE}, _V) ->
+ {237};
+e({'EventParameter', "Generalcause", ["UN"], asn1_NOVALUE}, _V) ->
+ {238};
+e({'EventParameter', "Generalcause", [Val], asn1_NOVALUE}, _V) ->
+ {239, Val};
+e({'EventParameter', "Generalcause", Val, asn1_NOVALUE}, _V) ->
+ {240, Val};
+e({'EventParameter', "Failurecause", [Val], asn1_NOVALUE}, _V) ->
+ {241, Val};
+e({'EventParameter', "Failurecause", Val, asn1_NOVALUE}, _V) ->
+ {242, Val};
+e({'EventParameter', EPN, Val, asn1_NOVALUE}, _V) ->
+ {243, EPN, Val};
+e({'EventParameter', EPN, Val, EI}, _V) ->
+ {244, EPN, Val, EI};
+
+e({serviceChangeReq, {'ServiceChangeRequest', TID, SCPs}}, V) ->
+ {260, el(TID, V), e(SCPs, V)};
+e({serviceChangeReq, SCR}, V) ->
+ {261, e(SCR, V)};
+e({'ServiceChangeRequest', TID, SCPs}, V) ->
+ {262, el(TID, V), e(SCPs, V)};
+
+e({serviceChangeReply, {'ServiceChangeReply', TID, SCR}}, V) ->
+ {270, el(TID, V), e(SCR, V)};
+e({serviceChangeReply, SCR}, V) ->
+ {271, e(SCR, V)};
+e({'ServiceChangeReply', TID, SCR}, V) -> %% KOLLA
+ {272, el(TID, V), e(SCR, V)};
+
+e({mediaDescriptor, {'MediaDescriptor', TSD, S}}, V) ->
+ {280, e(TSD, V), e(S, V)};
+e({mediaDescriptor, MD}, V) ->
+ {281, e(MD, V)};
+e({'MediaDescriptor', TSD, S}, V) ->
+ {282, e(TSD, V), e(S, V)};
+
+e({oneStream, S}, V) ->
+ {290, e(S, V)};
+e({multiStream, S}, V) ->
+ {291, el(S, V)};
+e({'StreamDescriptor', SID, SP}, V) ->
+ {292, e(SID, V), e(SP, V)};
+
+e({'StreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE}, V) when V < 3 ->
+ {300, e(LCD, V)};
+e({'StreamParms', LCD, LD, asn1_NOVALUE}, V) when V < 3 ->
+ {301, e(LCD, V), e(LD, V)};
+e({'StreamParms', LCD, LD, RD}, V) when V < 3 ->
+ {302, e(LCD, V), e(LD, V), e(RD, V)};
+
+e({'StreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {303, e(LCD, V)};
+e({'StreamParms', LCD, LD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {304, e(LCD, V), e(LD, V)};
+e({'StreamParms', LCD, LD, RD, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {305, e(LCD, V), e(LD, V), e(RD, V)};
+e({'StreamParms', LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {306, e(LCD, V), e(LD, V), e(RD, V), el(SD, V)};
+
+e({'LocalControlDescriptor', SM, RV, RG, PP}, V) ->
+ {310, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+
+e({'PropertyParm', "v", [Val], asn1_NOVALUE}, _V) ->
+ {320, Val};
+e({'PropertyParm', "v", Val, asn1_NOVALUE}, _V) ->
+ {321, Val};
+e({'PropertyParm', "o", [Val], asn1_NOVALUE}, _V) ->
+ {332, Val};
+e({'PropertyParm', "o", Val, asn1_NOVALUE}, _V) ->
+ {333, Val};
+e({'PropertyParm', "s", [Val], asn1_NOVALUE}, _V) ->
+ {334, Val};
+e({'PropertyParm', "s", Val, asn1_NOVALUE}, _V) ->
+ {335, Val};
+e({'PropertyParm', "i", [Val], asn1_NOVALUE}, _V) ->
+ {336, Val};
+e({'PropertyParm', "i", Val, asn1_NOVALUE}, _V) ->
+ {337, Val};
+e({'PropertyParm', "u", [Val], asn1_NOVALUE}, _V) ->
+ {338, Val};
+e({'PropertyParm', "u", Val, asn1_NOVALUE}, _V) ->
+ {339, Val};
+e({'PropertyParm', "e", [Val], asn1_NOVALUE}, _V) ->
+ {340, Val};
+e({'PropertyParm', "e", Val, asn1_NOVALUE}, _V) ->
+ {341, Val};
+e({'PropertyParm', "p", [Val], asn1_NOVALUE}, _V) ->
+ {342, Val};
+e({'PropertyParm', "p", Val, asn1_NOVALUE}, _V) ->
+ {343, Val};
+e({'PropertyParm', "c", [Val], asn1_NOVALUE}, _V) ->
+ {344, Val};
+e({'PropertyParm', "c", Val, asn1_NOVALUE}, _V) ->
+ {345, Val};
+e({'PropertyParm', "b", [Val], asn1_NOVALUE}, _V) ->
+ {346, Val};
+e({'PropertyParm', "b", Val, asn1_NOVALUE}, _V) ->
+ {347, Val};
+e({'PropertyParm', "z", [Val], asn1_NOVALUE}, _V) ->
+ {348, Val};
+e({'PropertyParm', "z", Val, asn1_NOVALUE}, _V) ->
+ {349, Val};
+e({'PropertyParm', "k", [Val], asn1_NOVALUE}, _V) ->
+ {350, Val};
+e({'PropertyParm', "k", Val, asn1_NOVALUE}, _V) ->
+ {351, Val};
+e({'PropertyParm', "a", [Val], asn1_NOVALUE}, _V) ->
+ {352, Val};
+e({'PropertyParm', "a", Val, asn1_NOVALUE}, _V) ->
+ {353, Val};
+e({'PropertyParm', "t", [Val], asn1_NOVALUE}, _V) ->
+ {354, Val};
+e({'PropertyParm', "t", Val, asn1_NOVALUE}, _V) ->
+ {355, Val};
+e({'PropertyParm', "r", [Val], asn1_NOVALUE}, _V) ->
+ {356, Val};
+e({'PropertyParm', "r", Val, asn1_NOVALUE}, _V) ->
+ {357, Val};
+e({'PropertyParm', "m", [Val], asn1_NOVALUE}, _V) ->
+ {358, Val};
+e({'PropertyParm', "m", Val, asn1_NOVALUE}, _V) ->
+ {359, Val};
+e({'PropertyParm', "nt/jit", [Val], asn1_NOVALUE}, _V) ->
+ {360, Val};
+e({'PropertyParm', "nt/jit", Val, asn1_NOVALUE}, _V) ->
+ {361, Val};
+e({'PropertyParm', "tdmc/ec", ["on"], asn1_NOVALUE}, _V) ->
+ {362};
+e({'PropertyParm', "tdmc/ec", ["off"], asn1_NOVALUE}, _V) ->
+ {363};
+e({'PropertyParm', "tdmc/gain", ["automatic"], asn1_NOVALUE}, _V) ->
+ {364};
+e({'PropertyParm', "tdmc/gain", [Val], asn1_NOVALUE}, _V) ->
+ {365, Val};
+e({'PropertyParm', "tdmc/gain", Val, asn1_NOVALUE}, _V) ->
+ {366, Val};
+e({'PropertyParm', "maxNumberOfContexts", [Val], asn1_NOVALUE}, _V) ->
+ {367, Val};
+e({'PropertyParm', "maxNumberOfContexts", Val, asn1_NOVALUE}, _V) ->
+ {368, Val};
+e({'PropertyParm', "maxTerminationsPerContext", [Val], asn1_NOVALUE}, _V) ->
+ {369, Val};
+e({'PropertyParm', "maxTerminationsPerContext", Val, asn1_NOVALUE}, _V) ->
+ {370, Val};
+e({'PropertyParm', "normalMGExecutionTime", [Val], asn1_NOVALUE}, _V) ->
+ {371, Val};
+e({'PropertyParm', "normalMGExecutionTime", Val, asn1_NOVALUE}, _V) ->
+ {372, Val};
+e({'PropertyParm', "normalMGCExecutionTime", [Val], asn1_NOVALUE}, _V) ->
+ {373, Val};
+e({'PropertyParm', "normalMGCExecutionTime", Val, asn1_NOVALUE}, _V) ->
+ {374, Val};
+e({'PropertyParm', "MGProvisionalResponseTimerValue", [Val], asn1_NOVALUE}, _V) ->
+ {375, Val};
+e({'PropertyParm', "MGProvisionalResponseTimerValue", Val, asn1_NOVALUE}, _V) ->
+ {376, Val};
+e({'PropertyParm', "MGCProvisionalResponseTimerValue", [Val], asn1_NOVALUE}, _V) ->
+ {377, Val};
+e({'PropertyParm', "MGCProvisionalResponseTimerValue", Val, asn1_NOVALUE}, _V) ->
+ {378, Val};
+e({'PropertyParm', N, [Val], asn1_NOVALUE}, _V) ->
+ {379, N, Val};
+e({'PropertyParm', N, Val, asn1_NOVALUE}, _V) ->
+ {380, N, Val};
+e({'PropertyParm', N, Val, EI}, _V) ->
+ {381, N, Val, EI};
+
+e({'LocalRemoteDescriptor', [[PG]]}, V) ->
+ {400, e(PG, V)};
+e({'LocalRemoteDescriptor', [PG]}, V) ->
+ {401, el(PG, V)};
+e({'LocalRemoteDescriptor', PG}, V) ->
+ {402, ell(PG, V)};
+
+e({'TerminationStateDescriptor', PP, EBC, SS}, V) ->
+ {410, el(PP, V), e(EBC, V), e(SS, V)};
+
+e({eventsDescriptor, {'EventsDescriptor', RID, [E]}}, V) ->
+ {420, e(RID, V), e(E, V)};
+e({eventsDescriptor, {'EventsDescriptor', RID, EL}}, V) ->
+ {421, e(RID, V), el(EL, V)};
+e({eventsDescriptor, ED}, V) ->
+ {422, e(ED, V)};
+e({'EventsDescriptor', RID, [E]}, V) ->
+ {423, e(RID, V), e(E, V)};
+e({'EventsDescriptor', RID, EL}, V) ->
+ {424, e(RID, V), el(EL, V)};
+
+e({'RequestedEvent', PN, SID, EA, EPL}, V) ->
+ {425, PN, e(SID, V), e(EA, V), el(EPL, V)};
+
+e({'RegulatedEmbeddedDescriptor', SED, SD}, V) ->
+ {430, e(SED, V), el(SD, V)};
+
+e({notifyImmediate, NI}, V) ->
+ {435, e(NI, V)};
+e({notifyRegulated, NR}, V) ->
+ {436, e(NR, V)};
+e({neverNotify, NN}, V) ->
+ {437, e(NN, V)};
+
+e({'RequestedActions', KA, EDM, SE, SD}, V) ->
+ {440, e(KA, V), e(EDM, V), e(SE, V), e(SD, V)};
+
+e({'RequestedActions', KA, EDM, SE, SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {441, e(KA, V), e(EDM, V), e(SE, V), e(SD, V)};
+e({'RequestedActions', KA, EDM, SE, SD, NB, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {442, e(KA, V), e(EDM, V), e(SE, V), e(SD, V), e(NB, V)};
+e({'RequestedActions', KA, EDM, SE, SD, NB, RED}, V)
+ when V >= 3 ->
+ {443, e(KA, V), e(EDM, V), e(SE, V), e(SD, V), e(NB, V), e(RED, V)};
+
+e({'SecondEventsDescriptor', RID, [E]}, V) ->
+ {450, e(RID, V), e(E, V)};
+e({'SecondEventsDescriptor', RID, EL}, V) ->
+ {451, e(RID, V), el(EL, V)};
+
+e({'SecondRequestedEvent', PN, SID, EA, EPL}, V) ->
+ {460, PN, e(SID, V), e(EA, V), e(EPL, V)};
+
+e({'SecondRequestedActions', KA, EDM, SD}, V) ->
+ {470, e(KA, V), e(EDM, V), e(SD, V)};
+
+e({'SecondRequestedActions', KA, EDM, SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {471, e(KA, V), e(EDM, V), e(SD, V)};
+e({'SecondRequestedActions', KA, EDM, SD, NB, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {472, e(KA, V), e(EDM, V), e(SD, V), e(NB, V)};
+e({'SecondRequestedActions', KA, EDM, SD, NB, RED}, V)
+ when V >= 3 ->
+ {473, e(KA, V), e(EDM, V), e(SD, V), e(NB, V), e(RED, V)};
+
+e({'EventSpec', EN, SID, EPL}, V) ->
+ {480, EN, e(SID, V), el(EPL, V)};
+
+e({'SeqSigList', ID, SL}, V) ->
+ {490, ID, el(SL, V)};
+
+e({signalsDescriptor, S}, V) ->
+ {500, el(S, V)};
+e({signal, S}, V) ->
+ {510, e(S, V)};
+
+e({'Signal', SN, SID, ST, D, NC, KA, SPL}, V) ->
+ {520, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V)};
+
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {521, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {522, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, RID, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {523, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V), e(RID, V)};
+e({'Signal', SN, SID, ST, D, NC, KA, SPL,
+ SD, RID, IsD}, V)
+ when V >= 3 ->
+ {524, SN, e(SID, V), e(ST, V), e(D, V), e(NC, V), e(KA, V), el(SPL, V),
+ e(SD, V), e(RID, V), e(IsD, V)};
+
+e({'SigParameter', SPN, Val, asn1_NOVALUE}, _V) ->
+ {530, SPN, Val};
+e({'SigParameter', SPN, Val, EI}, _V) ->
+ {531, SPN, Val, EI};
+
+e({modemDescriptor, MD}, V) ->
+ {550, e(MD, V)};
+e({'ModemDescriptor', MTL, MPL, asn1_NOVALUE}, _V) ->
+ {551, MTL, MPL};
+e({'ModemDescriptor', MTL, MPL, NSD}, _V) ->
+ {552, MTL, MPL, NSD};
+
+e({digitMapDescriptor, {'DigitMapDescriptor', DMN, DMV}}, V) ->
+ {560, DMN, e(DMV, V)};
+e({digitMapDescriptor, DMD}, V) ->
+ {561, e(DMD, V)};
+e({'DigitMapDescriptor', DMN, DMV}, V) ->
+ {562, DMN, e(DMV, V)};
+
+e({'DigitMapValue', Start, Stop, Long, DMB}, 1 = V) ->
+ {570, e(Start, V), e(Stop, V), e(Long, V), DMB};
+e({'DigitMapValue', Start, Stop, Long, DMB, Dur}, V) when V >= 2 ->
+ {571, e(Start, V), e(Stop, V), e(Long, V), DMB, e(Dur, V)};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, asn1_NOVALUE, asn1_NOVALUE}, V) ->
+ {580, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, asn1_NOVALUE}, V) ->
+ {581, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD}, V) ->
+ {582, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, asn1_NOVALUE}, V)
+ when V == 2 ->
+ {583, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V == 2 ->
+ {584, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD, e(Info, V)};
+
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD,
+ asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {585, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info,
+ asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {586, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), e(TS, V), NSD, e(Info, V)};
+e({'ServiceChangeParm', M, A, Ver, Prof, R, D, Id, TS, NSD, Info, Flag}, V)
+ when V >= 3 ->
+ {587, e(M, V), e(A, V), e(Ver, V), e(Prof, V), R, e(D, V), e(Id, V),
+ e(TS, V), NSD, e(Info, V), e(Flag, V)};
+
+e({serviceChangeResParms, {'ServiceChangeResParm', Id, A, Ver, Prof, TS}}, V) ->
+ {590, Id, e(A, V), Ver, e(Prof, V), TS};
+e({serviceChangeResParms, SCRP}, V) ->
+ {591, e(SCRP, V)};
+e({'ServiceChangeResParm', Id, A, Ver, Prof, TS}, V) ->
+ {592, Id, e(A, V), Ver, e(Prof, V), TS};
+
+e({portNumber, N}, _V) ->
+ {600, N};
+
+e({'TimeNotation', D, T}, _V) ->
+ {610, D, T};
+
+e({'ServiceChangeProfile', N, Ver}, _V) ->
+ {620, N, Ver};
+
+e({digitMapName, N}, _V) ->
+ {630, N};
+
+e({megaco_term_id, false, Id}, _V) ->
+ {640, Id};
+e({megaco_term_id, true, [[$*]]}, _V) ->
+ {641};
+e({megaco_term_id, true, [[$$]]}, _V) ->
+ {642};
+e({megaco_term_id, true, Id}, _V) ->
+ {643, Id};
+e({'TerminationID', W, ID}, _V) ->
+ {644, W, ID};
+
+e({modReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {650, el(TID, V)};
+e({modReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {651, el(TID, V), e(TA, V)};
+e({modReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {652, el(TID, V), el(TA, V)};
+e({modReply, R}, V) ->
+ {653, e(R, V)};
+
+e({moveReply, AR}, V) ->
+ {655, e(AR, V)};
+
+e({addReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {660, el(TID, V)};
+e({addReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {661, el(TID, V), e(TA, V)};
+e({addReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {662, el(TID, V), el(TA, V)};
+e({addReply, R}, V) ->
+ {663, e(R, V)};
+
+e({subtractReply, {'AmmsReply', TID, asn1_NOVALUE}}, V) ->
+ {670, el(TID, V)};
+e({subtractReply, {'AmmsReply', TID, [TA]}}, V) ->
+ {671, el(TID, V), e(TA, V)};
+e({subtractReply, {'AmmsReply', TID, TA}}, V) when is_list(TA) ->
+ {672, el(TID, V), el(TA, V)};
+e({subtractReply, R}, V) ->
+ {673, e(R, V)};
+
+e({'AmmsReply', TID, asn1_NOVALUE}, V) ->
+ {680, el(TID, V)};
+e({'AmmsReply', TID, [TA]}, V) ->
+ {681, el(TID, V), e(TA, V)};
+e({'AmmsReply', TID, TA}, V) when is_list(TA) ->
+ {682, el(TID, V), el(TA, V)};
+
+e({notifyReply, {'NotifyReply', TID, asn1_NOVALUE}}, V) ->
+ {690, el(TID, V)};
+e({notifyReply, {'NotifyReply', TID, ED}}, V) ->
+ {691, el(TID, V), e(ED, V)};
+e({notifyReply, R}, V) ->
+ {692, e(R, V)};
+e({'NotifyReply', TID, asn1_NOVALUE}, V) ->
+ {693, el(TID, V)};
+e({'NotifyReply', TID, ED}, V) ->
+ {694, el(TID, V), e(ED, V)};
+
+e({auditValueReply, AVR}, V) ->
+ {700, e(AVR, V)};
+
+e({contextAuditResult, TIDs}, V) ->
+ {705, el(TIDs, V)};
+
+e({auditResult, {'AuditResult', TID, [TAR]}}, V) ->
+ {710, e(TID, V), e(TAR, V)};
+e({auditResult, {'AuditResult', TID, TAR}}, V) ->
+ {711, e(TID, V), el(TAR, V)};
+e({auditResult, AR}, V) ->
+ {712, e(AR, V)};
+e({'AuditResult', TID, [TAR]}, V) ->
+ {713, e(TID, V), e(TAR, V)};
+e({'AuditResult', TID, TAR}, V) ->
+ {714, e(TID, V), el(TAR, V)};
+
+e({auditResultTermList, {'TermListAuditResult', TIDs, [TAR]}}, V) ->
+ {715, el(TIDs, V), e(TAR, V)};
+e({auditResultTermList, {'TermListAuditResult', TIDs, TAR}}, V) ->
+ {716, el(TIDs, V), el(TAR, V)};
+
+e({packagesDescriptor, PsD}, V) ->
+ {720, el(PsD, V)};
+
+e({'PackagesItem', "g", 1}, _V) ->
+ {730};
+e({'PackagesItem', "tonegen", 1}, _V) ->
+ {731};
+e({'PackagesItem', "tonedet", 1}, _V) ->
+ {732};
+e({'PackagesItem', "tg", 1}, _V) ->
+ {733};
+e({'PackagesItem', "dd", 1}, _V) ->
+ {734};
+e({'PackagesItem', "cg", 1}, _V) ->
+ {735};
+e({'PackagesItem', "cd", 1}, _V) ->
+ {736};
+e({'PackagesItem', "al", 1}, _V) ->
+ {737};
+e({'PackagesItem', "ct", 1}, _V) ->
+ {738};
+e({'PackagesItem', "nt", 1}, _V) ->
+ {739};
+e({'PackagesItem', "rtp", 1}, _V) ->
+ {740};
+e({'PackagesItem', "tdmc", 1}, _V) ->
+ {741};
+e({'PackagesItem', Name, Ver}, _V) ->
+ {742, Name, Ver};
+
+e({emptyDescriptors, AD}, V) ->
+ {760, e(AD, V)};
+
+e({statisticsDescriptor, [SD]}, V) ->
+ {770, e(SD, V)};
+e({statisticsDescriptor, SsD}, V) ->
+ {771, el(SsD, V)};
+
+e({'StatisticsParameter', Name, asn1_NOVALUE}, _V) ->
+ {780, Name};
+e({'StatisticsParameter', Name, Value}, _V) ->
+ {781, Name, Value};
+
+e({'MuxDescriptor', MT, TL, asn1_NOVALUE}, V) ->
+ {800, e(MT, V), el(TL, V)};
+e({'MuxDescriptor', MT, TL, NSD}, V) ->
+ {801, e(MT, V), el(TL, V), NSD};
+
+e({indAudPackagesDescriptor, {'IndAudPackagesDescriptor', N, Ver}}, V)
+ when (V >= 2) ->
+ {900, N, Ver};
+e({indAudPackagesDescriptor, IAPD}, V)
+ when (V >= 2) ->
+ {900, e(IAPD, V)};
+e({'IndAudPackagesDescriptor', N, Ver}, V)
+ when (V >= 2) ->
+ {901, N, Ver};
+
+e({indAudStatisticsDescriptor, {'IndAudStatisticsDescriptor', N}}, V)
+ when (V >= 2) ->
+ {910, N};
+e({indAudStatisticsDescriptor, IASD}, V)
+ when (V >= 2) ->
+ {911, e(IASD, V)};
+e({'IndAudStatisticsDescriptor', N}, V)
+ when (V >= 2) ->
+ {912, N};
+
+e({indAudDigitMapDescriptor, {'IndAudDigitMapDescriptor', DMN}}, V)
+ when (V >= 2) ->
+ {920, DMN};
+e({indAudDigitMapDescriptor, IADMD}, V)
+ when (V >= 2) ->
+ {921, e(IADMD, V)};
+e({'IndAudDigitMapDescriptor', DMN}, V)
+ when (V >= 2) ->
+ {922, DMN};
+
+e({indAudSignalsDescriptor, {seqSigList, IASD}}, V)
+ when (V >= 2) ->
+ {930, e(IASD, V)};
+e({indAudSignalsDescriptor, {signal, IAS}}, V)
+ when (V >= 2) ->
+ {931, e(IAS, V)};
+
+e({'IndAudSeqSigList', Id, SL}, V)
+ when (V >= 2) ->
+ {940, Id, e(SL, V)};
+
+e({'IndAudSignal', N, SID}, 2 = V) ->
+ {950, N, e(SID, V)};
+e({'IndAudSignal', N, SID, asn1_NOVALUE}, V)
+ when (V >= 3) ->
+ {951, N, e(SID, V)};
+e({'IndAudSignal', N, SID, RID}, V)
+ when (V >= 3) ->
+ {952, N, e(SID, V), e(RID, V)};
+
+e({indAudEventBufferDescriptor, {'IndAudEventBufferDescriptor', EN, SID}}, V)
+ when (V >= 2) ->
+ {960, EN, e(SID, V)};
+e({indAudEventBufferDescriptor, IAEBD}, V)
+ when (V >= 2) ->
+ {961, e(IAEBD, V)};
+e({'IndAudEventBufferDescriptor', EN, SID}, V)
+ when (V >= 2) ->
+ {962, EN, e(SID, V)};
+
+e({indAudEventsDescriptor, {'IndAudEventsDescriptor', RID, N, SID}}, V)
+ when (V >= 2) ->
+ {970, e(RID, V), N, e(SID, V)};
+e({indAudEventsDescriptor, IAED}, V)
+ when (V >= 2) ->
+ {971, e(IAED, V)};
+e({'IndAudEventsDescriptor', RID, N, SID}, V)
+ when (V >= 2) ->
+ {972, e(RID, V), N, e(SID, V)};
+
+e({indAudMediaDescriptor, {'IndAudMediaDescriptor', TSD, S}}, V) when V >= 2 ->
+ {980, e(TSD, V), e(S, V)};
+e({indAudMediaDescriptor, IAMD}, V) when V >= 2 ->
+ {981, e(IAMD, V)};
+e({'IndAudMediaDescriptor', TSD, S}, V) when V >= 2 ->
+ {982, e(TSD, V), e(S, V)};
+
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS}, 2 = V) ->
+ {990, el(PP, V), e(EBC, V), e(SS, V)};
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {991, el(PP, V), e(EBC, V), e(SS, V)};
+e({'IndAudTerminationStateDescriptor', PP, EBC, SS, SSS}, V)
+ when V >= 3 ->
+ {992, el(PP, V), e(EBC, V), e(SS, V), e(SSS, V)};
+
+e({'IndAudStreamDescriptor', SID, SP}, V) ->
+ {1000, e(SID, V), e(SP, V)};
+
+e({'IndAudStreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE}, 2 = V) ->
+ {1010, e(LCD, V)};
+e({'IndAudStreamParms', LCD, LD, RD}, 2 = V) ->
+ {1011, e(LCD, V), e(LD, V), e(RD, V)};
+e({'IndAudStreamParms', LCD, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1012, e(LCD, V)};
+e({'IndAudStreamParms', LCD, LD, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1013, e(LCD, V), e(LD, V)};
+e({'IndAudStreamParms', LCD, LD, RD, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1014, e(LCD, V), e(LD, V), e(RD, V)};
+e({'IndAudStreamParms', LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {1015, e(LCD, V), e(LD, V), e(RD, V), e(SD, V)};
+
+e({'IndAudLocalControlDescriptor', SM, RV, RG, asn1_NOVALUE}, 2 = V) ->
+ {1020, e(SM, V), e(RV, V), e(RG, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP}, 2 = V) when is_list(PP) ->
+ {1021, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, asn1_NOVALUE, asn1_NOVALUE}, V)
+ when V >= 3 ->
+ {1022, e(SM, V), e(RV, V), e(RG, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP, asn1_NOVALUE}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {1023, e(SM, V), e(RV, V), e(RG, V), el(PP, V)};
+e({'IndAudLocalControlDescriptor', SM, RV, RG, PP, SMS}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {1024, e(SM, V), e(RV, V), e(RG, V), el(PP, V), e(SMS, V)};
+
+e({'IndAudPropertyParm', N}, 2 = _V) ->
+ {1030, N};
+e({'IndAudPropertyParm', N, asn1_NOVALUE}, V) when V >= 3 ->
+ {1031, N};
+e({'IndAudPropertyParm', N, PP}, V) when V >= 3 ->
+ {1032, N, e(PP, V)};
+
+e(oneway, _V) ->
+ {1100};
+e(bothway, _V) ->
+ {1101};
+e(isolate, _V) ->
+ {1102};
+e(onewayexternal, _V) ->
+ {1103};
+e(onewayboth, _V) ->
+ {1104};
+
+e(T, _V) ->
+ %% io:format("e(~w) -> ~nT: ~w~n", [_V, T]),
+ T.
+
+
+d({1}, _) ->
+ asn1_NOVALUE;
+d({2}, _V) ->
+ 'NULL';
+d({3}, _V) ->
+ sendRecv;
+d({4}, _V) ->
+ recvOnly;
+d({5}, _V) ->
+ restart;
+d({6}, _) ->
+ mediaToken;
+d({7}, _) ->
+ eventsToken;
+d({8}, _) ->
+ signalsToken;
+d({9}, _) ->
+ digitMapToken;
+d({10}, _) ->
+ statsToken;
+d({11}, _) ->
+ packagesToken;
+d({12}, _V) ->
+ h221;
+d({13}, _V) ->
+ h223;
+d({14}, _V) ->
+ h226;
+d({15}, _V) ->
+ v76;
+
+d({20, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', 1, d(Mid, 1), d(Body, 1)}};
+d({21, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', 2, d(Mid, 2), d(Body, 2)}};
+d({22, V, Mid, Body}, _) ->
+ {'MegacoMessage', asn1_NOVALUE, {'Message', V, d(Mid, V), d(Body, V)}};
+d({23, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, 1), {'Message', 1, d(Mid, 1), d(Body, 1)}};
+d({24, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, 2), {'Message', 2, d(Mid, 2), d(Body, 2)}};
+d({25, V, AuthHeader, Mid, Body}, _) ->
+ {'MegacoMessage', d(AuthHeader, V), {'Message', V, d(Mid, V), d(Body, V)}};
+d({26, AuthHeader, Mess}, V) ->
+ {'MegacoMessage', d(AuthHeader, V), d(Mess, V)};
+d({27, V, Mid, Body}, _) ->
+ {'Message', V, d(Mid, V), d(Body, V)};
+
+d({30, Name}, _V) ->
+ {domainName, {'DomainName', Name, asn1_NOVALUE}};
+d({31, Name, PortNumber}, _V) ->
+ {domainName, {'DomainName', Name, PortNumber}};
+d({32, N}, V) ->
+ {domainName, d(N, V)};
+d({33, Name}, _V) ->
+ {'DomainName', Name, asn1_NOVALUE};
+d({34, Name, PortNumber}, _V) ->
+ {'DomainName', Name, PortNumber};
+d({35, Addr}, _V) ->
+ {ip4Address, {'IP4Address', Addr, asn1_NOVALUE}};
+d({36, Addr, PortNumber}, _V) ->
+ {ip4Address, {'IP4Address', Addr, PortNumber}};
+d({37, A}, V) ->
+ {ip4Address, d(A, V)};
+d({38, Addr}, _V) ->
+ {'IP4Address', Addr, asn1_NOVALUE};
+d({39, Addr, PortNumber}, _V) ->
+ {'IP4Address', Addr, PortNumber};
+d({40, Addr}, _V) ->
+ {ip6Address, {'IP6Address', Addr, asn1_NOVALUE}};
+d({41, Addr, PortNumber}, _V) ->
+ {ip6Address, {'IP6Address', Addr, PortNumber}};
+d({42, A}, V) ->
+ {ip6Address, d(A, V)};
+d({43, Addr}, _V) ->
+ {'IP6Address', Addr, asn1_NOVALUE};
+d({44, Addr, PortNumber}, _V) ->
+ {'IP6Address', Addr, PortNumber};
+
+d({50, Transaction}, V) ->
+ {transactions, [d(Transaction, V)]};
+d({51, Transactions}, V) ->
+ {transactions, dl(Transactions, V)};
+d({52, EC}, _V) ->
+ {messageError, {'ErrorDescriptor', EC, asn1_NOVALUE}};
+d({53, EC, ET}, _V) ->
+ {messageError, {'ErrorDescriptor', EC, ET}};
+d({54, Error}, V) ->
+ {messageError, d(Error, V)};
+d({55, TransId, Actions}, V) ->
+ {transactionRequest, {'TransactionRequest', TransId, dl(Actions, V)}};
+d({56, TransId}, _V) ->
+ {transactionPending, {'TransactionPending', TransId}};
+d({57, TransId, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, asn1_NOVALUE, d(TransRes, V)}};
+d({58, TransId, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, 'NULL', d(TransRes, V)}};
+d({59, TransId, ImmAckReq, TransRes}, V) ->
+ {transactionReply, {'TransactionReply', TransId, d(ImmAckReq, V), d(TransRes, V)}};
+d({60, T}, V) ->
+ {transactionResponseAck, dl(T, V)};
+d({61, FirstAck}, _V) ->
+ {'TransactionAck', FirstAck, asn1_NOVALUE};
+d({62, FirstAck, LastAck}, _V) ->
+ {'TransactionAck', FirstAck, LastAck};
+
+d({70, EC}, _V) ->
+ {'ErrorDescriptor', EC, asn1_NOVALUE};
+d({71, EC, ET}, _V) ->
+ {'ErrorDescriptor', EC, ET};
+
+d({80, Cid, CtxReq, CtxAAR, CmdReq}, V) ->
+ {'ActionRequest', Cid, d(CtxReq, V), d(CtxAAR, V), [d(CmdReq, V)]};
+d({81, Cid, CtxReq, CtxAAR, CmdReqs}, V) ->
+ {'ActionRequest', Cid, d(CtxReq, V), d(CtxAAR, V), dl(CmdReqs, V)};
+
+d({90, P, E, T}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V)};
+d({91, P, E, T}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({92, P, E, T, IC}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), asn1_NOVALUE, asn1_NOVALUE};
+d({93, P, E, T, IC, CP}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), dl(CP, V), asn1_NOVALUE};
+d({94, P, E, T, IC, CP, CL}, V) ->
+ {'ContextRequest', d(P, V), d(E, V), dl(T, V),
+ d(IC, V), dl(CP, V), dl(CL, V)};
+
+d({100, P, E, T}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V)};
+d({101, P, E, T}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({102, P, E, T, IC}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({103, P, E, T, IC, CPA}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({104, P, E, T, IC, CPA, SP}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({105, P, E, T, IC, CPA, SP, SE}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), asn1_NOVALUE, asn1_NOVALUE};
+d({106, P, E, T, IC, CPA, SP, SE, SIC}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), d(SIC, V), asn1_NOVALUE};
+d({107, P, E, T, IC, CPA, SP, SE, SIC, SL}, V) ->
+ {'ContextAttrAuditRequest', d(P, V), d(E, V), d(T, V),
+ d(IC, V), dl(CPA, V), d(SP, V), d(SE, V), d(SIC, V), d(SL, V)};
+
+d({110, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), asn1_NOVALUE, asn1_NOVALUE};
+d({111, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), 'NULL', asn1_NOVALUE};
+d({112, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), asn1_NOVALUE, 'NULL'};
+d({113, Cmd}, V) ->
+ {'CommandRequest', d(Cmd, V), 'NULL', 'NULL'};
+d({114, Cmd, Opt, WR}, V) ->
+ {'CommandRequest', d(Cmd, V), d(Opt, V), d(WR, V)};
+
+d({120, From, To, Dir}, 1 = V) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V)};
+d({121, From, To, Dir, SID}, 2 = V) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V)};
+d({122, From, To, Dir, SID}, V) when (V >= 3) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V), asn1_NOVALUE};
+d({123, From, To, Dir, SID, TDE}, V) when (V >= 3) ->
+ {'TopologyRequest', d(From, V), d(To, V), d(Dir, V), d(SID, V), d(TDE, V)};
+
+d({130, TID}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), []}};
+d({131, TID, Desc}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), [d(Desc, V)]}};
+d({132, TID, Descs}, V) ->
+ {modReq, {'AmmRequest', dl(TID, V), dl(Descs, V)}};
+d({133, TID}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), []}};
+d({134, TID, Desc}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), [d(Desc, V)]}};
+d({135, TID, Descs}, V) ->
+ {addReq, {'AmmRequest', dl(TID, V), dl(Descs, V)}};
+d({136, TID, Descs}, V) ->
+ {'AmmRequest', dl(TID, V), dl(Descs, V)};
+
+d({140, TID}, V) ->
+ {subtractReq, {'SubtractRequest', dl(TID, V), asn1_NOVALUE}};
+d({141, TID, AudDesc}, V) ->
+ {subtractReq, {'SubtractRequest', dl(TID, V), d(AudDesc, V)}};
+d({142, TID}, V) ->
+ {'SubtractRequest', dl(TID, V), asn1_NOVALUE};
+d({143, TID, AudDesc}, V) ->
+ {'SubtractRequest', dl(TID, V), d(AudDesc, V)};
+
+d({150, AR}, V) ->
+ {auditValueRequest, d(AR, V)};
+
+d({160, TID, AudDesc}, V) when V < 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V)};
+d({161, TID, AudDesc}, V) when V >= 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V), asn1_NOVALUE};
+d({162, TID, AudDesc, TIDs}, V) when V >= 3 ->
+ {'AuditRequest', d(TID, V), d(AudDesc, V), dl(TIDs, V)};
+
+d({170, AR}, V) ->
+ {actionReplies, [d(AR, V)]};
+d({171, ARs}, V) ->
+ {actionReplies, dl(ARs, V)};
+
+d({180, CID, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, [d(CmdRep, V)]};
+d({181, CID, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, asn1_NOVALUE, dl(CmdRep, V)};
+d({182, CID, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, d(CtxRep, V), [d(CmdRep, V)]};
+d({183, CID, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, asn1_NOVALUE, d(CtxRep, V), dl(CmdRep, V)};
+d({184, CID, ED, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), asn1_NOVALUE, [d(CmdRep, V)]};
+d({185, CID, ED, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), asn1_NOVALUE, dl(CmdRep, V)};
+d({186, CID, ED, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), d(CtxRep, V), [d(CmdRep, V)]};
+d({187, CID, ED, CtxRep, CmdRep}, V) ->
+ {'ActionReply', CID, d(ED, V), d(CtxRep, V), dl(CmdRep, V)};
+
+d({190}, 1 = _V) ->
+ {'AuditDescriptor', asn1_NOVALUE};
+d({191, AT}, 1 = V) ->
+ {'AuditDescriptor', dl(AT, V)};
+d({192}, V) when (V >= 2) ->
+ {'AuditDescriptor', asn1_NOVALUE, asn1_NOVALUE};
+d({193, AT, APT}, V) when is_list(AT) andalso is_list(APT) andalso (V >= 2) ->
+ {'AuditDescriptor', dl(AT, V), dl(APT, V)};
+d({194, AT, APT}, V) when is_list(APT) andalso (V >= 2) ->
+ {'AuditDescriptor', d(AT, V), dl(APT, V)};
+d({195, AT, APT}, V) when is_list(AT) andalso (V >= 2) ->
+ {'AuditDescriptor', dl(AT, V), d(APT, V)};
+d({196, AT, APT}, V) when (V >= 2) ->
+ {'AuditDescriptor', d(AT, V), d(APT, V)};
+
+d({200, TID, OED}, V) ->
+ {notifyReq, {'NotifyRequest', dl(TID, V), d(OED, V), asn1_NOVALUE}};
+d({201, TID, OED, ED}, V) ->
+ {notifyReq, {'NotifyRequest', dl(TID, V), d(OED, V), d(ED, V)}};
+d({202, TID, OED}, V) ->
+ {'NotifyRequest', dl(TID, V), d(OED, V), asn1_NOVALUE};
+d({203, TID, OED, ED}, V) ->
+ {'NotifyRequest', dl(TID, V), d(OED, V), d(ED, V)};
+
+d({210, RID, OEL}, V) ->
+ {'ObservedEventsDescriptor', RID, dl(OEL, V)};
+
+d({220, EN, SID, EPL, TN}, V) ->
+ {'ObservedEvent', EN, d(SID, V), dl(EPL, V), d(TN, V)};
+
+d({230}, _V) ->
+ {'EventParameter', "type", ["est"], asn1_NOVALUE};
+d({231, Val}, _V) ->
+ {'EventParameter', "type", [Val], asn1_NOVALUE};
+d({232, Val}, _V) ->
+ {'EventParameter', "type", Val, asn1_NOVALUE};
+d({233}, _V) ->
+ {'EventParameter', "Generalcause", ["NR"], asn1_NOVALUE};
+d({234}, _V) ->
+ {'EventParameter', "Generalcause", ["UR"], asn1_NOVALUE};
+d({235}, _V) ->
+ {'EventParameter', "Generalcause", ["FT"], asn1_NOVALUE};
+d({236}, _V) ->
+ {'EventParameter', "Generalcause", ["FP"], asn1_NOVALUE};
+d({237}, _V) ->
+ {'EventParameter', "Generalcause", ["IW"], asn1_NOVALUE};
+d({238}, _V) ->
+ {'EventParameter', "Generalcause", ["UN"], asn1_NOVALUE};
+d({239, Val}, _V) ->
+ {'EventParameter', "Generalcause", [Val], asn1_NOVALUE};
+d({240, Val}, _V) ->
+ {'EventParameter', "Generalcause", Val, asn1_NOVALUE};
+d({241, Val}, _V) ->
+ {'EventParameter', "Failurecause", [Val], asn1_NOVALUE};
+d({242, Val}, _V) ->
+ {'EventParameter', "Failurecause", Val, asn1_NOVALUE};
+d({243, EPN, Val}, _V) ->
+ {'EventParameter', EPN, Val, asn1_NOVALUE};
+d({244, EPN, Val, EI}, _V) ->
+ {'EventParameter', EPN, Val, EI};
+
+d({260, TID, SCPs}, V) ->
+ {serviceChangeReq, {'ServiceChangeRequest', dl(TID, V), d(SCPs, V)}};
+d({261, SCR}, V) ->
+ {serviceChangeReq, d(SCR, V)};
+d({262, TID, SCPs}, V) ->
+ {'ServiceChangeRequest', dl(TID, V), d(SCPs, V)};
+
+d({270, TID, SCR}, V) ->
+ {serviceChangeReply, {'ServiceChangeReply', dl(TID, V), d(SCR, V)}};
+d({271, SCR}, V) ->
+ {serviceChangeReply, d(SCR, V)};
+d({272, TID, SCR}, V) -> %% KOLLA
+ {'ServiceChangeReply', dl(TID, V), d(SCR, V)};
+
+d({280, TSD, S}, V) ->
+ {mediaDescriptor, {'MediaDescriptor', d(TSD, V), d(S, V)}};
+d({281, MD}, V) ->
+ {mediaDescriptor, d(MD, V)};
+d({282, TSD, S}, V) ->
+ {'MediaDescriptor', d(TSD, V), d(S, V)};
+
+d({290, S}, V) ->
+ {oneStream, d(S, V)};
+d({291, S}, V) ->
+ {multiStream, dl(S, V)};
+d({292, SID, SP}, V) ->
+ {'StreamDescriptor', d(SID, V), d(SP, V)};
+
+d({300, LCD}, V) ->
+ {'StreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({301, LCD, LD}, V) ->
+ {'StreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE};
+d({302, LCD, LD, RD}, V) ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V)};
+
+d({303, LCD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({304, LCD, LD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({305, LCD, LD, RD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V), asn1_NOVALUE};
+d({306, LCD, LD, RD, SD}, V)
+ when V >= 3 ->
+ {'StreamParms', d(LCD, V), d(LD, V), d(RD, V), dl(SD, V)};
+
+d({310, SM, RV, RG, PP}, V) ->
+ {'LocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V)};
+
+d({320, Val}, _V) ->
+ {'PropertyParm', "v", [Val], asn1_NOVALUE};
+d({321, Val}, _V) ->
+ {'PropertyParm', "v", Val, asn1_NOVALUE};
+d({332, Val}, _V) ->
+ {'PropertyParm', "o", [Val], asn1_NOVALUE};
+d({333, Val}, _V) ->
+ {'PropertyParm', "o", Val, asn1_NOVALUE};
+d({334, Val}, _V) ->
+ {'PropertyParm', "s", [Val], asn1_NOVALUE};
+d({335, Val}, _V) ->
+ {'PropertyParm', "s", Val, asn1_NOVALUE};
+d({336, Val}, _V) ->
+ {'PropertyParm', "i", [Val], asn1_NOVALUE};
+d({337, Val}, _V) ->
+ {'PropertyParm', "i", Val, asn1_NOVALUE};
+d({338, Val}, _V) ->
+ {'PropertyParm', "u", [Val], asn1_NOVALUE};
+d({339, Val}, _V) ->
+ {'PropertyParm', "u", Val, asn1_NOVALUE};
+d({340, Val}, _V) ->
+ {'PropertyParm', "e", [Val], asn1_NOVALUE};
+d({341, Val}, _V) ->
+ {'PropertyParm', "e", Val, asn1_NOVALUE};
+d({342, Val}, _V) ->
+ {'PropertyParm', "p", [Val], asn1_NOVALUE};
+d({343, Val}, _V) ->
+ {'PropertyParm', "p", Val, asn1_NOVALUE};
+d({344, Val}, _V) ->
+ {'PropertyParm', "c", [Val], asn1_NOVALUE};
+d({345, Val}, _V) ->
+ {'PropertyParm', "c", Val, asn1_NOVALUE};
+d({346, Val}, _V) ->
+ {'PropertyParm', "b", [Val], asn1_NOVALUE};
+d({347, Val}, _V) ->
+ {'PropertyParm', "b", Val, asn1_NOVALUE};
+d({348, Val}, _V) ->
+ {'PropertyParm', "z", [Val], asn1_NOVALUE};
+d({349, Val}, _V) ->
+ {'PropertyParm', "z", Val, asn1_NOVALUE};
+d({350, Val}, _V) ->
+ {'PropertyParm', "k", [Val], asn1_NOVALUE};
+d({351, Val}, _V) ->
+ {'PropertyParm', "k", Val, asn1_NOVALUE};
+d({352, Val}, _V) ->
+ {'PropertyParm', "a", [Val], asn1_NOVALUE};
+d({353, Val}, _V) ->
+ {'PropertyParm', "a", Val, asn1_NOVALUE};
+d({354, Val}, _V) ->
+ {'PropertyParm', "t", [Val], asn1_NOVALUE};
+d({355, Val}, _V) ->
+ {'PropertyParm', "t", Val, asn1_NOVALUE};
+d({356, Val}, _V) ->
+ {'PropertyParm', "r", [Val], asn1_NOVALUE};
+d({357, Val}, _V) ->
+ {'PropertyParm', "r", Val, asn1_NOVALUE};
+d({358, Val}, _V) ->
+ {'PropertyParm', "m", [Val], asn1_NOVALUE};
+d({359, Val}, _V) ->
+ {'PropertyParm', "m", Val, asn1_NOVALUE};
+d({360, Val}, _V) ->
+ {'PropertyParm', "nt/jit", [Val], asn1_NOVALUE};
+d({361, Val}, _V) ->
+ {'PropertyParm', "nt/jit", Val, asn1_NOVALUE};
+d({362}, _V) ->
+ {'PropertyParm', "tdmc/ec", ["on"], asn1_NOVALUE};
+d({363}, _V) ->
+ {'PropertyParm', "tdmc/ec", ["off"], asn1_NOVALUE};
+d({364}, _V) ->
+ {'PropertyParm', "tdmc/gain", ["automatic"], asn1_NOVALUE};
+d({365, Val}, _V) ->
+ {'PropertyParm', "tdmc/gain", [Val], asn1_NOVALUE};
+d({366, Val}, _V) ->
+ {'PropertyParm', "tdmc/gain", Val, asn1_NOVALUE};
+d({367, Val}, _V) ->
+ {'PropertyParm', "maxNumberOfContexts", [Val], asn1_NOVALUE};
+d({368, Val}, _V) ->
+ {'PropertyParm', "maxNumberOfContexts", Val, asn1_NOVALUE};
+d({369, Val}, _V) ->
+ {'PropertyParm', "maxTerminationsPerContext", [Val], asn1_NOVALUE};
+d({370, Val}, _V) ->
+ {'PropertyParm', "maxTerminationsPerContext", Val, asn1_NOVALUE};
+d({371, Val}, _V) ->
+ {'PropertyParm', "normalMGExecutionTime", [Val], asn1_NOVALUE};
+d({372, Val}, _V) ->
+ {'PropertyParm', "normalMGExecutionTime", Val, asn1_NOVALUE};
+d({373, Val}, _V) ->
+ {'PropertyParm', "normalMGCExecutionTime", [Val], asn1_NOVALUE};
+d({374, Val}, _V) ->
+ {'PropertyParm', "normalMGCExecutionTime", Val, asn1_NOVALUE};
+d({375, Val}, _V) ->
+ {'PropertyParm', "MGProvisionalResponseTimerValue", [Val], asn1_NOVALUE};
+d({376, Val}, _V) ->
+ {'PropertyParm', "MGProvisionalResponseTimerValue", Val, asn1_NOVALUE};
+d({377, Val}, _V) ->
+ {'PropertyParm', "MGCProvisionalResponseTimerValue", [Val], asn1_NOVALUE};
+d({378, Val}, _V) ->
+ {'PropertyParm', "MGCProvisionalResponseTimerValue", Val, asn1_NOVALUE};
+d({379, N, Val}, _V) ->
+ {'PropertyParm', N, [Val], asn1_NOVALUE};
+d({380, N, Val}, _V) ->
+ {'PropertyParm', N, Val, asn1_NOVALUE};
+d({381, N, Val, EI}, _V) ->
+ {'PropertyParm', N, Val, EI};
+
+d({400, PG}, V) ->
+ {'LocalRemoteDescriptor', [[d(PG, V)]]};
+d({401, PG}, V) ->
+ {'LocalRemoteDescriptor', [dl(PG, V)]};
+d({402, PG}, V) ->
+ {'LocalRemoteDescriptor', dll(PG, V)};
+
+d({410, PP, EBC, SS}, V) ->
+ {'TerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V)};
+
+d({420, RID, E}, V) ->
+ {eventsDescriptor, {'EventsDescriptor', d(RID, V), [d(E, V)]}};
+d({421, RID, EL}, V) ->
+ {eventsDescriptor, {'EventsDescriptor', d(RID, V), dl(EL, V)}};
+d({422, ED}, V) ->
+ {eventsDescriptor, d(ED, V)};
+d({423, RID, E}, V) ->
+ {'EventsDescriptor', d(RID, V), [d(E, V)]};
+d({424, RID, EL}, V) ->
+ {'EventsDescriptor', d(RID, V), dl(EL, V)};
+
+d({425, PN, SID, EA, EPL}, V) ->
+ {'RequestedEvent', PN, d(SID, V), d(EA, V), dl(EPL, V)};
+
+d({430, SED, SD}, V) ->
+ {'RegulatedEmbeddedDescriptor', d(SED, V), dl(SD, V)};
+
+d({435, NI}, V) ->
+ {notifyImmediate, d(NI, V)};
+d({436, NR}, V) ->
+ {notifyRegulated, d(NR, V)};
+d({437, NN}, V) ->
+ {neverNotify, d(NN, V)};
+
+d({440, KA, EDM, SE, SD}, V) ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V)};
+d({441, KA, EDM, SE, SD}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({442, KA, EDM, SE, SD, NB}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ d(NB, V), asn1_NOVALUE};
+d({443, KA, EDM, SE, SD, NB, RED}, V)
+ when V >= 3 ->
+ {'RequestedActions', d(KA, V), d(EDM, V), d(SE, V), d(SD, V),
+ d(NB, V), d(RED, V)};
+
+d({450, RID, E}, V) ->
+ {'SecondEventsDescriptor', d(RID, V), [d(E, V)]};
+d({451, RID, EL}, V) ->
+ {'SecondEventsDescriptor', d(RID, V), dl(EL, V)};
+
+d({460, PN, SID, EA, EPL}, V) ->
+ {'SecondRequestedEvent', PN, d(SID, V), d(EA, V), d(EPL, V)};
+
+d({470, KA, EDM, SD}, V) ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V)};
+d({471, KA, EDM, SD}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({472, KA, EDM, SD, NB}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ d(NB, V), asn1_NOVALUE};
+d({473, KA, EDM, SD, NB, RED}, V)
+ when V >= 3 ->
+ {'SecondRequestedActions', d(KA, V), d(EDM, V), d(SD, V),
+ d(NB, V), d(RED, V)};
+
+d({480, EN, SID, EPL}, V) ->
+ {'EventSpec', EN, d(SID, V), dl(EPL, V)};
+
+d({490, ID, SL}, V) ->
+ {'SeqSigList', ID, dl(SL, V)};
+
+d({500, S}, V) ->
+ {signalsDescriptor, dl(S, V)};
+
+d({510, S}, V) ->
+ {signal, d(S, V)};
+
+d({520, SN, SID, ST, D, NC, KA, SPL}, V) ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V)};
+d({521, SN, SID, ST, D, NC, KA, SPL}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({522, SN, SID, ST, D, NC, KA, SPL, SD}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({523, SN, SID, ST, D, NC, KA, SPL, SD, RID}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), d(RID, V), asn1_NOVALUE};
+d({524, SN, SID, ST, D, NC, KA, SPL, SD, RID, IsD}, V)
+ when V >= 3 ->
+ {'Signal',
+ SN, d(SID, V), d(ST, V), d(D, V), d(NC, V), d(KA, V), dl(SPL, V),
+ d(SD, V), d(RID, V), d(IsD, V)};
+
+d({530, SPN, Val}, _V) ->
+ {'SigParameter', SPN, Val, asn1_NOVALUE};
+d({531, SPN, Val, EI}, _V) ->
+ {'SigParameter', SPN, Val, EI};
+
+d({550, MD}, V) ->
+ {modemDescriptor, d(MD, V)};
+d({551, MTL, MPL}, _V) ->
+ {'ModemDescriptor', MTL, MPL, asn1_NOVALUE};
+d({552, MTL, MPL, NSD}, _V) ->
+ {'ModemDescriptor', MTL, MPL, NSD};
+
+d({560, DMN, DMV}, V) ->
+ {digitMapDescriptor, {'DigitMapDescriptor', DMN, d(DMV, V)}};
+d({561, DMD}, V) ->
+ {digitMapDescriptor, d(DMD, V)};
+d({562, DMN, DMV}, V) ->
+ {'DigitMapDescriptor', DMN, d(DMV, V)};
+
+d({570, Start, Stop, Long, DMB}, 1 = V) ->
+ {'DigitMapValue', d(Start, V), d(Stop, V), d(Long, V), DMB};
+d({571, Start, Stop, Long, DMB, Dur}, V) when V >= 2 ->
+ {'DigitMapValue', d(Start, V), d(Stop, V), d(Long, V), DMB, d(Dur, V)};
+
+d({580, M, A, Ver, Prof, R, D, Id}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ asn1_NOVALUE, asn1_NOVALUE};
+d({581, M, A, Ver, Prof, R, D, Id, TS}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), asn1_NOVALUE};
+d({582, M, A, Ver, Prof, R, D, Id, TS, NSD}, V) ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD};
+
+d({583, M, A, Ver, Prof, R, D, Id, TS, NSD}, V)
+ when V == 2 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, asn1_NOVALUE};
+d({584, M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V == 2 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V)};
+
+d({585, M, A, Ver, Prof, R, D, Id, TS, NSD}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, asn1_NOVALUE, asn1_NOVALUE};
+d({586, M, A, Ver, Prof, R, D, Id, TS, NSD, Info}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V), asn1_NOVALUE};
+d({587, M, A, Ver, Prof, R, D, Id, TS, NSD, Info, Flag}, V)
+ when V >= 3 ->
+ {'ServiceChangeParm',
+ d(M, V), d(A, V), d(Ver, V), d(Prof, V), R, d(D, V), d(Id, V),
+ d(TS, V), NSD, d(Info, V), d(Flag, V)};
+
+d({590, Id, A, Ver, Prof, TS}, V) ->
+ {serviceChangeResParms, {'ServiceChangeResParm', Id, d(A, V), Ver, d(Prof, V), TS}};
+d({591, SCRP}, V) ->
+ {serviceChangeResParms, d(SCRP, V)};
+d({592, Id, A, Ver, Prof, TS}, V) ->
+ {'ServiceChangeResParm', Id, d(A, V), Ver, d(Prof, V), TS};
+
+d({600, N}, _V) ->
+ {portNumber, N};
+
+d({610, D, T}, _V) ->
+ {'TimeNotation', D, T};
+
+d({620, N, Ver}, _V) ->
+ {'ServiceChangeProfile', N, Ver};
+
+d({630, N}, _) ->
+ {digitMapName, N};
+
+d({640, Id}, _V) ->
+ {megaco_term_id, false, Id};
+d({641}, _V) ->
+ {megaco_term_id, true, [[$*]]};
+d({642}, _V) ->
+ {megaco_term_id, true, [[$$]]};
+d({643, Id}, _V) ->
+ {megaco_term_id, true, Id};
+d({644, W, ID}, _V) ->
+ {'TerminationID', W, ID};
+
+d({650, TID}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({651, TID, TA}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({652, TID, TA}, V) ->
+ {modReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({653, R}, V) ->
+ {modReply, d(R, V)};
+
+d({655, AR}, V) ->
+ {moveReply, d(AR, V)};
+
+d({660, TID}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({661, TID, TA}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({662, TID, TA}, V) ->
+ {addReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({663, R}, V) ->
+ {addReply, d(R, V)};
+
+d({670, TID}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), asn1_NOVALUE}};
+d({671, TID, TA}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), [d(TA, V)]}};
+d({672, TID, TA}, V) ->
+ {subtractReply, {'AmmsReply', dl(TID, V), dl(TA, V)}};
+d({673, R}, V) ->
+ {subtractReply, d(R, V)};
+
+d({680, TID}, V) ->
+ {'AmmsReply', dl(TID, V), asn1_NOVALUE};
+d({681, TID, TA}, V) ->
+ {'AmmsReply', dl(TID, V), [d(TA, V)]};
+d({682, TID, TA}, V) ->
+ {'AmmsReply', dl(TID, V), dl(TA, V)};
+
+d({690, TID}, V) ->
+ {notifyReply, {'NotifyReply', dl(TID, V), asn1_NOVALUE}};
+d({691, TID, ED}, V) ->
+ {notifyReply, {'NotifyReply', dl(TID, V), d(ED, V)}};
+d({692, R}, V) ->
+ {notifyReply, d(R, V)};
+d({693, TID}, V) ->
+ {'NotifyReply', dl(TID, V), asn1_NOVALUE};
+d({694, TID, ED}, V) ->
+ {'NotifyReply', dl(TID, V), d(ED, V)};
+
+d({700, AVR}, V) ->
+ {auditValueReply, d(AVR, V)};
+
+d({705, TIDs}, V) ->
+ {contextAuditResult, dl(TIDs, V)};
+
+d({710, TID, TAR}, V) ->
+ {auditResult, {'AuditResult', d(TID, V), [d(TAR, V)]}};
+d({711, TID, TAR}, V) ->
+ {auditResult, {'AuditResult', d(TID, V), dl(TAR, V)}};
+d({712, AR}, V) ->
+ {auditResult, d(AR, V)};
+d({713, TID, TAR}, V) ->
+ {'AuditResult', d(TID, V), [d(TAR, V)]};
+d({714, TID, TAR}, V) ->
+ {'AuditResult', d(TID, V), dl(TAR, V)};
+
+d({715, TIDs, [TAR]}, V) ->
+ {auditResultTermList, {'TermListAuditResult', dl(TIDs, V), [d(TAR, V)]}};
+d({716, TIDs, TAR}, V) ->
+ {auditResultTermList, {'TermListAuditResult', dl(TIDs, V), dl(TAR, V)}};
+
+d({720, PsD}, V) ->
+ {packagesDescriptor, dl(PsD, V)};
+
+d({730}, _V) ->
+ {'PackagesItem', "g", 1};
+d({731}, _V) ->
+ {'PackagesItem', "tonegen", 1};
+d({732}, _V) ->
+ {'PackagesItem', "tonedet", 1};
+d({733}, _V) ->
+ {'PackagesItem', "tg", 1};
+d({734}, _V) ->
+ {'PackagesItem', "dd", 1};
+d({735}, _V) ->
+ {'PackagesItem', "cg", 1};
+d({736}, _V) ->
+ {'PackagesItem', "cd", 1};
+d({737}, _V) ->
+ {'PackagesItem', "al", 1};
+d({738}, _V) ->
+ {'PackagesItem', "ct", 1};
+d({739}, _V) ->
+ {'PackagesItem', "nt", 1};
+d({740}, _V) ->
+ {'PackagesItem', "rtp", 1};
+d({741}, _V) ->
+ {'PackagesItem', "tdmc", 1};
+d({742, Name, Ver}, _V) ->
+ {'PackagesItem', Name, Ver};
+
+d({760, AD}, V) ->
+ {emptyDescriptors, d(AD, V)};
+
+d({770, SD}, V) ->
+ {statisticsDescriptor, [d(SD, V)]};
+d({771, SsD}, V) ->
+ {statisticsDescriptor, dl(SsD, V)};
+
+d({780, Name}, _V) ->
+ {'StatisticsParameter', Name, asn1_NOVALUE};
+d({781, Name, Value}, _V) ->
+ {'StatisticsParameter', Name, Value};
+
+d({800, MT, TL}, V) ->
+ {'MuxDescriptor', d(MT, V), dl(TL, V), asn1_NOVALUE};
+d({801, MT, TL, NSD}, V) ->
+ {'MuxDescriptor', d(MT, V), dl(TL, V), NSD};
+
+d({900, N, Ver}, V) when (V >= 2) ->
+ {indAudPackagesDescriptor, {'IndAudPackagesDescriptor', N, Ver}};
+d({900, IAPD}, V) when (V >= 2) ->
+ {indAudPackagesDescriptor, d(IAPD, V)};
+d({901, N, Ver}, V) when (V >= 2) ->
+ {'IndAudPackagesDescriptor', N, Ver};
+
+d({910, N}, V) when (V >= 2) ->
+ {indAudStatisticsDescriptor, {'IndAudStatisticsDescriptor', N}};
+d({911, IASD}, V) when (V >= 2) ->
+ {indAudStatisticsDescriptor, d(IASD, V)};
+d({912, N}, V) when (V >= 2) ->
+ {'IndAudStatisticsDescriptor', N};
+
+d({920, DMN}, V) when (V >= 2) ->
+ {indAudDigitMapDescriptor, {'IndAudDigitMapDescriptor', DMN}};
+d({921, IADMD}, V) when (V >= 2) ->
+ {indAudDigitMapDescriptor, d(IADMD, V)};
+d({922, DMN}, V) when (V >= 2) ->
+ {'IndAudDigitMapDescriptor', DMN};
+
+d({930, IASD}, V) when (V >= 2) ->
+ {indAudSignalsDescriptor, {seqSigList, d(IASD, V)}};
+d({931, IAS}, V) when (V >= 2) ->
+ {indAudSignalsDescriptor, {signal, d(IAS, V)}};
+
+d({940, Id, SL}, V) when (V >= 2) ->
+ {'IndAudSeqSigList', Id, d(SL, V)};
+
+d({950, N, SID}, 2 = V) ->
+ {'IndAudSignal', N, d(SID, V)};
+d({951, N, SID}, V) when (V >= 3) ->
+ {'IndAudSignal', N, d(SID, V), asn1_NOVALUE};
+d({952, N, SID, RID}, V) when (V >= 3) ->
+ {'IndAudSignal', N, d(SID, V), d(RID, V)};
+
+d({960, EN, SID}, V) when (V >= 2) ->
+ {indAudEventBufferDescriptor,
+ {'IndAudEventBufferDescriptor', EN, d(SID, V)}};
+d({961, IAEBD}, V) when (V >= 2) ->
+ {indAudEventBufferDescriptor, d(IAEBD, V)};
+d({962, EN, SID}, V) when (V >= 2) ->
+ {'IndAudEventBufferDescriptor', EN, d(SID, V)};
+
+d({970, RID, N, SID}, V) when (V >= 2) ->
+ {indAudEventsDescriptor,
+ {'IndAudEventsDescriptor', d(RID, V), N, d(SID, V)}};
+d({971, IAED}, V) when (V >= 2) ->
+ {indAudEventsDescriptor, d(IAED, V)};
+d({972, RID, N, SID}, V) when (V >= 2) ->
+ {'IndAudEventsDescriptor', d(RID, V), N, d(SID, V)};
+
+d({980, TSD, S}, V) when (V >= 2) ->
+ {indAudMediaDescriptor, {'IndAudMediaDescriptor', d(TSD, V), d(S, V)}};
+d({981, IAMD}, V) when (V >= 2) ->
+ {indAudMediaDescriptor, d(IAMD, V)};
+d({982, TSD, S}, V) when (V >= 2) ->
+ {'IndAudMediaDescriptor', d(TSD, V), d(S, V)};
+
+d({990, PP, EBC, SS}, 2 = V) ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V)};
+d({991, PP, EBC, SS}, V) when V >= 3 ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V),
+ asn1_NOVALUE};
+d({992, PP, EBC, SS, SSS}, V) when V >= 3 ->
+ {'IndAudTerminationStateDescriptor', dl(PP, V), d(EBC, V), d(SS, V),
+ d(SSS, V)};
+
+d({1000, SID, SP}, V) ->
+ {'IndAudStreamDescriptor', d(SID, V), d(SP, V)};
+
+d({1010, LCD}, 2 = V) ->
+ {'IndAudStreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1011, LCD, LD, RD}, 2 = V) ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V)};
+d({1012, LCD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE};
+d({1013, LCD, LD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1014, LCD, LD, RD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V), asn1_NOVALUE};
+d({1015, LCD, LD, RD, SD}, V) when V >= 3 ->
+ {'IndAudStreamParms', d(LCD, V), d(LD, V), d(RD, V), d(SD, V)};
+
+d({1020, SM, RV, RG}, 2 = V) ->
+ {'IndAudLocalControlDescriptor',
+ d(SM, V), d(RV, V), d(RG, V), asn1_NOVALUE};
+d({1021, SM, RV, RG, PP}, 2 = V)
+ when is_list(PP) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V)};
+d({1022, SM, RV, RG}, V) when (V >= 3) ->
+ {'IndAudLocalControlDescriptor',
+ d(SM, V), d(RV, V), d(RG, V), asn1_NOVALUE, asn1_NOVALUE};
+d({1023, SM, RV, RG, PP}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V),
+ asn1_NOVALUE};
+d({1024, SM, RV, RG, PP, SMS}, V)
+ when is_list(PP) andalso (V >= 3) ->
+ {'IndAudLocalControlDescriptor', d(SM, V), d(RV, V), d(RG, V), dl(PP, V),
+ d(SMS, V)};
+
+d({1030, N}, 2 = _V) ->
+ {'IndAudPropertyParm', N};
+d({1031, N}, V) when V >= 3 ->
+ {'IndAudPropertyParm', N, asn1_NOVALUE};
+d({1032, N, PP}, V) when V >= 3 ->
+ {'IndAudPropertyParm', N, d(PP, V)};
+
+d({1100}, _V) ->
+ oneway;
+d({1101}, _V) ->
+ bothway;
+d({1102}, _V) ->
+ isolate;
+d({1103}, _V) ->
+ onewayexternal;
+d({1104}, _V) ->
+ onewayboth;
+
+d(T, _V) ->
+ %% io:format("d(~w) -> ~nT: ~w~n", [_V, T]),
+ T.
+
+
+%% i(F, A) ->
+%% %% i(get(dbg), F, A).
+%% i(true, F, A).
+
+%% i(true, F, A) ->
+%% io:format("DBG:" ++ F ++ "~n", A);
+%% i(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/engine/megaco_filter.erl b/lib/megaco/src/engine/megaco_filter.erl
new file mode 100644
index 0000000000..23a91b1f1d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_filter.erl
@@ -0,0 +1,350 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : megaco/H.248 customization of generic event tracer
+%%----------------------------------------------------------------------
+
+-module(megaco_filter).
+
+-export([start/0, start/1, filter/1,
+ pretty_error/1, string_to_term/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include_lib("et/include/et.hrl").
+
+start() ->
+ start([]).
+
+start(ExtraOptions) ->
+ Options =
+ [{event_order, event_ts},
+ {scale, 3},
+ {max_actors, infinity},
+ {trace_pattern, {megaco, max}},
+ {trace_global, true},
+ {dict_insert, {filter, ?MODULE}, fun filter/1},
+ {active_filter, ?MODULE},
+ {title, "Megaco tracer - Erlang/OTP"} | ExtraOptions],
+ et_viewer:start(Options).
+
+filter(E) when is_record(E, event) ->
+ From = filter_actor(E#event.from),
+ To = filter_actor(E#event.to),
+ E2 = E#event{from = From, to = To},
+ E3 = filter_contents(E#event.contents, E2, []),
+ {true, E3}.
+
+filter_actors(From, To, E)
+ when (E#event.from =:= ?APPLICATION) andalso (E#event.to =:= ?APPLICATION) ->
+ Label = E#event.label,
+ case lists:prefix("callback:", Label) of
+ true ->
+ E#event{from = filter_actor(From),
+ to = filter_user_actor(From)};
+ false ->
+ case lists:prefix("return:", Label) of
+ true ->
+ E#event{from = filter_user_actor(From),
+ to = filter_actor(From)};
+ false ->
+ case lists:prefix("receive bytes", Label) of
+ true ->
+ E#event{from = filter_actor(To),
+ to = filter_actor(From)};
+ false ->
+ E#event{from = filter_actor(From),
+ to = filter_actor(To)}
+ end
+ end
+ end;
+filter_actors(_From, _To, E) ->
+ E.
+
+filter_actor(Actor) ->
+ String = do_filter_actor(Actor),
+ if
+ length(String) > 21 ->
+ string:substr(String, 1, 21) ++ [$*];
+ true ->
+ String
+ end.
+
+filter_user_actor(Actor) ->
+ String = do_filter_actor(Actor) ++ "@user",
+ if
+ length(String) > 21 ->
+ string:substr(String, 1, 21) ++ [$*];
+ true ->
+ String
+ end.
+
+do_filter_actor(CH) when is_record(CH, megaco_conn_handle) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ do_filter_actor(Mid);
+do_filter_actor(Actor) ->
+ case Actor of
+ {ip4Address, {'IP4Address', [A1,A2,A3,A4], asn1_NOVALUE}} ->
+ integer_to_list(A1) ++ [$.] ++
+ integer_to_list(A2) ++ [$.] ++
+ integer_to_list(A3) ++ [$.] ++
+ integer_to_list(A4);
+ {ip4Address, {'IP4Address', [A1,A2,A3,A4], Port}} ->
+ integer_to_list(A1) ++ [$.] ++
+ integer_to_list(A2) ++ [$.] ++
+ integer_to_list(A3) ++ [$.] ++
+ integer_to_list(A4) ++ [$:] ++
+ integer_to_list(Port);
+ {domainName, {'DomainName', Name, asn1_NOVALUE}} ->
+ Name;
+ {domainName, {'DomainName', Name, Port}} ->
+ Name ++ [$:] ++ integer_to_list(Port);
+ {deviceName, Name} ->
+ Name;
+ unknown_remote_mid ->
+ "preliminary_mid";
+ preliminary_mid ->
+ "preliminary_mid";
+ megaco ->
+ megaco;
+ _Other ->
+ "UNKNOWN"
+ end.
+
+filter_contents([], E, Contents) ->
+ E#event{contents = lists:flatten(lists:reverse(Contents))};
+filter_contents([H | T], E, Contents) ->
+ case H of
+ {line, _Mod, _Line} ->
+ filter_contents(T, E, Contents);
+ CD when is_record(CD, conn_data) ->
+ CH = CD#conn_data.conn_handle,
+ From = CH#megaco_conn_handle.local_mid,
+ To = CH#megaco_conn_handle.remote_mid,
+ E2 = filter_actors(From, To, E),
+ Serial = CD#conn_data.serial,
+ E3 = append_serial(Serial, E2),
+ filter_contents(T, E3, Contents);
+ CH when is_record(CH, megaco_conn_handle) ->
+ From = CH#megaco_conn_handle.local_mid,
+ To = CH#megaco_conn_handle.remote_mid,
+ E2 = filter_actors(From, To, E),
+ filter_contents(T, E2, Contents);
+ {orig_conn_handle, _CH} ->
+ filter_contents(T, E, Contents);
+ RH when is_record(RH, megaco_receive_handle) ->
+ Actor = RH#megaco_receive_handle.local_mid,
+ E2 = filter_actors(Actor, Actor, E),
+ filter_contents(T, E2, Contents);
+ {pid, Pid} when is_pid(Pid) ->
+ filter_contents(T, E, Contents);
+ pending ->
+ filter_contents(T, E, Contents);
+ reply ->
+ filter_contents(T, E, Contents);
+ {error, Reason} ->
+ Pretty = pretty_error({error, Reason}),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ {'EXIT', Reason} ->
+ Pretty = pretty_error({'EXIT', Reason}),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ ED when is_record(ED, 'ErrorDescriptor') ->
+ Pretty = pretty_error(ED),
+ E2 = prepend_error(E),
+ filter_contents(T, E2, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionRequest') ->
+ Pretty = pretty({trans, {transactionRequest, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionReply') ->
+ Pretty = pretty({trans, {transactionReply, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionPending') ->
+ Pretty = pretty({trans, {transactionPending, Trans}}),
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Trans when is_record(Trans, 'TransactionAck') ->
+ Pretty = pretty({trans, {transactionResponseAck, [Trans]}}),
+ case Trans#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ filter_contents([], E, [[Pretty, "\n"], Contents]);
+ Last ->
+ Label = term_to_string(E#event.label),
+ E2 = E#event{label = Label ++ ".." ++ integer_to_list(Last)},
+ filter_contents([], E2, [[Pretty, "\n"], Contents])
+ end;
+ {context_id, _ContextId} ->
+ Pretty = pretty(H),
+ filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ {command_request, CmdReq} ->
+ Pretty = pretty(CmdReq),
+ filter_contents(T, E, [[Pretty, "\n"], Contents]);
+ {user_reply, {ok, ARS}} ->
+ Pretty = [[pretty(AR), "\n"] || AR <- ARS],
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ {user_reply, Error} ->
+ Pretty = pretty_error(Error),
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ {actionReplies, ARS} ->
+ Pretty = [[pretty(AR), "\n"] || AR <- ARS],
+ filter_contents(T, E, [["REPLY: \n", Pretty, "\n"], Contents]);
+ MegaMsg when is_record(MegaMsg, 'MegacoMessage') ->
+ Pretty = pretty(MegaMsg),
+ filter_contents(T, E, [["MESSAGE: \n", Pretty, "\n"], Contents]);
+ {bytes, Bin} when is_binary(Bin) ->
+ E2 =
+ case E#event.label of
+ [$s, $e, $n, $d, $ , $b, $y, $t, $e, $s | Tail] ->
+ L = lists:concat(["send ", size(Bin), " bytes", Tail]),
+ E#event{label = L};
+ [$r, $e, $c, $e, $i, $v, $e, $ , $b, $y, $t, $e, $s | Tail] ->
+ L = lists:concat(["receive ", size(Bin), " bytes", Tail]),
+ E#event{label = L};
+ _ ->
+ E
+ end,
+ CharList = erlang:binary_to_list(Bin),
+ filter_contents(T, E2, [[CharList , "\n"], Contents]);
+ [] ->
+ filter_contents(T, E, Contents);
+ {test_lib, _Mod, _Fun} ->
+ filter_contents(T, E, Contents);
+ Other ->
+ Pretty = pretty(Other),
+ filter_contents(T, E, [[Pretty, "\n"], Contents])
+ end.
+
+append_serial(Serial, E) when is_integer(Serial) ->
+ Label = term_to_string(E#event.label),
+ E#event{label = Label ++ " #" ++ integer_to_list(Serial)};
+append_serial(_Serial, E) ->
+ E.
+
+prepend_error(E) ->
+ Label = term_to_string(E#event.label),
+ E#event{label = "<ERROR> " ++ Label}.
+
+pretty({context_id, ContextId}) ->
+ if
+ ContextId =:= ?megaco_null_context_id ->
+ ["CONTEXT ID: -\n"];
+ ContextId =:= ?megaco_choose_context_id ->
+ ["CONTEXT ID: $\n"];
+ ContextId =:= ?megaco_all_context_id ->
+ ["CONTEXT ID: *\n"];
+ is_integer(ContextId) ->
+ ["CONTEXT ID: ",integer_to_list(ContextId), "\n"]
+ end;
+pretty(MegaMsg) when is_record(MegaMsg, 'MegacoMessage') ->
+ case catch megaco_pretty_text_encoder:encode_message([], MegaMsg) of
+ {ok, Bin} ->
+ term_to_string(Bin);
+ _Bad ->
+ term_to_string(MegaMsg)
+ end;
+pretty(CmdReq) when is_record(CmdReq, 'CommandRequest') ->
+ case catch megaco_pretty_text_encoder:encode_command_request(CmdReq) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(CmdReq)
+ end;
+pretty({complete_success, ContextId, RepList} = Res) ->
+ ActRep = #'ActionReply'{contextId = ContextId,
+ commandReply = RepList},
+ case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Res)
+ end;
+pretty(AR) when is_record(AR, 'ActionReply') ->
+ case catch megaco_pretty_text_encoder:encode_action_reply(AR) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(AR)
+ end;
+pretty({partial_failure, ContextId, RepList} = Res) ->
+ ActRep = #'ActionReply'{contextId = ContextId,
+ commandReply = RepList},
+ case catch megaco_pretty_text_encoder:encode_action_reply(ActRep) of
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Res)
+ end;
+pretty({trans, Trans}) ->
+ case catch megaco_pretty_text_encoder:encode_transaction(Trans) of
+ {ok, Bin} when is_binary(Bin) ->
+ IoList2 = lists:flatten(binary_to_list(Bin)),
+ term_to_string(IoList2);
+ {ok, IoList} ->
+ IoList2 = lists:flatten(IoList),
+ term_to_string(IoList2);
+ _Bad ->
+ term_to_string(Trans)
+ end;
+pretty(Other) ->
+ term_to_string(Other).
+
+pretty_error({error, Reason}) ->
+ ["ERROR: ", pretty_error(Reason)];
+pretty_error({'EXIT', Reason}) ->
+ ["EXIT: ", pretty_error(Reason)];
+pretty_error({'ErrorDescriptor', Code, Reason}) ->
+ ["CODE: ", integer_to_list(Code), " TEXT: ", pretty_error(Reason)];
+pretty_error(Ugly) ->
+ case string_to_term(Ugly) of
+ {ok, Pretty} -> ["\n", Pretty];
+ _ -> ["\n", term_to_string(Ugly)]
+ end.
+
+string_to_term(Chars) ->
+ do_string_to_term([], Chars, 1).
+
+do_string_to_term(Cont, Chars, Line) ->
+ case catch erl_scan:tokens(Cont, Chars, Line) of
+ {done, {ok, Tokens, _EndLine}, _Rest} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, Term} ->
+ {ok, Term};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {more, Cont2} ->
+ do_string_to_term(Cont2, ". ", Line);
+ Other ->
+ {error, Other}
+ end.
+
+term_to_string(Bin) when is_binary(Bin) ->
+ binary_to_list(Bin);
+term_to_string(Term) ->
+ case catch io_lib:format("~s", [Term]) of
+ {'EXIT', _} -> lists:flatten(io_lib:format("~p", [Term]));
+ GoodString -> lists:flatten(GoodString)
+ end.
diff --git a/lib/megaco/src/engine/megaco_message_internal.hrl b/lib/megaco/src/engine/megaco_message_internal.hrl
new file mode 100644
index 0000000000..44f38752a9
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_message_internal.hrl
@@ -0,0 +1,159 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Generated by the Erlang ASN.1 compiler version:1.2.7
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module MEDIA-GATEWAY-CONTROL
+%%----------------------------------------------------------------------
+
+-record('MegacoMessage',
+ {
+ authHeader = asn1_NOVALUE,
+ mess
+ }).
+
+-record('AuthenticationHeader',
+ {
+ secParmIndex,
+ seqNum,
+ ad
+ }).
+
+-record('Message',
+ {
+ version,
+ mId,
+ messageBody
+ }). % with extension mark
+
+-record('DomainName',
+ {
+ name,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP4Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('IP6Address',
+ {
+ address,
+ portNumber = asn1_NOVALUE
+ }).
+
+-record('TransactionRequest',
+ {
+ transactionId,
+ actions
+ }). % with extension mark
+
+-record('TransactionPending',
+ {
+ transactionId
+ }). % with extension mark
+
+
+%% --- TransactionReply ---
+
+-record('megaco_transaction_reply',
+ {
+ transactionId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult,
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ }).
+
+
+%% %% Pre v3 record def:
+%% -record('TransactionReply',
+%% {
+%% transactionId,
+%% immAckRequired = asn1_NOVALUE,
+%% transactionResult
+%% }). %% with extension mark
+
+%% %% v3 record def:
+%% -record('TransactionReply',
+%% {
+%% transactionId,
+%% immAckRequired = asn1_NOVALUE,
+%% transactionResult,
+%% %% with extension mark -- v3 --
+%% segmentNumber = asn1_NOVALUE,
+%% segmentationComplete = asn1_NOVALUE
+%% }).
+
+
+%% -- v3 --
+-record('SegmentReply',
+ {
+ transactionId,
+ segmentNumber,
+ segmentationComplete = asn1_NOVALUE
+ }). % with extension mark
+
+
+-record('TransactionAck',
+ {
+ firstAck,
+ lastAck = asn1_NOVALUE
+ }).
+
+-record('ErrorDescriptor',
+ {
+ errorCode,
+ errorText = asn1_NOVALUE
+ }).
+
+-record('DigitMapDescriptor',
+ {
+ digitMapName = asn1_NOVALUE,
+ digitMapValue = asn1_NOVALUE
+ }).
+
+-record('DigitMapValue',
+ {
+ startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ %% BUGBUG BUGBUG
+ %% Note that there should not really be a default value
+ %% for this item, but a problem with the flex scanner
+ %% makes it neccessary to swap the values of digitMapBody
+ %% and durationTimer. The same is done in the (erl) scanner
+ %% just so they behave the same. The values are later
+ %% swapped back by the parser...
+ digitMapBody = asn1_NOVALUE,
+ %% with extensions
+ durationTimer = asn1_NOVALUE
+ }).
+
+
+-record('TerminationID',
+ {
+ wildcard,
+ id
+ }). % with extension mark
+
diff --git a/lib/megaco/src/engine/megaco_messenger.erl b/lib/megaco/src/engine/megaco_messenger.erl
new file mode 100644
index 0000000000..a9e4fd67b2
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_messenger.erl
@@ -0,0 +1,5158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Send and process a (sequence of) Megaco/H.248 transactions
+%%----------------------------------------------------------------------
+
+-module(megaco_messenger).
+
+%% Application internal export
+-export([
+ process_received_message/4, process_received_message/5,
+ receive_message/4, receive_message/5,
+ connect/4, connect/5,
+ disconnect/2,
+ encode_actions/3,
+ call/3,
+ cast/3,
+ cancel/2,
+ request_timeout/2,
+ request_keep_alive_timeout/2,
+ pending_timeout/3,
+ reply_timeout/3,
+ segment_timeout/3,
+ %% segment_reply_timeout/4,
+
+ test_request/5,
+ test_reply/5
+ ]).
+
+%% MIB stat functions
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+%% Misc functions
+-export([
+ cleanup/2,
+ which_requests/1, which_replies/1
+ ]).
+
+%% Module internal export
+-export([
+ process_received_message/6,
+ handle_request/2,
+ handle_long_request/2,
+ connect_remote/3,
+ disconnect_local/2,
+ disconnect_remote/3,
+ send_request_remote/4,
+ receive_reply_remote/2, receive_reply_remote/3
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+%% N.B. Update cancel/1 with '_' when a new field is added
+-record(request,
+ {trans_id,
+ remote_mid,
+ timer_ref, % {short, Ref} | {long, Ref}
+ init_timer,
+ init_long_timer,
+ curr_timer,
+ version,
+ bytes, % {send, Data} | {no_send, Data}, Data = binary() | tuple()
+ send_handle,
+ user_mod,
+ user_args,
+ reply_action, % call | cast
+ reply_data,
+ seg_recv = [], % [integer()] (received segments)
+ init_seg_timer,
+ seg_timer_ref,
+ keep_alive_timer, % plain | integer() >= 0
+ keep_alive_ref % undefined | ref()
+ }).
+
+
+%% N.B. Update cancel/1 with '_' when a new field is added
+-record(reply,
+ {
+ trans_id,
+ local_mid,
+ state = prepare, % prepare | eval_request | waiting_for_ack | aborted
+ pending_timer_ref,
+ handler = undefined, % pid of the proc executing the callback func
+ timer_ref,
+ version,
+ %% bytes: Sent reply data: not acknowledged
+ bytes, % binary() | [{integer(), binary(), timer_ref()}]
+ ack_action, % discard_ack | {handle_ack, Data}
+ send_handle,
+ %% segments: Not sent reply data (segments)
+ segments = [] % [{integer(), binary()}]
+ }).
+
+-record(trans_id,
+ {
+ mid,
+ serial
+ }).
+
+
+-ifdef(MEGACO_TEST_CODE).
+-define(SIM(Other,Where),
+ fun(Afun,Bfun) ->
+ Kfun = {?MODULE,Bfun},
+ case (catch ets:lookup(megaco_test_data, Kfun)) of
+ [{Kfun,Cfun}] ->
+ Cfun(Afun);
+ _ ->
+ Afun
+ end
+ end(Other,Where)).
+-define(TC_AWAIT_CANCEL_EVENT(),
+ case megaco_tc_controller:lookup(block_on_cancel) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self()},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ {value, {sleep, To}} when is_integer(To) andalso (To > 0) ->
+ receive after To -> ok end;
+ _ ->
+ ok
+ end).
+-define(TC_AWAIT_REPLY_EVENT(Info),
+ case megaco_tc_controller:lookup(block_on_reply) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self(), Info},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ _Whatever ->
+ %% io:format("Whatever: ~p~n", [Whatever]),
+ ok
+ end).
+-else.
+-define(SIM(Other,Where),Other).
+-define(TC_AWAIT_CANCEL_EVENT(),ok).
+-define(TC_AWAIT_REPLY_EVENT(_),ok).
+-endif.
+
+
+-define(report_pending_limit_exceeded(ConnData),
+ ?report_important(ConnData, "<ERROR> pending limit exceeded", [])).
+
+-ifdef(megaco_extended_trace).
+-define(rt1(T,F,A),?report_trace(T,F,A)).
+-define(rt2(F,A), ?rt1(ignore,F,A)).
+-define(rt3(F), ?rt2(F,[])).
+-else.
+-define(rt1(T,F,A),ok).
+-define(rt2(F,A), ok).
+-define(rt3(F), ok).
+-endif.
+
+
+%%----------------------------------------------------------------------
+%% SNMP statistics handling functions
+%%----------------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+
+get_stats() ->
+ megaco_stats:get_stats(megaco_stats).
+
+get_stats(ConnHandleOrCounter) ->
+ megaco_stats:get_stats(megaco_stats, ConnHandleOrCounter).
+
+get_stats(ConnHandle, Counter) ->
+ megaco_stats:get_stats(megaco_stats, ConnHandle, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters)
+%%-----------------------------------------------------------------
+
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_stats).
+
+reset_stats(ConnHandleOrCounter) ->
+ megaco_stats:reset_stats(megaco_stats, ConnHandleOrCounter).
+
+
+
+%%----------------------------------------------------------------------
+%% cleanup utility functions
+%%----------------------------------------------------------------------
+
+cleanup(#megaco_conn_handle{local_mid = LocalMid}, Force)
+ when (Force =:= true) orelse (Force =:= false) ->
+ Pat = #reply{trans_id = '$1',
+ local_mid = LocalMid,
+ state = '$2',
+ _ = '_'},
+ do_cleanup(Pat, Force);
+cleanup(LocalMid, Force)
+ when (Force =:= true) orelse (Force =:= false) ->
+ Pat = #reply{trans_id = '$1',
+ local_mid = LocalMid,
+ state = '$2',
+ _ = '_'},
+ do_cleanup(Pat, Force).
+
+do_cleanup(Pat, Force) ->
+ Match = megaco_monitor:which_replies(Pat),
+ Reps = [{V1, V2} || [V1, V2] <- Match],
+ do_cleanup2(Reps, Force).
+
+do_cleanup2([], _) ->
+ ok;
+do_cleanup2([{TransId, aborted}|T], Force = false) ->
+ megaco_monitor:delete_reply(TransId),
+ do_cleanup2(T, Force);
+do_cleanup2([_|T], Force = false) ->
+ do_cleanup2(T, Force);
+do_cleanup2([{TransId, _State}|T], Force = true) ->
+ megaco_monitor:delete_reply(TransId),
+ do_cleanup2(T, Force).
+
+
+%%----------------------------------------------------------------------
+%% which_requests and which_replies utility functions
+%%----------------------------------------------------------------------
+
+which_requests(#megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid}) ->
+ Pat1 = #trans_id{mid = LocalMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #request{trans_id = Pat1,
+ remote_mid = RemoteMid,
+ _ = '_'},
+ Match = megaco_monitor:which_requests(Pat2),
+ [S || [S] <- Match];
+which_requests(LocalMid) ->
+ Pat1 = #trans_id{mid = LocalMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #request{trans_id = Pat1,
+ remote_mid = '$2', _ = '_'},
+ Match0 = megaco_monitor:which_requests(Pat2),
+ Match1 = [{mk_ch(LocalMid, V2), V1} || [V1, V2] <- Match0],
+ which_requests1(lists:sort(Match1)).
+
+which_requests1([]) ->
+ [];
+which_requests1([{CH, S}|T]) ->
+ which_requests2(T, CH, [S], []).
+
+which_requests2([], CH, Serials, Reqs) ->
+ lists:reverse([{CH, Serials}|Reqs]);
+which_requests2([{CH, S}|T], CH, Serials, Reqs) ->
+ which_requests2(T, CH, [S|Serials], Reqs);
+which_requests2([{CH1, S}|T], CH2, Serials, Reqs) ->
+ which_requests2(T, CH1, [S], [{CH2, lists:reverse(Serials)}| Reqs]).
+
+
+which_replies(#megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid}) ->
+ Pat1 = #trans_id{mid = RemoteMid,
+ serial = '$1', _ = '_'},
+ Pat2 = #reply{trans_id = Pat1,
+ local_mid = LocalMid,
+ state = '$2',
+ handler = '$3', _ = '_'},
+ Match = megaco_monitor:which_replies(Pat2),
+ [{V1, V2, V3} || [V1, V2, V3] <- Match];
+which_replies(LocalMid) ->
+ Pat1 = #trans_id{mid = '$1',
+ serial = '$2', _ = '_'},
+ Pat2 = #reply{trans_id = Pat1,
+ local_mid = LocalMid,
+ state = '$3',
+ handler = '$4', _ = '_'},
+ Match0 = megaco_monitor:which_replies(Pat2),
+ Match1 = [{mk_ch(LocalMid,V1),{V2,V3,V4}} || [V1, V2, V3, V4] <- Match0],
+ which_replies1(lists:sort(Match1)).
+
+which_replies1([]) ->
+ [];
+which_replies1([{CH, Data}|T]) ->
+ which_replies2(T, CH, [Data], []).
+
+which_replies2([], CH, Data, Reps) ->
+ lists:reverse([{CH, Data}|Reps]);
+which_replies2([{CH, Data}|T], CH, Datas, Reps) ->
+ which_replies2(T, CH, [Data|Datas], Reps);
+which_replies2([{CH1, Data}|T], CH2, Datas, Reps) ->
+ which_replies2(T, CH1, [Data], [{CH2, lists:reverse(Datas)}| Reps]).
+
+
+mk_ch(LM, RM) ->
+ #megaco_conn_handle{local_mid = LM, remote_mid = RM}.
+
+
+%%----------------------------------------------------------------------
+%% Register/unreister connections
+%%----------------------------------------------------------------------
+
+%% Returns {ok, ConnHandle} | {error, Reason}
+autoconnect(RH, RemoteMid, SendHandle, ControlPid, Extra)
+ when is_record(RH, megaco_receive_handle) ->
+ ?rt2("autoconnect", [RH, RemoteMid, SendHandle, ControlPid]),
+ case megaco_config:autoconnect(RH, RemoteMid, SendHandle, ControlPid) of
+ {ok, ConnData} ->
+ do_connect(ConnData, Extra);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+autoconnect(BadHandle, _CH, _SendHandle, _ControlPid, _Extra) ->
+ {error, {bad_receive_handle, BadHandle}}.
+
+connect(RH, RemoteMid, SendHandle, ControlPid) ->
+ Extra = ?default_user_callback_extra,
+ connect(RH, RemoteMid, SendHandle, ControlPid, Extra).
+connect(RH, RemoteMid, SendHandle, ControlPid, Extra)
+ when is_record(RH, megaco_receive_handle) ->
+ ?rt2("connect", [RH, RemoteMid, SendHandle, ControlPid, Extra]),
+
+ %% The purpose of this is to have a temoporary process, to
+ %% which one can set up a monitor or link and get a
+ %% notification when process exits. The entire connect is
+ %% done in the temporary worker process.
+ %% When it exits, the connect is either successfully done
+ %% or it failed.
+
+ ConnectorFun =
+ fun() ->
+
+ ConnectResult =
+ case megaco_config:connect(RH, RemoteMid,
+ SendHandle, ControlPid) of
+ {ok, ConnData} ->
+ do_connect(ConnData, Extra);
+ {error, Reason} ->
+ {error, Reason}
+ end,
+ ?rt2("connector: connected", [self(), ConnectResult]),
+ exit({result, ConnectResult})
+ end,
+ Flag = process_flag(trap_exit, true),
+ Connector = erlang:spawn_link(ConnectorFun),
+ receive
+ {'EXIT', Connector, {result, ConnectResult}} ->
+ ?rt2("connect result: received expected connector exit signal",
+ [Connector, ConnectResult]),
+ process_flag(trap_exit, Flag),
+ ConnectResult;
+ {'EXIT', Connector, OtherReason} ->
+ ?rt2("connect exit: received unexpected connector exit signal",
+ [Connector, OtherReason]),
+ process_flag(trap_exit, Flag),
+ {error, OtherReason}
+ end;
+connect(BadHandle, _CH, _SendHandle, _ControlPid, _Extra) ->
+ {error, {bad_receive_handle, BadHandle}}.
+
+do_connect(CD, Extra) ->
+ CH = CD#conn_data.conn_handle,
+ Version = CD#conn_data.protocol_version,
+ UserMod = CD#conn_data.user_mod,
+ UserArgs = CD#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [CH, Version | UserArgs];
+ _ ->
+ [CH, Version, Extra | UserArgs]
+ end,
+ ?report_trace(CD, "callback: connect", [Args]),
+ Res = (catch apply(UserMod, handle_connect, Args)),
+ ?report_debug(CD, "return: connect", [{return, Res}]),
+ case Res of
+ ok ->
+ ?SIM(ok, do_connect), % do_encode),
+ monitor_process(CH, CD#conn_data.control_pid);
+ error ->
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, error}};
+ {error, ED} when is_record(ED,'ErrorDescriptor') ->
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, ED}};
+ _Error ->
+ warning_msg("connect callback failed: ~w", [Res]),
+ megaco_config:disconnect(CH),
+ {error, {connection_refused, CD, Res}}
+ end.
+
+finish_connect(#conn_data{control_pid = ControlPid} = CD)
+ when is_pid(ControlPid) andalso (node(ControlPid) =:= node()) ->
+ ?rt1(CD, "finish local connect", [ControlPid]),
+ do_finish_connect(CD);
+finish_connect(#conn_data{conn_handle = CH,
+ control_pid = ControlPid} = CD)
+ when is_pid(ControlPid) andalso (node(ControlPid) =/= node()) ->
+ ?rt1(CD, "finish remote connect", [ControlPid]),
+ RemoteNode = node(ControlPid),
+ UserMonitorPid = whereis(megaco_monitor),
+ Args = [CH, ControlPid, UserMonitorPid],
+ case rpc:call(RemoteNode, ?MODULE, connect_remote, Args) of
+ {ok, ControlMonitorPid} ->
+ do_finish_connect(CD#conn_data{control_pid = ControlMonitorPid});
+ {error, Reason} ->
+ disconnect(CH, {connect_remote, Reason}),
+ {error, Reason};
+ {badrpc, Reason} ->
+ Reason2 = {'EXIT', Reason},
+ disconnect(CH, {connect_remote, Reason2}),
+ {error, Reason2}
+ end.
+
+do_finish_connect(#conn_data{conn_handle = CH,
+ send_handle = SendHandle,
+ control_pid = ControlPid} = CD) ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ MFA = {M, F, A},
+ case megaco_config:finish_connect(CH, SendHandle, ControlPid, MFA) of
+ {ok, Ref} ->
+ {ok, CD#conn_data{monitor_ref = Ref}};
+ {error, Reason} ->
+ {error, {config_update, Reason}}
+ end.
+
+
+monitor_process(CH, ControlPid)
+ when is_pid(ControlPid) andalso (node(ControlPid) =:= node()) ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlPid),
+ case megaco_config:update_conn_info(CH, monitor_ref, Ref) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_local);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end;
+monitor_process(CH, ControlPid)
+ when is_pid(ControlPid) andalso (node(ControlPid) =/= node()) ->
+ RemoteNode = node(ControlPid),
+ UserMonitorPid = whereis(megaco_monitor),
+ Args = [CH, ControlPid, UserMonitorPid],
+ case rpc:call(RemoteNode, ?MODULE, connect_remote, Args) of
+ {ok, ControlMonitorPid} ->
+ M = ?MODULE,
+ F = disconnect_local,
+ A = [CH],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, ControlMonitorPid),
+ case megaco_config:update_conn_info(CH, monitor_ref, Ref) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_remote);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ disconnect(CH, {connect_remote, Reason}),
+ {error, Reason};
+ {badrpc, Reason} ->
+ Reason2 = {'EXIT', Reason},
+ disconnect(CH, {connect_remote, Reason2}),
+ {error, Reason2}
+ end;
+monitor_process(CH, undefined = _ControlPid) ->
+ %% We have to do this later (setting up the monitor),
+ %% when the first message arrives. The 'connected' atom is
+ %% the indication for the first arriving message to finish
+ %% the connect.
+ %% This may be the case when an MGC performs a pre-connect
+ %% in order to speed up the handling of an (expected) connecting
+ %% MG.
+ case megaco_config:update_conn_info(CH, monitor_ref, connected) of
+ ok ->
+ ?SIM({ok, CH}, monitor_process_local);
+ {error, Reason} ->
+ disconnect(CH, {config_update, Reason}),
+ {error, Reason}
+ end.
+
+connect_remote(CH, ControlPid, UserMonitorPid)
+ when node(ControlPid) =:= node() andalso node(UserMonitorPid) =/= node() ->
+ case megaco_config:lookup_local_conn(CH) of
+ [_ConnData] ->
+ UserNode = node(UserMonitorPid),
+ M = ?MODULE,
+ F = disconnect_remote,
+ A = [CH, UserNode],
+ Ref = megaco_monitor:apply_at_exit(M, F, A, UserMonitorPid),
+ case megaco_config:connect_remote(CH, UserNode, Ref) of
+ ok ->
+ ControlMonitorPid = whereis(megaco_monitor),
+ ?SIM({ok, ControlMonitorPid}, connect_remote);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ [] ->
+ {error, {no_connection, CH}}
+ end.
+
+cancel_apply_at_exit({connecting, _ConnectorPid}) ->
+ ok;
+cancel_apply_at_exit(connected) ->
+ ok;
+cancel_apply_at_exit(ControlRef) ->
+ megaco_monitor:cancel_apply_at_exit(ControlRef).
+
+node_of_control_pid(Pid) when is_pid(Pid) ->
+ node(Pid);
+node_of_control_pid(_) ->
+ node().
+
+disconnect(ConnHandle, DiscoReason)
+ when is_record(ConnHandle, megaco_conn_handle) ->
+ case megaco_config:disconnect(ConnHandle) of
+ {ok, ConnData, RemoteConnData} ->
+ ControlRef = ConnData#conn_data.monitor_ref,
+ cancel_apply_at_exit(ControlRef),
+ handle_disconnect_callback(ConnData, DiscoReason),
+ ControlNode = node_of_control_pid(ConnData#conn_data.control_pid),
+ case ControlNode =:= node() of
+ true ->
+ %% Propagate to remote users
+ CancelFun =
+ fun(RCD) ->
+ UserRef = RCD#remote_conn_data.monitor_ref,
+ cancel_apply_at_exit(UserRef),
+ RCD#remote_conn_data.user_node
+ end,
+ Nodes = lists:map(CancelFun, RemoteConnData),
+ %% io:format("NODES: ~p~n", [Nodes]),
+ M = ?MODULE,
+ F = disconnect,
+ A = [ConnHandle, DiscoReason],
+ case rpc:multicall(Nodes, M, F, A) of
+ {Res, []} ->
+ Check = fun(ok) -> false;
+ ({error, {no_connection, _CH}}) -> false;
+ (_) -> true
+ end,
+ case lists:filter(Check, Res) of
+ [] ->
+ ok;
+ Bad ->
+ {error, {remote_disconnect_error, ConnHandle, Bad}}
+ end;
+ {_Res, Bad} ->
+ {error, {remote_disconnect_crash, ConnHandle, Bad}}
+ end;
+ false when (RemoteConnData =:= []) ->
+ %% Propagate to remote control node
+ M = ?MODULE,
+ F = disconnect_remote,
+ A = [DiscoReason, ConnHandle, node()],
+ case rpc:call(ControlNode, M, F, A) of
+ {badrpc, Reason} ->
+ {error, {'EXIT', Reason}};
+ Other ->
+ Other
+ end
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end;
+disconnect(BadHandle, Reason) ->
+ {error, {bad_conn_handle, BadHandle, Reason}}.
+
+disconnect_local(Reason, ConnHandle) ->
+ disconnect(ConnHandle, {no_controlling_process, Reason}).
+
+disconnect_remote(_Reason, ConnHandle, UserNode) ->
+ case megaco_config:disconnect_remote(ConnHandle, UserNode) of
+ [RCD] ->
+ Ref = RCD#remote_conn_data.monitor_ref,
+ cancel_apply_at_exit(Ref),
+ ok;
+ [] ->
+ {error, {no_connection, ConnHandle}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Handle incoming message
+%%----------------------------------------------------------------------
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, Bin) ->
+ Extra = ?default_user_callback_extra,
+ receive_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra).
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra) ->
+ Opts = [link , {min_heap_size, 5000}],
+ spawn_opt(?MODULE,
+ process_received_message,
+ [ReceiveHandle, ControlPid, SendHandle, Bin, self(), Extra], Opts),
+ ok.
+
+%% This function is called via the spawn_opt function with the link
+%% option, therefor the unlink before the exit.
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Receiver,
+ Extra) ->
+ process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra),
+ unlink(Receiver),
+ exit(normal).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin) ->
+ Extra = ?default_user_callback_extra,
+ process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra).
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, Bin, Extra) ->
+ Flag = process_flag(trap_exit, true),
+ case prepare_message(ReceiveHandle, SendHandle, Bin, ControlPid, Extra) of
+ {ok, ConnData, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ ?rt1(ConnData, "message prepared", [MegaMsg]),
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ case Mess#'Message'.messageBody of
+ {transactions, Transactions} ->
+ {AckList, ReqList} =
+ prepare_trans(ConnData, Transactions, [], [], Extra),
+ handle_acks(AckList, Extra),
+ case ReqList of
+ [] ->
+ ?rt3("no transaction requests"),
+ ignore;
+ [Req|Reqs] when (ConnData#conn_data.threaded =:= true) ->
+ ?rt3("handle requests (spawned)"),
+ lists:foreach(
+ fun(R) ->
+ spawn(?MODULE, handle_request, [R, Extra])
+ end,
+ Reqs),
+ handle_request(Req, Extra);
+ _ ->
+ ?rt3("handle requests"),
+ case handle_requests(ReqList, [], Extra) of
+ [] ->
+ ignore;
+ [LongRequest | More] ->
+ lists:foreach(
+ fun(LR) ->
+ spawn(?MODULE, handle_long_request, [LR, Extra])
+ end,
+ More),
+ handle_long_request(LongRequest, Extra)
+ end
+ end;
+ {messageError, Error} ->
+ handle_message_error(ConnData, Error, Extra)
+ end;
+ {silent_fail, ConnData, {_Code, Reason, Error}} ->
+ ?report_debug(ConnData, Reason, [no_reply, Error]),
+ ignore;
+ {verbose_fail, ConnData, {Code, Reason, Error}} ->
+ ?report_debug(ConnData, Reason, [Error]),
+ send_message_error(ConnData, Code, Reason)
+ end,
+ process_flag(trap_exit, Flag),
+ ok.
+
+prepare_message(RH, SH, Bin, Pid, Extra)
+ when is_record(RH, megaco_receive_handle) andalso is_pid(Pid) ->
+ ?report_trace(RH, "receive bytes", [{bytes, Bin}]),
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ ProtVersion = RH#megaco_receive_handle.protocol_version,
+ case (catch EncodingMod:decode_message(EncodingConfig, ProtVersion, Bin)) of
+ {ok, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ ?report_trace(RH, "receive message", [{message, MegaMsg}]),
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ RemoteMid = Mess#'Message'.mId,
+ Version = Mess#'Message'.version,
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ case megaco_config:lookup_local_conn(CH) of
+
+ %%
+ %% Message is not of the negotiated version
+ %%
+
+ [#conn_data{protocol_version = NegVersion,
+ strict_version = true} = ConnData]
+ when NegVersion =/= Version ->
+ %% Use already established connection,
+ %% but incorrect version
+ ?rt1(ConnData, "not negotiated version", [Version]),
+ Error = {error, {not_negotiated_version,
+ NegVersion, Version}},
+ handle_syntax_error_callback(RH, ConnData,
+ prepare_error(Error),
+ Extra);
+
+
+ [ConnData] ->
+
+ %%
+ %% Use an already established connection
+ %%
+ %% This *may* have been set up in the
+ %% "non-official" way, so we may need to
+ %% create the monitor to the control process
+ %% and store the SendHandle (which is normally
+ %% done when creating the "temporary" connection).
+ %%
+
+ ?rt1(ConnData, "use already established connection", []),
+ ConnData2 = ConnData#conn_data{send_handle = SH,
+ control_pid = Pid,
+ protocol_version = Version},
+ check_message_auth(CH, ConnData2, MegaMsg, Bin);
+
+ [] ->
+ %% Setup a temporary connection
+ ?rt3("setup a temporary connection"),
+ case autoconnect(RH, RemoteMid, SH, Pid, Extra) of
+ {ok, _} ->
+ do_prepare_message(RH, CH, SH, MegaMsg, Pid, Bin);
+ {error, {already_connected, _ConnHandle}} ->
+ do_prepare_message(RH, CH, SH, MegaMsg, Pid, Bin);
+ {error, {connection_refused, ConnData, Reason}} ->
+ Error = prepare_error({error, {connection_refused, Reason}}),
+ {verbose_fail, ConnData, Error};
+ {error, Reason} ->
+ ConnData = fake_conn_data(RH, RemoteMid, SH, Pid),
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ Error = prepare_error({error, Reason}),
+ {verbose_fail, ConnData2, Error}
+ end
+ end;
+ Error ->
+ ?rt2("decode error", [Error]),
+ ConnData = handle_decode_error(Error,
+ RH, SH, Bin, Pid,
+ EncodingMod,
+ EncodingConfig,
+ ProtVersion),
+ handle_syntax_error_callback(RH, ConnData, prepare_error(Error), Extra)
+ end;
+prepare_message(RH, SendHandle, _Bin, ControlPid, _Extra) ->
+ ConnData = fake_conn_data(RH, SendHandle, ControlPid),
+ Error = prepare_error({'EXIT', {bad_receive_handle, RH}}),
+ {verbose_fail, ConnData, Error}.
+
+
+handle_decode_error({error, {unsupported_version, _}},
+ #megaco_receive_handle{local_mid = LocalMid} = RH, SH,
+ Bin, Pid,
+ EM, EC, V) ->
+ case (catch EM:decode_mini_message(EC, V, Bin)) of
+ {ok, #'MegacoMessage'{mess = #'Message'{version = _Ver,
+ mId = RemoteMid}}} ->
+ ?rt2("erroneous message received", [SH, RemoteMid, _Ver]),
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ incNumErrors(CH),
+ %% We cannot put the version into conn-data, that will
+ %% make the resulting error message impossible to sent
+ %% (unsupported version)
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ ?rt3("known to us"),
+ ConnData#conn_data{send_handle = SH};
+ [] ->
+ ?rt3("unknown to us"),
+ ConnData = fake_conn_data(RH, SH, Pid),
+ ConnData#conn_data{conn_handle = CH}
+ end;
+
+ _ ->
+ ?rt2("erroneous message received", [SH]),
+ incNumErrors(),
+ fake_conn_data(RH, SH, Pid)
+ end;
+
+handle_decode_error(_,
+ #megaco_receive_handle{local_mid = LocalMid} = RH, SH,
+ Bin, Pid,
+ EM, EC, V) ->
+ case (catch EM:decode_mini_message(EC, V, Bin)) of
+ {ok, #'MegacoMessage'{mess = #'Message'{version = Ver,
+ mId = RemoteMid}}} ->
+ ?rt2("erroneous message received", [SH, Ver, RemoteMid]),
+ CH = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ incNumErrors(CH),
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ ?rt3("known to us"),
+ ConnData#conn_data{send_handle = SH,
+ protocol_version = Ver};
+ [] ->
+ ?rt3("unknown to us"),
+ ConnData = fake_conn_data(RH, SH, Pid),
+ ConnData#conn_data{conn_handle = CH,
+ protocol_version = Ver}
+ end;
+
+ _ ->
+ ?rt2("erroneous message received", [SH]),
+ incNumErrors(),
+ fake_conn_data(RH, SH, Pid)
+ end.
+
+
+do_prepare_message(RH, CH, SendHandle, MegaMsg, ControlPid, Bin) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ case check_message_auth(CH, ConnData, MegaMsg, Bin) of
+ {ok, ConnData2, MegaMsg} ->
+ %% Let the connection be permanent
+ {ok, ConnData2, MegaMsg};
+ {ReplyTag, ConnData, Reason} ->
+ %% Remove the temporary connection
+ disconnect(CH, {bad_auth, Reason}),
+ {ReplyTag, ConnData, Reason}
+ end;
+ [] ->
+ Reason = no_connection,
+ disconnect(CH, Reason),
+ RemoteMid = CH#megaco_conn_handle.remote_mid,
+ ConnData = fake_conn_data(RH, RemoteMid, SendHandle, ControlPid),
+ Error = prepare_error({error, Reason}),
+ {silent_fail, ConnData, Error}
+ end.
+
+check_message_auth(_ConnHandle, ConnData, MegaMsg, Bin) ->
+ MsgAuth = MegaMsg#'MegacoMessage'.authHeader,
+ Mess = MegaMsg#'MegacoMessage'.mess,
+ Version = Mess#'Message'.version,
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ ConnAuth = ConnData2#conn_data.auth_data,
+ ?report_trace(ConnData2, "check message auth", [{bytes, Bin}]),
+ if
+ (MsgAuth =:= asn1_NOVALUE) andalso (ConnAuth =:= asn1_NOVALUE) ->
+ ?SIM({ok, ConnData2, MegaMsg}, check_message_auth);
+ true ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_unauthorized,
+ errorText = "Autentication is not supported"},
+ {verbose_fail, ConnData2, prepare_error({error, ED})}
+ end.
+
+handle_syntax_error_callback(ReceiveHandle, ConnData, PrepError, Extra) ->
+ {Code, Reason, Error} = PrepError,
+ ErrorDesc = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Version =
+ case Error of
+ {error, {unsupported_version, UV}} ->
+ UV;
+ _ ->
+ ConnData#conn_data.protocol_version
+ end,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ?report_trace(ReceiveHandle, "callback: syntax error", [ErrorDesc, Error]),
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ReceiveHandle, Version, ErrorDesc | UserArgs];
+ _ ->
+ [ReceiveHandle, Version, ErrorDesc, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_syntax_error, Args)),
+ ?report_debug(ReceiveHandle, "return: syntax error",
+ [{return, Res}, ErrorDesc, Error]),
+ case Res of
+ reply ->
+ {verbose_fail, ConnData, PrepError};
+ {reply,#'ErrorDescriptor'{errorCode = Code1, errorText = Reason1}} ->
+ {verbose_fail, ConnData, {Code1,Reason1,Error}};
+ no_reply ->
+ {silent_fail, ConnData, PrepError};
+ {no_reply,#'ErrorDescriptor'{errorCode=Code2,errorText=Reason2}} ->
+ {silent_fail, ConnData, {Code2,Reason2,Error}}; %%% OTP-????
+ _ ->
+ warning_msg("syntax error callback failed: ~w", [Res]),
+ {verbose_fail, ConnData, PrepError}
+ end.
+
+fake_conn_data(CH) when is_record(CH, megaco_conn_handle) ->
+ case (catch megaco_config:conn_info(CH, receive_handle)) of
+ RH when is_record(RH, megaco_receive_handle) ->
+ RemoteMid = CH#megaco_conn_handle.remote_mid,
+ ConnData =
+ fake_conn_data(RH, RemoteMid, no_send_handle, no_control_pid),
+ ConnData#conn_data{conn_handle = CH};
+ {'EXIT', _} ->
+ UserMid = CH#megaco_conn_handle.local_mid,
+ case catch megaco_config:user_info(UserMid, receive_handle) of
+ {'EXIT', _} -> % No such user
+ #conn_data{conn_handle = CH,
+ serial = undefined_serial,
+ control_pid = no_control_pid,
+ monitor_ref = undefined_monitor_ref,
+ send_mod = no_send_mod,
+ send_handle = no_send_handle,
+ encoding_mod = no_encoding_mod,
+ encoding_config = no_encoding_config,
+ reply_action = undefined,
+ sent_pending_limit = infinity,
+ recv_pending_limit = infinity};
+ RH ->
+ ConnData =
+ fake_conn_data(RH, no_send_handle, no_control_pid),
+ ConnData#conn_data{conn_handle = CH}
+ end
+ end.
+
+fake_conn_data(RH, SendHandle, ControlPid) ->
+ fake_conn_data(RH, unknown_remote_mid, SendHandle, ControlPid).
+
+fake_conn_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ case catch megaco_config:init_conn_data(RH, RemoteMid, SendHandle, ControlPid) of
+ {'EXIT', _} -> % No such user
+ fake_user_data(RH, RemoteMid, SendHandle, ControlPid);
+ ConnData ->
+ ConnData
+ end.
+
+fake_user_data(RH, RemoteMid, SendHandle, ControlPid) ->
+ LocalMid = RH#megaco_receive_handle.local_mid,
+ RH2 = RH#megaco_receive_handle{local_mid = default},
+ case catch megaco_config:init_conn_data(RH2, RemoteMid, SendHandle, ControlPid) of
+ {'EXIT', _} -> % Application stopped?
+ ConnHandle = #megaco_conn_handle{local_mid = LocalMid,
+ remote_mid = RemoteMid},
+ EncodingMod = RH#megaco_receive_handle.encoding_mod,
+ EncodingConfig = RH#megaco_receive_handle.encoding_config,
+ SendMod = RH#megaco_receive_handle.send_mod,
+ #conn_data{conn_handle = ConnHandle,
+ serial = undefined_serial,
+ control_pid = ControlPid,
+ monitor_ref = undefined_monitor_ref,
+ send_mod = SendMod,
+ send_handle = SendHandle,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig,
+ reply_action = undefined,
+ sent_pending_limit = infinity,
+ recv_pending_limit = infinity};
+ ConnData ->
+ ConnData
+ end.
+
+prepare_error(Error) ->
+ case Error of
+ {error, ED} when is_record(ED, 'ErrorDescriptor') ->
+ Code = ED#'ErrorDescriptor'.errorCode,
+ Reason = ED#'ErrorDescriptor'.errorText,
+ {Code, Reason, Error};
+ {error, [{reason, {bad_token, [BadToken, _Acc]}, Line}]} when is_integer(Line) ->
+ Reason =
+ lists:flatten(
+ io_lib:format("Illegal token (~p) on line ~w", [BadToken, Line])),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {bad_token, _}, Line}]} when is_integer(Line) ->
+ Reason = lists:concat(["Illegal token on line ", Line]),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {Line, _ParserMod, RawReasonString}} | _]} when is_integer(Line) andalso is_list(RawReasonString) ->
+ Reason =
+ case RawReasonString of
+ [[$s, $y, $n, $t, $a, $x | _], TokenString] ->
+ lists:flatten(
+ io_lib:format("Syntax error on line ~w before token ~s", [Line, TokenString]));
+ _ ->
+ lists:flatten(io_lib:format("Syntax error on line ~w", [Line]))
+ end,
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, [{reason, {Line, _, _}} | _]} when is_integer(Line) ->
+ Reason = lists:concat(["Syntax error on line ", Line]),
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {error, {connection_refused, ED}} when is_record(ED,'ErrorDescriptor') ->
+ Code = ED#'ErrorDescriptor'.errorCode,
+ Reason = ED#'ErrorDescriptor'.errorText,
+ {Code, Reason, Error};
+ {error, {connection_refused, _}} ->
+ Reason = "Connection refused by user",
+ Code = ?megaco_unauthorized,
+ {Code, Reason, Error};
+ {error, {unsupported_version, V}} ->
+ Reason =
+ lists:flatten(io_lib:format("Unsupported version: ~w",[V])),
+ Code = ?megaco_version_not_supported,
+ {Code, Reason, Error};
+ {error, {not_negotiated_version, NegV, MsgV}} ->
+ Reason =
+ lists:flatten(
+ io_lib:format("Not negotiated version: ~w [negotiated ~w]",
+ [MsgV, NegV])),
+ Code = ?megaco_version_not_supported,
+ {Code, Reason, Error};
+ {error, _} ->
+ Reason = "Syntax error",
+ Code = ?megaco_bad_request,
+ {Code, Reason, Error};
+ {ok, MegaMsg} when is_record(MegaMsg, 'MegacoMessage') ->
+ Reason = "MID does not match config",
+ Code = ?megaco_incorrect_identifier,
+ {Code, Reason, Error};
+ _ ->
+ Reason = "Fatal syntax error",
+ Code = ?megaco_internal_gateway_error,
+ {Code, Reason, Error}
+ end.
+
+prepare_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_trans_done);
+
+prepare_trans(ConnData, Trans, AckList, ReqList, Extra)
+ when ConnData#conn_data.monitor_ref =:= undefined_auto_monitor_ref ->
+
+ ?rt3("prepare_trans - autoconnect"),
+
+ %% <BUGBUG>
+ %% Do we need something here, if we send more then one
+ %% trans per message?
+ %% </BUGBUG>
+
+ %% May occur if another process has already setup a
+ %% temporary connection, but the handle_connect callback
+ %% function has not yet returned before the eager MG
+ %% re-sends its initial service change message.
+
+ prepare_autoconnecting_trans(ConnData, Trans, AckList, ReqList, Extra);
+
+prepare_trans(#conn_data{monitor_ref = connected} = ConnData,
+ Trans, AckList, ReqList, Extra) ->
+
+ ?rt3("prepare_trans - connected"),
+
+ %%
+ %% This will happen when the "MGC" user performs a "pre" connect,
+ %% instead of waiting for the auto-connect (which normally
+ %% happen when the MGC receives the first message from the
+ %% MG).
+ %%
+
+ %%
+ %% The monitor_ref will have this value when the pre-connect
+ %% is complete, so we finish it here and then continue with the
+ %% normal transaction prepare.
+ %%
+
+ case finish_connect(ConnData) of
+ {ok, CD} ->
+ prepare_normal_trans(CD, Trans, AckList, ReqList, Extra);
+ {error, Reason} ->
+ disconnect(ConnData#conn_data.conn_handle, Reason),
+ {[], []}
+ end;
+
+prepare_trans(#conn_data{monitor_ref = {connecting, _}} = _ConnData,
+ _Trans, _AckList, _ReqList, _Extra) ->
+
+ ?rt3("prepare_trans - connecting"),
+
+ %%
+ %% This will happen when the "MGC" user performs a "pre" connect,
+ %% instead of waiting for the auto-connect (which normally
+ %% happen when the MGC receives the first message from the
+ %% MG).
+ %%
+
+ %%
+ %% The monitor_ref will have this value when the pre-connect
+ %% is in progress. We drop (ignore) this message and hope the
+ %% other side (MG) will resend.
+ %%
+
+ %% prepare_connecting_trans(ConnData, Trans, AckList, ReqList, Extra);
+ {[], []};
+
+prepare_trans(ConnData, Trans, AckList, ReqList, Extra) ->
+
+ ?rt3("prepare_trans - normal"),
+
+ %% Handle transaction in the normal case
+
+ prepare_normal_trans(ConnData, Trans, AckList, ReqList, Extra).
+
+
+prepare_autoconnecting_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_autoconnecting_trans_done);
+
+prepare_autoconnecting_trans(ConnData, [Trans | Rest], AckList, ReqList, Extra) ->
+ ?rt1(ConnData, "[autoconnecting] prepare trans", [Trans]),
+ case Trans of
+ {transactionRequest, T} when is_record(T, 'TransactionRequest') ->
+
+ Serial = T#'TransactionRequest'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ ?report_trace(ConnData2, "Pending handle_connect", [T]),
+
+ %% ------------------------------------------
+ %%
+ %% Check pending limit
+ %%
+ %% ------------------------------------------
+
+ Limit = ConnData#conn_data.sent_pending_limit,
+ TransId = to_remote_trans_id(ConnData2),
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+ send_pending(ConnData2);
+ error ->
+ %% Pending limit:
+ %% In this (granted, highly hypothetical case)
+ %% we would make the user very confused if we
+ %% called the abort callback function, since
+ %% the request callback function has not yet
+ %% been called. Alas, we skip this call here.
+ send_pending_limit_error(ConnData);
+ aborted ->
+ ignore
+ end,
+ prepare_autoconnecting_trans(ConnData2, Rest, AckList, ReqList,
+ Extra);
+ _ ->
+ prepare_autoconnecting_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+ end.
+
+
+%% =================================================================
+%%
+%% Note that the TransactionReply record was changed i v3 (two
+%% new fields where added), and since we don't know which version,
+%% we cannot use the record definition of TransactionReply.
+%% Instead we transform the record into our own internal format
+%% #megaco_transaction_reply{}
+%%
+%% =================================================================
+
+prepare_normal_trans(_ConnData, [], AckList, ReqList, _Extra) ->
+ ?SIM({AckList, ReqList}, prepare_normal_trans_done);
+
+prepare_normal_trans(ConnData, [Trans | Rest], AckList, ReqList, Extra) ->
+ ?rt1(ConnData, "prepare [normal] trans", [Trans]),
+ case Trans of
+ {transactionRequest, #'TransactionRequest'{transactionId = asn1_NOVALUE}} ->
+ ConnData2 = ConnData#conn_data{serial = 0},
+ Code = ?megaco_bad_request,
+ Reason = "Syntax error in message: transaction id missing",
+ send_trans_error(ConnData2, Code, Reason),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionRequest, T} when is_record(T, 'TransactionRequest') ->
+ Serial = T#'TransactionRequest'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ prepare_request(ConnData2, T, Rest, AckList, ReqList, Extra);
+ {transactionPending, T} when is_record(T, 'TransactionPending') ->
+ Serial = T#'TransactionPending'.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ handle_pending(ConnData2, T, Extra),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionReply, T} when is_tuple(T) andalso
+ (element(1, T) == 'TransactionReply') ->
+ T2 = transform_transaction_reply_dec(T),
+ Serial = T2#megaco_transaction_reply.transactionId,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ handle_reply(ConnData2, T2, Extra),
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+ {transactionResponseAck, List} when is_list(List) ->
+ prepare_ack(ConnData, List, Rest, AckList, ReqList, Extra);
+ {segmentReply, SR} when is_record(SR, 'SegmentReply') ->
+ handle_segment_reply(ConnData, SR, Extra),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra)
+
+ end.
+
+
+prepare_request(ConnData, T, Rest, AckList, ReqList, Extra) ->
+ ?rt2("prepare request", [T]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ TransId = to_remote_trans_id(ConnData),
+ ?rt2("prepare request", [LocalMid, TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ ?rt3("brand new request"),
+
+ %% Brand new request
+
+ %% Check pending limit:
+ %%
+ %% We should actually check the pending limit here
+ %% but since we have to do it later in the
+ %% handle_request function (just before we call
+ %% the handle_trans_request callback function) we
+ %% can just as well wait (this is after all a very
+ %% unlikely case: see function prepare_trans when
+ %% monitor_ref == undefined_auto_monitor_ref).
+ %%
+
+ #conn_data{send_handle = SendHandle,
+ pending_timer = InitTimer,
+ protocol_version = Version} = ConnData,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ M = ?MODULE,
+ F = pending_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ PendingRef = megaco_monitor:apply_after(M, F, A, WaitFor),
+ Rep = #reply{send_handle = SendHandle,
+ trans_id = TransId,
+ local_mid = LocalMid,
+ pending_timer_ref = PendingRef,
+ handler = self(),
+ version = Version},
+ case megaco_monitor:insert_reply_new(Rep) of
+ true ->
+ prepare_normal_trans(ConnData, Rest, AckList,
+ [{ConnData, TransId, T} | ReqList],
+ Extra);
+ false ->
+ %% Oups - someone got there before we did...
+ ?report_debug(ConnData,
+ "prepare request: conflicting requests",
+ [TransId]),
+ send_pending(ConnData),
+ megaco_monitor:cancel_apply_after(PendingRef),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+ end;
+
+ [#reply{state = State,
+ handler = Pid,
+ pending_timer_ref = Ref} = Rep]
+ when (State =:= prepare) orelse (State =:= eval_request) ->
+
+ ?rt2("request resend", [State, Pid, Ref]),
+
+ %% Pending limit:
+ %% We are still preparing/evaluating the request
+ %% Check if the pending limit has been exceeded...
+ %% If the pending limit is _not_ exceeded then
+ %% we shall send a pending (and actually restart
+ %% the pending timer, but that we cannot do).
+ %% Don't care about Msg and Rep version diff
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+
+ %% ------------------------------------------
+ %%
+ %% Pending limit not exceeded
+ %%
+ %% 1) Increment number of pendings sent
+ %% (done in the check function above)
+ %% 2) Send pending message
+ %% (We should really restart the pending
+ %% timer, but we have no way of doing that).
+ %%
+ %% ------------------------------------------
+
+ send_pending(ConnData),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra);
+
+
+ error ->
+
+ %% -------------------------------------------
+ %%
+ %% Pending limit exceeded
+ %%
+ %% 1) Cancel pending timer
+ %% 2) Send 506 error message to other side
+ %% 3) Inform user (depends on state)
+ %% 4) Set reply in aborted state
+ %%
+ %% -------------------------------------------
+
+ %%
+ %% State == eval_request:
+ %% This means that the request is currently beeing
+ %% evaluated by the user, and the reply timer has
+ %% not yet been started.
+ %% Either:
+ %% a) The "other side" will resend (which will
+ %% trigger a pending message send) until we pass the
+ %% pending limit
+ %% b) We will send pending messages (when the pending
+ %% timer expire) until we pass the pending limit.
+ %% In any event, we cannot delete the reply record
+ %% or the pending counter in this case. Is there
+ %% a risk we accumulate aborted reply records?
+ %%
+ %% State == prepare:
+ %% The user does not know about this request
+ %% so we can safely perform cleanup.
+ %%
+ megaco_monitor:cancel_apply_after(Ref),
+ send_pending_limit_error(ConnData),
+ if
+ State == eval_request ->
+ %%
+ %% What if the user never replies?
+ %% In that case we will have a record
+ %% (and counters) that is never cleaned up...
+ NewFields =
+ [{#reply.state, aborted},
+ {#reply.pending_timer_ref, undefined}],
+ megaco_monitor:update_reply_fields(TransId,
+ NewFields),
+ handle_request_abort_callback(ConnData,
+ TransId, Pid, Extra);
+ true ->
+ %% Since the user does not know about
+ %% this call yet, it is safe to cleanup.
+ %% Should we inform?
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(ConnData, Rep2, aborted),
+ ok
+ end,
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra);
+
+
+ aborted ->
+
+ %% -------------------------------------------
+ %%
+ %% Pending limit already exceeded
+ %%
+ %% Cleanup, just to make sure:
+ %% reply record & pending counter
+ %%
+ %% -------------------------------------------
+
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(ConnData, Rep2, aborted),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList,
+ Extra)
+
+ end;
+
+ [#reply{state = waiting_for_ack,
+ bytes = Bin,
+ version = Version} = Rep] ->
+ ?rt3("request resend when waiting for ack"),
+
+ %% We have already sent a reply, but the receiver
+ %% has obviously not got it. Resend the reply but
+ %% don't restart the reply_timer.
+ ConnData2 = ConnData#conn_data{protocol_version = Version},
+ ?report_trace(ConnData2,
+ "re-send trans reply", [T | {bytes, Bin}]),
+ case megaco_messenger_misc:send_message(ConnData2, true, Bin) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ %% Pass it on to the user (via handle_ack)
+ cancel_reply(ConnData2, Rep, Reason)
+ end,
+ prepare_normal_trans(ConnData2, Rest, AckList, ReqList, Extra);
+
+ [#reply{state = aborted} = Rep] ->
+ ?rt3("request resend when already in aborted state"),
+
+ %% OTP-4956:
+ %% Already aborted so ignore.
+ %% This furthermore means that the abnoxious user at the
+ %% other end has already been informed (pending-limit
+ %% passed => error descriptor sent), but keeps sending...
+ %%
+ %% Shall we perform a cleanup?
+ cancel_reply(ConnData, Rep, aborted),
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra)
+ end.
+
+prepare_ack(ConnData, [TA | T], Rest, AckList, ReqList, Extra)
+ when is_record(TA, 'TransactionAck') ->
+ First = TA#'TransactionAck'.firstAck,
+ Last = TA#'TransactionAck'.lastAck,
+ TA2 = TA#'TransactionAck'{lastAck = asn1_NOVALUE},
+ ConnData2 = ConnData#conn_data{serial = First},
+ AckList2 = do_prepare_ack(ConnData2, TA2, AckList),
+ if
+ Last =:= asn1_NOVALUE ->
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra);
+ First < Last ->
+ TA3 = TA#'TransactionAck'{firstAck = First + 1},
+ prepare_ack(ConnData, [TA3 | T], Rest, AckList2, ReqList, Extra);
+ First =:= Last ->
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra);
+ First > Last ->
+ %% Protocol violation from the sender of this ack
+ ?report_important(ConnData, "<ERROR> discard trans",
+ [TA, {error, "firstAck > lastAck"}]),
+ prepare_ack(ConnData, T, Rest, AckList2, ReqList, Extra)
+ end;
+prepare_ack(ConnData, [], Rest, AckList, ReqList, Extra) ->
+ prepare_normal_trans(ConnData, Rest, AckList, ReqList, Extra).
+
+do_prepare_ack(ConnData, T, AckList) ->
+ TransId = to_remote_trans_id(ConnData),
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ %% The reply has already been garbage collected. Ignore.
+ ?report_trace(ConnData, "discard ack (no receiver)", [T]),
+ AckList;
+ [Rep] when Rep#reply.state =:= waiting_for_ack ->
+ %% Don't care about Msg and Rep version diff
+ [{ConnData, Rep, T} | AckList];
+ [_Rep] ->
+ %% Protocol violation from the sender of this ack
+ ?report_important(ConnData, "<ERROR> discard trans",
+ [T, {error, "got ack before reply was sent"}]),
+ AckList
+ end.
+
+
+increment_request_keep_alive_counter(#conn_data{conn_handle = CH}, TransId) ->
+ ?rt1(CH, "increment request keep alive counter", [TransId]),
+ megaco_config:incr_reply_counter(CH, TransId).
+
+create_or_maybe_increment_request_keep_alive_counter(
+ #conn_data{conn_handle = CH}, TransId) ->
+ ?rt1(CH, "create or maybe increment request keep alive counter",
+ [TransId]),
+ try
+ begin
+ megaco_config:cre_reply_counter(CH, TransId)
+ end
+ catch
+ _:_ ->
+ megaco_config:incr_reply_counter(CH, TransId)
+ end.
+
+
+check_and_maybe_create_pending_limit(infinity, _, _) ->
+ ok;
+check_and_maybe_create_pending_limit(Limit, Direction, TransId) ->
+ ?rt2("check and maybe create pending limit counter",
+ [Limit, Direction, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val =< Limit ->
+ %% Since we have no intention to increment here, it
+ %% is ok to be _at_ the limit
+ ok;
+ _ ->
+ aborted
+ catch
+ _:_ ->
+ %% Has not been created yet (connect).
+ megaco_config:cre_pending_counter(Direction, TransId, 0),
+ ok
+ end.
+
+%% check_and_maybe_create_pending_limit(infinity, _, _) ->
+%% ok;
+%% check_and_maybe_create_pending_limit(Limit, Direction, TransId) ->
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% Has not been created yet (connect).
+%% megaco_config:cre_pending_counter(Direction, TransId, 0),
+%% ok;
+%% Val when Val =< Limit ->
+%% %% Since we have no intention to increment here, it
+%% %% is ok to be _at_ the limit
+%% ok;
+%% _ ->
+%% aborted
+%% end.
+
+
+check_pending_limit(infinity, _, _) ->
+ {ok, 0};
+check_pending_limit(Limit, Direction, TransId) ->
+ ?rt2("check pending limit", [Direction, Limit, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val =< Limit ->
+ %% Since we have no intention to increment here, it
+ %% is ok to be _at_ the limit
+ ?rt2("check pending limit - ok", [Val]),
+ {ok, Val};
+ _Val ->
+ ?rt2("check pending limit - aborted", [_Val]),
+ aborted
+ catch
+ _:_ ->
+ %% This function is only called when we "know" the
+ %% counter to exist. So, the only reason that this
+ %% would happen is of the counter has been removed.
+ %% This only happen if the pending limit has been
+ %% reached. In any case, this is basically the same
+ %% as aborted!
+ ?rt2("check pending limit - exit", []),
+ aborted
+ end.
+
+%% check_pending_limit(infinity, _, _) ->
+%% {ok, 0};
+%% check_pending_limit(Limit, Direction, TransId) ->
+%% ?rt2("check pending limit", [Direction, Limit, TransId]),
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% This function is only called when we "know" the
+%% %% counter to exist. So, the only reason that this
+%% %% would happen is of the counter has been removed.
+%% %% This only happen if the pending limit has been
+%% %% reached. In any case, this is basically the same
+%% %% as aborted!
+%% ?rt2("check pending limit - exit", []),
+%% aborted;
+%% Val when Val =< Limit ->
+%% %% Since we have no intention to increment here, it
+%% %% is ok to be _at_ the limit
+%% ?rt2("check pending limit - ok", [Val]),
+%% {ok, Val};
+%% _Val ->
+%% ?rt2("check pending limit - aborted", [_Val]),
+%% aborted
+%% end.
+
+
+check_and_maybe_incr_pending_limit(infinity, _, _) ->
+ ok;
+check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
+ %%
+ %% We need this kind of test to detect when we _pass_ the limit
+ %%
+ ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
+ try megaco_config:get_pending_counter(Direction, TransId) of
+ Val when Val > Limit ->
+ ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
+ aborted; % Already passed the limit
+ Val ->
+ ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
+ megaco_config:incr_pending_counter(Direction, TransId),
+ if
+ Val < Limit ->
+ ok; % Still within the limit
+ true ->
+ ?rt2("check and maybe incr - error",
+ [Direction, Val, Limit]),
+ error % Passed the limit
+ end
+ catch
+ _:_ ->
+ %% Has not been created yet (connect).
+ megaco_config:cre_pending_counter(Direction, TransId, 1),
+ ok
+ end.
+
+
+%% check_and_maybe_incr_pending_limit(infinity, _, _) ->
+%% ok;
+%% check_and_maybe_incr_pending_limit(Limit, Direction, TransId) ->
+%% %%
+%% %% We need this kind of test to detect when we _pass_ the limit
+%% %%
+%% ?rt2("check and maybe incr pending limit", [Direction, Limit, TransId]),
+%% case (catch megaco_config:get_pending_counter(Direction, TransId)) of
+%% {'EXIT', _} ->
+%% %% Has not been created yet (connect).
+%% megaco_config:cre_pending_counter(Direction, TransId, 1),
+%% ok;
+%% Val when Val > Limit ->
+%% ?rt2("check and maybe incr - aborted", [Direction, Val, Limit]),
+%% aborted; % Already passed the limit
+%% Val ->
+%% ?rt2("check and maybe incr - incr", [Direction, Val, Limit]),
+%% megaco_config:incr_pending_counter(Direction, TransId),
+%% if
+%% Val < Limit ->
+%% ok; % Still within the limit
+%% true ->
+%% ?rt2("check and maybe incr - error",
+%% [Direction, Val, Limit]),
+%% error % Passed the limit
+%% end
+%% end.
+
+
+%% BUGBUG BUGBUG BUGBUG
+%%
+%% Do we know that the Rep is still valid? A previous transaction
+%% could have taken a lot of time.
+%%
+handle_request({ConnData, TransId, T}, Extra) ->
+ case handle_request(ConnData, TransId, T, Extra) of
+ {pending, _RequestData} ->
+ handle_long_request(ConnData, TransId, T, Extra);
+ Else ->
+ Else
+ end.
+
+handle_request(ConnData, TransId, T, Extra) ->
+ ?report_trace(ConnData, "handle request", [TransId, T]),
+
+ %% Pending limit:
+ %% Ok, before we begin, lets check that this request
+ %% has not been aborted. I.e. exceeded the pending
+ %% limit, so go check it...
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_and_maybe_create_pending_limit(Limit, sent, TransId) of
+ ok ->
+ %% Ok so far, now update state
+ case megaco_monitor:update_reply_field(TransId,
+ #reply.state,
+ eval_request) of
+ true ->
+ Actions = T#'TransactionRequest'.actions,
+ {AckAction, SendReply} =
+ handle_request_callback(ConnData, TransId, Actions,
+ T, Extra),
+
+ %% Next step, while we where in the callback function,
+ %% the pending limit could have been exceeded, so check
+ %% it again...
+ do_handle_request(AckAction, SendReply,
+ ConnData, TransId);
+
+ false ->
+ %% Ugh?
+ ignore
+ end;
+
+ aborted ->
+ %% Pending limit
+ %% Already exceeded the limit
+ %% The user does not yet know about this request, so
+ %% don't bother telling that it has been aborted...
+ %% Furthermore, the reply timer has not been started,
+ %% so do the cleanup now
+ ?rt1(ConnData, "pending limit already passed", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ cancel_reply(ConnData, Rep, aborted);
+ _ ->
+ ok
+ end,
+ ignore
+ end.
+
+do_handle_request(_, ignore, _ConnData, _TransId) ->
+ ?rt1(_ConnData, "ignore: don't reply", [_TransId]),
+ ignore;
+do_handle_request(_, ignore_trans_request, ConnData, TransId) ->
+ ?rt1(ConnData, "ignore trans request: don't reply", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{} = Rep] ->
+ cancel_reply(ConnData, Rep, ignore);
+ _ ->
+ ignore
+ end;
+do_handle_request({pending, _RequestData}, {aborted, ignore}, _, _) ->
+ ?rt2("handle request: pending - aborted - ignore => don't reply", []),
+ ignore;
+do_handle_request({pending, _RequestData}, {aborted, _SendReply}, _, _) ->
+ ?rt2("handle request: pending - aborted => don't reply", []),
+ ignore;
+do_handle_request({pending, RequestData}, _SendReply, _ConnData, _) ->
+ ?rt2("handle request: pending", [RequestData]),
+ {pending, RequestData};
+do_handle_request(AckAction, {ok, Bin}, ConnData, TransId)
+ when is_binary(Bin) ->
+ ?rt1(ConnData, "handle request - ok", [AckAction, TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{pending_timer_ref = PendingRef} = Rep] ->
+
+ #conn_data{reply_timer = InitTimer,
+ conn_handle = ConnHandle} = ConnData,
+
+ %% Pending limit update:
+ %% - Cancel the pending timer, if running
+ %% - Delete the pending counter
+ %%
+
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_config:del_pending_counter(sent, TransId),
+
+ Method = timer_method(AckAction),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ OptBin = opt_garb_binary(CurrTimer, Bin),
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A,
+ WaitFor),
+ Rep2 = Rep#reply{pending_timer_ref = undefined,
+ handler = undefined,
+ bytes = OptBin,
+ state = waiting_for_ack,
+ timer_ref = Ref,
+ ack_action = AckAction},
+ megaco_monitor:insert_reply(Rep2), % Timing problem?
+ ignore;
+
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_request(AckAction, {ok, {Sent, NotSent}}, ConnData, TransId)
+ when is_list(Sent) andalso is_list(NotSent) ->
+ ?rt1(ConnData, "handle request - ok [segmented reply]",
+ [AckAction, TransId]),
+
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{pending_timer_ref = PendingRef} = Rep] ->
+
+ %% d("do_handle_request -> found reply record:"
+ %% "~n Rep: ~p", [Rep]),
+
+ #conn_data{reply_timer = InitTimer,
+ conn_handle = ConnHandle} = ConnData,
+
+ %% Pending limit update:
+ %% - Cancel the pending timer, if running
+ %% - Delete the pending counter
+ %%
+
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_config:del_pending_counter(sent, TransId),
+
+ Method = timer_method(AckAction),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ Garb = fun(Bin) -> opt_garb_binary(CurrTimer, Bin) end,
+ OptBins = [{SN, Garb(Bin), undefined} || {SN, Bin} <- Sent],
+
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A, WaitFor),
+
+ Rep2 = Rep#reply{pending_timer_ref = undefined,
+ handler = undefined,
+ bytes = OptBins,
+ state = waiting_for_ack,
+ timer_ref = Ref,
+ ack_action = AckAction,
+ segments = NotSent},
+ megaco_monitor:insert_reply(Rep2), % Timing problem?
+
+ ignore;
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_request(_, {error, aborted}, ConnData, TransId) ->
+ ?report_trace(ConnData, "aborted during our absence", [TransId]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ cancel_reply(ConnData, Rep, aborted);
+ _ ->
+ ok
+ end,
+ ignore;
+do_handle_request(AckAction, {error, Reason}, ConnData, TransId) ->
+ ?report_trace(ConnData, "error", [TransId, Reason]),
+ case megaco_monitor:lookup_reply(TransId) of
+ [Rep] ->
+ Rep2 = Rep#reply{state = waiting_for_ack,
+ ack_action = AckAction},
+ cancel_reply(ConnData, Rep2, Reason);
+ _ ->
+ ok
+ end,
+ ignore;
+do_handle_request(AckAction, SendReply, ConnData, TransId) ->
+ ?report_trace(ConnData, "unknown send trans reply result",
+ [TransId, AckAction, SendReply]),
+ ignore.
+
+
+handle_requests([{ConnData, TransId, T} | Rest], Pending, Extra) ->
+ ?rt2("handle requests", [TransId]),
+ case handle_request(ConnData, TransId, T, Extra) of
+ {pending, RequestData} ->
+ handle_requests(Rest, [{ConnData,TransId,RequestData} | Pending], Extra);
+ _ ->
+ handle_requests(Rest, Pending, Extra)
+ end;
+handle_requests([], Pending, _Extra) ->
+ ?rt2("handle requests - done", [Pending]),
+ Pending.
+
+%% opt_garb_binary(timeout, _Bin) -> garb_binary; % Need msg at restart of timer
+opt_garb_binary(_Timer, Bin) -> Bin.
+
+timer_method(discard_ack) ->
+ apply_method;
+timer_method(_) ->
+ spawn_method.
+
+
+handle_long_request({ConnData, TransId, RequestData}, Extra) ->
+
+ ?rt2("handle long request", [TransId, RequestData]),
+
+ %% Pending limit:
+ %% We need to check the pending limit, in case it was
+ %% exceeded before we got this far...
+ %% We dont need to be able to create the counter here,
+ %% since that was done in the handle_request function.
+
+ #conn_data{sent_pending_limit = Limit} = ConnData,
+
+ case check_pending_limit(Limit, sent, TransId) of
+ {ok, _} ->
+ handle_long_request(ConnData, TransId, RequestData, Extra);
+ _ ->
+ %% Already exceeded the limit
+ ignore
+ end.
+
+handle_long_request(ConnData, TransId, RequestData, Extra) ->
+ ?report_trace(ConnData, "callback: trans long request",
+ [TransId, {request_data, RequestData}]),
+
+ %% Attempt to update the handler field for this reply record
+ %% (if there is one).
+ case megaco_monitor:update_reply_field(TransId, #reply.handler, self()) of
+ true ->
+ {AckAction, Res} =
+ handle_long_request_callback(ConnData, TransId,
+ RequestData, Extra),
+ do_handle_long_request(AckAction, Res, ConnData, TransId);
+ false ->
+ %% Been removed already?
+ ignore
+ end.
+
+
+do_handle_long_request(AckAction, {ok, Bin}, ConnData, TransId) ->
+ case megaco_monitor:lookup_reply_field(TransId, #reply.trans_id) of
+ {ok, _} ->
+ Method = timer_method(AckAction),
+ InitTimer = ConnData#conn_data.reply_timer,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ OptBin = opt_garb_binary(CurrTimer, Bin),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ Ref = megaco_monitor:apply_after(Method, M, F, A, WaitFor),
+ NewFields =
+ [{#reply.bytes, OptBin},
+ {#reply.state, waiting_for_ack},
+ {#reply.timer_ref, Ref},
+ {#reply.ack_action, AckAction}],
+ megaco_monitor:update_reply_fields(TransId, NewFields); % Timing problem?
+ _ ->
+ %% Been removed already?
+ ignore
+ end;
+do_handle_long_request(_, {error, Reason}, ConnData, TransId) ->
+ ?report_trace(ConnData, "send trans reply", [TransId, {error, Reason}]),
+ ignore.
+
+handle_request_abort_callback(ConnData, TransId, Pid) ->
+ Extra = ?default_user_callback_extra,
+ handle_request_abort_callback(ConnData, TransId, Pid, Extra).
+
+handle_request_abort_callback(ConnData, TransId, Pid, Extra) ->
+ ?report_trace(ConnData, "callback: trans request aborted", [TransId, Pid]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Serial = TransId#trans_id.serial,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Serial, Pid | UserArgs];
+ _ ->
+ [ConnHandle, Version, Serial, Pid, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_request_abort, Args)),
+ ?report_debug(ConnData, "return: trans request aborted",
+ [TransId, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction request abort callback failed: ~w",
+ [Res]),
+ ok
+ end.
+
+handle_request_callback(ConnData, TransId, Actions, T, Extra) ->
+ ?report_trace(ConnData, "callback: trans request", [T]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Actions | UserArgs];
+ _ ->
+ [ConnHandle, Version, Actions, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_request, Args)),
+ ?report_debug(ConnData, "return: trans request", [T, {return, Res}]),
+ case Res of
+ ignore -> %% NOTE: Only used for testing!!
+ {discard_ack, ignore};
+
+ ignore_trans_request ->
+ {discard_ack, ignore_trans_request};
+
+ {discard_ack, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Error} when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Replies, SendOpts} when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+
+ {{handle_pending_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_pending_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, when_pending_sent),
+ {{handle_ack, AckData}, SendReply};
+
+ {{handle_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+
+ {{handle_sloppy_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Error}
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Replies, SendOpts}
+ when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_sloppy_ack, AckData}, Error, SendOpts}
+ when is_record(Error, 'ErrorDescriptor') andalso
+ is_list(SendOpts) ->
+ Reply = {transactionError, Error},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {{handle_ack, AckData}, SendReply};
+
+ {pending, RequestData} ->
+ %% The user thinks that this request will take
+ %% quite a while to evaluate. Maybe respond with
+ %% a pending trans (depends on the pending limit)
+ SendReply = maybe_send_pending(ConnData, TransId),
+ {{pending, RequestData}, SendReply};
+
+ Error ->
+ ErrorText = atom_to_list(UserMod),
+ ED = #'ErrorDescriptor'{
+ errorCode = ?megaco_internal_gateway_error,
+ errorText = ErrorText},
+ ?report_important(ConnData,
+ "callback: <ERROR> trans request",
+ [ED, {error, Error}]),
+ error_msg("transaction request callback failed: ~w", [Error]),
+ Reply = {transactionError, ED},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply}
+ end.
+
+handle_long_request_callback(ConnData, TransId, RequestData, Extra) ->
+ ?report_trace(ConnData, "callback: trans long request", [RequestData]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, RequestData | UserArgs];
+ _ ->
+ [ConnHandle, Version, RequestData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_long_request, Args)),
+ ?report_debug(ConnData, "return: trans long request",
+ [{request_data, RequestData}, {return, Res}]),
+ case Res of
+ ignore ->
+ {discard_ack, ignore};
+
+ {discard_ack, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply};
+ {discard_ack, Replies, SendOpts} when is_list(Replies) andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, asn1_NOVALUE),
+ {discard_ack, SendReply};
+
+ {{handle_ack, AckData}, Replies} when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+ {{handle_ack, AckData}, Replies, SendOpts} when is_list(Replies)
+ andalso
+ is_list(SendOpts) ->
+ Reply = {actionReplies, Replies},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ SendOpts, 'NULL'),
+ {{handle_ack, AckData}, SendReply};
+
+ Error ->
+ ErrorText = atom_to_list(UserMod),
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_internal_gateway_error,
+ errorText = ErrorText},
+ ?report_important(ConnData, "callback: <ERROR> trans long request",
+ [ED, {error, Error}]),
+ error_msg("long transaction request callback failed: ~w", [Error]),
+ Reply = {transactionError, ED},
+ SendReply = maybe_send_reply(ConnData, TransId, Reply,
+ [], asn1_NOVALUE),
+ {discard_ack, SendReply}
+ end.
+
+handle_pending(ConnData, T, Extra) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle pending", [T, TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [Req] ->
+
+ %% ------------------------------------------
+ %%
+ %% Check received pending limit
+ %%
+ %% ------------------------------------------
+
+ Limit = ConnData#conn_data.recv_pending_limit,
+ case check_and_maybe_incr_pending_limit(Limit,
+ recv, TransId) of
+
+ ok ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit not exceeded
+ %%
+ %% ----------------------------------------------------
+
+ handle_recv_pending(ConnData, TransId, Req, T);
+
+ error ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit exceeded
+ %%
+ %% Time to give up on this transaction
+ %% 1) Delete request record
+ %% 2) Cancel timers
+ %% 3) Delete the (receive) pending counter
+ %% 4) Inform the user (handle_trans_reply)
+ %%
+ %% ----------------------------------------------------
+
+ handle_recv_pending_error(ConnData, TransId, Req, T, Extra);
+
+
+ aborted ->
+ %% ----------------------------------------------------
+ %%
+ %% Received pending limit already exceeded
+ %%
+ %% BMK BMK BMK -- can this really happen?
+ %%
+ %% The user has already been notified about this
+ %% (see error above)
+ %%
+ %% ----------------------------------------------------
+
+ ok
+
+ end;
+
+ [] ->
+ ?report_trace(ConnData, "remote pending (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end.
+
+handle_recv_pending(#conn_data{long_request_resend = LRR,
+ conn_handle = ConnHandle} = ConnData,
+ TransId,
+ #request{timer_ref = {short, Ref},
+ init_long_timer = InitTimer}, T) ->
+
+ ?rt2("handle pending - long request", [LRR, InitTimer]),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% Start using the long timer.
+ %% We can now drop the "bytes", since we will
+ %% not resend from now on.
+
+ megaco_monitor:cancel_apply_after(Ref),
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ case LRR of
+ true ->
+ [{#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, CurrTimer}];
+ false ->
+ [{#request.bytes, {no_send, garb_binary}},
+ {#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, CurrTimer}]
+ end,
+ ?report_trace(ConnData, "trans pending (timer restarted)", [T]),
+ megaco_monitor:update_request_fields(TransId, NewFields); % Timing problem?
+
+handle_recv_pending(_ConnData, _TransId,
+ #request{timer_ref = {long, _Ref},
+ curr_timer = timeout}, _T) ->
+
+ ?rt3("handle pending - timeout"),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% This can happen if the timer is running for the last
+ %% time. I.e. next time it expires, will be the last.
+ %% Therefor we really do not need to do anything here.
+ %% The cleanup will be done in request_timeout.
+
+ ok;
+
+handle_recv_pending(#conn_data{conn_handle = ConnHandle} = ConnData, TransId,
+ #request{timer_ref = {long, Ref},
+ curr_timer = CurrTimer}, T) ->
+
+ ?rt2("handle pending - still waiting", [CurrTimer]),
+
+ %% The request seems to take a while,
+ %% let's reset our transmission timer.
+ %% We now know the other side has got
+ %% the request and is working on it,
+ %% so there is no need to keep the binary
+ %% message for re-transmission.
+
+ %% We just need to recalculate the timer, i.e.
+ %% increment the timer (one "slot" has been consumed).
+
+ megaco_monitor:cancel_apply_after(Ref),
+ {WaitFor, Timer2} = megaco_timer:restart(CurrTimer),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.timer_ref, {long, Ref2}},
+ {#request.curr_timer, Timer2}],
+ ?report_trace(ConnData,
+ "long trans pending"
+ " (timer restarted)", [T]),
+ %% Timing problem?
+ megaco_monitor:update_request_fields(TransId, NewFields).
+
+
+handle_recv_pending_error(ConnData, TransId, Req, T, Extra) ->
+ %% 1) Delete the request record
+ megaco_monitor:delete_request(TransId),
+
+ %% 2) Possibly cancel the timer
+ case Req#request.timer_ref of
+ {_, Ref} ->
+ megaco_monitor:cancel_apply_after(Ref);
+ _ ->
+ ok
+ end,
+
+ %% 3) Delete the (receive) pending counter
+ megaco_config:del_pending_counter(recv, TransId),
+
+ %% 4) Inform the user that his/her request reached
+ %% the receive pending limit
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, exceeded_recv_pending_limit},
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+
+ ?report_trace(ConnData, "receive pending limit reached", [T]),
+ return_reply(ConnData2, TransId, UserReply, Extra).
+
+
+%%
+%% This _is_ a segmented message.
+%%
+%% Since this is not the last segment, we shall not send any ack.
+%% (even if three-way-handshake has been configured).
+%%
+handle_reply(
+ ConnData,
+ #megaco_transaction_reply{segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} = T, Extra)
+ when is_integer(SN) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle segmented reply", [T, TransId, SN]),
+ case megaco_monitor:lookup_request(TransId) of
+
+ %% ---------------------------------------------------------
+ %% The first segment, so stop the request timer. No longer
+ %% needed when the segment(s) start to arrive.
+
+ [#request{timer_ref = {_Type, Ref},
+ seg_recv = [],
+ seg_timer_ref = undefined} = Req] ->
+
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - first seg",
+ [T]),
+
+ %% Stop the request timer
+ megaco_monitor:cancel_apply_after(Ref), %% OTP-4843
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% First segment for this reply
+ NewFields =
+ [{#request.timer_ref, undefined},
+ {#request.seg_recv, [SN]}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, false, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, false, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+
+ %% ---------------------------------------------------------
+ %% This is not the first segment.
+ %% The segment timer has not been started, so the last
+ %% segment have been received.
+ %% We must check that this is not a re-transmission!
+
+ [#request{seg_recv = Segs,
+ seg_timer_ref = undefined} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% Updated/handle received segment
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission, so we shall not pass
+ %% it on to the user (or update the request record).
+ ok;
+ false ->
+ %% First time for this segment
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_recv,
+ [ SN | Segs ]),
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, false, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, false, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+
+ %% ---------------------------------------------------------
+ %% The segment timer is running!
+ %% This could be the last (out-of-order) segment!
+ %% We must check that this is not a re-transmission!
+
+ [#request{seg_recv = Segs,
+ seg_timer_ref = SegRef} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the segment
+ send_segment_reply(ConnData, SN),
+
+ %% Updated received segments
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission
+ ok;
+ false ->
+ %% First time for this segment,
+ %% we may now have a complete set
+ Last =
+ case is_all_segments([SN | Segs]) of
+ {true, _Sorted} ->
+ megaco_monitor:cancel_apply_after(SegRef),
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true;
+ {false, Sorted} ->
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_recv,
+ Sorted),
+ false
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+
+ [] ->
+ ?report_trace(ConnData, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end;
+
+
+%%
+%% This _is_ a segmented message and it's the last segment of the
+%% message.
+%%
+handle_reply(
+ ConnData,
+ #megaco_transaction_reply{segmentNumber = SN,
+ segmentationComplete = 'NULL'} = T, Extra)
+ when is_integer(SN) ->
+ TransId = to_local_trans_id(ConnData),
+ ?rt2("handle (last) segmented reply", [T, TransId, SN]),
+ case megaco_monitor:lookup_request(TransId) of
+
+ %% ---------------------------------------------------------
+ %% The first segment, so stop the request timer. No longer
+ %% needed when the segment(s) start to arrive.
+
+ [#request{timer_ref = {_Type, Ref},
+ seg_recv = [],
+ seg_timer_ref = undefined} = Req] ->
+
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - "
+ "first/complete seg", [T]),
+
+ %% Stop the request timer
+ megaco_monitor:cancel_apply_after(Ref), %% OTP-4843
+
+ %% Acknowledge the ("last") segment
+ send_segment_reply_complete(ConnData, SN),
+
+ %% It is ofcourse pointless to split
+ %% a transaction into just one segment,
+ %% but just to be sure, we handle that
+ %% case also
+ Last =
+ if
+ SN > 1 ->
+ %% More then one segment
+ %% First time for this segment
+ ConnHandle = ConnData#conn_data.conn_handle,
+ InitSegTmr = Req#request.init_seg_timer,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitSegTmr),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ SegRef =
+ megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.timer_ref, undefined},
+ {#request.seg_recv, [SN]},
+ {#request.seg_timer_ref, SegRef}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+ false;
+ true ->
+ %% Just one segment!
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+
+ [#request{seg_recv = Segs} = Req] ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(ConnData, "[segmented] trans reply - no seg acc",
+ [T]),
+
+ %% Acknowledge the ("last") segment
+ send_segment_reply_complete(ConnData, SN),
+
+ %% Updated received segments
+ %% This is _probably_ the last segment, but some of
+ %% the previous segments may have been lost, so we
+ %% may not have a complete set!
+ case lists:member(SN, Segs) of
+ true ->
+ %% This is a re-transmission
+ ok;
+ false ->
+ Last =
+ case is_all_segments([SN | Segs]) of
+ {true, _Sorted} ->
+ ?report_trace(ConnData,
+ "[segmented] trans reply - "
+ "complete set", [T]),
+ megaco_monitor:delete_request(TransId),
+ send_ack(ConnData),
+ true;
+ {false, Sorted} ->
+ ConnHandle = ConnData#conn_data.conn_handle,
+ InitSegTmr = Req#request.init_seg_timer,
+ {WaitFor, CurrTimer} =
+ megaco_timer:init(InitSegTmr),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, CurrTimer],
+ SegRef =
+ megaco_monitor:apply_after(M, F, A,
+ WaitFor),
+ NewFields =
+ [{#request.seg_recv, Sorted},
+ {#request.seg_timer_ref, SegRef}],
+ megaco_monitor:update_request_fields(TransId, NewFields),
+ false
+ end,
+
+ %% Handle the reply
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, {SN, Last, Reason}};
+ {actionReplies, Replies} ->
+ {ok, {SN, Last, Replies}}
+ end,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra)
+
+ end;
+
+ [] ->
+ ?report_trace(ConnData, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(ConnData, T, Extra)
+ end;
+
+
+%%
+%% This is _not_ a segmented message,
+%% i.e. it's an ordinary transaction reply
+%%
+handle_reply(#conn_data{conn_handle = CH} = CD, T, Extra) ->
+ TransId = to_local_trans_id(CD),
+ ?rt2("handle reply", [T, TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [Req] when (is_record(Req, request) andalso
+ (CD#conn_data.cancel =:= true)) ->
+ ?TC_AWAIT_REPLY_EVENT(true),
+ do_handle_reply_cancel(CD, Req, T);
+
+ [#request{remote_mid = RMid} = Req] when ((RMid =:= preliminary_mid) orelse
+ (RMid =:= CH#megaco_conn_handle.remote_mid)) ->
+ ?TC_AWAIT_REPLY_EVENT(false),
+ %% Just in case conn_data got update after our lookup
+ %% but before we looked up the request record, we
+ %% check the cancel field again.
+ case megaco_config:conn_info(CD, cancel) of
+ true ->
+ do_handle_reply_cancel(CD, Req, T);
+ false ->
+ do_handle_reply(CD, Req, TransId, T, Extra)
+ end;
+
+ [#request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ remote_mid = RMid}] ->
+ ?report_trace(CD,
+ "received trans reply with invalid remote mid",
+ [T, RMid]),
+ WrongMid = CH#megaco_conn_handle.remote_mid,
+ T2 = transform_transaction_reply_enc(CD#conn_data.protocol_version,
+ T),
+ UserReply = {error, {wrong_mid, WrongMid, RMid, T2}},
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+ [] ->
+ ?TC_AWAIT_REPLY_EVENT(undefined),
+ ?report_trace(CD, "trans reply (no receiver)", [T]),
+ return_unexpected_trans(CD, T, Extra)
+ end.
+
+do_handle_reply_cancel(CD, #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData}, T) ->
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_unexpected_trans(CD2, T).
+
+%% Plain old handling of incomming replies
+do_handle_reply(CD,
+ #request{timer_ref = {_Type, Ref}, % OTP-4843
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ keep_alive_timer = RKAT},
+ TransId, T, Extra)
+ when ((RKAT =:= plain) orelse (Action =:= call)) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply", [T]),
+
+ %% This is the first reply (maybe of many)
+ megaco_monitor:delete_request(TransId),
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ %% Send acknowledgement
+ maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD),
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, Reason};
+ {actionReplies, Replies} ->
+ {ok, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+%% This may be the first reply (of maybe many)
+do_handle_reply(CD,
+ #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData,
+ keep_alive_ref = undefined} = Req,
+ TransId, T, Extra) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply", [T]),
+
+ %% Could be the first reply, in which case we shall start the
+ %% Request Keep Alive timer...
+ %% This could happen for more than one (1) reply though, so
+ %% we need to check if the counter value actually equals one (1)!
+
+ ReplyNo =
+ create_or_maybe_increment_request_keep_alive_counter(CD, TransId),
+ if
+ (ReplyNo =:= 1) ->
+ %% This *is* the first reply!!
+ %% 1) Stop resend timer
+ {_Type, Ref} = Req#request.timer_ref, % OTP-4843
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+
+ %% 2) Delete pending counter
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ %% 3) Start request keep alive timer
+ ConnHandle = CD#conn_data.conn_handle,
+ RKATimer = Req#request.keep_alive_timer,
+ {RKAWaitFor, _} = megaco_timer:init(RKATimer),
+ RKARef = megaco_monitor:apply_after(?MODULE,
+ request_keep_alive_timeout,
+ [ConnHandle, TransId],
+ RKAWaitFor),
+
+ %% 4) Maybe send acknowledgement (three-way-handshake)
+ maybe_send_ack(T#megaco_transaction_reply.immAckRequired, CD),
+
+ %% 5) And finally store the updated request record
+ Req2 = Req#request{keep_alive_ref = RKARef},
+ megaco_monitor:insert_request(Req2);
+
+ true ->
+ ok
+ end,
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, ReplyNo, Reason};
+ {actionReplies, Replies} ->
+ {ok, ReplyNo, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra);
+
+%% This is *not* the first reply (of many)
+do_handle_reply(CD, #request{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData}, TransId, T, Extra) ->
+ %% Don't care about Req and Rep version diff
+ ?report_trace(CD, "trans reply (first reply already delivered)", [T]),
+
+ ReplyNo = increment_request_keep_alive_counter(CD, TransId),
+
+ UserReply =
+ case T#megaco_transaction_reply.transactionResult of
+ {transactionError, Reason} ->
+ {error, ReplyNo, Reason};
+ {actionReplies, Replies} ->
+ {ok, ReplyNo, Replies}
+ end,
+ CD2 = CD#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(CD2, TransId, UserReply, Extra).
+
+is_all_segments(Segs) ->
+ Sorted = lists:sort(Segs),
+ {is_all_segments(Sorted, 1, lists:last(Sorted)), Sorted}.
+
+is_all_segments([Last], Last, Last) ->
+ true;
+is_all_segments([_], _, _) ->
+ false;
+is_all_segments([SN|Segs], SN, Last) when (SN < Last) ->
+ is_all_segments(Segs, SN+1, Last);
+is_all_segments([SN1|_], SN2, _Last) when SN1 =/= SN2 ->
+ false.
+
+
+handle_segment_reply(CD,
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = SC}, Extra) ->
+ ?rt2("handle segment reply", [{trans_id, TransId},
+ {segment_no, SN},
+ {segmentation_complete, SC}]),
+ TransId2 = to_remote_trans_id(CD#conn_data{serial = TransId}),
+ case megaco_monitor:lookup_reply(TransId2) of
+ [#reply{bytes = Sent,
+ segments = []} = Rep] when is_list(Sent) ->
+ ?rt2("no unsent segments", [Sent]),
+ handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
+ case lists:keysearch(SN, 1, Sent) of
+ {value, {SN, _Bin, SegTmr}} ->
+ megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK
+ case lists:keydelete(SN, 1, Sent) of
+ [] -> %% We are done
+ Ref = Rep#reply.timer_ref,
+ megaco_monitor:cancel_apply_after(Ref),
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ []),
+ ok;
+ NewSent ->
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ NewSent),
+ ok
+ end;
+ _ ->
+ ok
+ end;
+
+ [#reply{bytes = Sent,
+ segments = NotSent}] when is_list(Sent) andalso
+ is_list(NotSent) ->
+ ?rt2("unsent segments", [Sent, NotSent]),
+ handle_segment_reply_callback(CD, TransId, SN, SC, Extra),
+ case lists:keysearch(SN, 1, Sent) of
+ {value, {SN, _Bin, SegTmr}} ->
+ megaco_monitor:cancel_apply_after(SegTmr), %% BMK BMK
+ NewSent = lists:keydelete(SN, 1, Sent),
+ [{SN2, Bin2}|NewNotSent] = NotSent,
+ case send_reply_segment(CD, "send trans reply segment",
+ SN2, Bin2) of
+ {ok, Bin3} ->
+ ?rt2("another segment sent", [Bin3]),
+ NewSent2 = [{SN2, Bin3, undefined}|NewSent],
+ NewFields =
+ [{#reply.bytes, NewSent2},
+ {#reply.segments, NewNotSent}],
+ megaco_monitor:update_reply_fields(TransId2,
+ NewFields),
+ ok;
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ ?report_important(CD, "failed sending segment",
+ [{segment_no, SN2},
+ {error, Error}]),
+ error_msg("failed sending transaction reply [~w] "
+ "segment [~w]: ~w",
+ [TransId, SN2, Error]),
+ megaco_monitor:update_reply_field(TransId2,
+ #reply.bytes,
+ NewSent),
+ ok
+ end;
+ _ ->
+ ok
+ end;
+
+ [#reply{state = State}] ->
+ %% We received a segment reply for a segmented reply we have
+ %% not yet sent? This is either some sort of race condition
+ %% or the "the other side" is really confused.
+ %% Ignore the message but issue a warning just in case...
+ warning_msg("received unexpected segment reply: "
+ "~n Transaction Id: ~p"
+ "~n Segment Number: ~p"
+ "~n Segmentation Complete: ~p"
+ "~n Reply state: ~p",
+ [TransId2, SN, SC, State]),
+ ignore;
+
+ [] ->
+ ignore
+
+ end.
+
+
+%%
+%% This should be passed on to the user only if the user wish it
+%% (sri = segment reply indication)
+%%
+handle_segment_reply_callback(#conn_data{segment_reply_ind = true,
+ conn_handle = ConnHandle,
+ protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs},
+ TransId, SN, SC, Extra) ->
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, TransId, SN, SC | UserArgs];
+ _ ->
+ [ConnHandle, Version, TransId, SN, SC, Extra | UserArgs]
+ end,
+ (catch apply(UserMod, handle_segment_reply, Args));
+handle_segment_reply_callback(_CD, _TransId, _SN, _SC, _Extra) ->
+ ok.
+
+
+handle_acks([{ConnData, Rep, T} | Rest], Extra)
+ when Rep#reply.state == waiting_for_ack ->
+ handle_ack(ConnData, ok, Rep, T, Extra),
+ handle_acks(Rest, Extra);
+handle_acks([], _Extra) ->
+ ok.
+
+%% If the reply to which this is the ack was segmented,
+%% then we also need to check that we have received all
+%% the segment-replies. If not, an error callback call
+%% shall be made instead.
+handle_ack(ConnData, AckStatus,
+ #reply{trans_id = TransId,
+ bytes = Bytes,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = AckAction}, T, Extra)
+ when is_binary(Bytes) orelse (Bytes =:= undefined) ->
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra);
+
+handle_ack(ConnData, AckStatus,
+ #reply{trans_id = TransId,
+ bytes = [],
+ segments = [],
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = AckAction}, T, Extra) ->
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra);
+
+handle_ack(ConnData, OrigAckStatus,
+ #reply{trans_id = TransId,
+ bytes = SegSent,
+ segments = NotSent,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef, %% BMK Still running?
+ ack_action = OrigAckAction}, T, Extra)
+ when is_list(SegSent) andalso is_list(NotSent) ->
+ SN_NotAcked = [SN || {SN, _, _} <- SegSent],
+ SN_NotSent = [SN || {SN, _} <- NotSent],
+ AckStatus = {error, {segment_failure,
+ [{original_ack_status, OrigAckStatus},
+ {segments_not_acked, SN_NotAcked},
+ {segments_not_sent, SN_NotSent}]}},
+ AckAction =
+ case OrigAckAction of
+ {handle_ack, _} ->
+ OrigAckAction;
+ _ ->
+ {handle_ack, segmented_reply}
+ end,
+ cancel_segment_timers(SegSent),
+ handle_ack_cleanup(TransId, ReplyRef, PendingRef),
+ handle_ack_callback(ConnData, AckStatus, AckAction, T, Extra).
+
+handle_ack_cleanup(TransId, ReplyRef, PendingRef) ->
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef),
+ megaco_monitor:delete_reply(TransId),
+ megaco_config:del_pending_counter(sent, TransId). %% BMK: Still existing?
+
+cancel_segment_timers(SegSent) when is_list(SegSent) ->
+ Cancel = fun({_, _, Ref}) ->
+ megaco_monitor:cancel_apply_after(Ref)
+ end,
+ lists:foreach(Cancel, SegSent);
+cancel_segment_timers(_) ->
+ ok.
+
+handle_ack_callback(_CD, ok = _AS, discard_ack = _AA, _T, _Extra) ->
+ ok;
+handle_ack_callback(ConnData, {error, Reason}, discard_ack = AckAction, T, Extra) ->
+ ?report_trace(ConnData, "handle ack (no callback)",
+ [T, AckAction, {error, Reason}, Extra]);
+handle_ack_callback(ConnData, AckStatus, {handle_ack, AckData}, T, Extra) ->
+ ?report_trace(ConnData, "callback: trans ack", [{ack_data, AckData}]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, AckStatus, AckData | UserArgs];
+ _ ->
+ [ConnHandle, Version, AckStatus, AckData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_ack, Args)),
+ ?report_debug(ConnData, "return: trans ack", [T, AckData, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction ack callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+handle_message_error(ConnData, _Error, _Extra)
+ when ConnData#conn_data.monitor_ref == undefined_monitor_ref ->
+ %% May occur if another process already has setup a
+ %% temporary connection, but the handle_connect callback
+ %% function has not yet returned before the eager MG
+ %% re-sends its initial service change message.
+ ignore;
+handle_message_error(ConnData, Error, Extra) ->
+ ?report_trace(ConnData, "callback: message error", [Error]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Error | UserArgs];
+ _ ->
+ [ConnHandle, Version, Error, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_message_error, Args)),
+ ?report_debug(ConnData, "return: message error", [Error, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("message error callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+handle_disconnect_callback(ConnData, UserReason)
+ when is_record(ConnData, conn_data) ->
+ ?report_trace(ConnData, "callback: disconnect", [{reason, UserReason}]),
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ Args = [ConnHandle, Version, UserReason | UserArgs],
+ Res = (catch apply(UserMod, handle_disconnect, Args)),
+ ?report_debug(ConnData, "return: disconnect", [{reason, UserReason}, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("disconnect callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+%%----------------------------------------------------------------------
+%% Test "outgoing" messages
+%%----------------------------------------------------------------------
+
+%% test_request/5 -> {MegacoMessage, EncodingRes}
+%%
+%% This function is only intended for testing
+%% (e.g. answer the question: have I constructed a valid action request?)
+%%
+%% It's not exactly the same code as a call to 'call'
+%% or 'cast' but close enough.
+%%
+test_request(ConnHandle, Actions,
+ Version, EncodingMod, EncodingConfig)
+ when is_record(ConnHandle, megaco_conn_handle) and
+ is_integer(Version) andalso is_atom(EncodingMod) ->
+ %% Create a fake conn_data structure
+ ConnData = #conn_data{serial = 1,
+ protocol_version = Version,
+ conn_handle = ConnHandle,
+ auth_data = asn1_NOVALUE,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig},
+
+ TRs = test_req_compose_transactions(ConnData, Actions),
+ Body = {transactions, TRs},
+ MegaMsg = megaco_messenger_misc:compose_message(ConnData, Version, Body),
+ EncodeRes = megaco_messenger_misc:encode_message(ConnData, MegaMsg),
+ {MegaMsg, EncodeRes}.
+
+
+test_req_compose_transactions(ConnData, [A|_] = ActionsList) when is_list(A) ->
+ LastSerial = ConnData#conn_data.serial,
+ test_req_compose_transactions(LastSerial, lists:reverse(ActionsList), []);
+test_req_compose_transactions(#conn_data{serial = Serial}, Actions) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = Actions},
+ [{transactionRequest, TR}].
+
+test_req_compose_transactions(_Serial, [], Acc) ->
+ lists:reverse(Acc);
+test_req_compose_transactions(Serial, [A|As], Acc) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = A},
+ test_req_compose_transactions(Serial, As, [{transactionRequest, TR}|Acc]).
+
+
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Error)
+ when is_record(Error, 'ErrorDescriptor') ->
+ Reply = {transactionError, Error},
+ test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply);
+test_reply(ConnHandle, Version, EncodingMod, EncodingConfig, Replies)
+ when is_list(Replies) ->
+ Reply = {actionReplies, Replies},
+ test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply).
+
+test_reply_encode(ConnHandle, Version, EncodingMod, EncodingConfig, Reply) ->
+ ImmAck = asn1_NOVALUE,
+ Serial = 1,
+ %% Create a fake conn_data structure
+ CD = #conn_data{serial = Serial,
+ protocol_version = Version,
+ conn_handle = ConnHandle,
+ auth_data = asn1_NOVALUE,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig},
+ TR0 = #megaco_transaction_reply{transactionId = Serial,
+ immAckRequired = ImmAck,
+ transactionResult = Reply},
+ TR = megaco_messenger_misc:transform_transaction_reply(CD, TR0),
+ Body = {transactions, [{transactionReply, TR}]},
+ MegaMsg = megaco_messenger_misc:compose_message(CD, Version, Body),
+ EncodeRes = megaco_messenger_misc:encode_message(CD, MegaMsg),
+ {MegaMsg, EncodeRes}.
+
+
+%%----------------------------------------------------------------------
+%% Send (or prepare) outgoing messages
+%%----------------------------------------------------------------------
+
+%% Description:
+%% Encode a list of actions or a list of list of actions for
+%% later sending (using call or cast).
+%%
+%% encode_actions(CH, Acts, Opts) -> {ok, encoded_actions()} | {error, Reason}
+%% CH -> connection_handle()
+%% Acts -> action_reqs() | [action_reqs()]
+%% action_reqs() -> [action_req()]
+%% action_req() -> #'ActionRequest'{}
+%% Opts -> [option()]
+%% option() -> {Tab, Val}
+%% Tag -> atom()
+%% Val -> term()
+%% encoded_actions() -> binary() | [binary()]
+%% Reason -> term()
+encode_actions(CH, [A|_] = ActionsList, Opts)
+ when is_record(CH, megaco_conn_handle) andalso is_list(A) ->
+ (catch encode_multi_actions(CH, ActionsList, Opts));
+
+encode_actions(CH, [A|_] = Actions, Opts)
+ when is_record(CH, megaco_conn_handle) andalso is_tuple(A) ->
+ do_encode_actions(CH, Actions, Opts).
+
+encode_multi_actions(CH, ActionsList, Opts) ->
+ case prepare_req_send_options(CH, Opts) of
+ {ok, CD} ->
+ ActsList = [encode_multi_actions(CD, Acts) || Acts <- ActionsList],
+ {ok, ActsList};
+ Error ->
+ Error
+ end.
+
+encode_multi_actions(CD, Actions) ->
+ case megaco_messenger_misc:encode_actions(CD,
+ "encode multi actions",
+ Actions) of
+ {ok, Bin} ->
+ Bin;
+ Error ->
+ throw(Error)
+ end.
+
+do_encode_actions(CH, Actions, Opts)
+ when is_record(CH, megaco_conn_handle) ->
+ case prepare_req_send_options(CH, Opts) of
+ {ok, CD} ->
+ megaco_messenger_misc:encode_actions(CD,
+ "encode actions",
+ Actions);
+ Error ->
+ Error
+ end.
+
+prepare_req_send_options(CH, Opts) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] ->
+ override_req_send_options(any, CD, Opts);
+ [] ->
+ {error, {not_found, conn_data}}
+ end.
+
+
+call(ConnHandle, Actions, Options) ->
+ case lists:keymember(reply_data, 1, Options) of
+ true ->
+ {error, {bad_option, reply_data}};
+ false ->
+ Self = self(),
+ ProxyFun = fun() -> call_proxy(Self) end,
+ {Proxy, MRef} = erlang:spawn_monitor(ProxyFun),
+ Options2 = [{reply_data, Proxy} | Options],
+ call_or_cast(call, ConnHandle, Actions, Options2, MRef)
+ end.
+
+cast(ConnHandle, Actions, Options) ->
+ call_or_cast(cast, ConnHandle, Actions, Options, undefined).
+
+%% In a transaction there can be several actions, so if the
+%% First element of the Actions list is an ''ActionRequest''
+%% record this a list of ActionRequest's for one Transaction
+%% request. If on the other hand this is not the case, then
+%% the Actions list is assumed to be a list of list of
+%% ActionRequest. That is, action requests for several transactions.
+%% It could also be a binary or a list of binaries (if
+%% the actions has already been encoded).
+call_or_cast(CallOrCast, ConnHandle, [A|_] = Actions, Options, ProxyMon)
+ when is_tuple(A) ->
+ %% Just one transaction
+ case call_or_cast(CallOrCast, ConnHandle, [Actions], Options, ProxyMon) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, Reason};
+ {Version, [Reply]} when is_integer(Version) ->
+ {Version, Reply};
+ {Version, Error} when is_integer(Version) ->
+ {Version, Error}
+ end;
+
+call_or_cast(CallOrCast, ConnHandle, Actions, Options, ProxyMon)
+ when is_binary(Actions) ->
+ %% Just one transaction (although the actions has already been encoded)
+ case call_or_cast(CallOrCast, ConnHandle, [Actions], Options, ProxyMon) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, Reason};
+ {Version, [Reply]} when is_integer(Version) ->
+ {Version, Reply};
+ {Version, Error} when is_integer(Version) ->
+ {Version, Error}
+ end;
+
+call_or_cast(CallOrCast, ConnHandle, ActionsList, Options, ProxyMon)
+ when is_record(ConnHandle, megaco_conn_handle) ->
+ case prepare_req_send_options(CallOrCast,
+ ConnHandle, Options, ActionsList) of
+ {ok, ConnData} ->
+ ?report_trace(ConnData, "call_or_cast - options prepared", []),
+ case encode_requests(ConnData, ActionsList) of
+ {ok, TRs, BinOrBins} ->
+ ?report_trace(ConnData,
+ "call_or_cast - request encoded", []),
+ send_request(ConnData, ConnHandle,
+ TRs, CallOrCast, BinOrBins),
+ case CallOrCast of
+ call ->
+ TransIds = to_local_trans_id(ConnData, TRs),
+ wait_for_reply(ConnData, TransIds, ProxyMon);
+ cast ->
+ ok
+ end;
+ {error, Reason} ->
+ call_proxy_cleanup(ConnData, ProxyMon),
+ Version = ConnData#conn_data.protocol_version,
+ return_error(CallOrCast, Version, {error, Reason})
+ end;
+ {error, Reason} ->
+ call_proxy_cleanup(Options, ProxyMon),
+ return_error(CallOrCast, 1, {error, Reason})
+ end;
+call_or_cast(CallOrCast, ConnHandle, _Actions, Options, ProxyMon) ->
+ call_proxy_cleanup(Options, ProxyMon),
+ return_error(CallOrCast, 1, {error, {bad_megaco_conn_handle, ConnHandle}}).
+
+
+return_error(Action, Version, Error) ->
+ case Action of
+ call -> {Version, Error};
+ cast -> Error
+ end.
+
+wait_for_reply(CD, TransIds, ProxyMon) ->
+ ProxyPid = CD#conn_data.reply_data,
+ ProxyPid ! {go, self(), CD, TransIds},
+ receive
+ {reply, ProxyPid, Reply} ->
+ erlang:demonitor(ProxyMon, [flush]),
+ Reply;
+ {'DOWN', ProxyMon, process, ProxyPid, Info} ->
+ UserReply = {error, {call_proxy_crash, Info}},
+ {CD#conn_data.protocol_version, UserReply}
+ end.
+
+
+call_proxy_cleanup(#conn_data{reply_data = ProxyPid}, ProxyMon) ->
+ do_call_proxy_cleanup(ProxyPid, ProxyMon);
+call_proxy_cleanup(Options, ProxyMon) when is_list(Options) ->
+ ProxyPid =
+ case lists:keysearch(reply_data, 1, Options) of
+ {value, {reply_data, Data}} ->
+ Data;
+ _ ->
+ undefined
+ end,
+ do_call_proxy_cleanup(ProxyPid, ProxyMon);
+call_proxy_cleanup(ProxyPid, ProxyMon) ->
+ do_call_proxy_cleanup(ProxyPid, ProxyMon).
+
+do_call_proxy_cleanup(ProxyPid, ProxyMon) ->
+ maybe_demonitor(ProxyMon),
+ maybe_stop_proxy(ProxyPid),
+ ok.
+
+maybe_demonitor(undefined) ->
+ ok;
+maybe_demonitor(Mon) ->
+ (catch erlang:demonitor(Mon, [flush])),
+ ok.
+
+maybe_stop_proxy(Pid) when is_pid(Pid) ->
+ Pid ! {stop, self()},
+ ok;
+maybe_stop_proxy(_) ->
+ ok.
+
+
+call_proxy(Parent) ->
+ receive
+ {go, Parent, CD, TransIds} ->
+ call_proxy(Parent, CD, TransIds);
+ {stop, Parent} ->
+ exit(normal)
+ end.
+
+call_proxy(Parent, CD, TransIds) ->
+ Reply = proxy_wait_for_reply(CD, TransIds, []),
+ Parent ! {reply, self(), Reply},
+ call_proxy_gc(CD, CD#conn_data.call_proxy_gc_timeout).
+
+call_proxy_gc(CD, Timeout) when (Timeout > 0) ->
+ T = t(),
+ receive
+ {?MODULE, TransId, Version, Result} -> % Old format
+ CD2 = CD#conn_data{protocol_version = Version},
+ Extra = ?default_user_callback_extra,
+ return_unexpected_trans_reply(CD2, TransId, Result, Extra),
+ call_proxy_gc(CD, Timeout - (t() - T));
+
+ {?MODULE, TransId, Version, Result, Extra} ->
+ CD2 = CD#conn_data{protocol_version = Version},
+ return_unexpected_trans_reply(CD2, TransId, Result, Extra),
+ call_proxy_gc(CD, Timeout - (t() - T))
+
+ after Timeout ->
+ exit(normal)
+ end;
+call_proxy_gc(_CD, _Timeout) ->
+ exit(normal).
+
+proxy_wait_for_reply(_CD, [], Replies0) ->
+ % Make sure they come in the same order as the requests where sent
+ Replies1 = lists:keysort(2, Replies0),
+ %% Must all be the same version
+ [{Version, _, _}|_] = Replies1,
+ Replies2 = [Result || {_Version, _TransId, Result} <- Replies1],
+ {Version, Replies2};
+proxy_wait_for_reply(CD, TransIds, Replies) ->
+ receive
+ {?MODULE, TransId, Version, Reply} -> % Old format
+ {TransIds2, Replies2} =
+ wfr_handle_reply(CD,
+ TransIds, TransId,
+ Version, Replies, Reply),
+ proxy_wait_for_reply(CD, TransIds2, Replies2);
+
+ {?MODULE, TransId, Version, Reply, Extra} ->
+ {TransIds2, Replies2} =
+ wfr_handle_reply(CD,
+ TransIds, TransId,
+ Version, Replies, Reply, Extra),
+ proxy_wait_for_reply(CD, TransIds2, Replies2)
+ end.
+
+wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply) ->
+ Extra = ?default_user_callback_extra,
+ wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply, Extra).
+
+wfr_handle_reply(CD, TransIds, TransId, Version, Replies, Reply, Extra) ->
+ %% Is this meant for us?
+ case lists:member(TransId, TransIds) of
+ true -> % Yep
+ wfr_update(TransIds, TransId, Version, Replies, Reply, Extra);
+ false -> % Nop
+ CD2 = CD#conn_data{protocol_version = Version},
+ return_unexpected_trans_reply(CD2, TransId, Reply, Extra),
+ {TransIds, Replies}
+ end.
+
+wfr_mk_reply(Version, TransId, Result, ?default_user_callback_extra = _Extra) ->
+ {Version, TransId, Result};
+wfr_mk_reply(Version, TransId, Result0, Extra) ->
+ Result = list_to_tuple(lists:append(tuple_to_list(Result0), [Extra])),
+ {Version, TransId, Result}.
+
+%% Last segment of a reply
+%% transactionResult "=" actionReplies
+wfr_update(TransIds, TransId, Version, Results, {ok, {SegNo, Last, ARs}}, Extra)
+ when is_integer(SegNo) andalso (Last == true) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% All segments ok (actionReplies)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ SegReps2 = lists:keysort(1, [{SegNo, ARs}|SegReps]),
+ Rep = wfr_mk_reply(V, TransId, {ok, SegReps2}, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Atleast one segment error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = lists:keysort(1, [{SegNo, ARs}|OkSegs]),
+ ErrSegs2 = lists:keysort(1, ErrSegs),
+ Error = {error, {segment, OkSegs2, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First and only segment
+ Rep = wfr_mk_reply(Version, TransId, {ok, [{SegNo, ARs}]}, Extra),
+ {TransIds2, [Rep | Results]}
+
+ end;
+
+%% Last segment of a reply
+%% transactionResult "=" transactionError
+wfr_update(TransIds, TransId, Version, Results, {error, {SegNo, Last, ED}}, Extra)
+ when is_integer(SegNo) andalso (Last == true) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ OkSegs = lists:keysort(1, [{SegNo, ED}|SegReps]),
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = lists:keysort(1, OkSegs),
+ ErrSegs2 = lists:keysort(1, [{SegNo, ED}|ErrSegs]),
+ Error = {error, {segment, OkSegs2, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First and only segment
+ OkSegs = [],
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds2, [Rep]}
+
+ end;
+
+%% One segment of a reply
+%% transactionResult "=" actionReplies
+wfr_update(TransIds, TransId, Version, Results, {ok, {SegNo, _Last, ARs}}, Extra)
+ when is_integer(SegNo) ->
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% All segments ok (actionReplies)
+ {value, {V, TransId, {ok, SegReps}}} ->
+ SegReps2 = [{SegNo, ARs}|SegReps],
+ Rep = wfr_mk_reply(V, TransId, {ok, SegReps2}, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ %% Atleast one segment error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ OkSegs2 = [{SegNo, ARs}|OkSegs],
+ Error = {error, {segment, OkSegs2, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ false ->
+ %% First and only segment
+ Rep = wfr_mk_reply(Version, TransId, {ok, [{SegNo, ARs}]}, Extra),
+ {TransIds, [Rep | Results]}
+
+ end;
+
+%% One segment of a reply
+%% transactionResult "=" transactionError
+wfr_update(TransIds, TransId, Version, Results, {error, {SegNo, _Last, ED}}, Extra)
+ when is_integer(SegNo) ->
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, OkSegs}}} ->
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {OkSegs, ErrSegs}}}} ->
+ ErrSegs2 = [{SegNo, ED}|ErrSegs],
+ Error = {error, {segment, OkSegs, ErrSegs2}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds, Results2};
+
+ false ->
+ %% First segment
+ OkSegs = [],
+ ErrSegs = [{SegNo, ED}],
+ Error = {error, {segment, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds, [Rep]}
+
+ end;
+
+%% This means that some segments did not make it in time
+wfr_update(TransIds, TransId, Version, Results,
+ {error, {segment_timeout, Missing}}, Extra) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ case lists:keysearch(TransId, 2, Results) of
+
+ %% First segment with error (transactionError)
+ {value, {V, TransId, {ok, OkSegs}}} ->
+ Error = {error, {segment_timeout, Missing, OkSegs, []}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ %% Another segment with error (transactionError)
+ {value, {V, TransId, {error, {segment, OkSegs, ErrSegs}}}} ->
+ Error = {error, {segment_timeout, Missing, OkSegs, ErrSegs}},
+ Rep = wfr_mk_reply(V, TransId, Error, Extra),
+ Results2 = lists:keyreplace(TransId, 2, Results, Rep),
+ {TransIds2, Results2};
+
+ false ->
+ %% First segment
+ Error = {error, {segment_timeout, Missing, [], []}},
+ Rep = wfr_mk_reply(Version, TransId, Error, Extra),
+ {TransIds2, [Rep]}
+
+ end;
+
+%% And all other results (presumably results without segments).
+wfr_update(TransIds, TransId, Version, Results, Result, Extra) ->
+ TransIds2 = lists:delete(TransId, TransIds),
+ Results2 = [wfr_mk_reply(Version, TransId, Result, Extra)|Results],
+ {TransIds2, Results2}.
+
+
+%% TransInfo is either [trans_id()] or a [trans_req()]
+
+%% This is the normal case where we have just one
+%% transaction to be sent (using call or cast) using
+%% the transaction sender process.
+send_request(#conn_data{control_pid = CP,
+ trans_req = true,
+ trans_sender = Pid} = CD,
+ CH, [Serial], Action, [Bin])
+ when is_pid(Pid) andalso
+ is_integer(Serial) andalso
+ (node(CP) =:= node()) ->
+
+ ?report_trace(CD,
+ "send_request - one transaction via trans-sender",
+ [Serial]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ TransId = to_local_trans_id(CH, Serial),
+ insert_request(CD, CH, TransId, Action, {Serial, Bin},
+ InitTimer, LongTimer),
+ megaco_trans_sender:send_req(Pid, Serial, Bin);
+
+%% This is the general case where we have several transactions
+%% beeing sent (using call or cast) at once using
+%% the transaction sender process.
+send_request(#conn_data{control_pid = CP,
+ trans_req = true,
+ trans_sender = Pid} = CD,
+ CH, TransInfo, Action, Bins)
+ when is_pid(Pid) andalso
+ is_list(Bins) andalso
+ (node(CP) =:= node()) ->
+
+ ?report_trace(CD,
+ "send_request - multi transactions via trans_sender",
+ [TransInfo, Pid]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ insert_requests(CD, CH, TransInfo, Action, Bins,
+ InitTimer, LongTimer),
+ megaco_trans_sender:send_reqs(Pid, TransInfo, Bins);
+
+%% This is the case when one or more transactions is
+%% beeing sent in one message immediatelly (not using
+%% the transaction sender process. E.g. the binary is
+%% this encoded message.
+send_request(#conn_data{control_pid = CP} = CD,
+ CH, TRs, Action, Bin)
+ when is_list(TRs) andalso
+ is_binary(Bin) andalso
+ (node(CP) =:= node()) ->
+
+ %% d("send_request -> entry with"
+ %% "~n TRs: ~p", [TRs]),
+
+ ?report_trace(CD, "send_request - multi transaction", [TRs]),
+
+ #conn_data{request_timer = InitTimer,
+ long_request_timer = LongTimer} = CD,
+ insert_requests(CD, CH, TRs, Action, Bin,
+ InitTimer, LongTimer),
+ case megaco_messenger_misc:send_message(CD, false, Bin) of
+ {error, Reason} ->
+ cancel_requests(CD, TRs, Reason);
+ {ok, _} ->
+ ignore
+ end;
+
+%% This is the case where we are not on the node where the
+%% transport process run.
+send_request(#conn_data{control_pid = CP} = CD,
+ CH, TransInfo, Action, Bin)
+ when node(CP) =/= node() ->
+
+ ?report_trace(CD, "send_request - remote", [TransInfo]),
+
+ InitTimer = infinity,
+ LongTimer = infinity,
+ insert_requests(CD, CH, TransInfo, Action, Bin,
+ InitTimer, LongTimer),
+ Node = node(CP),
+ Args = [node(), CD, TransInfo, Bin],
+ rpc:cast(Node, ?MODULE, send_request_remote, Args).
+
+
+insert_requests(_, _, [], _, _, _, _) ->
+ ok;
+
+insert_requests(ConnData, ConnHandle, [Serial|Serials],
+ Action, [Bin|Bins], InitTimer, LongTimer)
+ when is_integer(Serial) andalso is_binary(Bin) ->
+ TransId = to_local_trans_id(ConnHandle, Serial),
+ insert_request(ConnData, ConnHandle,
+ TransId, Action, Bin, InitTimer, LongTimer),
+
+ insert_requests(ConnData, ConnHandle, Serials, Action, Bins,
+ InitTimer, LongTimer);
+
+insert_requests(ConnData, ConnHandle,
+ [{transactionRequest, TR}|TRs],
+ Action, Bin, InitTimer, LongTimer)
+ when is_record(TR, 'TransactionRequest') andalso is_binary(Bin) ->
+ #'TransactionRequest'{transactionId = Serial} = TR,
+ TransId = to_local_trans_id(ConnHandle, Serial),
+ insert_request(ConnData, ConnHandle,
+ TransId, Action, TR, InitTimer, LongTimer),
+
+ insert_requests(ConnData, ConnHandle, TRs, Action, Bin,
+ InitTimer, LongTimer).
+
+
+insert_request(ConnData, ConnHandle, TransId,
+ Action, Data, InitTimer, LongTimer) ->
+ #megaco_conn_handle{remote_mid = RemoteMid} = ConnHandle,
+ #conn_data{protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ send_handle = SendHandle,
+ reply_data = ReplyData,
+ segment_recv_timer = InitSegTimer,
+ request_keep_alive_timeout = RKATimer} = ConnData,
+ {WaitFor, CurrTimer} = megaco_timer:init(InitTimer),
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref = megaco_monitor:apply_after(M, F, A, WaitFor),
+ Req = #request{trans_id = TransId,
+ remote_mid = RemoteMid,
+ timer_ref = ?SIM({short, Ref}, init_request_timer),
+ init_timer = InitTimer,
+ init_long_timer = LongTimer,
+ curr_timer = CurrTimer,
+ version = Version,
+ bytes = {send, Data},
+ send_handle = SendHandle,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = ReplyData,
+ init_seg_timer = InitSegTimer,
+ keep_alive_timer = RKATimer},
+ megaco_monitor:insert_request(Req). % Timing problem?
+
+
+send_request_remote(ReplyNode, ConnData, TransInfo, Bin) ->
+ Action = remote,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ ConnData2 = ConnData#conn_data{reply_data = ReplyNode},
+ send_request(ConnData2, ConnHandle, TransInfo, Action, Bin).
+
+prepare_req_send_options(CallOrCast, ConnHandle, Options, Actions) ->
+ %% Ensures that two processes cannot get same transaction id.
+ %% Bad send options may cause spurious transaction id to be consumed.
+ Incr = number_of_transactions(Actions),
+ case megaco_config:incr_trans_id_counter(ConnHandle, Incr) of
+ {ok, ConnData} ->
+ override_req_send_options(CallOrCast, ConnData, Options);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+number_of_transactions([Action|_]) when is_tuple(Action) ->
+ 1;
+number_of_transactions(ActionsList) ->
+ length(ActionsList).
+
+override_req_send_options(ReplyAction, ConnData, [{Key, Val} | Tail]) ->
+ case Key of
+ protocol_version ->
+ ConnData2 = ConnData#conn_data{protocol_version = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ send_handle ->
+ ConnData2 = ConnData#conn_data{send_handle = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ request_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{request_timer = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ long_request_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{long_request_timer = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ call_proxy_gc_timeout when (ReplyAction =:= call) orelse
+ (ReplyAction =:= any) ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 =
+ ConnData#conn_data{call_proxy_gc_timeout = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ request_keep_alive_timeout when (ReplyAction =:= cast) orelse
+ (ReplyAction =:= any) ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 =
+ ConnData#conn_data{request_keep_alive_timeout = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ reply_data ->
+ ConnData2 = ConnData#conn_data{reply_data = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ user_mod when is_atom(Val) ->
+ ConnData2 = ConnData#conn_data{user_mod = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ user_args when is_list(Val) ->
+ ConnData2 = ConnData#conn_data{user_args = Val},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ trans_req when Val =:= false ->
+ %% We only allow turning the transaction-sender off, since
+ %% the opposite (turning it on) would causing to much headake...
+ %% This will allow not using the transaction sender for
+ %% occasional messages
+ ConnData2 = ConnData#conn_data{trans_req = Val,
+ trans_sender = undefined},
+ override_req_send_options(ReplyAction, ConnData2, Tail);
+ _Bad ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+override_req_send_options(_ReplyAction, ConnData, []) ->
+ {ok, ConnData}.
+
+override_rep_send_options(ConnData, [{Key, Val} | Tail]) ->
+ case Key of
+ protocol_version ->
+ ConnData2 = ConnData#conn_data{protocol_version = Val},
+ override_rep_send_options(ConnData2, Tail);
+ send_handle ->
+ ConnData2 = ConnData#conn_data{send_handle = Val},
+ override_rep_send_options(ConnData2, Tail);
+ reply_timer ->
+ case megaco_config:verify_val(Key, Val) of
+ true ->
+ ConnData2 = ConnData#conn_data{reply_timer = Val},
+ override_rep_send_options(ConnData2, Tail);
+ false ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+ trans_req when Val =:= false ->
+ %% We only allow turning the transaction-sender off, since
+ %% the opposite (turning it on) would causing to much headake...
+ %% This will allow not using the transaction sender for
+ %% occasional messages
+ ConnData2 = ConnData#conn_data{trans_req = Val,
+ trans_sender = undefined},
+ override_rep_send_options(ConnData2, Tail);
+ _Bad ->
+ {error, {bad_send_option, {Key, Val}}}
+ end;
+override_rep_send_options(ConnData, []) ->
+ {ok, ConnData}.
+
+
+%% ----
+%% This list is allways atleast one (list of actions) long.
+%% ----
+%% The proper number of transaction id numbers has already
+%% been "allocated", and the connection data record is
+%% updated accordingly.
+encode_requests(#conn_data{trans_req = true,
+ trans_sender = Pid,
+ serial = LastSerial} = CD, ActionsList)
+ when is_pid(Pid) ->
+ (catch encode_requests(CD, LastSerial,
+ lists:reverse(ActionsList), [], []));
+encode_requests(#conn_data{serial = LastSerial} = CD, ActionsList) ->
+ %% We shall not accumulate transactions.
+ %% This means that we shall not encode
+ %% the transactions individually (and send
+ %% them to the sender process, which
+ %% accumulate transactions for later sending),
+ %% Instead we encode the entire message directly.
+ %% => We shall return one binary, containing,
+ %% possibly, many transactions
+ encode_requests_in_msg(CD, LastSerial, lists:reverse(ActionsList)).
+
+
+%% This means that we shall compose and encode one complete
+%% megaco message, containing one or more transactions.
+encode_requests_in_msg(CD, LastSerial, ActionsList) ->
+ TRs = compose_requests_in_msg(LastSerial, ActionsList, []),
+ Body = {transactions, TRs},
+ Res = megaco_messenger_misc:encode_body(CD,
+ "encode trans request(s) msg",
+ Body),
+ case Res of
+ {ok, Bin} ->
+ {ok, TRs, Bin};
+ Error ->
+ Error
+ end.
+
+compose_requests_in_msg(_S, [], TRs) ->
+ TRs;
+compose_requests_in_msg(Serial, [A|As], Acc) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = A},
+ compose_requests_in_msg(Serial - 1, As, [{transactionRequest, TR}|Acc]).
+
+
+%% We have done the encoding in reverse order, so there
+%% is no need to reverse now.
+encode_requests(_, _, [], Serials, EncodedTRs) ->
+ {ok, Serials, EncodedTRs};
+encode_requests(CD, Serial, [Actions|ActionsList], Serials, EncodedTRs) ->
+ case do_encode_request(CD, Serial, Actions) of
+ {ok, Bin} ->
+ encode_requests(CD, Serial - 1, ActionsList,
+ [Serial|Serials], [Bin|EncodedTRs]);
+ Error ->
+ throw(Error)
+ end.
+
+
+do_encode_request(CD, Serial, Actions) ->
+ TR = #'TransactionRequest'{transactionId = Serial,
+ actions = Actions},
+ megaco_messenger_misc:encode_trans_request(CD, TR).
+
+
+imm_ack_req(Counter, when_pending_sent) when (Counter > 0) -> 'NULL';
+imm_ack_req(_Counter, when_pending_sent) -> asn1_NOVALUE;
+imm_ack_req(_Counter, ImmAck) -> ImmAck.
+
+maybe_send_reply(#conn_data{sent_pending_limit = Limit} = ConnData,
+ TransId, Result, SendOpts, ImmAck) ->
+
+ %% d("maybe_send_reply -> entry with"
+ %% "~n Limit: ~p"
+ %% "~n TransId: ~p"
+ %% "~n Result: ~p"
+ %% "~n SendOpts: ~p"
+ %% "~n ImmAck: ~p", [Limit, TransId, Result, SendOpts, ImmAck]),
+
+ %% Pending limit
+ %% Before we can send the reply we must check that we have
+ %% not passed the pending limit (and sent an error message).
+ case check_pending_limit(Limit, sent, TransId) of
+ {ok, Counter} ->
+ case override_rep_send_options(ConnData, SendOpts) of
+ {ok, ConnData2} ->
+ send_reply(ConnData2, Result,
+ imm_ack_req(Counter, ImmAck));
+ Error ->
+ Error
+ end;
+ aborted ->
+ {error, aborted}
+ end.
+
+encode_reply(CD, TR) ->
+ megaco_messenger_misc:encode_trans_reply(CD, TR).
+
+send_reply(#conn_data{serial = Serial,
+ trans_req = TransReq,
+ trans_sender = TransSnd} = CD, TransRes, ImmAck) ->
+
+ %% Encapsule the transaction result into a reply message
+
+ %% d("send_reply -> entry with"
+ %% "~n Serial: ~p"
+ %% "~n TransRes: ~p"
+ %% "~n ImmAck: ~p", [Serial, TransRes, ImmAck]),
+
+ TR = #megaco_transaction_reply{transactionId = Serial,
+ immAckRequired = ImmAck,
+ transactionResult = TransRes},
+ case encode_reply(CD, TR) of
+ {ok, Bin} when is_binary(Bin) andalso (TransReq =:= true) ->
+ ?rt2("send_reply - pass it on to the transaction sender",
+ [size(Bin)]),
+ megaco_trans_sender:send_reply(TransSnd, Bin),
+ {ok, Bin};
+
+ {ok, Bin} when is_binary(Bin) ->
+ ?rt2("send_reply - encoded", [size(Bin)]),
+ TraceLabel = "send trans reply",
+ Body = {transactions, [Bin]},
+ megaco_messenger_misc:send_body(CD, TraceLabel, Body);
+
+ {ok, Bins} when is_list(Bins) ->
+ ?rt2("send_reply - encoded (segmented)", [length(Bins)]),
+ Res = send_reply_segments(CD, Bins),
+ {ok, Res};
+
+ {error, not_implemented} ->
+ %% Oups, we cannot segment regardless the config,
+ %% so pack it all into one message and hope for
+ %% the best...
+ ?rt2("send_reply - cannot encode separate transactions", []),
+ TR2 = megaco_messenger_misc:transform_transaction_reply(CD, TR),
+ Body = {transactions, [{transactionReply, TR2}]},
+ megaco_messenger_misc:send_body(CD, "encode trans reply", Body);
+
+ {error, Reason} = Error ->
+ Code = ?megaco_internal_gateway_error,
+ Text = "encode transaction reply",
+ ED = #'ErrorDescriptor'{errorCode = Code,
+ errorText = Text},
+ Res = {transactionError, ED},
+ TR2 = #megaco_transaction_reply{transactionId = Serial,
+ transactionResult = Res},
+ TR3 = megaco_messenger_misc:transform_transaction_reply(CD, TR2),
+ TraceLabel = "<ERROR> encode trans reply body failed",
+ ?report_important(CD, TraceLabel, [TR, TR3, ED, Error]),
+ error_msg("failed encoding transaction reply body: ~s",
+ [format_encode_error_reason(Reason)]),
+ Body = {transactions, [{transactionReply, TR3}]},
+ megaco_messenger_misc:send_body(CD, TraceLabel, Body),
+ Error
+ end.
+
+send_reply_segments(CD, Bins) ->
+ TraceLabelPre = "send segmented trans reply",
+ (catch send_reply_segments(CD, TraceLabelPre, Bins)).
+
+send_reply_segments(#conn_data{segment_send = infinity} = CD, Label, Bins) ->
+ send_reply_segments(CD, Label, length(Bins), Bins);
+
+send_reply_segments(#conn_data{segment_send = K} = CD, Label, Bins)
+ when is_integer(K) andalso (K =< length(Bins)) ->
+ send_reply_segments(CD, Label, K, Bins);
+
+send_reply_segments(#conn_data{segment_send = K} = CD, Label, Bins)
+ when is_integer(K) ->
+ send_reply_segments(CD, Label, length(Bins), Bins).
+
+send_reply_segments(CD, Label, K, Bins) ->
+ send_reply_segments(CD, Label, K, Bins, []).
+
+send_reply_segments(_CD, _Label, 0, Bins, Sent) ->
+ ?rt2("send_reply_segments - done", [Sent, Bins]),
+ {Sent, Bins};
+send_reply_segments(CD, TraceLabelPre, K, [{SN, Bin}|Bins], Sent) ->
+ case send_reply_segment(CD, TraceLabelPre, SN, Bin) of
+ {ok, Bin2} ->
+ ?rt2("send_reply_segments - send", [K, SN]),
+ send_reply_segments(CD, TraceLabelPre, K-1,
+ Bins, [{SN, Bin2}|Sent]);
+ Error ->
+ throw(Error)
+ end.
+
+send_reply_segment(CD, TraceLabelPre, SN, Bin) ->
+ Label = lists:flatten(io_lib:format("~s[~w]", [TraceLabelPre, SN])),
+ Body = {transactions, [Bin]},
+ megaco_messenger_misc:send_body(CD, Label, Body).
+
+
+format_encode_error_reason(Reason) ->
+ FS =
+ case Reason of
+ {Mod, Func, [EC, Msg], {AE, CS}} when is_atom(Mod) andalso
+ is_atom(Func) andalso
+ is_list(EC) and
+ is_tuple(Msg) and
+ is_list(CS) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Func: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p"
+ "~n Call stack: ~w",
+ [Mod, Func, EC, Msg, AE, CS]);
+
+ {Mod, Func, [EC, Msg], AE} when is_atom(Mod) andalso
+ is_atom(Func) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Func: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p",
+ [Mod, Func, EC, Msg, AE]);
+
+ {Mod, [EC, Msg], {AE, CS}} when is_atom(Mod) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) andalso
+ is_list(CS) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p"
+ "~n Call stack: ~w",
+ [Mod, EC, Msg, AE, CS]);
+
+ {Mod, [EC, Msg], AE} when is_atom(Mod) andalso
+ is_list(EC) andalso
+ is_tuple(Msg) ->
+ io_lib:format("~n Encode module: ~w"
+ "~n Encode config: ~w"
+ "~n Message part: ~p"
+ "~n Actual error: ~p",
+ [Mod, EC, Msg, AE]);
+
+ Error ->
+ io_lib:format("~n ~w", [Error])
+ end,
+ lists:flatten(FS).
+
+
+%% Presumably the user would return immediately (with {pending, Data}) if it
+%% knows or suspects a request to take a long time to process.
+%% For this reason we assume that handling a resent request
+%% could not have caused an update of the pending limit counter.
+maybe_send_pending(#conn_data{sent_pending_limit = Limit} = ConnData,
+ TransId) ->
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+ send_pending(ConnData);
+ error ->
+ SendReply = send_pending_limit_error(ConnData),
+ {aborted, SendReply};
+ aborted ->
+ {aborted, ignore}
+ end.
+
+
+send_pending(#conn_data{serial = Serial,
+ trans_req = true,
+ trans_sender = Pid}) ->
+ megaco_trans_sender:send_pending(Pid, Serial);
+send_pending(#conn_data{serial = Serial} = CD) ->
+ %% Encapsule the transaction result into a pending message
+ TP = #'TransactionPending'{transactionId = Serial},
+ Body = {transactions, [{transactionPending, TP}]},
+ megaco_messenger_misc:send_body(CD, "send trans pending", Body).
+
+
+maybe_send_ack('NULL', #conn_data{serial = Serial,
+ trans_ack = true,
+ trans_sender = Pid}) ->
+ megaco_trans_sender:send_ack_now(Pid, Serial);
+maybe_send_ack('NULL', CD) ->
+ send_ack(CD);
+maybe_send_ack(_, #conn_data{auto_ack = false}) ->
+ ignore;
+maybe_send_ack(_, #conn_data{serial = Serial,
+ trans_ack = true,
+ trans_sender = Pid})
+ when is_pid(Pid) ->
+ %% Send (later) via the transaction sender
+ megaco_trans_sender:send_ack(Pid, Serial),
+ ok;
+maybe_send_ack(_, CD) ->
+ %% Send now
+ send_ack(CD).
+
+
+send_ack(#conn_data{serial = Serial} = CD) ->
+ %% Encapsule the transaction result into a ack message
+ TRA = #'TransactionAck'{firstAck = Serial},
+ Body = {transactions, [{transactionResponseAck, [TRA]}]},
+ megaco_messenger_misc:send_body(CD, "send trans ack", Body).
+
+
+send_segment_reply(#conn_data{serial = Serial} = CD, SegNo) ->
+ SR = #'SegmentReply'{transactionId = Serial,
+ segmentNumber = SegNo},
+ Body = {transactions, [{segmentReply, SR}]},
+ megaco_messenger_misc:send_body(CD, "send segment reply", Body).
+
+send_segment_reply(#conn_data{serial = Serial} = CD, SegNo, Complete) ->
+ SR = #'SegmentReply'{transactionId = Serial,
+ segmentNumber = SegNo,
+ segmentationComplete = Complete},
+ Body = {transactions, [{segmentReply, SR}]},
+ megaco_messenger_misc:send_body(CD, "send segment reply", Body).
+
+send_segment_reply_complete(CD, SegNo) ->
+ send_segment_reply(CD, SegNo, 'NULL').
+
+
+send_pending_limit_error(ConnData) ->
+ ?report_pending_limit_exceeded(ConnData),
+ Code = ?megaco_number_of_transactionpending_exceeded,
+ Reason = "Pending limit exceeded",
+ send_trans_error(ConnData, Code, Reason).
+
+send_trans_error(ConnData, Code, Reason) ->
+ %% Encapsulate the transaction error into a reply message
+ ED = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Serial = ConnData#conn_data.serial,
+ %% Version = ConnData#conn_data.protocol_version,
+ TransRes = {transactionError, ED},
+ TR = #megaco_transaction_reply{transactionId = Serial,
+ transactionResult = TransRes},
+ TR2 = megaco_messenger_misc:transform_transaction_reply(ConnData, TR),
+ Body = {transactions, [{transactionReply, TR2}]},
+ case megaco_messenger_misc:send_body(ConnData, "send trans error", Body) of
+ {error, Reason2} ->
+ ?report_important(ConnData,
+ "<ERROR> failed sending transaction error",
+ [Body, {error, Reason2}]),
+ error;
+ _ ->
+ ok
+ end.
+
+
+send_message_error(ConnData, Code, Reason) ->
+ ED = #'ErrorDescriptor'{errorCode = Code, errorText = Reason},
+ Body = {messageError, ED},
+ case megaco_messenger_misc:send_body(ConnData, "send trans error", Body) of
+ {error, Reason2} ->
+ ?report_important(ConnData,
+ "<ERROR> failed sending message error",
+ [Body, {error, Reason2}]),
+ error;
+ _ ->
+ ok
+ end.
+
+
+cancel(ConnHandle, Reason) when is_record(ConnHandle, megaco_conn_handle) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] ->
+ megaco_config:update_conn_info(CD, cancel, true),
+ do_cancel(ConnHandle, Reason, CD#conn_data{cancel = true}),
+ megaco_config:update_conn_info(CD, cancel, false),
+ ok;
+ [] ->
+ ConnData = fake_conn_data(ConnHandle),
+ do_cancel(ConnHandle, Reason, ConnData)
+ end.
+
+do_cancel(ConnHandle, Reason, ConnData) ->
+ ?report_trace(ConnData, "cancel", [ConnHandle, Reason]),
+ LocalMid = ConnHandle#megaco_conn_handle.local_mid,
+ RemoteMid = ConnHandle#megaco_conn_handle.remote_mid,
+ ReqTransIdPat = #trans_id{mid = LocalMid, _ = '_'},
+ ReqPat = #request{trans_id = ReqTransIdPat,
+ remote_mid = RemoteMid,
+ _ = '_'},
+ CancelReq = fun(Req) ->
+ cancel_request(ConnData, Req, Reason),
+ {_Type, Ref} = Req#request.timer_ref, %% OTP-4843
+ megaco_monitor:cancel_apply_after(Ref)
+ end,
+ Requests = megaco_monitor:match_requests(ReqPat),
+ lists:foreach(CancelReq, Requests),
+ RemoteMid = ConnHandle#megaco_conn_handle.remote_mid,
+ RepTransIdPat = #trans_id{mid = RemoteMid, _ = '_'}, % BUGBUG List here?
+ RepPat = #reply{trans_id = RepTransIdPat,
+ local_mid = LocalMid,
+ _ = '_'},
+ CancelRep = fun(Rep) ->
+ cancel_reply(ConnData, Rep, Reason)
+ end,
+ Replies = megaco_monitor:match_replies(RepPat),
+ lists:foreach(CancelRep, Replies),
+ ok.
+
+cancel_requests(_ConnData, [], _Reason) ->
+ ok;
+cancel_requests(ConnData, [{transactionRequest,TR}|TRs], Reason) ->
+ #'TransactionRequest'{transactionId = TransId0} = TR,
+ TransId = to_local_trans_id(ConnData#conn_data.conn_handle, TransId0),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ ignore;
+ [Req] when is_record(Req, request) ->
+ cancel_request(ConnData, Req, Reason)
+ end,
+ cancel_requests(ConnData, TRs, Reason).
+
+cancel_request(ConnData, Req, Reason) ->
+ ?report_trace(ignore, "cancel request", [Req]),
+ ?TC_AWAIT_CANCEL_EVENT(),
+ TransId = Req#request.trans_id,
+ Version = Req#request.version,
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, Reason},
+ ConnData2 = ConnData#conn_data{protocol_version = Version,
+ user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ cancel_request2(ConnData2, TransId, UserReply).
+
+cancel_request2(ConnData, TransId, UserReply) ->
+ megaco_monitor:delete_request(TransId),
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+ Serial = TransId#trans_id.serial,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ return_reply(ConnData2, TransId, UserReply).
+
+
+return_reply(ConnData, TransId, UserReply) ->
+ Extra = ?default_user_callback_extra,
+ return_reply(ConnData, TransId, UserReply, Extra).
+
+return_reply(ConnData, TransId, UserReply, Extra) ->
+ ?report_trace(ConnData, "callback: trans reply", [UserReply]),
+ Version = ConnData#conn_data.protocol_version,
+ UserData = ConnData#conn_data.reply_data,
+ case ConnData#conn_data.reply_action of
+ call when is_pid(UserData) ->
+ ?report_trace(ConnData, "callback: (call) trans reply",
+ [UserReply]),
+ Pid = UserData,
+ Pid ! {?MODULE, TransId, Version, UserReply, Extra};
+ cast ->
+ ?report_trace(ConnData, "callback: (cast) trans reply", [UserReply]),
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, UserReply, UserData | UserArgs];
+ _ ->
+ [ConnHandle, Version, UserReply, UserData, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_trans_reply, Args)),
+ ?report_debug(ConnData, "return: (cast) trans reply",
+ [UserReply, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("transaction reply callback failed: ~w",
+ [Res]),
+ ok
+ end,
+ Res;
+ remote ->
+ ?report_trace(ConnData, "callback: (remote) trans reply", [UserReply]),
+ Node = UserData,
+ Args = [ConnData, UserReply, Extra],
+ rpc:cast(Node, ?MODULE, receive_reply_remote, Args)
+ end.
+
+receive_reply_remote(ConnData, UserReply) ->
+ Extra = ?default_user_callback_extra,
+ receive_reply_remote(ConnData, UserReply, Extra).
+
+receive_reply_remote(ConnData, UserReply, Extra) ->
+ TransId = to_local_trans_id(ConnData),
+ case (catch megaco_monitor:lookup_request(TransId)) of
+ [#request{timer_ref = {_Type, Ref}} = Req] -> %% OTP-4843
+ %% Don't care about Req and Rep version diff
+ megaco_monitor:delete_request(TransId),
+ megaco_monitor:cancel_apply_after(Ref), % OTP-4843
+ megaco_config:del_pending_counter(recv, TransId), % OTP-7189
+
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply, Extra);
+
+ _ ->
+ ?report_trace(ConnData, "remote reply (no receiver)",
+ [UserReply]),
+ return_unexpected_trans_reply(ConnData, TransId, UserReply, Extra)
+ end.
+
+cancel_reply(ConnData, #reply{state = waiting_for_ack} = Rep, Reason) ->
+ ?report_trace(ignore, "cancel reply [waiting_for_ack]", [Rep]),
+ megaco_monitor:cancel_apply_after(Rep#reply.pending_timer_ref),
+ Serial = (Rep#reply.trans_id)#trans_id.serial,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ T = #'TransactionAck'{firstAck = Serial},
+ Extra = ?default_user_callback_extra,
+ handle_ack(ConnData2, {error, Reason}, Rep, T, Extra);
+
+cancel_reply(_ConnData, #reply{state = aborted} = Rep, _Reason) ->
+ ?report_trace(ignore, "cancel reply [aborted]", [Rep]),
+ #reply{trans_id = TransId,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef} = Rep,
+ megaco_monitor:delete_reply(TransId),
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef), % Still running?
+ megaco_config:del_pending_counter(sent, TransId), % Still existing?
+ ok;
+
+cancel_reply(_ConnData, Rep, ignore) ->
+ ?report_trace(ignore, "cancel reply [ignore]", [Rep]),
+ #reply{trans_id = TransId,
+ timer_ref = ReplyRef,
+ pending_timer_ref = PendingRef} = Rep,
+ megaco_monitor:delete_reply(TransId),
+ megaco_monitor:cancel_apply_after(ReplyRef),
+ megaco_monitor:cancel_apply_after(PendingRef), % Still running?
+ megaco_config:del_pending_counter(sent, TransId), % Still existing?
+ ok;
+
+cancel_reply(_CD, _Rep, _Reason) ->
+ ok.
+
+
+request_keep_alive_timeout(ConnHandle, TransId) ->
+ megaco_config:del_pending_counter(ConnHandle, TransId),
+ megaco_monitor:lookup_request(TransId),
+ ok.
+
+
+request_timeout(ConnHandle, TransId) ->
+ ?rt1(ConnHandle, "request timeout", [TransId]),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ request_not_found_ignore;
+ [Req] when is_record(Req, request) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel =:= true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ incNumTimerRecovery(ConnHandle),
+ do_request_timeout(ConnHandle, TransId, CD, Req);
+ [] when ConnHandle#megaco_conn_handle.remote_mid =:= preliminary_mid ->
+ %% There are two possibillities:
+ %% 1) The connection has just been upgraded from a
+ %% preliminary to a real connection. So this timeout
+ %% is just a glitch. E.g. between the removel of this
+ %% ConnHandle and the timer.
+ %% 2) The first message sent, the service-change, got no
+ %% reply (UDP without three-way-handshake).
+ %% And then the other side (MGC) sends a request,
+ %% which causes an auto-upgrade
+ request_timeout_upgraded(ConnHandle, Req);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ ConnData = fake_conn_data(ConnHandle),
+ do_request_timeout(ConnHandle, TransId, ConnData, Req)
+ end
+ end.
+
+request_timeout_upgraded(ConnHandle, Req) ->
+ CD = fake_conn_data(ConnHandle),
+ cancel_request(CD, Req, timeout).
+
+do_request_timeout(ConnHandle, TransId, ConnData,
+ #request{curr_timer = CurrTimer} = Req) ->
+
+ ?rt1(ConnHandle, "process request timeout", [TransId, CurrTimer]),
+
+ SendHandle = Req#request.send_handle,
+ Version = Req#request.version,
+ ConnData2 = ConnData#conn_data{send_handle = SendHandle,
+ protocol_version = Version},
+ case CurrTimer of
+ timeout -> %%%%%%%
+ cancel_request(ConnData2, Req, timeout),
+ timeout1;
+
+ %% Restartable timer
+ %% (max_retries = infinity_restartable)
+ {_, timeout} ->
+ cancel_request(ConnData2, Req, timeout),
+ timeout2;
+
+ Timer ->
+ {SendOrNoSend, Data} = Req#request.bytes,
+ case SendOrNoSend of
+ send ->
+ case maybe_encode(ConnData2, Data) of
+ {ok, Bin} ->
+ ?report_trace(ConnData2, "re-send trans request",
+ [{bytes, Bin}]),
+ case maybe_send_message(ConnData2, true, Bin) of
+ ok ->
+ sent1_ignore;
+ {ok, _} ->
+ sent2_ignore;
+ {error, Reason} ->
+ ?report_important(ConnData2,
+ "<ERROR> "
+ "re-send trans "
+ "request failed",
+ [{bytes, Bin},
+ {error, Reason}])
+ end;
+
+ {error, Reason} ->
+ %% Since it was possible to encode the original
+ %% message this should really never happen...
+ ?report_important(ConnData2,
+ "<ERROR> "
+ "re-send trans request failed",
+ [{transaction,
+ Req#request.bytes},
+ {error, Reason}])
+ end;
+ no_send ->
+ not_sent_ok
+ end,
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ OptBin = opt_garb_binary(Timer2, Data),
+ {Type, _} = Req#request.timer_ref,
+ M = ?MODULE,
+ F = request_timeout,
+ A = [ConnHandle, TransId],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#request.bytes, {SendOrNoSend, OptBin}},
+ {#request.timer_ref, {Type, Ref2}},
+ {#request.curr_timer, Timer2}],
+ megaco_monitor:update_request_fields(TransId, NewFields), % Timing problem
+ {restarted, WaitFor, Timer2}
+
+ end.
+
+maybe_encode(#conn_data{trans_req = false} = CD, {_Serial, Bin})
+ when is_binary(Bin) ->
+ Body = {transactions, [{transactionRequest, Bin}]},
+ megaco_messenger_misc:encode_body(CD, "encode trans request msg", Body);
+maybe_encode(_CD, {_Serial, Bin} = D) when is_binary(Bin) ->
+ {ok, D};
+maybe_encode(#conn_data{trans_req = true,
+ trans_sender = Pid} = CD,
+ #'TransactionRequest'{transactionId = Serial} = TR)
+ when is_pid(Pid) ->
+ case megaco_messenger_misc:encode_trans_request(CD, TR) of
+ {ok, Bin} ->
+ {ok, {Serial, Bin}};
+ Error ->
+ Error
+ end;
+maybe_encode(CD, TR)
+ when is_record(TR, 'TransactionRequest') ->
+ Body = {transactions, [{transactionRequest, TR}]},
+ megaco_messenger_misc:encode_body(CD, "encode trans request msg", Body);
+maybe_encode(_CD, Trash) ->
+ {error, {invalid_bin, Trash}}.
+
+maybe_send_message(CD, Resend, Bin) when is_binary(Bin) ->
+ megaco_messenger_misc:send_message(CD, Resend, Bin);
+maybe_send_message(#conn_data{trans_sender = Pid}, _Resend, {Serial, Bin})
+ when is_pid(Pid) andalso is_integer(Serial) andalso is_binary(Bin) ->
+ megaco_trans_sender:send_req(Pid, Serial, Bin).
+
+
+reply_timeout(ConnHandle, TransId, timeout) ->
+ handle_reply_timer_timeout(ConnHandle, TransId);
+
+%% This means that infinity_restartable was used for max_retries.
+%% There is currently no reason to use this for the reply_timeout,
+%% since there is no external event to restart the timer!
+reply_timeout(ConnHandle, TransId, {_, timeout}) ->
+ handle_reply_timer_timeout(ConnHandle, TransId);
+
+reply_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "reply timeout", [Timer, TransId]),
+
+ case megaco_monitor:lookup_reply(TransId) of
+ [] ->
+ reply_not_found_ignore;
+
+ [#reply{state = waiting_for_ack,
+ ack_action = {handle_ack, _}} = Rep] ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel =:= true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ incNumTimerRecovery(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ CD = fake_conn_data(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, CD, Timer, Rep)
+ end;
+
+ [#reply{state = waiting_for_ack,
+ bytes = Sent} = Rep] when is_list(Sent) ->
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData] ->
+ incNumTimerRecovery(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, ConnData,
+ Timer, Rep);
+ [] ->
+ incNumTimerRecovery(ConnHandle),
+ ConnData = fake_conn_data(ConnHandle),
+ do_reply_timeout(ConnHandle, TransId, ConnData,
+ Timer, Rep)
+ end;
+
+ [#reply{state = waiting_for_ack} = Rep] ->
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+ [#reply{state = aborted} = Rep] ->
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+ _ ->
+ ignore
+
+ end.
+
+do_reply_timeout(ConnHandle, TransId, ConnData, Timer,
+ #reply{send_handle = SH,
+ version = V,
+ bytes = Bytes} = Rep) when is_binary(Bytes) ->
+
+%% d("do_reply_timeout -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n TransId: ~p"
+%% "~n Timer: ~p"
+%% "~n Rep: ~p"
+%% "~n", [ConnHandle, TransId, Timer, Rep]),
+
+ CD = ConnData#conn_data{send_handle = SH,
+ protocol_version = V},
+
+ ?rt1(CD, "re-send trans reply", [{bytes, Bytes}]),
+ case megaco_messenger_misc:send_message(CD, true, Bytes) of
+ {ok, _} ->
+ ignore;
+ {error, Reason} ->
+ ?report_important(CD, "<ERROR> re-send trans reply failed",
+ [{bytes, Bytes}, {error, Reason}])
+ end,
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+do_reply_timeout(ConnHandle, TransId, ConnData, Timer,
+ #reply{send_handle = SH,
+ version = V,
+ bytes = Sent} = Rep) when is_list(Sent) ->
+
+%% d("do_reply_timeout -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n TransId: ~p"
+%% "~n Timer: ~p"
+%% "~n Rep: ~p"
+%% "~n", [ConnHandle, TransId, Timer, Rep]),
+
+ CD = ConnData#conn_data{send_handle = SH,
+ protocol_version = V},
+
+ ReSend =
+ fun({SN, Bytes}) ->
+ ?rt1(CD, "re-send segmented trans reply",
+ [{segment_no, SN}, {bytes, Bytes}]),
+ case megaco_messenger_misc:send_message(CD, true, Bytes) of
+%% ok ->
+%% ignore;
+ {ok, _} ->
+ ignore;
+ {error, Reason} ->
+ ?report_important(CD,
+ "<ERROR> re-send segmented "
+ "trans reply failed",
+ [{segment_no, SN},
+ {bytes, Bytes},
+ {error, Reason}])
+ end
+ end,
+ lists:foreach(ReSend, Sent),
+ do_reply_timeout(ConnHandle, TransId, Timer, Rep).
+
+do_reply_timeout(ConnHandle, TransId, Timer, #reply{bytes = Bytes}) ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ OptBin = case Bytes of
+ Bin when is_binary(Bin) ->
+ opt_garb_binary(Timer2, Bin);
+ Sent when is_list(Sent) ->
+ Garb = fun(Bin) -> opt_garb_binary(Timer2, Bin) end,
+ [{SN, Garb(Bin)} || {SN, Bin} <- Sent]
+ end,
+ M = ?MODULE,
+ F = reply_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ Ref2 = megaco_monitor:apply_after(M, F, A, WaitFor),
+ NewFields =
+ [{#reply.bytes, OptBin},
+ {#reply.timer_ref, Ref2}],
+ megaco_monitor:update_reply_fields(TransId, NewFields), % Timing problem?
+ {restarted, WaitFor, Timer2}.
+
+
+handle_reply_timer_timeout(ConnHandle, TransId) ->
+ ?report_trace(ConnHandle, "handle reply timeout", [timeout, TransId]),
+ incNumTimerRecovery(ConnHandle),
+ %% OTP-4378
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{state = waiting_for_ack} = Rep] ->
+ Serial = (Rep#reply.trans_id)#trans_id.serial,
+ ConnData =
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData0] ->
+ ConnData0;
+ [] ->
+ fake_conn_data(ConnHandle)
+ end,
+ ConnData2 = ConnData#conn_data{serial = Serial},
+ T = #'TransactionAck'{firstAck = Serial},
+ Extra = ?default_user_callback_extra,
+ handle_ack(ConnData2, {error, timeout}, Rep, T, Extra);
+ [#reply{pending_timer_ref = Ref, % aborted?
+ bytes = SegSent}] -> % may be a binary
+ megaco_monitor:cancel_apply_after(Ref),
+ cancel_segment_timers(SegSent),
+ megaco_monitor:delete_reply(TransId),
+ megaco_config:del_pending_counter(sent, TransId);
+ [] ->
+ ignore_reply_removed
+ end.
+
+%% segment_reply_timeout(ConnHandle, TransId, SN, timeout) ->
+%% ?report_trace(ConnHandle, "segment reply timeout", [timeout, SN, TransId]),
+%% D = fun({_, _, SegRef}) ->
+%% megaco_monitor:cancel_apply_after(SegRef)
+%% end,
+%% incNumTimerRecovery(ConnHandle),
+%% %% OTP-4378
+%% case megaco_monitor:lookup_reply(TransId) of
+%% [#reply{state = waiting_for_ack,
+%% bytes = Sent} = Rep] ->
+%% Serial = (Rep#reply.trans_id)#trans_id.serial,
+%% ConnData =
+%% case megaco_config:lookup_local_conn(ConnHandle) of
+%% [ConnData0] ->
+%% ConnData0;
+%% [] ->
+%% fake_conn_data(ConnHandle)
+%% end,
+%% ConnData2 = ConnData#conn_data{serial = Serial},
+%% T = #'TransactionAck'{firstAck = Serial},
+%% lists:foreach(D, Sent),
+%% Extra = ?default_user_callback_extra,
+%% handle_ack(ConnData2, {error, timeout}, Rep, T, Extra);
+%% [#reply{pending_timer_ref = Ref,
+%% bytes = Sent}] -> % aborted?
+%% lists:foreach(D, Sent),
+%% megaco_monitor:cancel_apply_after(Ref),
+%% megaco_monitor:delete_reply(TransId),
+%% megaco_config:del_pending_counter(sent, TransId);
+
+%% [] ->
+%% ignore
+
+%% end.
+
+%% segment_reply_timeout(ConnHandle, TransId, SN, Timer) ->
+%% ?report_trace(ConnHandle, "reply timeout", [Timer, SN, TransId]),
+
+%% %% d("reply_timeout -> entry with"
+%% %% "~n ConnHandle: ~p"
+%% %% "~n TransId: ~p"
+%% %% "~n Timer: ~p", [ConnHandle, TransId, Timer]),
+
+%% case megaco_monitor:lookup_reply(TransId) of
+%% [] ->
+%% ignore; % Trace ??
+
+%% [#reply{state = waiting_for_ack,
+%% bytes = ack_action = {handle_ack, _}} = Rep] ->
+%% case megaco_config:lookup_local_conn(ConnHandle) of
+%% [ConnData] ->
+%% incNumTimerRecovery(ConnHandle),
+%% do_reply_timeout(ConnHandle, TransId, ConnData,
+%% Timer, Rep);
+%% [] ->
+%% incNumTimerRecovery(ConnHandle),
+%% ConnData = fake_conn_data(ConnHandle),
+%% do_reply_timeout(ConnHandle, TransId, ConnData,
+%% Timer, Rep)
+%% end;
+
+%% [#reply{state = waiting_for_ack} = Rep] ->
+%% do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+%% [#reply{state = aborted} = Rep] ->
+%% do_reply_timeout(ConnHandle, TransId, Timer, Rep);
+
+%% _ ->
+%% ignore
+
+%% end.
+
+
+%% This clause is to catch the timers started prior to the code-upgrade
+pending_timeout(#conn_data{conn_handle = CH}, TransId, Timer) ->
+ ?report_trace(CH, "pending timeout(1)", [Timer, TransId]),
+ pending_timeout(CH, TransId, Timer);
+
+pending_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "pending timeout(2)", [Timer, TransId]),
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [CD] when (CD#conn_data.cancel == true) ->
+ cancel_in_progress_ignore;
+ [CD] ->
+ Serial = TransId#trans_id.serial,
+ handle_pending_timeout(CD#conn_data{serial = Serial},
+ TransId, Timer);
+ [] ->
+ no_such_connection_ignore
+ end.
+
+handle_pending_timeout(CD, TransId, Timer) ->
+ ?report_trace(CD, "handle pending timeout", []),
+ case megaco_monitor:lookup_reply(TransId) of
+ [#reply{state = State,
+ handler = Pid} = Rep] when (State =:= prepare) orelse
+ (State =:= eval_request) ->
+
+ #conn_data{sent_pending_limit = Limit,
+ conn_handle = ConnHandle} = CD,
+
+ %% ------------------------------------------
+ %%
+ %% Check pending limit
+ %%
+ %% ------------------------------------------
+
+ case check_and_maybe_incr_pending_limit(Limit, sent, TransId) of
+ ok ->
+
+ %% ---------------------------------------------
+ %%
+ %% 1) Send pending message
+ %% 2) Possibly restart the pending timer
+ %%
+ %% ---------------------------------------------
+
+ send_pending(CD),
+ case Timer of
+ timeout ->
+ %% We are done
+ incNumTimerRecovery(ConnHandle),
+ timeout1;
+ {_, timeout} ->
+ %% We are done
+ incNumTimerRecovery(ConnHandle),
+ timeout2;
+ _ ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ M = ?MODULE,
+ F = pending_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ PendingRef =
+ megaco_monitor:apply_after(M, F, A, WaitFor),
+ %% Timing problem?
+ megaco_monitor:update_reply_field(TransId,
+ #reply.pending_timer_ref,
+ PendingRef),
+ {restarted, WaitFor, Timer2}
+ end;
+
+
+ error ->
+
+ %% ------------------------------------------
+ %%
+ %% 1) Send 506 error message to other side
+ %% 2) Notify user
+ %% 3) Set reply data in aborted state
+ %%
+ %% -------------------------------------------
+
+ send_pending_limit_error(CD),
+ handle_request_abort_callback(CD, TransId, Pid),
+ %% Timing problem?
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(CD, Rep2, aborted),
+ pending_limit_error;
+
+
+ aborted ->
+
+ %% ------------------------------------------
+ %%
+ %% Pending limit already passed
+ %%
+ %% -------------------------------------------
+ Rep2 = Rep#reply{state = aborted},
+ cancel_reply(CD, Rep2, aborted),
+ pending_limit_aborted
+
+ end;
+ [] ->
+ reply_not_found; % Trace ??
+
+ [#reply{state = waiting_for_ack}] ->
+ %% The reply has already been sent
+ %% No need for any pending trans reply
+ reply_has_been_sent;
+
+ [#reply{state = aborted} = Rep] ->
+ %% glitch, but cleanup just the same
+ cancel_reply(CD, Rep, aborted),
+ reply_aborted_state
+
+ end.
+
+
+segment_timeout(ConnHandle, TransId, timeout = Timer) ->
+ ?report_trace(ConnHandle, "segment timeout", [TransId, Timer]),
+ incNumTimerRecovery(ConnHandle),
+ case megaco_monitor:lookup_request(TransId) of
+ [] ->
+ timeout_not_found_ignore;
+
+ [#request{seg_recv = Segs} = Req] ->
+ ConnData =
+ case megaco_config:lookup_local_conn(ConnHandle) of
+ [ConnData0] ->
+ ConnData0;
+ [] ->
+ fake_conn_data(ConnHandle)
+ end,
+ Last = lists:last(lists:sort(Segs)),
+ All = lists:seq(1,Last),
+ case All -- Segs of
+ [] ->
+ %% The last segment has just arrived, ignore
+ ok;
+ Missing ->
+ %% Send the error message
+ Code = ?megaco_segments_not_received,
+ Reason = missing_to_str(Missing),
+ send_message_error(ConnData, Code, Reason),
+
+ %% Report to the user
+ UserMod = Req#request.user_mod,
+ UserArgs = Req#request.user_args,
+ Action = Req#request.reply_action,
+ UserData = Req#request.reply_data,
+ UserReply = {error, {segment_timeout, Missing}},
+ ConnData2 = ConnData#conn_data{user_mod = UserMod,
+ user_args = UserArgs,
+ reply_action = Action,
+ reply_data = UserData},
+ return_reply(ConnData2, TransId, UserReply)
+ end
+ end;
+
+segment_timeout(ConnHandle, TransId, Timer) ->
+ ?report_trace(ConnHandle, "segment timeout", [TransId, Timer]),
+ case megaco_monitor:lookup_request_field(TransId, #request.trans_id) of
+ {ok, _} ->
+ {WaitFor, Timer2} = megaco_timer:restart(Timer),
+ M = ?MODULE,
+ F = segment_timeout,
+ A = [ConnHandle, TransId, Timer2],
+ Ref = megaco_monitor:apply_after(M, F, A, WaitFor),
+ %% Timing problem?
+ megaco_monitor:update_request_field(TransId,
+ #request.seg_timer_ref,
+ Ref),
+ {restarted, WaitFor, Timer2};
+ _ ->
+ not_found_ignore
+ end.
+
+%% segment_reply_timeout() ->
+%% ok.
+
+missing_to_str(Missing) ->
+ lists:flatten(missing_to_str2(Missing)).
+
+missing_to_str2([X]) ->
+ [integer_to_list(X)];
+missing_to_str2([H|T]) ->
+ [integer_to_list(H) , "," | missing_to_str2(T)].
+
+return_unexpected_trans_reply(ConnData, TransId,
+ {actionReplies, _} = UserReply, Extra) ->
+ Trans = make_transaction_reply(ConnData, TransId, UserReply),
+ return_unexpected_trans(ConnData, Trans, Extra);
+return_unexpected_trans_reply(ConnData, TransId,
+ {transactionError, _} = UserReply, Extra) ->
+ Trans = make_transaction_reply(ConnData, TransId, UserReply),
+ return_unexpected_trans(ConnData, Trans, Extra);
+return_unexpected_trans_reply(CD, TransId, {error, Reason}, Extra) ->
+ ?report_important(CD, "unexpected trans reply with error",
+ [TransId, Reason, Extra]),
+ ok;
+return_unexpected_trans_reply(CD, TransId, Crap, Extra) ->
+ ?report_important(CD, "unexpected trans reply with crap",
+ [TransId, Crap, Extra]),
+ ok.
+
+return_unexpected_trans(ConnData, Trans) ->
+ Extra = ?default_user_callback_extra,
+ return_unexpected_trans(ConnData, Trans, Extra).
+
+return_unexpected_trans(ConnData, Trans0, Extra) ->
+ UserMod = ConnData#conn_data.user_mod,
+ UserArgs = ConnData#conn_data.user_args,
+ ConnHandle = ConnData#conn_data.conn_handle,
+ Version = ConnData#conn_data.protocol_version,
+ Trans = transform_transaction_reply_enc(Version, Trans0),
+ Args =
+ case Extra of
+ ?default_user_callback_extra ->
+ [ConnHandle, Version, Trans | UserArgs];
+ _ ->
+ [ConnHandle, Version, Trans, Extra | UserArgs]
+ end,
+ Res = (catch apply(UserMod, handle_unexpected_trans, Args)),
+ ?report_debug(ConnData, "return: unexpected trans",
+ [Trans, {return, Res}]),
+ case Res of
+ ok ->
+ ok;
+ _ ->
+ warning_msg("unexpected transaction callback failed: ~w", [Res]),
+ ok
+ end,
+ Res.
+
+
+%%-----------------------------------------------------------------
+
+to_remote_trans_id(#conn_data{conn_handle = CH, serial = Serial}) ->
+ Mid = CH#megaco_conn_handle.remote_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+to_local_trans_id(#conn_data{conn_handle = CH, serial = Serial}) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+to_local_trans_id(#conn_data{conn_handle = CH}, [S|_] = Serials)
+ when is_integer(S) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ [#trans_id{mid = Mid, serial = Serial} || Serial <- Serials];
+to_local_trans_id(#conn_data{conn_handle = CH},
+ [{transactionRequest, TR}|_] = TRs)
+ when is_record(TR, 'TransactionRequest') ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ [#trans_id{mid = Mid, serial = Serial} ||
+ {transactionRequest,
+ #'TransactionRequest'{transactionId = Serial}} <- TRs];
+
+to_local_trans_id(#megaco_conn_handle{local_mid = Mid}, Serial)
+ when is_integer(Serial) ->
+ #trans_id{mid = Mid, serial = Serial};
+to_local_trans_id(#conn_data{conn_handle = CH}, Serial)
+ when is_integer(Serial) ->
+ Mid = CH#megaco_conn_handle.local_mid,
+ #trans_id{mid = Mid, serial = Serial}.
+
+
+%%-----------------------------------------------------------------
+
+transform_transaction_reply_dec({'TransactionReply',
+ TransId, IAR, TransRes}) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes};
+transform_transaction_reply_dec({'TransactionReply',
+ TransId, IAR, TransRes,
+ SegNo, SegComplete}) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete}.
+
+transform_transaction_reply_enc(
+ 3,
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete}) ->
+ {'TransactionReply', TransId, IAR, TransRes, SegNo, SegComplete};
+transform_transaction_reply_enc(
+ Version,
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes})
+ when (Version < 3) ->
+ {'TransactionReply', TransId, IAR, TransRes};
+transform_transaction_reply_enc(_, TR) ->
+ TR.
+
+make_transaction_reply(#conn_data{protocol_version = Version},
+ TransId, TransRes) ->
+ make_transaction_reply(Version, TransId, asn1_NOVALUE, TransRes).
+
+%% make_transaction_reply(#conn_data{protocol_version = Version},
+%% TransId, IAR, TransRes) ->
+%% make_transaction_reply(Version, TransId, IAR, TransRes);
+
+make_transaction_reply(3, TransId, IAR, TransRes) ->
+ {'TransactionReply', TransId, IAR, TransRes, asn1_NOVALUE, asn1_NOVALUE};
+make_transaction_reply(_, TransId, IAR, TransRes) ->
+ {'TransactionReply', TransId, IAR, TransRes}.
+
+
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+warning_msg(F, A) ->
+ ?megaco_warning(F, A).
+
+error_msg(F, A) ->
+ ?megaco_error(F, A).
+
+
+%%-----------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%%
+%% d(F,A) ->
+%% d(true,F,A).
+%% %% d(get(dbg),F,A).
+%%
+%% d(true,F,A) ->
+%% io:format("*** [~s] ~p:~p ***"
+%% "~n " ++ F ++ "~n",
+%% [format_timestamp(now()), self(),?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.
+%%
+%% format_timestamp({_N1, _N2, N3} = Now) ->
+%% {Date, Time} = calendar:now_to_datetime(Now),
+%% {YYYY,MM,DD} = Date,
+%% {Hour,Min,Sec} = Time,
+%% FormatDate =
+%% io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+%% [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+%% lists:flatten(FormatDate).
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumErrors/0, incNumErrors/1, incNumTimerRecovery/1
+%% Description: SNMP counter increment functions
+%%-----------------------------------------------------------------
+incNumErrors() ->
+ incNum(medGwyGatewayNumErrors).
+
+incNumErrors(CH) ->
+ incNum({CH, medGwyGatewayNumErrors}).
+
+incNumTimerRecovery(CH) ->
+ incNum({CH, medGwyGatewayNumTimerRecovery}).
+
+incNum(Cnt) ->
+ case (catch ets:update_counter(megaco_stats, Cnt, 1)) of
+ {'EXIT', {badarg, _Reason}} ->
+ ets:insert(megaco_stats, {Cnt, 1});
+ Old ->
+ Old
+ end.
+
diff --git a/lib/megaco/src/engine/megaco_messenger_misc.erl b/lib/megaco/src/engine/megaco_messenger_misc.erl
new file mode 100644
index 0000000000..3c340a8484
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_messenger_misc.erl
@@ -0,0 +1,409 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Misc functions used both from the megaco_messenger module
+%% and the megaco_ack_sender module.
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_messenger_misc).
+
+%% Application internal export
+-export([encode_body/3,
+ encode_trans_request/2,
+ encode_trans_reply/2,
+ encode_actions/3,
+ send_body/3,
+ send_message/3,
+
+ transform_transaction_reply/2
+ ]).
+
+%% Test functions
+-export([compose_message/3, encode_message/2]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+-define(MSG_HDR_SZ, 128). % This is just a guess...
+
+-ifdef(MEGACO_TEST_CODE).
+-define(SIM(Other,Where),
+ fun(Afun,Bfun) ->
+ Kfun = {?MODULE,Bfun},
+ case (catch ets:lookup(megaco_test_data, Kfun)) of
+ [{Kfun,Cfun}] ->
+ Cfun(Afun);
+ _ ->
+ Afun
+ end
+ end(Other,Where)).
+-define(TC_AWAIT_SEND_EVENT(SendFunction),
+ case megaco_tc_controller:lookup(send_function) of
+ {value, {Tag, Pid}} when is_pid(Pid) ->
+ Pid ! {Tag, self(), SendFuncion},
+ receive
+ {Tag, Pid} ->
+ ok
+ end;
+ _ ->
+ ok
+ end).
+-else.
+-define(SIM(Other,Where),Other).
+-define(TC_AWAIT_SEND_EVENT(_),ok).
+-endif.
+
+
+%%----------------------------------------------------------------------
+%% Encode the transaction request
+%%----------------------------------------------------------------------
+
+encode_trans_request(CD, TR) when is_record(TR, 'TransactionRequest') ->
+ ?report_debug(CD, "encode trans request", [TR]),
+ Trans = {transactionRequest, TR},
+ encode_transaction(CD, Trans).
+
+encode_trans_reply(#conn_data{segment_send = SegSend,
+ max_pdu_size = Max,
+ protocol_version = V} = CD, Reply)
+ when (SegSend == infinity) or (is_integer(SegSend) and (SegSend > 0)) and
+ is_integer(V) and (V >= 3) and
+ is_integer(Max) and (Max >= ?MSG_HDR_SZ) ->
+ (catch encode_segmented_trans_reply(CD, Reply));
+encode_trans_reply(CD, TR) when is_record(TR, megaco_transaction_reply) ->
+ ?report_debug(CD, "encode trans reply", [TR]),
+ Trans = {transactionReply, transform_transaction_reply(CD, TR)},
+ encode_transaction(CD, Trans);
+encode_trans_reply(CD, TR) when is_tuple(TR) and
+ (element(1, TR) == 'TransactionReply') ->
+ ?report_debug(CD, "encode trans reply", [TR]),
+ Trans = {transactionReply, TR},
+ encode_transaction(CD, Trans).
+
+
+encode_segmented_trans_reply(#conn_data{max_pdu_size = Max} = CD, Rep) ->
+ #megaco_transaction_reply{transactionResult = Res1} = Rep,
+ case Res1 of
+ {actionReplies, AR} when is_list(AR) andalso (length(AR) >= 1) ->
+ case encode_action_replies(CD, AR) of
+ {Size, EncodedARs} when Size =< (Max - ?MSG_HDR_SZ) ->
+ ?report_debug(CD, "action replies encoded size ok",
+ [Size, Max]),
+ %% No need to segment message: within size limit
+ Res2 = {actionReplies, EncodedARs},
+ TR = Rep#megaco_transaction_reply{transactionResult = Res2},
+ TR2 = transform_transaction_reply(CD, TR),
+ Trans = {transactionReply, TR2},
+ encode_transaction(CD, Trans);
+
+ {Size, EncodecARs} ->
+ ?report_debug(CD,
+ "action replies encoded size to large - "
+ "segment",
+ [Size, Max]),
+ %% Over size limit, so go segment the message
+ encode_segments(CD, Rep, EncodecARs)
+ end;
+ _ ->
+ TR = transform_transaction_reply(CD, Rep),
+ Trans = {transactionReply, TR},
+ encode_transaction(CD, Trans)
+ end.
+
+encode_segments(CD, Reply, EncodecARs) ->
+ encode_segments(CD, Reply, EncodecARs, 1, []).
+
+encode_segments(CD, Reply, [EncodedAR], SN, EncodedSegs) ->
+ Bin = encode_segment(CD, Reply, EncodedAR, SN, 'NULL'),
+ {ok, lists:reverse([{SN, Bin}|EncodedSegs])};
+encode_segments(CD, Reply, [EncodedAR|EncodedARs], SN, EncodedSegs) ->
+ Bin = encode_segment(CD, Reply, EncodedAR, SN, asn1_NOVALUE),
+ encode_segments(CD, Reply, EncodedARs, SN + 1, [{SN, Bin}|EncodedSegs]).
+
+encode_segment(CD, Reply, EncodedAR, SN, SC) ->
+ Res = {actionReplies, [EncodedAR]},
+ TR0 = Reply#megaco_transaction_reply{transactionResult = Res,
+ segmentNumber = SN,
+ segmentationComplete = SC},
+ TR = transform_transaction_reply(CD, TR0),
+ Trans = {transactionReply, TR},
+ case encode_transaction(CD, Trans) of
+ {ok, Bin} ->
+ Bin;
+ Error ->
+ throw(Error)
+ end.
+
+
+encode_transaction(#conn_data{protocol_version = V,
+ encoding_mod = EM,
+ encoding_config = EC} = CD, Trans) ->
+ case (catch EM:encode_transaction(EC, V, Trans)) of
+ {ok, Bin} ->
+ ?SIM({ok, Bin}, encode_trans);
+ {'EXIT', {undef, _}} ->
+ {error, not_implemented};
+ {error, not_implemented} = Error1 ->
+ Error1;
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_transaction, [EC, V, Trans], Reason}};
+ Error2 ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_transaction, [EC, V, Trans], Error2}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the action request's
+%%----------------------------------------------------------------------
+
+encode_actions(#conn_data{protocol_version = V} = CD, TraceLabel, ARs) ->
+ ?report_debug(CD, TraceLabel, [ARs]),
+
+ %% Encode the actions
+ EM = CD#conn_data.encoding_mod,
+ EC = CD#conn_data.encoding_config,
+ case (catch EM:encode_action_requests(EC, V, ARs)) of
+ {ok, Bin} when is_binary(Bin) ->
+ ?SIM({ok, Bin}, encode_actions);
+ {'EXIT', {undef, _}} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ Reason = not_implemented,
+ {error, {EM, encode_action_requests, [EC, ARs], Reason}};
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_action_requests, [EC, ARs], Reason}};
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ {error, {EM, encode_action_requests, [EC, ARs], Error}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the action reply's
+%%----------------------------------------------------------------------
+
+encode_action_replies(CD, AR) ->
+ encode_action_replies(CD, AR, 0, []).
+
+encode_action_replies(_, [], Size, Acc) ->
+ {Size, lists:reverse(Acc)};
+encode_action_replies(#conn_data{protocol_version = V,
+ encoding_mod = Mod,
+ encoding_config = Conf} = CD,
+ [AR|ARs], Size, Acc) ->
+ case (catch Mod:encode_action_reply(Conf, V, AR)) of
+ {ok, Bin} when is_binary(Bin) ->
+ encode_action_replies(CD, ARs, Size + size(Bin), [Bin|Acc]);
+ {'EXIT', {undef, _}} ->
+ throw({error, not_implemented});
+ {error, not_implemented} = Error1 ->
+ throw(Error1);
+ {error, Reason} ->
+ incNumErrors(CD#conn_data.conn_handle),
+ throw({error, {Mod, encode_action_reply, [Conf, AR], Reason}});
+ Error ->
+ incNumErrors(CD#conn_data.conn_handle),
+ throw({error, {Mod, encode_action_reply, [Conf, AR], Error}})
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Encode the message body
+%%----------------------------------------------------------------------
+
+encode_body(#conn_data{protocol_version = V} = ConnData,
+ TraceLabel, Body) ->
+ %% Create the message envelope
+ MegaMsg = compose_message(ConnData, V, Body),
+
+ ?report_debug(ConnData, TraceLabel, [MegaMsg]),
+
+ %% Encode the message
+ EM = ConnData#conn_data.encoding_mod,
+ EC = ConnData#conn_data.encoding_config,
+ case (catch EM:encode_message(EC, V, MegaMsg)) of
+ {ok, Bin} when is_binary(Bin) ->
+ ?SIM({ok, Bin}, encode_body);
+ {error, Reason} ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ {error, {EM, [EC, MegaMsg], Reason}};
+ Error ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ {error, {EM, [EC, MegaMsg], Error}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Compose and encode a message
+%%----------------------------------------------------------------------
+compose_message(#conn_data{conn_handle = CH,
+ auth_data = MsgAuth}, V, Body) ->
+ LocalMid = CH#megaco_conn_handle.local_mid,
+ Msg = #'Message'{version = V,
+ mId = LocalMid,
+ messageBody = Body},
+ MegaMsg = #'MegacoMessage'{authHeader = MsgAuth, % BUGBUG: Compute?
+ mess = Msg},
+ MegaMsg.
+
+
+encode_message(#conn_data{protocol_version = Version,
+ encoding_mod = EncodingMod,
+ encoding_config = EncodingConfig}, MegaMsg) ->
+ (catch EncodingMod:encode_message(EncodingConfig, Version, MegaMsg)).
+
+
+%%----------------------------------------------------------------------
+%% Send the message body
+%%----------------------------------------------------------------------
+
+send_body(ConnData, TraceLabel, Body) ->
+ case encode_body(ConnData, TraceLabel, Body) of
+ {ok, Bin} ->
+ send_message(ConnData, false, Bin);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Send the (encoded) message
+%%----------------------------------------------------------------------
+
+send_message(#conn_data{resend_indication = flag} = ConnData,
+ Resend, Bin) ->
+ do_send_message(ConnData, send_message, Bin, [Resend]);
+
+send_message(#conn_data{resend_indication = true} = ConnData,
+ true, Bin) ->
+ do_send_message(ConnData, resend_message, Bin, []);
+
+send_message(ConnData, _Resend, Bin) ->
+ do_send_message(ConnData, send_message, Bin, []).
+
+do_send_message(ConnData, SendFunc, Bin, Extra) ->
+ %% Send the message
+ #conn_data{send_mod = SendMod,
+ send_handle = SendHandle} = ConnData,
+
+ ?TC_AWAIT_SEND_EVENT(SendFunc),
+
+ ?report_trace(ConnData, "send bytes", [{bytes, Bin},
+ {send_func, SendFunc}]),
+
+ Args = [SendHandle, Bin | Extra],
+ case (catch apply(SendMod, SendFunc, Args)) of
+ ok ->
+ ?SIM({ok, Bin}, send_message);
+ {cancel, Reason} ->
+ ?report_trace(ConnData, "<CANCEL> send_message callback",
+ [{bytes, Bin}, {cancel, Reason}]),
+ {error, {send_message_cancelled, Reason}};
+ {error, Reason} ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {error, Reason}]),
+ error_msg("failed (error) sending message [using ~w] (~p):"
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Reason}};
+ {'EXIT', Reason} = Error ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {exit, Reason}]),
+ error_msg("failed (exit) sending message [using ~w] (~p):"
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Error}};
+ Reason ->
+ incNumErrors(ConnData#conn_data.conn_handle),
+ ?report_important(ConnData, "<ERROR> send_message callback",
+ [{bytes, Bin}, {error, Reason}]),
+ error_msg("failed sending message [using ~w] on (~p): "
+ "~n~w", [SendFunc, SendHandle, Reason]),
+ {error, {send_message_failed, Reason}}
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Misc internal util functions
+%%%-----------------------------------------------------------------
+
+transform_transaction_reply(#conn_data{protocol_version = V}, TR)
+ when is_integer(V) and (V >= 3) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes,
+ segmentNumber = SegNo,
+ segmentationComplete = SegComplete} = TR,
+ {'TransactionReply', TransId, IAR, TransRes, SegNo, SegComplete};
+transform_transaction_reply(_, TR) ->
+ #megaco_transaction_reply{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = TransRes} = TR,
+ {'TransactionReply', TransId, IAR, TransRes}.
+
+
+%%-----------------------------------------------------------------
+%% Func: error_msg/2
+%% Description: Send an error message
+%%-----------------------------------------------------------------
+
+error_msg(F, A) ->
+ ?megaco_error(F, A).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumErrors/0, incNumErrors/1, incNumTimerRecovery/1
+%% Description: SNMP counter increment functions
+%%-----------------------------------------------------------------
+
+incNumErrors(CH) ->
+ incNum({CH, medGwyGatewayNumErrors}).
+
+incNum(Cnt) ->
+ case (catch ets:update_counter(megaco_stats, Cnt, 1)) of
+ {'EXIT', {badarg, _R}} ->
+ ets:insert(megaco_stats, {Cnt, 1});
+ Old ->
+ Old
+ end.
+
+%% p(F, A) ->
+%% print(now(), F, A).
+
+%% print(Ts, F, A) ->
+%% io:format("*** [~s] ~p ***"
+%% "~n " ++ F ++ "~n",
+%% [format_timestamp(Ts), self() | A]).
+
+%% format_timestamp(Now) ->
+%% {_N1, _N2, N3} = Now,
+%% {Date, Time} = calendar:now_to_datetime(Now),
+%% {YYYY,MM,DD} = Date,
+%% {Hour,Min,Sec} = Time,
+%% FormatDate =
+%% io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+%% [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+%% lists:flatten(FormatDate).
diff --git a/lib/megaco/src/engine/megaco_misc_sup.erl b/lib/megaco/src/engine/megaco_misc_sup.erl
new file mode 100644
index 0000000000..07fe96871d
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_misc_sup.erl
@@ -0,0 +1,77 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The top supervisor for the Megaco/H.248 application
+%%----------------------------------------------------------------------
+
+-module(megaco_misc_sup).
+
+-behaviour(supervisor).
+
+%% public
+-export([start/0, start/2, stop/1, init/1]).
+-export([start_permanent_worker/4]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% application and supervisor callback functions
+
+start(normal, Args) ->
+ SupName = {local,?MODULE},
+ case supervisor:start_link(SupName, ?MODULE, [Args]) of
+ {ok, Pid} ->
+ {ok, Pid, {normal, Args}};
+ Error ->
+ Error
+ end;
+start(_, _) ->
+ {error, badarg}.
+
+start() ->
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) -> % Supervisor
+ init();
+init(BadArg) ->
+ {error, {badarg, BadArg}}.
+
+init() ->
+ Flags = {one_for_one, 0, 1},
+ Workers = [],
+ {ok, {Flags, Workers}}.
+
+
+%%----------------------------------------------------------------------
+%% Function: start_permanent_worker/3
+%% Description: Starts a permanent worker (child) process
+%%----------------------------------------------------------------------
+
+start_permanent_worker(M, F, A, Modules) ->
+ Spec = {M, {M,F,A}, permanent, timer:seconds(1), worker, [M] ++ Modules},
+ supervisor:start_child(?MODULE, Spec).
+
+
+
+
diff --git a/lib/megaco/src/engine/megaco_monitor.erl b/lib/megaco/src/engine/megaco_monitor.erl
new file mode 100644
index 0000000000..f95a20cf58
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_monitor.erl
@@ -0,0 +1,365 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Monitor connections and timers
+%%----------------------------------------------------------------------
+
+-module(megaco_monitor).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%% Application internal exports
+-export([
+ start_link/0,
+ stop/0,
+
+ apply_after/4,
+ apply_after/5,
+ cancel_apply_after/1,
+
+ lookup_request/1,
+ lookup_request_field/2,
+ match_requests/1,
+ which_requests/1,
+ insert_request/1,
+ update_request_field/3, update_request_fields/2,
+ delete_request/1,
+
+ lookup_reply/1,
+ lookup_reply_field/2,
+ match_replies/1,
+ which_replies/1,
+ insert_reply/1, insert_reply_new/1,
+ update_reply_field/3, update_reply_fields/2,
+ delete_reply/1,
+
+ apply_at_exit/4,
+ cancel_apply_at_exit/1
+ ]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-record(state, {parent_pid}).
+-record(apply_at_exit, {ref, pid, module, function, arguments}).
+
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start_link() ->
+ ?d("start -> entry", []),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], []).
+
+stop() ->
+ call(stop).
+
+lookup_request(Key) ->
+ ets:lookup(megaco_requests, Key).
+
+lookup_request_field(Key, Field) ->
+ try
+ begin
+ {ok, ets:lookup_element(megaco_requests, Key, Field)}
+ end
+ catch
+ error:badarg ->
+ {error, not_found}
+ end.
+
+match_requests(Pat) ->
+ ets:match_object(megaco_requests, Pat).
+
+which_requests(Pat) ->
+ Spec = [{Pat, [], ['$$']}],
+ ets:select(megaco_requests, Spec).
+
+insert_request(Rec) ->
+ ets:insert(megaco_requests, Rec).
+
+update_request_field(Key, Field, NewValue) ->
+ ets:update_element(megaco_requests, Key, {Field, NewValue}).
+
+update_request_fields(Key, NewFields) when is_list(NewFields) ->
+ ets:update_element(megaco_requests, Key, NewFields).
+
+delete_request(Key) ->
+ ets:delete(megaco_requests, Key).
+
+lookup_reply(Key) ->
+ ets:lookup(megaco_replies, Key).
+
+lookup_reply_field(Key, Field) ->
+ try
+ begin
+ {ok, ets:lookup_element(megaco_replies, Key, Field)}
+ end
+ catch
+ error:badarg ->
+ {error, not_found}
+ end.
+
+match_replies(Pat) ->
+ ets:match_object(megaco_replies, Pat).
+
+which_replies(Pat) ->
+ Spec = [{Pat, [], ['$$']}],
+ ets:select(megaco_replies, Spec).
+
+insert_reply(Rec) ->
+ ets:insert(megaco_replies, Rec).
+
+insert_reply_new(Rec) ->
+ ets:insert_new(megaco_replies, Rec).
+
+update_reply_field(Key, Field, NewValue) ->
+ ets:update_element(megaco_replies, Key, {Field, NewValue}).
+
+update_reply_fields(Key, NewFields) when is_list(NewFields) ->
+ ets:update_element(megaco_replies, Key, NewFields).
+
+delete_reply(Key) ->
+ ets:delete(megaco_replies, Key).
+
+apply_after(M, F, A, Time) ->
+ apply_after(spawn_method, M, F, A, Time).
+
+apply_after(Method, M, F, A, Time)
+ when is_atom(M) andalso is_atom(F) andalso is_list(A) ->
+ if
+ Time =:= infinity ->
+ apply_after_infinity;
+ is_integer(Time) ->
+ Msg = {apply_after, Method, M, F, A},
+ Ref = erlang:send_after(Time, whereis(?SERVER), Msg),
+ {apply_after, Ref}
+ end.
+
+cancel_apply_after({apply_after, Ref}) ->
+ case erlang:cancel_timer(Ref) of
+ TimeLeft when is_integer(TimeLeft) ->
+ {ok, TimeLeft};
+ _ ->
+ {ok, 0}
+ end;
+cancel_apply_after(apply_after_infinity) ->
+ ok;
+cancel_apply_after(BadRef) ->
+ {error, {bad_ref, BadRef}}.
+
+%% Performs apply(M, F, [Reason | A]) when process Pid dies
+apply_at_exit(M, F, A, Pid)
+ when is_atom(M) andalso is_atom(F) andalso is_list(A) andalso is_pid(Pid) ->
+ Ref = call({apply_at_exit, M, F, A, Pid}),
+ {apply_at_exit, Ref}.
+
+cancel_apply_at_exit({apply_at_exit, Ref}) ->
+ cast({cancel_apply_at_exit, Ref});
+cancel_apply_at_exit(BadRef) ->
+ {error, {bad_ref, BadRef}}.
+
+call(Request) ->
+ gen_server:call(?SERVER, Request, infinity).
+
+cast(Msg) ->
+ ?SERVER ! Msg, ok.
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+
+init([Parent]) ->
+ ?d("init -> entry", []),
+ process_flag(trap_exit, true),
+ ets:new(megaco_requests, [public, named_table, {keypos, 2}]),
+ ets:new(megaco_replies, [public, named_table, {keypos, 2}]),
+ ?d("init -> done", []),
+ {ok, #state{parent_pid = Parent}}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_call({apply_at_exit, M, F, A, Pid}, _From, S) ->
+ Ref = erlang:monitor(process, Pid),
+ AAE = #apply_at_exit{ref = Ref,
+ pid = Pid,
+ module = M,
+ function = F,
+ arguments = A},
+ put({?MODULE, Ref}, AAE),
+ Reply = Ref,
+ {reply, Reply, S};
+
+handle_call(stop, {Parent, _} = _From, #state{parent_pid = Parent} = S) ->
+ {stop, normal, ok, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w",[From, Req]),
+ {reply, {error, {bad_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+
+handle_info({cancel_apply_at_exit, Ref}, S) ->
+ case erase({?MODULE, Ref}) of
+ undefined ->
+ %% Reply = {error, {already_cancelled, {apply_at_exit, Ref}}},
+ {noreply, S};
+ _AAE ->
+ erlang:demonitor(Ref),
+ {noreply, S}
+ end;
+
+handle_info({apply_after, Method, M, F, A}, S) ->
+ handle_apply(Method, M, F, A, apply_after),
+ {noreply, S};
+
+%% Handle the old format also...
+handle_info({apply_after, M, F, A}, S) ->
+ handle_apply(M, F, A, apply_after),
+ {noreply, S};
+
+handle_info({'DOWN', Ref, process, _Pid, Reason}, S) ->
+ case erase({?MODULE, Ref}) of
+ undefined ->
+ {noreply, S};
+ AAE ->
+ M = AAE#apply_at_exit.module,
+ F = AAE#apply_at_exit.function,
+ A = AAE#apply_at_exit.arguments,
+ handle_apply(M, F, [Reason | A], apply_at_exit),
+ {noreply, S}
+ end;
+
+handle_info({'EXIT', Pid, Reason}, S) when Pid == S#state.parent_pid ->
+ %% [megaco_messenger:disconnect(CH, {stopped, Reason})
+ %% || CH <- megaco:lookup_system_info(connections)],
+ {stop, Reason, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unknown info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+handle_apply(M, F, A, _ErrorTag) ->
+ spawn(M, F, A).
+
+handle_apply(spawn_method, M, F, A, _ErrorTag) ->
+ spawn(M, F, A);
+handle_apply(_Method, M, F, A, _ErrorTag) ->
+ (catch apply(M, F, A)).
+
+
+warning_msg(F, A) ->
+ ?megaco_warning("Monitor server: " ++ F, A).
+
+
+% d(F) ->
+% d(F,[]).
+
+% d(F,A) ->
+% %% d(true,F,A).
+% d(get(dbg),F,A).
+
+% d(true,F,A) ->
+% io:format("*** [~s] ~p:~p ***"
+% "~n " ++ F ++ "~n",
+% [format_timestamp(now()), self(),?MODULE|A]);
+% d(_, _, _) ->
+% ok.
+
+% format_timestamp(Now) ->
+% {N1, N2, N3} = Now,
+% {Date, Time} = calendar:now_to_datetime(Now),
+% {YYYY,MM,DD} = Date,
+% {Hour,Min,Sec} = Time,
+% FormatDate =
+% io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+% [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+% lists:flatten(FormatDate).
+
+
diff --git a/lib/megaco/src/engine/megaco_sdp.erl b/lib/megaco/src/engine/megaco_sdp.erl
new file mode 100644
index 0000000000..90911fe24a
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_sdp.erl
@@ -0,0 +1,1645 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: RFC 4566
+%%----------------------------------------------------------------------
+
+-module(megaco_sdp).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/include/megaco_sdp.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+
+-export([
+ decode/1, encode/1,
+ get_sdp_record_from_PropertyGroup/2
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+%% ---------------------------------------------------------------------
+%% decode(PP) -> {ok, SDP} | {error, Reason}
+%%
+%% This function performs the following conversion:
+%% property_parm() -> sdp()
+%% property_group() -> sdp_property_group()
+%% property_groups() -> sdp_property_groups()
+%%
+%% ---------------------------------------------------------------------
+
+decode(SDP) ->
+ case (catch do_decode(SDP)) of
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERR ->
+ ERR;
+ {'EXIT', Reason} ->
+ {error, {exit, Reason}};
+ CRAP ->
+ {error, {crap, CRAP}}
+ end.
+
+do_decode(PP) when is_record(PP, 'PropertyParm') ->
+ decode_PropertyParm(PP);
+do_decode([PP|_] = PG) when is_record(PP, 'PropertyParm') ->
+ decode_PropertyGroup(PG);
+do_decode([H|_] = PGs) when is_list(H) ->
+ decode_PropertyGroups(PGs);
+do_decode(asn1_NOVALUE = V) ->
+ {ok, V};
+do_decode(Bad) ->
+ {error, {bad_sdp, Bad}}.
+
+
+%% ---------------------------------------------------------------------
+%% encode(SDPs) -> {ok, PP} | {error, Reason}
+%%
+%% This function performs the following conversion:
+%% sdp() -> property_parm()
+%% sdp_property_group() -> property_group()
+%% sdp_property_groups() -> property_groups()
+%%
+%% ---------------------------------------------------------------------
+
+encode(SDP) ->
+ case (catch do_encode(SDP)) of
+ {ok, _} = OK ->
+ OK;
+ {error, _} = ERR ->
+ ERR;
+ {'EXIT', Reason} ->
+ {error, {exit, Reason}};
+ CRAP ->
+ {error, {crap, CRAP}}
+ end.
+
+do_encode(SDP) when is_tuple(SDP) ->
+ {ok, encode_PropertyParm(SDP)};
+do_encode([SDP|_] = PG) when is_tuple(SDP) ->
+ encode_PropertyGroup(PG);
+do_encode([H|_] = PGs) when is_list(H) ->
+ encode_PropertyGroups(PGs);
+do_encode(asn1_NOVALUE = V) ->
+ {ok, V}.
+
+
+%%-----------------------------------------------------------------
+%% Generate sdp records from PropertyParm records
+%%-----------------------------------------------------------------
+
+decode_PropertyGroups(PGs) ->
+ decode_PropertyGroups(PGs, []).
+
+decode_PropertyGroups([], DecodedPGs) ->
+ {ok, lists:reverse(DecodedPGs)};
+
+decode_PropertyGroups([PG | PGs], DecodedPGs) ->
+ {ok, DecodedPG} = decode_PropertyGroup(PG),
+ decode_PropertyGroups(PGs, [DecodedPG | DecodedPGs]).
+
+
+decode_PropertyGroup(PG) ->
+ {ok, decode_PropertyGroup(PG, [])}.
+
+decode_PropertyGroup([], Acc) ->
+ lists:reverse(Acc);
+
+decode_PropertyGroup([PP | PG], Acc) ->
+ case (catch decode_PropertyParm(PP)) of
+ {ok, PP2} ->
+ decode_PropertyGroup(PG, [PP2 | Acc]);
+ {error, Reason} ->
+ decode_PropertyGroup(PG, [{PP, Reason} | Acc]);
+ Error ->
+ decode_PropertyGroup(PG, [{PP, Error} | Acc])
+ end.
+
+
+%% ===== Protocol Version =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "v",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_protocol_version(V);
+
+
+%% ===== Origin =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "o",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_origin(V);
+
+
+%% ===== Session Name =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "s",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_session_name(V);
+
+
+%% ===== Session and Media Information =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "i",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_session_media_id(V);
+
+
+%% ===== URI =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "u",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_uri(V);
+
+
+%% ===== Email Address and Phone Number =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "e",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_email(V);
+
+decode_PropertyParm(#'PropertyParm'{name = "p",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_phone(V);
+
+
+%% ===== Connection Data =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "c",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_connection_data(V);
+
+
+%% ===== Bandwidth =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "b",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_bandwidth(V);
+
+
+%% ===== Times, Repeat Times and Time Zones =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "t",
+ value = [V],
+ extraInfo = asn1_NOVALUE }) ->
+ decode_pp_times(V);
+decode_PropertyParm(#'PropertyParm'{name = "r",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_rtimes(V);
+decode_PropertyParm(#'PropertyParm'{name = "z",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_tzones(V);
+
+
+%% ===== Encryption Keys =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "k",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_encryption_keys(V);
+
+
+%% ===== Attributes =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "a",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_attribute(V);
+
+
+%% ===== Media Announcements =====
+%%
+decode_PropertyParm(#'PropertyParm'{name = "m",
+ value = [V],
+ extraInfo = asn1_NOVALUE}) ->
+ decode_pp_media_announcement(V);
+
+
+decode_PropertyParm(_PP) ->
+ ?d("decode_PropertyParm -> entry with"
+ "~n _PP: ~p", [_PP]),
+ {error, undefined_PropertyParm}.
+
+
+%%-----------------------------------------------------------------
+%% Generate PropertyParm records from sdp records
+%%-----------------------------------------------------------------
+
+encode_PropertyGroups(PGs) ->
+ encode_PropertyGroups(PGs, []).
+
+
+encode_PropertyGroups([], Acc) ->
+ {ok, lists:reverse(Acc)};
+encode_PropertyGroups([PG | PGs], Acc) ->
+ {ok, EncodedPG} = encode_PropertyGroup(PG),
+ encode_PropertyGroups(PGs, [EncodedPG | Acc]).
+
+
+encode_PropertyGroup(PG) ->
+ encode_PropertyGroup(PG, []).
+
+encode_PropertyGroup([], Acc) ->
+ {ok, lists:reverse(Acc)};
+encode_PropertyGroup([PP | PG], Acc) ->
+ EncodedPP = encode_PropertyParm(PP),
+ encode_PropertyGroup(PG, [EncodedPP | Acc]).
+
+
+%% ===== Protocol Version =====
+%%
+encode_PropertyParm(#megaco_sdp_v{version = Version}) ->
+ encode_pp_protocol_version(Version);
+
+
+%% ===== Origin =====
+%%
+encode_PropertyParm(#megaco_sdp_o{user_name = User,
+ session_id = SessionId,
+ version = Version,
+ network_type = Network,
+ address_type = AddrType,
+ address = Addr}) ->
+ encode_pp_origin(User, SessionId, Version, Network, AddrType, Addr);
+
+
+%% ===== Session Name =====
+%%
+encode_PropertyParm(#megaco_sdp_s{name = Name}) ->
+ encode_pp_session_name(Name);
+
+
+%% ===== Session and Media Information =====
+%%
+encode_PropertyParm(#megaco_sdp_i{session_descriptor = SD}) ->
+ encode_pp_session_media_id(SD);
+
+
+%% ===== URI =====
+%%
+encode_PropertyParm(#megaco_sdp_u{uri = URI}) ->
+ encode_pp_uri(URI);
+
+
+%% ===== Email Address and Phone Number =====
+%%
+encode_PropertyParm(#megaco_sdp_e{email = Email}) ->
+ encode_pp_email(Email);
+
+encode_PropertyParm(#megaco_sdp_p{phone_number = Num}) ->
+ encode_pp_phone(Num);
+
+
+%% ===== Connection Data =====
+%%
+encode_PropertyParm(#megaco_sdp_c{network_type = NetType,
+ address_type = AddressType,
+ connection_addr = ConnectionAddr}) ->
+ encode_pp_connection_data(NetType, AddressType, ConnectionAddr);
+
+
+%% ===== Bandwidth =====
+%%
+encode_PropertyParm(#megaco_sdp_b{bwtype = BwType,
+ bandwidth = Bandwidth}) ->
+ encode_pp_bandwidth(BwType, Bandwidth);
+
+
+%% ===== Times, Repeat Times and Time Zones =====
+%%
+encode_PropertyParm(#megaco_sdp_t{start = Start, stop = Stop}) ->
+ encode_pp_times(Start, Stop);
+
+encode_PropertyParm(#megaco_sdp_r{repeat_interval = Repeat,
+ active_duration = Duration,
+ list_of_offsets = ListOfOffsets}) ->
+ encode_pp_rtimes(Repeat, Duration, ListOfOffsets);
+
+encode_PropertyParm(#megaco_sdp_z{list_of_adjustments = LOA}) ->
+ encode_pp_tzones(LOA);
+
+
+%% ===== Encryption Keys =====
+%%
+encode_PropertyParm(#megaco_sdp_k{method = Method,
+ encryption_key = EncryptionKey}) ->
+ encode_pp_encryption_keys(Method, EncryptionKey);
+
+
+%% ===== Attributes =====
+%%
+encode_PropertyParm(#megaco_sdp_a_cat{category = Category}) ->
+ encode_pp_attribute_cat(Category);
+
+encode_PropertyParm(#megaco_sdp_a_keywds{keywords = Keywords}) ->
+ encode_pp_attribute_keywds(Keywords);
+
+encode_PropertyParm(#megaco_sdp_a_tool{name_and_version = NameAndVersion}) ->
+ encode_pp_attribute_tool(NameAndVersion);
+
+encode_PropertyParm(#megaco_sdp_a_ptime{packet_time = PacketTime}) ->
+ encode_pp_attribute_ptime(PacketTime);
+
+encode_PropertyParm(
+ #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}) ->
+ encode_pp_attribute_maxptime(MaxPacketTime);
+
+encode_PropertyParm(#megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate,
+ encoding_parms = EncPar}) ->
+ encode_pp_attribute_rtpmap(Payload, EncName, ClockRate, EncPar);
+
+encode_PropertyParm(#megaco_sdp_a_orient{orientation = Orientation}) ->
+ encode_pp_attribute_orient(Orientation);
+
+encode_PropertyParm(#megaco_sdp_a_type{conf_type = CType}) ->
+ encode_pp_attribute_type(CType);
+
+encode_PropertyParm(#megaco_sdp_a_charset{char_set = CharSet}) ->
+ encode_pp_attribute_charset(CharSet);
+
+encode_PropertyParm(#megaco_sdp_a_sdplang{tag = Tag}) ->
+ encode_pp_attribute_sdplang(Tag);
+
+encode_PropertyParm(#megaco_sdp_a_lang{tag = Tag}) ->
+ encode_pp_attribute_lang(Tag);
+
+encode_PropertyParm(#megaco_sdp_a_framerate{frame_rate = FrameRate}) ->
+ encode_pp_attribute_framerate(FrameRate);
+
+encode_PropertyParm(#megaco_sdp_a_quality{quality = Quality}) ->
+ encode_pp_attribute_quality(Quality);
+
+encode_PropertyParm(#megaco_sdp_a_fmtp{format = Fmt, param = Params}) ->
+ encode_pp_attribute_fmtp(Fmt, Params);
+
+encode_PropertyParm(#megaco_sdp_a{attribute = Attr, value = Value}) ->
+ encode_pp_attribute(Attr, Value);
+
+
+%% ===== Media Announcements =====
+%%
+encode_PropertyParm(#megaco_sdp_m{media = Media,
+ port = Port,
+ num_ports = NOP,
+ transport = Transport,
+ fmt_list = FMT}) ->
+ encode_pp_media_announcement(Media, Port, NOP, Transport, FMT);
+
+
+%% This is a "manually" encoded PropertyParm, leave it as is.
+%%
+encode_PropertyParm(PP) when is_record(PP, 'PropertyParm') ->
+ PP;
+
+
+%% Bad data
+encode_PropertyParm(SDP) ->
+ error({unknown_sdp, SDP}).
+
+
+%%-----------------------------------------------------------------
+%% Func: get_sdp_record_from_PropertGroup/2
+%% Description: Get all sdp records of a certain type from a
+%% property group
+%%-----------------------------------------------------------------
+
+get_sdp_record_from_PropertyGroup(Type, PG)
+ when is_atom(Type) and is_list(PG) ->
+ F = fun(R) -> not is_pg_record(Type, R) end,
+ lists:filter(F, PG).
+
+is_pg_record(v, R) when is_record(R, megaco_sdp_v) -> true;
+is_pg_record(c, R) when is_record(R, megaco_sdp_c) -> true;
+is_pg_record(m, R) when is_record(R, megaco_sdp_m) -> true;
+is_pg_record(o, R) when is_record(R, megaco_sdp_o) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a_ptime) -> true;
+is_pg_record(a, R) when is_record(R, megaco_sdp_a_rtpmap) -> true;
+is_pg_record(b, R) when is_record(R, megaco_sdp_b) -> true;
+is_pg_record(t, R) when is_record(R, megaco_sdp_t) -> true;
+is_pg_record(r, R) when is_record(R, megaco_sdp_r) -> true;
+is_pg_record(z, R) when is_record(R, megaco_sdp_z) -> true;
+is_pg_record(k, R) when is_record(R, megaco_sdp_k) -> true;
+is_pg_record(s, R) when is_record(R, megaco_sdp_s) -> true;
+is_pg_record(i, R) when is_record(R, megaco_sdp_i) -> true;
+is_pg_record(u, R) when is_record(R, megaco_sdp_u) -> true;
+is_pg_record(e, R) when is_record(R, megaco_sdp_e) -> true;
+is_pg_record(p, R) when is_record(R, megaco_sdp_p) -> true;
+is_pg_record(_, _) -> false.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% ===== Protocol Version =====
+%%
+decode_pp_protocol_version(Value) when is_list(Value) ->
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Value: ~p", [Value]),
+ Version = s2i(Value, invalid_protocol_version),
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ decode_pp_protocol_version(Version);
+decode_pp_protocol_version(Version) when is_integer(Version) ->
+ ?d("decode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ {ok, #megaco_sdp_v{version = Version}}.
+
+encode_pp_protocol_version(Version) when is_integer(Version) ->
+ ?d("encode_pp_protocol_version -> entry with"
+ "~n Version: ~w", [Version]),
+ #'PropertyParm'{name = "v",
+ value = [integer_to_list(Version)]};
+encode_pp_protocol_version(Version) ->
+ error({invalid_protocol_version, Version}).
+
+
+%% ===== Origin =====
+%%
+decode_pp_origin(Value) ->
+ ?d("decode_pp_origin -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [User, SessId, SessVersion, NetType, AddrType, UnicastAddress] ->
+ ?d("decode_pp_origin -> entry with"
+ "~n User: ~p"
+ "~n SessionId: ~p"
+ "~n Version: ~p"
+ "~n NetType: ~p"
+ "~n AddrType: ~p"
+ "~n UnicastAddress: ~p",
+ [User, SessId, SessVersion, NetType, AddrType, UnicastAddress]),
+ F = fun(X, R) ->
+ case (catch list_to_integer(X)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ error({invalid_origin, {R, X}})
+ end
+ end,
+ SID = F(SessId, sess_id),
+ V = F(SessVersion, sess_version),
+ SDP = #megaco_sdp_o{user_name = User,
+ session_id = SID,
+ version = V,
+ network_type = decode_network_type(NetType),
+ address_type = decode_address_type(AddrType),
+ address = UnicastAddress},
+ {ok, SDP};
+ Err ->
+ ?d("decode_pp_origin -> "
+ "~n Err: ~p", [Err]),
+ invalid_pp(origin, Value, Err)
+ end.
+
+encode_pp_origin(User0, SessionId0, SessVersion0,
+ NetType0, AddrType0, UnicastAddr0) ->
+ ?d("do_encode_pp_origin -> entry with"
+ "~n User0: ~p"
+ "~n SessionId0: ~p"
+ "~n SessVersion0: ~p"
+ "~n NetType0: ~p"
+ "~n AddrType0: ~p"
+ "~n UnicastAddr0: ~p",
+ [User0, SessionId0, SessVersion0, NetType0, AddrType0, UnicastAddr0]),
+ User = encode_origin_user(User0),
+ SessionId = encode_origin_session_id(SessionId0),
+ SessVersion = encode_origin_sess_version(SessVersion0),
+ NetType = encode_origin_network_type(NetType0),
+ AddrType = encode_origin_address_type(AddrType0),
+ UnicastAddr = encode_origin_unicast_address(UnicastAddr0),
+ #'PropertyParm'{name = "o",
+ value = [
+ User ++ " " ++
+ SessionId ++ " " ++
+ SessVersion ++ " " ++
+ NetType ++ " " ++
+ AddrType ++ " " ++
+ UnicastAddr
+ ]}.
+
+encode_origin_user(User) when is_list(User) ->
+ User;
+encode_origin_user(BadUser) ->
+ error({invalid_origin_user, BadUser}).
+
+encode_origin_session_id(SID) when is_integer(SID) ->
+ integer_to_list(SID);
+encode_origin_session_id(BadSID) ->
+ error({invalid_origin_session_id, BadSID}).
+
+encode_origin_sess_version(SessVersion) when is_integer(SessVersion) ->
+ integer_to_list(SessVersion);
+encode_origin_sess_version(BadSessVersion) ->
+ error({invalid_origin_sess_version, BadSessVersion}).
+
+encode_origin_network_type(NT) ->
+ case (catch encode_network_type(NT)) of
+ {error, _} ->
+ error({invalid_origin_network_type, NT});
+ Val ->
+ Val
+ end.
+
+encode_origin_address_type(AT) ->
+ case (catch encode_address_type(AT)) of
+ {error, _} ->
+ error({invalid_origin_address_type, AT});
+ Val ->
+ Val
+ end.
+
+encode_origin_unicast_address(UnicastAddr) when is_list(UnicastAddr) ->
+ UnicastAddr;
+encode_origin_unicast_address(BadUnicastAddr) ->
+ error({invalid_origin_unicast_address, BadUnicastAddr}).
+
+
+%% ===== Session Name =====
+%%
+decode_pp_session_name(Value) ->
+ ?d("decode_pp_session_name -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_s{name = Value}}.
+
+encode_pp_session_name(Name) when is_list(Name) ->
+ ?d("encode_pp_session_name -> entry with"
+ "~n Name: '~s'", [Name]),
+ #'PropertyParm'{name = "s",
+ value = [Name]};
+encode_pp_session_name(BadName) ->
+ error({invalid_session_name, BadName}).
+
+
+%% ===== Session and Media Information =====
+%%
+decode_pp_session_media_id(Value) ->
+ ?d("decode_pp_session_media_id -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_i{session_descriptor = Value}}.
+
+encode_pp_session_media_id(SD) when is_list(SD) ->
+ ?d("encode_pp_session_media_id -> entry with"
+ "~n SD: '~s'", [SD]),
+ #'PropertyParm'{name = "i",
+ value = [SD]};
+encode_pp_session_media_id(BadSD) ->
+ error({invalid_session_media_id, BadSD}).
+
+
+%% ===== URI =====
+%%
+decode_pp_uri(Value) ->
+ ?d("decode_pp_uri -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_u{uri = Value}}.
+
+encode_pp_uri(URI) when is_list(URI) ->
+ ?d("encode_pp_uri -> entry with"
+ "~n URI: ~p", [URI]),
+ #'PropertyParm'{name = "u",
+ value = [URI]};
+encode_pp_uri(BadUri) ->
+ error({invalid_uri, BadUri}).
+
+
+%% ===== Email Address and Phone Number =====
+%%
+decode_pp_email(Value) ->
+ ?d("decode_pp_email -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_e{email = Value}}.
+
+encode_pp_email(Email) when is_list(Email) ->
+ ?d("encode_pp_email -> entry with"
+ "~n Email: ~p", [Email]),
+ #'PropertyParm'{name = "e",
+ value = [Email]};
+encode_pp_email(BadEmail) ->
+ error({invalid_email, BadEmail}).
+
+decode_pp_phone(Value) ->
+ ?d("decode_pp_phone -> entry with"
+ "~n Value: ~p", [Value]),
+ {ok, #megaco_sdp_p{phone_number = Value}}.
+
+encode_pp_phone(Phone) when is_list(Phone) ->
+ ?d("encode_pp_phone -> entry with"
+ "~n Phone: ~p", [Phone]),
+ #'PropertyParm'{name = "p",
+ value = [Phone]};
+encode_pp_phone(BadPhone) ->
+ error({invalid_phone, BadPhone}).
+
+
+%% ===== Connection Data =====
+%%
+decode_pp_connection_data(Value) ->
+ ?d("decode_pp_connection_data -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [NetType, AddrType, ConnectionAddr] ->
+ ?d("decode_pp_connection_data -> "
+ "~n NetType: ~p"
+ "~n AddrType: ~p"
+ "~n ConnectionAddr: ~p", [NetType, AddrType, ConnectionAddr]),
+ NT = decode_network_type(NetType),
+ AT = decode_address_type(AddrType),
+ case AT of
+ ip4 ->
+ ?d("decode_pp_connection_data -> ip4", []),
+ ConnAddr =
+ case string:tokens(ConnectionAddr, "\/") of
+ [Base, TtlStr, NumOfAddrs] ->
+ ?d("decode_pp_connection_data -> "
+ "~n Base: ~p"
+ "~n TtlStr: ~p"
+ "~n NumOfAddrs:~p",
+ [Base, TtlStr, NumOfAddrs]),
+ TTL = s2i(TtlStr,
+ invalid_connection_data_ttl),
+ ?d("decode_pp_connection_data -> TTL: ~p",
+ [TTL]),
+ NOA =
+ s2i(NumOfAddrs,
+ invalid_connection_data_conn_addr_num_of),
+ ?d("decode_pp_connection_data -> NOA: ~p",
+ [NOA]),
+ #megaco_sdp_c_conn_addr{base = Base,
+ ttl = TTL,
+ num_of = NOA};
+ [Base, TtlStr] ->
+ ?d("decode_pp_connection_data -> "
+ "~n Base: ~p"
+ "~n TtlStr: ~p",
+ [Base, TtlStr]),
+ TTL =
+ s2i(TtlStr,
+ invalid_connection_data_conn_addr_ttl),
+ ?d("decode_pp_connection_data -> TTL: ~p",
+ [TTL]),
+ #megaco_sdp_c_conn_addr{base = Base,
+ ttl = TTL};
+ [Base] ->
+ Base
+ end,
+ ?d("decode_pp_connection_data -> "
+ "~n ConnAddr: ~p", [ConnAddr]),
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnAddr},
+ {ok, SDP};
+ ip6 ->
+ ?d("decode_pp_connection_data -> ip6", []),
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnectionAddr},
+ {ok, SDP};
+ _ ->
+ SDP = #megaco_sdp_c{network_type = NT,
+ address_type = AT,
+ connection_addr = ConnectionAddr},
+ {ok, SDP}
+ end;
+ Err ->
+ invalid_pp(connection_data, Value, Err)
+ end.
+
+encode_pp_connection_data(NetType0, AddrType0, ConnAddr0) ->
+ ?d("encode_pp_connection_data -> entry with"
+ "~n NetType0: ~p"
+ "~n AddrType0: ~p"
+ "~n ConnAddr0: ~p", [NetType0, AddrType0, ConnAddr0]),
+ NetType = encode_conn_data_network_type(NetType0),
+ AddrType = encode_conn_data_address_type(AddrType0),
+ ConnAddr = encode_conn_data_conn_addr(AddrType0, ConnAddr0),
+ Val = NetType ++ " " ++ AddrType ++ " " ++ ConnAddr,
+ #'PropertyParm'{name = "c",
+ value = [Val]}.
+
+encode_conn_data_network_type(NT) ->
+ case (catch encode_network_type(NT)) of
+ {error, _} ->
+ error({invalid_connection_data_network_type, NT});
+ Val ->
+ Val
+ end.
+
+encode_conn_data_address_type(AT) ->
+ case (catch encode_address_type(AT)) of
+ {error, _} ->
+ error({invalid_connection_data_address_type, AT});
+ Val ->
+ Val
+ end.
+
+encode_conn_data_conn_addr(_, CA) when is_list(CA) ->
+ CA;
+encode_conn_data_conn_addr(ip4, CA)
+ when is_record(CA, megaco_sdp_c_conn_addr) ->
+ encode_conn_data_conn_addr(CA);
+encode_conn_data_conn_addr(AT, CA)
+ when is_list(AT) and is_record(CA, megaco_sdp_c_conn_addr) ->
+ case tolower(AT) of
+ "ip4" ->
+ encode_conn_data_conn_addr(CA);
+ _ ->
+ error({invalid_connection_data_conn_addr, {AT, CA}})
+ end;
+encode_conn_data_conn_addr(_, BadCA) ->
+ error({invalid_connection_data_conn_addr, BadCA}).
+
+encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0,
+ ttl = TTL0,
+ num_of = undefined}) ->
+ Base = encode_conn_data_conn_addr_base(Base0),
+ TTL = encode_conn_data_conn_addr_ttl(TTL0),
+ Base ++ "/" ++ TTL;
+encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0,
+ ttl = TTL0,
+ num_of = NumOf0}) ->
+ Base = encode_conn_data_conn_addr_base(Base0),
+ TTL = encode_conn_data_conn_addr_ttl(TTL0),
+ NumOf = encode_conn_data_conn_addr_num_of(NumOf0),
+ Base ++ "/" ++ TTL ++ "/" ++ NumOf.
+
+encode_conn_data_conn_addr_base(Base) when is_list(Base) ->
+ Base;
+encode_conn_data_conn_addr_base(BadBase) ->
+ error({invalid_connection_data_conn_addr_base, BadBase}).
+
+encode_conn_data_conn_addr_ttl(TTL) when is_integer(TTL) ->
+ integer_to_list(TTL);
+encode_conn_data_conn_addr_ttl(BadTTL) ->
+ error({invalid_connection_data_conn_addr_ttl, BadTTL}).
+
+encode_conn_data_conn_addr_num_of(NumOf) when is_integer(NumOf) ->
+ integer_to_list(NumOf);
+encode_conn_data_conn_addr_num_of(BadNumOf) ->
+ error({invalid_connection_data_conn_addr_num_of, BadNumOf}).
+
+
+%% ===== Bandwidth =====
+%%
+decode_pp_bandwidth(Value) ->
+ ?d("decode_pp_bandwidth -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, ":") of
+ [BwTypeStr, BandwidthStr] ->
+ ?d("decode_pp_bandwidth -> "
+ "~n BwTypeStr: ~p"
+ "~n BandwidthStr: ~p", [BwTypeStr, BandwidthStr]),
+ BwType = decode_bandwidth_bwt(BwTypeStr),
+ ?d("decode_pp_bandwidth -> "
+ "~n BwType: ~w", [BwType]),
+ Bandwidth = decode_bandwidth_bw(BandwidthStr),
+ ?d("decode_pp_bandwidth -> "
+ "~n Bandwidth: ~w", [Bandwidth]),
+ SDP = #megaco_sdp_b{bwtype = BwType,
+ bandwidth = Bandwidth},
+ {ok, SDP};
+ Err ->
+ invalid_pp(bandwidth_info, Value, Err)
+ end.
+
+encode_pp_bandwidth(BwType0, Bandwidth0) ->
+ ?d("encode_pp_bandwidth -> entry with"
+ "~n BwType0: ~p"
+ "~n Bandwidth0: ~p", [BwType0, Bandwidth0]),
+ BwType = encode_bandwidth_bwt(BwType0),
+ Bandwidth = encode_bandwidth_bw(Bandwidth0),
+ Val = BwType ++ ":" ++ Bandwidth,
+ #'PropertyParm'{name = "b",
+ value = [Val]}.
+
+decode_bandwidth_bwt("CT") ->
+ ct;
+decode_bandwidth_bwt("AS") ->
+ as;
+decode_bandwidth_bwt(BwType) when is_list(BwType) ->
+ BwType;
+decode_bandwidth_bwt(BadBwType) ->
+ error({invalid_bandwidth_bwtype, BadBwType}).
+
+encode_bandwidth_bwt(ct) ->
+ "CT";
+encode_bandwidth_bwt(as) ->
+ "AS";
+encode_bandwidth_bwt(BwType) when is_list(BwType) ->
+ BwType;
+encode_bandwidth_bwt(BadBwType) ->
+ error({invalid_bandwidth_bwtype, BadBwType}).
+
+decode_bandwidth_bw(Bandwidth) ->
+ s2i(Bandwidth, invalid_bandwidth_bandwidth).
+
+encode_bandwidth_bw(Bandwidth) when is_integer(Bandwidth) ->
+ integer_to_list(Bandwidth);
+encode_bandwidth_bw(BadBandwidth) ->
+ error({invalid_bandwidth_bandwidth, BadBandwidth}).
+
+
+%% ===== Times =====
+%%
+decode_pp_times(Value) ->
+ ?d("decode_pp_times -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [StartStr, StopStr] ->
+ ?d("decode_pp_times -> "
+ "~n StartStr: ~p"
+ "~n StopStr: ~p", [StartStr, StopStr]),
+ Start = decode_times_start(StartStr),
+ ?d("decode_pp_times -> entry with"
+ "~n Stop: ~w", [Start]),
+ Stop = decode_times_stop(StopStr),
+ ?d("decode_pp_times -> entry with"
+ "~n Stop: ~w", [Stop]),
+ SDP = #megaco_sdp_t{start = Start,
+ stop = Stop},
+ {ok, SDP};
+ Err ->
+ invalid_pp(times, Value, Err)
+ end.
+
+encode_pp_times(Start0, Stop0) ->
+ ?d("encode_pp_times -> entry with"
+ "~n Start0: ~p"
+ "~n Stop0: ~p", [Start0, Stop0]),
+ Start = encode_times_start(Start0),
+ Stop = encode_times_stop(Stop0),
+ Val = Start ++ " " ++ Stop,
+ #'PropertyParm'{name = "t",
+ value = [Val]}.
+
+decode_times_start(Time) ->
+ s2i(Time, invalid_times_start).
+
+encode_times_start(Time) when is_integer(Time) ->
+ integer_to_list(Time);
+encode_times_start(BadTime) ->
+ error({invalid_times_start, BadTime}).
+
+decode_times_stop(Time) ->
+ s2i(Time, invalid_times_stop).
+
+encode_times_stop(Time) when is_integer(Time) ->
+ integer_to_list(Time);
+encode_times_stop(BadTime) ->
+ error({invalid_times_stop, BadTime}).
+
+
+%% ===== Repeat Times =====
+%%
+decode_pp_rtimes(Value) ->
+ ?d("decode_pp_rtimes -> entry with"
+ "~n Value: ~p", [Value]),
+ case string:tokens(Value, " \t") of
+ [Repeat, Duration | ListOfOffsets] ->
+ ?d("decode_pp_rtimes -> "
+ "~n Repeat: ~p"
+ "~n Duration: ~p"
+ "~n ListOfOffsets: ~p", [Repeat, Duration, ListOfOffsets]),
+ SDP = #megaco_sdp_r{repeat_interval = Repeat,
+ active_duration = Duration,
+ list_of_offsets = ListOfOffsets},
+ {ok, SDP};
+ Err ->
+ invalid_pp(repeat_times, Value, Err)
+ end.
+
+encode_pp_rtimes(Repeat0, Duration0, ListOfOffsets0) ->
+ ?d("encode_pp_rtimes -> entry with"
+ "~n Repeat0: ~p"
+ "~n Duration0: ~p"
+ "~n ListOfOffsets0: ~p", [Repeat0, Duration0, ListOfOffsets0]),
+ Repeat = encode_rtimes_repeat(Repeat0),
+ Duration = encode_rtimes_duration(Duration0),
+ ListOfOffsets = encode_rtimes_list_of_offsets(ListOfOffsets0),
+ Val = Repeat ++ " " ++ Duration ++ ListOfOffsets,
+ #'PropertyParm'{name = "r",
+ value = [Val]}.
+
+encode_rtimes_repeat(Repeat) when is_list(Repeat) ->
+ Repeat;
+encode_rtimes_repeat(BadRepeat) ->
+ error({invalid_rtimes_repeat, BadRepeat}).
+
+encode_rtimes_duration(Duration) when is_list(Duration) ->
+ Duration;
+encode_rtimes_duration(BadDuration) ->
+ error({invalid_rtimes_duration, BadDuration}).
+
+encode_rtimes_list_of_offsets(LOO) when is_list(LOO) ->
+ F = fun(Off, Acc) when is_list(Off) ->
+ Acc ++ " " ++ Off;
+ (BadOff, Acc) ->
+ error({invalid_rtimes_list_of_offsets, {BadOff, Acc}})
+ end,
+ lists:foldl(F, [], LOO);
+encode_rtimes_list_of_offsets(BadLoo) ->
+ error({invalid_rtimes_list_of_offsets, BadLoo}).
+
+
+%% ===== Time Zones =====
+%%
+decode_pp_tzones(Value) when is_list(Value) and (length(Value) > 0) ->
+ ?d("decode_pp_ztimes -> entry with"
+ "~n Value: ~p", [Value]),
+ LOA = decode_tzones_list_of_adjustments(string:tokens(Value, " \t"), []),
+ {ok, #megaco_sdp_z{list_of_adjustments = LOA}};
+decode_pp_tzones(BadValue) ->
+ error({invalid_tzones_list_of_adjustments, BadValue}).
+
+encode_pp_tzones(LOA) ->
+ ?d("encode_pp_ztimes -> entry with"
+ "~n LOA: ~p", [LOA]),
+ Val = encode_tzones_list_of_adjustments(LOA),
+ #'PropertyParm'{name = "z",
+ value = [Val]}.
+
+decode_tzones_list_of_adjustments([], Acc) ->
+ lists:reverse(Acc);
+decode_tzones_list_of_adjustments([Adj], Acc) ->
+ error({invalid_tzones_list_of_adjustments, Adj, lists:reverse(Acc)});
+decode_tzones_list_of_adjustments([Time, Offset | LOA], Acc) ->
+ Adj = #megaco_sdp_z_adjustement{time = Time, offset = Offset},
+ decode_tzones_list_of_adjustments(LOA, [Adj | Acc]).
+
+encode_tzones_list_of_adjustments([H|_] = LOA)
+ when is_record(H, megaco_sdp_z_adjustement) ->
+ F = fun(#megaco_sdp_z_adjustement{time = T, offset = O}, Acc) ->
+ Acc ++ " " ++ T ++ " " ++ O;
+ (BadAdjustment, Acc) ->
+ error({invalid_tzones_list_of_adjustments,
+ {BadAdjustment, Acc}})
+ end,
+ lists:foldl(F, [], LOA);
+encode_tzones_list_of_adjustments(LOA) ->
+ error({invalid_tzones_list_of_adjustments, LOA}).
+
+
+%% ===== Encryption Keys =====
+%%
+decode_pp_encryption_keys(Value) ->
+ ?d("decode_pp_encryption_keys -> entry with"
+ "~n Value: ~p", [Value]),
+ {M, E} =
+ case string:tokens(Value, ":") of
+ [Method, EncryptionKey] ->
+ ?d("decode_pp_encryption_keys -> "
+ "~n Method: ~p"
+ "~n EncryptionKey: ~p", [Method, EncryptionKey]),
+ {Method, EncryptionKey};
+ [Method] ->
+ ?d("decode_pp_encryption_keys -> "
+ "~n Method: ~p", [Method]),
+ {Method, undefined};
+ Err ->
+ invalid_pp(encryption_key, Value, Err)
+ end,
+ M2 =
+ case tolower(M) of
+ "clear" ->
+ clear;
+ "base64" ->
+ base64;
+ "uri" ->
+ uri;
+ "prompt" ->
+ prompt;
+ _ ->
+ M
+ end,
+ ?d("decode_pp_encryption_keys -> "
+ "~n M2: ~p", [M2]),
+ SDP = #megaco_sdp_k{method = M2,
+ encryption_key = E},
+ {ok, SDP}.
+
+encode_pp_encryption_keys(prompt = _Method, undefined) ->
+ ?d("encode_pp_encryption_keys(prompt) -> entry", []),
+ #'PropertyParm'{name = "k",
+ value = ["prompt"]};
+encode_pp_encryption_keys(clear = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(clear) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["clear:" ++ EncryptionKey]};
+encode_pp_encryption_keys(base64 = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(base64) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["base64:" ++ EncryptionKey]};
+encode_pp_encryption_keys(uri = _Method, EncryptionKey)
+ when is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys(uri) -> entry with"
+ "~n EncryptionKey: ~p", [EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = ["uri:" ++ EncryptionKey]};
+encode_pp_encryption_keys(Method, EncryptionKey)
+ when is_list(Method) and is_list(EncryptionKey) ->
+ ?d("encode_pp_encryption_keys -> entry with"
+ "~n Method: ~p"
+ "~n EncryptionKey: ~p", [Method, EncryptionKey]),
+ #'PropertyParm'{name = "k",
+ value = [Method ++ ":" ++ EncryptionKey]};
+encode_pp_encryption_keys(BadMethod, BadEK) ->
+ error({invalid_encryption_keys, {BadMethod, BadEK}}).
+
+
+%% ===== Attributes =====
+%%
+decode_pp_attribute(Value) ->
+ ?d("decode_pp_attribute -> entry with"
+ "~n Value: ~p", [Value]),
+ First = string:chr(Value, $:),
+ if
+ (First > 0) and (First < length(Value)) ->
+ ?d("decode_pp_attribute -> value attribute", []),
+ Attr = string:substr(Value, 1, First -1),
+ AttrValue = string:substr(Value, First + 1),
+ ?d("decode_pp_attribute -> "
+ "~n Attr: ~p"
+ "~n AttrValue: ~p", [Attr, AttrValue]),
+ decode_pp_attribute_value(Attr, AttrValue);
+
+ First > 0 ->
+ ?d("decode_pp_attribute -> value attribute (empty)", []),
+ Attr = string:substr(Value, 1, First -1),
+ ?d("decode_pp_attribute -> "
+ "~n Attr: ~p", [Attr]),
+ decode_pp_attribute_value(Attr, []);
+
+ true ->
+ ?d("decode_pp_attribute -> binary attribute", []),
+ {ok, #megaco_sdp_a{attribute = Value}}
+
+ end.
+
+decode_pp_attribute_value("cat", AttrValue) ->
+ ?d("decode_pp_attribute -> cat", []),
+ SDP = #megaco_sdp_a_cat{category = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("keywds", AttrValue) ->
+ ?d("decode_pp_attribute -> keywds", []),
+ SDP = #megaco_sdp_a_keywds{keywords = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("tool", AttrValue) ->
+ ?d("decode_pp_attribute -> tool", []),
+ SDP = #megaco_sdp_a_tool{name_and_version = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("ptime", AttrValue) ->
+ ?d("decode_pp_attribute -> ptime", []),
+ PacketTimeStr = string:strip(AttrValue, both, $ ),
+ PacketTime =
+ s2i(PacketTimeStr, invalid_ptime_packet_time),
+ ?d("decode_pp_attribute -> PacketTime: ~w", [PacketTime]),
+ SDP = #megaco_sdp_a_ptime{packet_time = PacketTime},
+ {ok, SDP};
+
+decode_pp_attribute_value("maxptime", AttrValue) ->
+ ?d("decode_pp_attribute -> maxptime", []),
+ MaxPacketTimeStr = string:strip(AttrValue, both, $ ),
+ MaxPacketTime =
+ s2i(MaxPacketTimeStr, invalid_maxptime_maximum_packet_time),
+ ?d("decode_pp_attribute -> MaxPacketTime: ~w", [MaxPacketTime]),
+ SDP = #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime},
+ {ok, SDP};
+
+decode_pp_attribute_value("rtpmap", AttrValue) ->
+ ?d("decode_pp_attribute -> rtpmap", []),
+ case string:tokens(AttrValue, "\/ \t") of
+ [PayloadStr, EncName, ClockRateStr | EncPar] ->
+ ?d("decode_pp_attribute -> "
+ "~n PayloadStr: ~p"
+ "~n EncName: ~p"
+ "~n ClockRateStr: ~p"
+ "~n EncPar: ~p",
+ [PayloadStr, EncName, ClockRateStr, EncPar]),
+ Payload =
+ s2i(PayloadStr, invalid_rtpmap_payload),
+ ?d("decode_pp_attribute -> Payload: ~w",
+ [Payload]),
+ ClockRate =
+ s2i(ClockRateStr, invalid_rtpmap_payload),
+ ?d("decode_pp_attribute -> ClockRate: ~w",
+ [ClockRate]),
+ SDP =
+ #megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate,
+ encoding_parms = EncPar},
+ {ok, SDP};
+ _ ->
+ error({invalid_rtpmap, AttrValue})
+ end;
+
+decode_pp_attribute_value("orient", AttrValue) ->
+ ?d("decode_pp_attribute -> orient", []),
+ Orientation = decode_attribute_orientation(AttrValue),
+ SDP = #megaco_sdp_a_orient{orientation = Orientation},
+ {ok, SDP};
+
+decode_pp_attribute_value("type", AttrValue) ->
+ ?d("decode_pp_attribute -> type", []),
+ SDP = #megaco_sdp_a_type{conf_type = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("charset", AttrValue) ->
+ ?d("decode_pp_attribute -> charset", []),
+ SDP = #megaco_sdp_a_charset{char_set = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("sdplang", AttrValue) ->
+ ?d("decode_pp_attribute -> sdplang", []),
+ SDP = #megaco_sdp_a_sdplang{tag = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("lang", AttrValue) ->
+ ?d("decode_pp_attribute -> lang", []),
+ SDP = #megaco_sdp_a_lang{tag = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("framerate", AttrValue) ->
+ ?d("decode_pp_attribute -> framerate", []),
+ SDP = #megaco_sdp_a_framerate{frame_rate = AttrValue},
+ {ok, SDP};
+
+decode_pp_attribute_value("quality", AttrValue) ->
+ ?d("decode_pp_attribute -> quality", []),
+ QualityStr = AttrValue,
+ Quality = s2i(QualityStr, invalid_quality_quality),
+ ?d("decode_pp_attribute -> Quality: ~w", [Quality]),
+ SDP = #megaco_sdp_a_quality{quality = Quality},
+ {ok, SDP};
+
+decode_pp_attribute_value("fmtp", AttrValue) ->
+ ?d("decode_pp_attribute -> fmtp", []),
+ FMTP = AttrValue,
+ First = string:chr(FMTP, $ ),
+ if
+ (First > 0) and (First < length(FMTP)) ->
+ ?d("decode_pp_attribute_value -> valid fmtp with params", []),
+ Format = string:substr(FMTP, 1, First - 1),
+ Params = string:substr(FMTP, First + 1),
+ ?d("decode_pp_attribute_value -> "
+ "~n Format: ~p"
+ "~n Params: ~p", [Format, Params]),
+ SDP = #megaco_sdp_a_fmtp{format = Format,
+ param = Params},
+ {ok, SDP};
+
+ First > 0 ->
+ ?d("decode_pp_attribute -> valid fmtp", []),
+ Format = string:substr(FMTP, 1, First - 1),
+ ?d("decode_pp_attribute -> "
+ "~n Format: ~p", [Format]),
+ {ok, #megaco_sdp_a_fmtp{format = Format, param = []}};
+
+ true ->
+ ?d("decode_pp_attribute_value -> no params", []),
+ {ok, #megaco_sdp_a_fmtp{format = FMTP, param = []}}
+
+ end;
+
+decode_pp_attribute_value(Attr, AttrValue) ->
+ ?d("decode_pp_attribute -> unknown value attribute", []),
+ {ok, #megaco_sdp_a{attribute = Attr, value = AttrValue}}.
+
+decode_attribute_orientation("portrait") ->
+ portrait;
+decode_attribute_orientation("landscape") ->
+ landscape;
+decode_attribute_orientation("seascape") ->
+ seascape;
+decode_attribute_orientation(BadOrientation) ->
+ error({invalid_orient_orientation, BadOrientation}).
+
+encode_attribute_orientation(portrait) ->
+ "portrait";
+encode_attribute_orientation(landscape) ->
+ "landscape";
+encode_attribute_orientation(seascape) ->
+ "seascape";
+encode_attribute_orientation(BadOrientation) ->
+ error({invalid_orient_orientation, BadOrientation}).
+
+
+encode_pp_attribute_cat(Cat) when is_list(Cat) ->
+ ?d("encode_pp_attribute_cat -> entry with"
+ "~n Cat: ~p", [Cat]),
+ #'PropertyParm'{name = "a",
+ value = ["cat:" ++ Cat]};
+encode_pp_attribute_cat(BadCat) ->
+ error({invalid_cat_category, BadCat}).
+
+
+encode_pp_attribute_keywds(Keywords) when is_list(Keywords) ->
+ ?d("encode_pp_attribute_keywds -> entry with"
+ "~n Keywords: ~p", [Keywords]),
+ #'PropertyParm'{name = "a",
+ value = ["keywds:" ++ Keywords]};
+encode_pp_attribute_keywds(BadKeywords) ->
+ error({invalid_keywds_keywords, BadKeywords}).
+
+
+encode_pp_attribute_tool(NameAndVersion) when is_list(NameAndVersion) ->
+ ?d("encode_pp_attribute_tool -> entry with"
+ "~n NameAndVersion: ~p", [NameAndVersion]),
+ #'PropertyParm'{name = "a",
+ value = ["tool:" ++ NameAndVersion]};
+encode_pp_attribute_tool(BadNameAndVersion) ->
+ error({invalid_tool_name_and_version, BadNameAndVersion}).
+
+
+encode_pp_attribute_ptime(PacketTime) when is_integer(PacketTime) ->
+ ?d("encode_pp_attribute_ptime -> entry with"
+ "~n PacketTime: ~w", [PacketTime]),
+ #'PropertyParm'{name = "a",
+ value = ["ptime:" ++ integer_to_list(PacketTime)]};
+encode_pp_attribute_ptime(BadPT) ->
+ error({invalid_ptime_packet_time, BadPT}).
+
+
+encode_pp_attribute_maxptime(MaxPacketTime) when is_integer(MaxPacketTime) ->
+ ?d("encode_pp_attribute_maxptime -> entry with"
+ "~n MaxPacketTime: ~w", [MaxPacketTime]),
+ #'PropertyParm'{name = "a",
+ value = ["maxptime:" ++ integer_to_list(MaxPacketTime)]};
+encode_pp_attribute_maxptime(BadMPT) ->
+ error({invalid_maxptime_maximum_packet_time, BadMPT}).
+
+
+encode_pp_attribute_rtpmap(Payload0, EncName0, ClockRate0, EncPar0) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Payload0: ~p"
+ "~n EncName0: ~p"
+ "~n ClockRate0: ~p"
+ "~n EncPar0: ~p", [Payload0, EncName0, ClockRate0, EncPar0]),
+ Payload = encode_rtpmap_payload(Payload0),
+ EncName = encode_rtpmap_encoding_name(EncName0),
+ ClockRate = encode_rtpmap_clockrate(ClockRate0),
+ EncPar = encode_rtpmap_encoding_parms(EncPar0),
+ Val = "rtpmap:" ++ Payload ++ " " ++
+ EncName ++ "/" ++ ClockRate ++ EncPar,
+ #'PropertyParm'{name = "a",
+ value = [Val]}.
+
+encode_rtpmap_payload(Payload) when is_integer(Payload) ->
+ integer_to_list(Payload);
+encode_rtpmap_payload(BadPayload) ->
+ error({invalid_rtpmap_payload, BadPayload}).
+
+encode_rtpmap_encoding_name(EncName) when is_list(EncName) ->
+ EncName;
+encode_rtpmap_encoding_name(BadEncName) ->
+ error({invalid_rtpmap_encoding_name, BadEncName}).
+
+encode_rtpmap_clockrate(ClockRate) when is_integer(ClockRate) ->
+ integer_to_list(ClockRate);
+encode_rtpmap_clockrate(BadClockRate) ->
+ error({invalid_rtpmap_clockrate, BadClockRate}).
+
+encode_rtpmap_encoding_parms(EncPar) when is_list(EncPar) ->
+ F = fun(EP, Acc) when is_list(EP) ->
+ Acc ++ "/" ++ EP;
+ (BadEP, Acc) ->
+ error({invalid_rtpmap_encoding_parms, {BadEP, Acc}})
+ end,
+ lists:foldl(F, [], EncPar);
+encode_rtpmap_encoding_parms(BadEncPar) ->
+ error({invalid_rtpmap_encoding_parms, BadEncPar}).
+
+
+encode_pp_attribute_orient(Orientation0) ->
+ ?d("encode_pp_attribute_orient -> entry with"
+ "~n Orientation0: ~w", [Orientation0]),
+ Orientation = encode_attribute_orientation(Orientation0),
+ #'PropertyParm'{name = "a",
+ value = ["orient:" ++ Orientation]}.
+
+
+encode_pp_attribute_type(CType) when is_list(CType) ->
+ ?d("encode_pp_attribute_type -> entry with"
+ "~n CType: ~p", [CType]),
+ #'PropertyParm'{name = "a",
+ value = ["type:" ++ CType]};
+encode_pp_attribute_type(BadCType) ->
+ error({invalid_type_conf_type, BadCType}).
+
+
+encode_pp_attribute_charset(CharSet) when is_list(CharSet) ->
+ ?d("encode_pp_attribute_charset -> entry with"
+ "~n CharSet: ~p", [CharSet]),
+ #'PropertyParm'{name = "a",
+ value = ["charset:" ++ CharSet]};
+encode_pp_attribute_charset(BadCharSet) ->
+ error({invalid_charset_char_set, BadCharSet}).
+
+
+encode_pp_attribute_sdplang(SdpLang) when is_list(SdpLang) ->
+ ?d("encode_pp_attribute_sdplang -> entry with"
+ "~n SdpLang: ~p", [SdpLang]),
+ #'PropertyParm'{name = "a",
+ value = ["sdplang:" ++ SdpLang]};
+encode_pp_attribute_sdplang(BadSdpLang) ->
+ error({invalid_sdplang_tag, BadSdpLang}).
+
+
+encode_pp_attribute_lang(Lang) when is_list(Lang) ->
+ ?d("encode_pp_attribute_lang -> entry with"
+ "~n Lang: ~p", [Lang]),
+ #'PropertyParm'{name = "a",
+ value = ["lang:" ++ Lang]};
+encode_pp_attribute_lang(BadLang) ->
+ error({invalid_lang_tag, BadLang}).
+
+
+encode_pp_attribute_framerate(FrameRate) when is_list(FrameRate) ->
+ ?d("encode_pp_attribute_framerate -> entry with"
+ "~n FrameRate: ~p", [FrameRate]),
+ #'PropertyParm'{name = "a",
+ value = ["framerate:" ++ FrameRate]};
+encode_pp_attribute_framerate(BadFrameRate) ->
+ error({invalid_framerate_frame_rate, BadFrameRate}).
+
+
+encode_pp_attribute_quality(Quality) when is_integer(Quality) ->
+ ?d("encode_pp_attribute_quality -> entry with"
+ "~n Quality: ~w", [Quality]),
+ #'PropertyParm'{name = "a",
+ value = ["quality:" ++ integer_to_list(Quality)]};
+encode_pp_attribute_quality(BadQ) ->
+ error({invalid_quality_quality, BadQ}).
+
+
+encode_pp_attribute_fmtp(Fmt0, Params0) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Fmt0: ~p"
+ "~n Params0: ~p", [Fmt0, Params0]),
+ Fmt = encode_fmtp_format(Fmt0),
+ Params = encode_fmtp_param(Params0),
+ Val = "fmtp:" ++ Fmt ++ " " ++ Params,
+ #'PropertyParm'{name = "a",
+ value = [Val]}.
+
+encode_fmtp_format(Fmt) when is_list(Fmt) ->
+ Fmt;
+encode_fmtp_format(BadFmt) ->
+ error({invalid_fmtp_format, BadFmt}).
+
+encode_fmtp_param(Param) when is_list(Param) ->
+ Param;
+encode_fmtp_param(BadParam) ->
+ error({invalid_fmtp_param, BadParam}).
+
+
+encode_pp_attribute(Attr, undefined) when is_list(Attr) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Attr: ~p", [Attr]),
+ #'PropertyParm'{name = "a",
+ value = [Attr]};
+encode_pp_attribute(Attr, Value) when is_list(Attr) and is_list(Value) ->
+ ?d("encode_pp_attribute_rtpmap -> entry with"
+ "~n Attr: ~p"
+ "~n Value: ~p", [Attr, Value]),
+ #'PropertyParm'{name = "a",
+ value = [Attr ++ ":" ++ Value]};
+encode_pp_attribute(BadAttr, BadAttrValue) ->
+ error({invalid_attribute, {BadAttr, BadAttrValue}}).
+
+
+%% ===== Media Announcements =====
+%%
+decode_pp_media_announcement(Value) ->
+ case string:tokens(Value, " \t") of
+ [Media0, PortInfo, Transport | FMT] ->
+ Media =
+ case tolower(Media0) of
+ "audio" -> audio;
+ "video" -> video;
+ "application" -> application;
+ "data" -> data;
+ "control" -> control;
+ _ -> Media0
+ end,
+ {Port, NoOfPorts} =
+ case string:tokens(PortInfo, "/") of
+ [P1, NP] ->
+ {s2i(P1, invalid_media_announcement_port),
+ s2i(NP, invalid_media_announcement_nof_ports)};
+ [P2] ->
+ {s2i(P2, invalid_media_announcement_port),
+ undefined};
+ Err ->
+ invalid_pp(mnta_port_info, Value, Err)
+ end,
+ SDP = #megaco_sdp_m{media = Media,
+ port = Port,
+ num_ports = NoOfPorts,
+ transport = Transport,
+ fmt_list = FMT},
+ {ok, SDP};
+ Err ->
+ invalid_pp(media_name_transp_addr, Value, Err)
+ end.
+
+
+encode_pp_media_announcement(Media0, Port0, undefined, Transport0, FMT0) ->
+ ?d("encode_pp_media_announcement -> entry with"
+ "~n Media0: ~p"
+ "~n Port0: ~p"
+ "~n Transport0: ~p"
+ "~n FMT0: ~p", [Media0, Port0, Transport0, FMT0]),
+ Media = encode_media_announcement_media(Media0),
+ Port = encode_media_announcement_port(Port0),
+ Transport = encode_media_announcement_transport(Transport0),
+ FMT = encode_media_announcement_fmt_list(FMT0),
+ do_encode_pp_media_announcement(Media, Port, "", Transport, FMT);
+encode_pp_media_announcement(Media0, Port0, NumPorts0, Transport0, FMT0) ->
+ ?d("encode_pp_media_announcement -> entry with"
+ "~n Media0: ~p"
+ "~n Port0: ~p"
+ "~n NumPorts0: ~p"
+ "~n Transport0: ~p"
+ "~n FMT0: ~p", [Media0, Port0, NumPorts0, Transport0, FMT0]),
+ Media = encode_media_announcement_media(Media0),
+ Port = encode_media_announcement_port(Port0),
+ NumPorts = encode_media_announcement_num_port(NumPorts0),
+ Transport = encode_media_announcement_transport(Transport0),
+ FMT = encode_media_announcement_fmt_list(FMT0),
+ do_encode_pp_media_announcement(Media, Port, NumPorts, Transport, FMT).
+
+do_encode_pp_media_announcement(Media, Port, NumOfPorts, Transport, FMT) ->
+ Val = Media ++ " " ++ Port ++ NumOfPorts ++ " " ++ Transport ++ FMT,
+ #'PropertyParm'{name = "m",
+ value = [Val]}.
+
+encode_media_announcement_media(Media) when is_atom(Media) ->
+ MaMedia = [audio, video, application, data, control],
+ case lists:member(Media, MaMedia) of
+ true ->
+ atom_to_list(Media);
+ false ->
+ error({invalid_media_announcement_media, Media})
+ end;
+encode_media_announcement_media(Media) when is_list(Media) ->
+ Media;
+encode_media_announcement_media(BadMedia) ->
+ error({invalid_media_announcement_media, BadMedia}).
+
+encode_media_announcement_port(Port) when is_integer(Port) ->
+ integer_to_list(Port);
+encode_media_announcement_port(BadPort) ->
+ error({invalid_media_announcement_port, BadPort}).
+
+encode_media_announcement_num_port(NumPort) when is_integer(NumPort) ->
+ "/" ++ integer_to_list(NumPort);
+encode_media_announcement_num_port(BadNumPort) ->
+ error({invalid_media_announcement_num_port, BadNumPort}).
+
+encode_media_announcement_transport(Transport) when is_list(Transport) ->
+ Transport;
+encode_media_announcement_transport(BadTransport) ->
+ error({invalid_media_announcement_transport, BadTransport}).
+
+encode_media_announcement_fmt_list(FmtList) when is_list(FmtList) ->
+ F = fun(FMT, Acc) when is_list(FMT) ->
+ Acc ++ " " ++ FMT;
+ (BadFMT, Acc) ->
+ error({invalid_media_announcement_fmt_list, {BadFMT, Acc}})
+ end,
+ lists:foldl(F, [], FmtList);
+encode_media_announcement_fmt_list(BadFmtList) ->
+ error({invalid_media_announcement_fmt_list, BadFmtList}).
+
+
+decode_network_type(NT) when is_list(NT) ->
+ case tolower(NT) of
+ "in" -> in;
+ _ -> NT
+ end.
+
+encode_network_type(in) -> "IN";
+encode_network_type(NT) when is_list(NT) -> NT;
+encode_network_type(Bad) ->
+ {error, {invalid_network_type, Bad}}.
+
+
+decode_address_type(AT) when is_list(AT) ->
+ case tolower(AT) of
+ "ip4" -> ip4;
+ "ip6" -> ip6;
+ _ -> AT
+ end.
+
+encode_address_type(ip4) -> "IP4";
+encode_address_type(ip6) -> "IP6";
+encode_address_type(AT) when is_list(AT) ->
+ case toupper(AT) of
+ "IP4" -> "IP4";
+ "IP6" -> "IP6";
+ _ -> AT
+ end;
+encode_address_type(Crap) ->
+ {error, {invalid_address_type, Crap}}.
+
+
+s2i(S, E) ->
+ case (catch list_to_integer(S)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ error({E, S})
+ end.
+
+-define(LOWER(Char),
+ if
+ Char >= $A, Char =< $Z ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+tolower(Chars) ->
+ [?LOWER(Char) || Char <- Chars].
+
+-define(UPPER(Char),
+ if
+ Char >= $a, Char =< $z ->
+ Char + ($A - $a);
+ true ->
+ Char
+ end).
+toupper(Chars) ->
+ [?UPPER(Char) || Char <- Chars].
+
+invalid_pp(What, Value, Error) ->
+ {error, {invalid_PropertyParm, {What, Value, Error}}}.
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/megaco/src/engine/megaco_stats.erl b/lib/megaco/src/engine/megaco_stats.erl
new file mode 100644
index 0000000000..af180fb9d6
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_stats.erl
@@ -0,0 +1,207 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Functions for handling statistic counters
+%%-----------------------------------------------------------------
+-module(megaco_stats).
+
+
+%%-----------------------------------------------------------------
+%% Application internal exports
+%%-----------------------------------------------------------------
+
+-export([init/1, init/2]).
+
+-export([inc/2, inc/3, inc/4]).
+
+-export([get_stats/1, get_stats/2, get_stats/3,
+ reset_stats/1, reset_stats/2]).
+
+%% -include_lib("megaco/include/megaco.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Func: init/1, init/2
+%% Description: Initiate the statistics. Creates the stats table
+%% and the global counters.
+%%-----------------------------------------------------------------
+init(Name) ->
+ init(Name, []).
+
+init(Name, GlobalCounters) ->
+ ets:new(Name, [public, named_table, {keypos, 1}]),
+ ets:insert(Name, {global_counters, GlobalCounters}),
+ create_global_snmp_counters(Name, GlobalCounters).
+
+
+create_global_snmp_counters(_Name, []) ->
+ ok;
+create_global_snmp_counters(Name, [Counter|Counters]) ->
+ ets:insert(Name, {Counter, 0}),
+ create_global_snmp_counters(Name, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Func: inc/2, inc/3, inc/4
+%% Description: Increment counter value. Default increment is one
+%% (1).
+%%-----------------------------------------------------------------
+inc(Tab, GlobalCnt) when is_atom(GlobalCnt) ->
+ inc(Tab, GlobalCnt, 1).
+
+inc(Tab, GlobalCnt, Incr)
+ when is_atom(GlobalCnt) andalso (is_integer(Incr) andalso (Incr > 0)) ->
+ do_inc(Tab, GlobalCnt, Incr);
+inc(Tab, Handle, Cnt)
+ when is_atom(Cnt) ->
+ inc(Tab, Handle, Cnt, 1).
+
+inc(Tab, Handle, Cnt, Incr)
+ when is_atom(Cnt) andalso (is_integer(Incr) andalso (Incr > 0)) ->
+ Key = {Handle, Cnt},
+ do_inc(Tab, Key, Incr).
+
+do_inc(Tab, Key, Incr) ->
+ case (catch ets:update_counter(Tab, Key, Incr)) of
+ {'EXIT', {badarg, _Reason}} ->
+ ets:insert(Tab, {Key, Incr}),
+ Incr;
+ Val ->
+ Val
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/1, get_stats/2, get_stats/3
+%% Description: Get statistics
+%%-----------------------------------------------------------------
+get_stats(Ets) ->
+ Handles = get_handles_and_global_counters(Ets),
+ (catch do_get_stats(Ets, Handles, [])).
+
+do_get_stats(_Ets, [], Acc) ->
+ {ok, lists:reverse(Acc)};
+do_get_stats(Ets, [Handle|Handles], Acc) ->
+ case get_stats(Ets, Handle) of
+ {ok, Stats} ->
+ do_get_stats(Ets, Handles, [{Handle, Stats}|Acc]);
+ {error, Reason} ->
+ throw({error, Reason})
+ end.
+
+get_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) ->
+ case (catch ets:lookup(Ets, GlobalCounter)) of
+ [{GlobalCounter, Val}] ->
+ {ok, Val};
+ [] ->
+ {error, {no_such_counter, GlobalCounter}}
+ end;
+
+get_stats(Ets, Handle) ->
+ case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of
+ CounterVals when is_list(CounterVals) ->
+ {ok, [{Counter, Val} || [Counter, Val] <- CounterVals]};
+ Other ->
+ {error, {unexpected_result, Other}}
+ end.
+
+
+get_stats(Ets, Handle, Counter) when is_atom(Counter) ->
+ Key = {Handle, Counter},
+ case (catch ets:lookup(Ets, Key)) of
+ [{Key, Val}] ->
+ {ok, Val};
+ _ ->
+ {error, {undefined_counter, Counter}}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Funcs: reset_stats/1, reset_stats/2
+%% Description: Reset statistics
+%%-----------------------------------------------------------------
+reset_stats(Ets) ->
+ Handles = get_handles_and_global_counters(Ets),
+ (catch do_reset_stats(Ets, Handles, [])).
+
+do_reset_stats(_Ets, [], Acc) ->
+ {ok, lists:reverse(Acc)};
+do_reset_stats(Ets, [Handle|Handles], Acc) ->
+ case reset_stats(Ets, Handle) of
+ {ok, OldStats} ->
+ do_reset_stats(Ets, Handles, [{Handle, OldStats}|Acc]);
+ {error, Reason} ->
+ throw({error, Reason})
+ end.
+
+reset_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) ->
+ %% First get the current value of the counter
+ case (catch ets:lookup(Ets, GlobalCounter)) of
+ [{GlobalCounter, Val}] ->
+ ets:insert(Ets, {GlobalCounter, 0}),
+ {ok, Val};
+ [] -> %% Oooups
+ {error, {no_such_counter, GlobalCounter}}
+ end;
+
+reset_stats(Ets, Handle) ->
+ case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of
+ CounterVals when is_list(CounterVals) ->
+ CVs = [{Counter, Val} || [Counter, Val] <- CounterVals],
+ reset_stats(Ets, Handle, CVs),
+ {ok, CVs};
+ Other ->
+ {error, {unexpected_result, Other}}
+ end.
+
+reset_stats(_Ets, _Handle, []) ->
+ ok;
+reset_stats(Ets, Handle, [{Counter, _}|CVs]) ->
+ ets:insert(Ets, {{Handle, Counter}, 0}),
+ reset_stats(Ets, Handle, CVs).
+
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+get_handles_and_global_counters(Ets) ->
+ GlobalCounters =
+ case ets:lookup(Ets, global_counters) of
+ [{global_counters, GC}] ->
+ GC;
+ [] ->
+ []
+ end,
+ L1 = ets:match(Ets, {{'$1', '_'}, '_'}),
+ GlobalCounters ++
+ lists:sort([Handle || [Handle] <- remove_duplicates(L1, [])]).
+
+remove_duplicates([], L) ->
+ L;
+remove_duplicates([H|T], L) ->
+ case lists:member(H,T) of
+ true ->
+ remove_duplicates(T, L);
+ false ->
+ remove_duplicates(T, [H|L])
+ end.
+
diff --git a/lib/megaco/src/engine/megaco_sup.erl b/lib/megaco/src/engine/megaco_sup.erl
new file mode 100644
index 0000000000..c61a1da298
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_sup.erl
@@ -0,0 +1,116 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The top supervisor for the Megaco/H.248 application
+%%----------------------------------------------------------------------
+
+-module(megaco_sup).
+
+-behaviour(application).
+-behaviour(supervisor).
+
+%% public
+-export([start/0, start/2, stop/1]).
+-export([start_sup_child/1, stop_sup_child/1]).
+
+%% internal
+-export([init/1]).
+
+%% debug
+-export([supervisor_timeout/1]).
+
+
+%% -define(d(F,A), io:format("~p~p:" ++ F ++ "~n", [self(),?MODULE|A])).
+-define(d(F,A), ok).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% application and supervisor callback functions
+
+start(normal, Args) ->
+ ?d("start(normal) -> entry with"
+ "~n Args: ~p", [Args]),
+ SupName = {local, ?MODULE},
+ case supervisor:start_link(SupName, ?MODULE, [Args]) of
+ {ok, Pid} ->
+ {ok, Pid, {normal, Args}};
+ Error ->
+ Error
+ end;
+start(_, _) ->
+ {error, badarg}.
+
+start() ->
+ ?d("start -> entry", []),
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) -> % Supervisor
+ init();
+init([[]]) -> % Application
+ init();
+init(BadArg) ->
+ ?d("init -> entry when"
+ "~n BadArg: ~p",[BadArg]),
+ {error, {badarg, BadArg}}.
+
+init() ->
+ ?d("init -> entry", []),
+ Flags = {one_for_one, 0, 1},
+ Sups = [sup_spec(megaco_misc_sup),
+ sup_spec(megaco_trans_sup),
+ worker_spec(megaco_config, [gen_server]),
+ worker_spec(megaco_monitor, [gen_server])],
+ ?d("init -> done when"
+ "~n Flags: ~p"
+ "~n Sups: ~p", [Flags, Sups]),
+ {ok, {Flags, Sups}}.
+
+
+start_sup_child(Name) ->
+ ?d("start_sup_child -> entry with Name: ~p", [Name]),
+ Spec = sup_spec(Name),
+ supervisor:start_child(?MODULE, Spec).
+
+
+stop_sup_child(Name) ->
+ ?d("stop_sup_child -> entry with Name: ~p", [Name]),
+ ok = supervisor:terminate_child(?MODULE, Name),
+ ok = supervisor:delete_child(?MODULE, Name).
+
+
+
+sup_spec(Name) ->
+ {Name, {Name, start, []}, permanent, 2000, supervisor,[Name, supervisor]}.
+
+worker_spec(Name, Modules) ->
+ {Name, {Name, start_link, []}, permanent, 2000, worker, [Name] ++ Modules}.
+
+-ifdef(debug_shutdown).
+supervisor_timeout(_KillAfter) -> timer:hours(500).
+-else.
+supervisor_timeout(KillAfter) -> KillAfter.
+-endif.
+
+
diff --git a/lib/megaco/src/engine/megaco_timer.erl b/lib/megaco/src/engine/megaco_timer.erl
new file mode 100644
index 0000000000..9f524523a8
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_timer.erl
@@ -0,0 +1,117 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Timer handling
+%%----------------------------------------------------------------------
+
+-module(megaco_timer).
+
+%% Application internal export
+-export([
+ init/1,
+ restart/1,
+ verify/1
+ ]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+
+
+%%-----------------------------------------------------------------
+
+%% init(Timer) -> {TimeoutTime, NewTimer}
+%% Timer = megaco_timer()
+%% NewTimer = megaco_timer()
+%% TimeoutTime = infinity | integer()
+%%
+init(SingleWaitFor) when SingleWaitFor == infinity ->
+ {SingleWaitFor, timeout};
+init(SingleWaitFor) when is_integer(SingleWaitFor) and (SingleWaitFor >= 0) ->
+ {SingleWaitFor, timeout};
+init(Timer) when is_record(Timer, megaco_incr_timer) ->
+ return_incr(Timer).
+
+
+%% Returns {WaitFor, NewTimer} | {WaitFor, timeout}
+restart(#megaco_incr_timer{wait_for = Old,
+ factor = Factor,
+ incr = Incr,
+ max_retries = MaxRetries} = Timer) ->
+ New = wait_for(Old, Factor, Incr),
+ Max = decr(MaxRetries),
+ Timer2 = Timer#megaco_incr_timer{wait_for = New,
+ max_retries = Max},
+ return_incr(Timer2);
+restart({Timer, timeout}) when is_record(Timer, megaco_incr_timer) ->
+ restart(Timer).
+
+wait_for(Old, Factor, Incr) ->
+ New = (Old * Factor) + Incr,
+ if
+ New < 0 ->
+ 0;
+ true ->
+ New
+ end.
+
+verify(#megaco_incr_timer{wait_for = WaitFor,
+ factor = Factor,
+ incr = Incr,
+ max_retries = MaxRetries}) ->
+ (megaco_config:verify_strict_uint(WaitFor) and
+ megaco_config:verify_strict_uint(Factor) and
+ megaco_config:verify_strict_int(Incr) and
+ verify_max_retries(MaxRetries));
+verify(Timer) ->
+ megaco_config:verify_uint(Timer).
+
+verify_max_retries(infinity_restartable) ->
+ true;
+verify_max_retries(Val) ->
+ megaco_config:verify_uint(Val).
+
+
+%%-----------------------------------------------------------------
+
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = infinity} = Timer) ->
+ {WaitFor, Timer};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = infinity_restartable} = Timer) ->
+ {WaitFor, {Timer, timeout}};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = Int} = Timer)
+ when is_integer(Int) and (Int > 0) ->
+ {WaitFor, Timer};
+
+return_incr(#megaco_incr_timer{wait_for = WaitFor,
+ max_retries = 0} = _Timer) ->
+ {WaitFor, timeout}.
+
+
+decr(infinity = V) -> V;
+decr(infinity_restartable = V) -> V;
+decr(Int) when is_integer(Int) -> Int - 1.
+
+
diff --git a/lib/megaco/src/engine/megaco_trans_sender.erl b/lib/megaco/src/engine/megaco_trans_sender.erl
new file mode 100644
index 0000000000..710fef405a
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_trans_sender.erl
@@ -0,0 +1,699 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Transaction sender process
+%%----------------------------------------------------------------------
+
+-module(megaco_trans_sender).
+
+-export([start_link/5,
+ stop/1,
+ upgrade/2,
+ send_req/3,
+ send_reqs/3,
+ send_ack/2,
+ send_ack_now/2,
+ send_pending/2,
+ send_reply/2,
+ timeout/2,
+ ack_maxcount/2,
+ req_maxcount/2,
+ req_maxsize/2]).
+-export([system_continue/3, system_terminate/4, system_code_change/4]).
+-export([init/6]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include("megaco_message_internal.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-record(state,
+ {
+ parent,
+ conn_handle,
+ timeout,
+ req_sz = 0,
+ req_maxsize, %% Max total size of all accumulated reqs
+ req_maxcount,
+ ack_maxcount,
+ reqs = [],
+ acks = []
+ }).
+
+
+%%%-----------------------------------------------------------------
+%%% Public API
+%%%-----------------------------------------------------------------
+start_link(CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks) ->
+ ?d("start_link -> entry with"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n MaxSzReqs: ~p"
+ "~n MaxNoReqs: ~p"
+ "~n MaxNoAcks: ~p", [CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks]),
+ Args = [self(), CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks],
+ proc_lib:start_link(?MODULE, init, Args).
+
+stop(Pid) when is_pid(Pid) ->
+ Pid ! stop,
+ ok.
+
+upgrade(Pid, CH) when is_pid(Pid) ->
+ Pid ! {upgrade, CH},
+ ok.
+
+send_req(Pid, Tid, Req) when is_pid(Pid) andalso is_binary(Req) ->
+ Pid ! {send_req, Tid, Req},
+ ok.
+
+send_reqs(Pid, Tids, Reqs)
+ when is_pid(Pid) andalso
+ is_list(Tids) andalso
+ is_list(Reqs) andalso
+ (length(Tids) =:= length(Reqs)) ->
+ Pid ! {send_reqs, Tids, Reqs},
+ ok.
+
+send_ack(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_ack, Serial},
+ ok.
+
+send_ack_now(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_ack_now, Serial},
+ ok.
+
+send_pending(Pid, Serial) when is_pid(Pid) andalso is_integer(Serial) ->
+ Pid ! {send_pending, Serial},
+ ok.
+
+send_reply(Pid, Reply) when is_pid(Pid) andalso is_binary(Reply) ->
+ Pid ! {send_reply, Reply}.
+
+ack_maxcount(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {ack_maxcount, Max},
+ ok.
+
+req_maxcount(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {req_maxcount, Max},
+ ok.
+
+req_maxsize(Pid, Max) when is_pid(Pid) andalso is_integer(Max) ->
+ Pid ! {req_maxsize, Max},
+ ok.
+
+timeout(Pid, Timeout) when is_pid(Pid) ->
+ Pid ! {timeout, Timeout},
+ ok.
+
+
+
+%%%-----------------------------------------------------------------
+%%% Internal exports
+%%%-----------------------------------------------------------------
+
+init(Parent, CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks) ->
+ ?d("init -> entry with"
+ "~n Parent: ~p"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n MaxSzReqs: ~p"
+ "~n MaxNoReqs: ~p"
+ "~n MaxNoAcks: ~p", [Parent, CH, To, MaxSzReqs, MaxNoReqs, MaxNoAcks]),
+ process_flag(trap_exit, true),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ S = #state{parent = Parent,
+ conn_handle = CH,
+ timeout = To,
+ req_maxsize = MaxSzReqs,
+ req_maxcount = MaxNoReqs,
+ ack_maxcount = MaxNoAcks},
+ loop(S, To).
+
+
+%%%-----------------------------------------------------------------
+%%% Internal functions
+%%%-----------------------------------------------------------------
+%% idle (= empty)
+loop(#state{reqs = [], acks = [], timeout = Timeout} = S, _) ->
+ receive
+ {send_ack, Serial} ->
+ ?d("loop(empty) -> received send_ack [~w] request", [Serial]),
+ loop(S#state{acks = [Serial]}, Timeout);
+
+ {send_ack_now, Serial} ->
+ ?d("loop(empty) -> received send_ack_now [~w] request", [Serial]),
+ send_msg(S#state.conn_handle, [], [Serial]),
+ loop(S, Timeout);
+
+ {send_req, Tid, Req} when size(Req) >= S#state.req_maxsize ->
+ ?d("loop(empty) -> received (big) send_req request ~w", [Tid]),
+ send_msg(S#state.conn_handle, [{Tid, Req}], []),
+ loop(S, Timeout);
+
+ {send_req, Tid, Req} ->
+ ?d("loop(empty) -> received send_req request ~w", [Tid]),
+ loop(S#state{req_sz = size(Req), reqs = [{Tid,Req}]}, Timeout);
+
+ {send_reqs, Tids, Reqs} ->
+ ?d("loop(empty) -> received send_reqs request: ~w", [Tids]),
+ {NewS, _} = handle_send_reqs(Tids, Reqs, S),
+ loop(NewS, Timeout);
+
+ {send_pending, Serial} ->
+ ?d("loop(empty) -> received send_pending [~w] request", [Serial]),
+ handle_send_result(
+ send_pending(S#state.conn_handle, Serial, [], [])
+ ),
+ loop(S, Timeout);
+
+ {send_reply, Reply} ->
+ ?d("loop(empty) -> received send_reply request", []),
+ #state{conn_handle = CH, req_maxsize = MaxSz} = S,
+ handle_send_result( send_reply(CH, Reply, MaxSz, 0, [], []) ),
+ loop(S, Timeout);
+
+ {upgrade, CH} ->
+ ?d("loop(empty) -> received upgrade request:"
+ "~n CH: ~p", [CH]),
+ loop(S#state{conn_handle = CH}, Timeout);
+
+ {ack_maxcount, NewMax} ->
+ ?d("loop(empty) -> received ack_maxcount request", []),
+ loop(S#state{ack_maxcount = NewMax}, Timeout);
+
+ {req_maxcount, NewMax} ->
+ ?d("loop(empty) -> received req_maxcount request", []),
+ loop(S#state{req_maxcount = NewMax}, Timeout);
+
+ {req_maxsize, NewMax} ->
+ ?d("loop(empty) -> received req_maxsize request", []),
+ loop(S#state{req_maxsize = NewMax}, Timeout);
+
+ {timeout, NewTimeout} ->
+ ?d("loop(empty) -> received timeout request", []),
+ loop(S#state{timeout = NewTimeout}, NewTimeout);
+
+ stop ->
+ ?d("loop(empty) -> received stop request", []),
+ exit(normal);
+
+ {system, From, Msg} ->
+ ?d("loop(empty) -> received system message:"
+ "~n From: ~p"
+ "~n Msg: ~p", [From, Msg]),
+ Parent = S#state.parent,
+ sys:handle_system_msg(Msg, From, Parent,
+ ?MODULE, [], {S, Timeout});
+
+ {'EXIT', Parent, Reason} when S#state.parent == Parent ->
+ ?d("loop(empty) -> received upgrade request", []),
+ exit(Reason);
+
+ M ->
+ warning_msg("received unexpected message (ignoring): "
+ "~n~p", [M]),
+ loop(S, Timeout)
+
+ end;
+
+%% active (= some acks or reqs waiting to to be sent)
+loop(#state{reqs = Reqs, acks = Acks, ack_maxcount = MaxAcks,
+ timeout = Timeout} = S, To)
+ when To >= 0 ->
+ Start = t(),
+ receive
+ {send_ack, Serial} when length(Acks) + 1 >= MaxAcks ->
+ ?d("loop(active,~w) -> "
+ "received [~w] send_ack [~w] request",
+ [To, length(Acks), Serial]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, Reqs, [Serial|Acks])
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {send_ack, Serial} ->
+ ?d("loop(active,~w) -> received send_ack [~w] request",
+ [To, Serial]),
+ loop(S#state{acks = [Serial|Acks]}, to(To, Start));
+
+ {send_ack_now, Serial} ->
+ ?d("loop(active,~w) -> [~w,~w] "
+ "received send_ack_now [~w] request",
+ [To, length(Reqs), length(Acks), Serial]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, Reqs, [Serial|Acks])
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ %% We need to check that this is not a resend!!
+ %% In that case, send whatever we have in store
+ {send_req, Tid, Req} ->
+ ?d("loop(active,~w) -> received send_req request ~w", [To,Tid]),
+ {NewS, NewT} =
+ case handle_send_req(Tid, Req, S) of
+ {S1, true} ->
+ {S1, Timeout};
+ {S1, false} ->
+ {S1, to(To, Start)}
+ end,
+ loop(NewS, NewT);
+
+ {send_reqs, Tids, NewReqs} ->
+ ?d("loop(active,~w) -> received send_reqs request ~w", [To,Tids]),
+ {NewS, NewT} =
+ case handle_send_reqs(Tids, NewReqs, S) of
+ {S1, true} ->
+ {S1, Timeout};
+ {S1, false} ->
+ {S1, to(To, Start)}
+ end,
+ loop(NewS, NewT);
+
+ {send_pending, Serial} ->
+ ?d("loop(active,~w) -> received send_pending [~w] request",
+ [To, Serial]),
+ handle_send_result(
+ send_pending(S#state.conn_handle, Serial, Reqs, Acks)
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {send_reply, Reply} ->
+ ?d("loop(active,~w) -> received send_reply request", [To]),
+ #state{conn_handle = CH, req_maxsize = MaxSz, req_sz = ReqSz} = S,
+ handle_send_result(
+ send_reply(CH, Reply, MaxSz, ReqSz, Reqs, Acks)
+ ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout);
+
+ {upgrade, CH} ->
+ ?d("loop(active,~w) -> received upgrade request", [To]),
+ loop(S#state{conn_handle = CH}, to(To, Start));
+
+ {req_maxsize, NewMax} ->
+ ?d("loop(active,~w) -> received req_maxsize request", [To]),
+ loop(S#state{req_maxsize = NewMax}, to(To, Start));
+
+ {req_maxcount, NewMax} ->
+ ?d("loop(active,~w) -> received req_maxcount request", [To]),
+ loop(S#state{req_maxcount = NewMax}, to(To, Start));
+
+ {ack_maxcount, NewMax} ->
+ ?d("loop(active,~w) -> received ack_maxcount request", [To]),
+ loop(S#state{ack_maxcount = NewMax}, to(To, Start));
+
+ {timeout, NewTimeout} when NewTimeout > Timeout ->
+ ?d("loop(active,~w) -> received timeout request: ~w",
+ [To, NewTimeout]),
+ %% We need to recalculate To
+ NewTo = NewTimeout - (Timeout - to(To, Start)),
+ loop(S#state{timeout = NewTimeout}, NewTo);
+
+ {timeout, NewTimeout} ->
+ ?d("loop(active,~w) -> received timeout request: ~w",
+ [To, NewTimeout]),
+ %% We need to recalculate To
+ NewTo = to(To, Start) - (Timeout - NewTimeout),
+ loop(S#state{timeout = NewTimeout}, NewTo);
+
+ stop ->
+ ?d("loop(active,~w) -> received stop request", [To]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ exit(normal);
+
+ {system, From, Msg} ->
+ ?d("loop(active,~w) -> received system message:"
+ "~n From: ~p"
+ "~n Msg: ~p", [To, From, Msg]),
+ Parent = S#state.parent,
+ sys:handle_system_msg(Msg, From, Parent,
+ ?MODULE, [], {S, to(To, Start)});
+
+ {'EXIT', Parent, Reason} when S#state.parent == Parent ->
+ ?d("loop(active,~w) -> received exit request", [To]),
+ exit(Reason);
+
+ M ->
+ warning_msg("received unexpected message (ignoring): "
+ "~n~p", [M]),
+ loop(S, to(To, Start))
+
+ after To ->
+ ?d("loop(active,~w) -> timeout - time to send", [To]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout)
+ end;
+
+loop(#state{reqs = Reqs, acks = Acks, timeout = Timeout} = S, _To) ->
+ ?d("loop(active) -> timeout [~w, ~w]", [length(Reqs),length(Acks)]),
+ handle_send_result( send_msg(S#state.conn_handle, Reqs, Acks) ),
+ loop(S#state{req_sz = 0, reqs = [], acks = []}, Timeout).
+
+
+%%%-----------------------------------------------------------------
+
+%% The request is itself larger then the max size, so first send
+%% everything we have stored in one message, and then the new request
+%% in another.
+%% Note that it does not matter if we with this request
+%% passed the maxcount limit.
+%% Note that this message cannot be a re-sent, since
+%% such a request would have been stored, but sent immediatly.
+handle_send_req(Tid, Req,
+ #state{conn_handle = CH,
+ req_maxsize = MaxSz, reqs = Reqs, acks = Acks} = S)
+ when size(Req) >= MaxSz ->
+ ?d("handle_send_req -> request bigger then maxsize ~w", [MaxSz]),
+ handle_send_result( send_msg(CH, Reqs, Acks) ),
+ handle_send_result( send_msg(CH, [{Tid, Req}], []) ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+%% And handle all the other cases
+handle_send_req(Tid, Req,
+ #state{conn_handle = CH, req_sz = ReqSz,
+ req_maxcount = MaxReqs, req_maxsize = MaxSz,
+ reqs = Reqs, acks = Acks} = S) ->
+ case lists:keymember(Tid, 1, Reqs) of
+ true ->
+ %% A re-send, time to send whatever we have in the store
+ ?d("handle_send_req -> was a re-send, so flush",[]),
+ handle_send_result( send_msg(CH, Reqs, Acks) ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false when length(Reqs) + 1 >= MaxReqs ->
+ %% We finally passed the req-maxcount limit
+ ?d("handle_send_req -> maxcount ~w passed", [MaxReqs]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, [{Tid, Req}|Reqs], Acks)
+ ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false when size(Req) + ReqSz >= MaxSz ->
+ %% We finally passed the req-maxsize limit
+ ?d("handle_send_req -> maxsize ~w passed", [MaxSz]),
+ handle_send_result(
+ send_msg(S#state.conn_handle, [{Tid, Req}|Reqs], Acks)
+ ),
+ {S#state{req_sz = 0, reqs = [], acks = []}, true};
+
+ false ->
+ %% Still not time to send
+ ?d("handle_send_req -> nothing to be sent",[]),
+ {S#state{req_sz = ReqSz + size(Req), reqs = [{Tid, Req}|Reqs]},
+ false}
+ end.
+
+
+%% We passed the req-maxcount limit: Time to send, atleast some of
+%% the stuff...
+handle_send_reqs(Tids, Reqs0,
+ #state{conn_handle = CH,
+ req_maxsize = MaxSz, req_sz = ReqSz,
+ req_maxcount = MaxReqs, reqs = Reqs, acks = Acks} = S)
+ when length(Reqs0) + length(Reqs) >= MaxReqs ->
+ ?d("handle_send_reqs -> maxcount ~w: ~w, ~w",
+ [MaxSz,length(Reqs0),length(Reqs)]),
+ Reqs1 = merge_tids_and_reqs(Tids, Reqs0, []),
+ {NewReqs, NewReqSz} = send_reqs(CH, Reqs1, Acks, Reqs, ReqSz, MaxSz),
+ ?d("handle_send_reqs -> sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs, acks = []}, true};
+
+%% We did not pass the req-maxcount limit, but we could have passed the
+%% req-maxsize limit, so maybe send...
+handle_send_reqs(Tids, Reqs0, #state{conn_handle = CH,
+ req_maxsize = MaxSz, req_sz = ReqSz,
+ reqs = Reqs, acks = Acks} = S) ->
+ ?d("handle_send_reqs -> not maxcount - maybe maxsize (~w)", [MaxSz]),
+ Reqs1 = merge_tids_and_reqs(Tids, Reqs0, []),
+
+ case maybe_send_reqs(CH, Reqs1, Acks, Reqs, ReqSz, MaxSz, false) of
+ {NewReqs, NewReqSz, true} ->
+ ?d("handle_send_reqs -> sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs, acks = []}, true};
+ {NewReqs, NewReqSz, false} ->
+ ?d("handle_send_reqs -> not sent:"
+ "~n NewReqSz: ~w"
+ "~n length(NewReqs): ~w", [NewReqSz, length(NewReqs)]),
+ {S#state{req_sz = NewReqSz, reqs = NewReqs}, false}
+ end.
+
+merge_tids_and_reqs([], [], Reqs) ->
+ Reqs;
+merge_tids_and_reqs([Tid|Tids], [Req|Reqs], Acc) ->
+ merge_tids_and_reqs(Tids, Reqs, [{Tid,Req}|Acc]).
+
+%% We know that we shall send, so if maybe_send_reqs does not,
+%% we send it our self...
+send_reqs(CH, Reqs, Acks, Acc, AccSz, MaxSz) ->
+ ?d("send_reqs -> entry when"
+ "~n length(Reqs): ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w"
+ "~n AccSz: ~w", [length(Reqs), Acks, length(Acc), AccSz]),
+ case maybe_send_reqs(CH, Reqs, Acks, Acc, AccSz, MaxSz, false) of
+ {NewReqs, _NewReqSz, false} ->
+ ?d("send_reqs -> nothing sent yet"
+ "~n length(NewReqs): ~w", [length(NewReqs)]),
+ handle_send_result( send_msg(CH, NewReqs, Acks) ),
+ {[], 0};
+ {NewReqs, NewReqSz, true} ->
+ ?d("send_reqs -> something sent"
+ "~n length(NewReqs): ~w"
+ "~n NewReqSz: ~w", [length(NewReqs), NewReqSz]),
+ {NewReqs, NewReqSz}
+ end.
+
+
+maybe_send_reqs(_CH, [], _Acks, Acc, AccSz, _MaxSz, Sent) ->
+ ?d("maybe_send_reqs -> done when"
+ "~n Sent: ~w"
+ "~n AccSz: ~w"
+ "~n length(Acc): ~w", [Sent, AccSz, length(Acc)]),
+ {Acc, AccSz, Sent};
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, _AccSz, MaxSz, _Sent)
+ when size(Req) >= MaxSz ->
+ %% The request was above the maxsize limit, so first send
+ %% what's in store and the the big request.
+ ?d("maybe_send_reqs -> entry when request [~w] size (~w) > max size"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w", [Tid, size(Req), Acks, length(Acc)]),
+ handle_send_result( send_msg(CH, Acc, Acks) ),
+ handle_send_result( send_msg(CH, [{Tid, Req}], []) ),
+ maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true);
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, _Sent)
+ when AccSz + size(Req) >= MaxSz ->
+ %% We _did_ pass the maxsize limit with this request, so send
+ ?d("maybe_send_reqs -> entry when sum of requests (~w) > max size"
+ "~n Tid: ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w", [Tid, size(Req) + AccSz, Acks, length(Acc)]),
+ handle_send_result( send_msg(CH, [{Tid, Req}|Acc], Acks) ),
+ maybe_send_reqs(CH, Reqs, [], [], 0, MaxSz, true);
+maybe_send_reqs(CH, [{Tid, Req}|Reqs], Acks, Acc, AccSz, MaxSz, Sent) ->
+ ?d("maybe_send_reqs -> entry when"
+ "~n Tid: ~w"
+ "~n size(Req): ~w"
+ "~n Acks: ~w"
+ "~n length(Acc): ~w"
+ "~n AccSz: ~w", [Tid, size(Req), Acks, length(Acc), AccSz]),
+ NewAcc = [{Tid,Req}|Acc],
+ NewAccSz = AccSz + size(Req),
+ maybe_send_reqs(CH, Reqs, Acks, NewAcc, NewAccSz, MaxSz, Sent).
+
+
+%%%-----------------------------------------------------------------
+
+send_pending(CH, Serial, Reqs, Acks) ->
+ ?d("send_pending -> entry with"
+ "~n Serial: ~w"
+ "~n length(Reqs): ~w"
+ "~n length(Acks): ~w", [Serial, length(Reqs), length(Acks)]),
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] ->
+ TP = #'TransactionPending'{transactionId = Serial},
+ Pend = {transactionPending, TP},
+ do_send_msg(CD, Pend, lists:reverse(Reqs), Acks);
+ [] ->
+ ok
+ end.
+
+
+%% We need to check the size of the reply. If the reply itself is
+%% larger then the max limit, then it is sent in a separate message.
+send_reply(CH, Reply, MaxSz, _ReqSz, Reqs, Acks) ->
+ ?d("send_reply -> entry with"
+ "~n length(Reqs): ~w"
+ "~n length(Acks): ~w", [length(Reqs), length(Acks)]),
+ case megaco_config:lookup_local_conn(CH) of
+ [CD] when size(Reply) > MaxSz ->
+ handle_send_result( send_msg(CD, lists:reverse(Reqs), Acks) ),
+ Rep = {transactionReply, Reply},
+ do_send_msg(CD, Rep, [], []);
+ [CD] ->
+ Rep = {transactionReply, Reply},
+ do_send_msg(CD, Rep, lists:reverse(Reqs), Acks);
+ [] ->
+ ok
+ end.
+
+do_send_msg(CD, Trans, [], []) ->
+ Body = {transactions, [Trans]},
+ Slogan = "send trans reply/pending",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, Reqs0, []) ->
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ Body = {transactions, [Trans|Reqs]},
+ Slogan = "send trans reply/pending and reqs",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, [], SerialRanges) ->
+ Acks = make_acks(ranges(SerialRanges), []),
+ Body = {transactions, [Trans, {transactionResponseAck, Acks}]},
+ Slogan = "send trans reply/pending and acks",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body);
+do_send_msg(CD, Trans, Reqs0, SerialRanges) ->
+ Acks = make_acks(ranges(SerialRanges), []),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ Body = {transactions, [Trans, {transactionResponseAck, Acks}|Reqs]},
+ Slogan = "send trans reply/pending, reqs and acks",
+ ?d("do_send_msg -> ~s", [Slogan]),
+ megaco_messenger_misc:send_body(CD, Slogan, Body).
+
+
+
+send_msg(_, [], []) ->
+ ok;
+send_msg(CH, Reqs, Serials) ->
+ case megaco_config:lookup_local_conn(CH) of
+ [ConnData] ->
+ do_send_msg(ConnData, lists:reverse(Reqs), Serials);
+ [] ->
+ ok
+ end.
+
+
+do_send_msg(CD, Reqs0, []) ->
+ ?d("do_send_msg -> entry with"
+ "~n length(Reqs0): ~p", [length(Reqs0)]),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, Reqs},
+ megaco_messenger_misc:send_body(CD, "send trans reqs", Body);
+do_send_msg(CD, [], SerialRanges) ->
+ ?d("do_send_msg -> entry with"
+ "~n SerialRanges: ~p", [SerialRanges]),
+ Acks = make_acks(ranges(SerialRanges), []),
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, [{transactionResponseAck, Acks}]},
+ megaco_messenger_misc:send_body(CD, "send trans acks", Body);
+do_send_msg(CD, Reqs0, SerialRanges) ->
+ ?d("do_send_msg -> entry with"
+ "~n length(Reqs0): ~p"
+ "~n SerialRanges: ~p", [length(Reqs0), SerialRanges]),
+ Acks = make_acks(ranges(SerialRanges), []),
+ Reqs = [{transactionRequest, Req} || {_, Req} <- Reqs0],
+ %% ?d("do_send_msg -> Reqs: ~n~p", [Reqs]),
+ Body = {transactions, [{transactionResponseAck, Acks}|Reqs]},
+ megaco_messenger_misc:send_body(CD, "send trans reqs and acks", Body).
+
+
+handle_send_result(ok) ->
+ ok;
+handle_send_result({ok, _}) ->
+ ok;
+handle_send_result({error, {send_message_cancelled, _Reason}}) ->
+ ok;
+handle_send_result({error, {send_message_failed, Reason}}) ->
+ error_msg("Failed sending message: ~n ~p", [Reason]),
+ error;
+handle_send_result(Error) ->
+ error_msg("Failed sending message: ~n ~p", [Error]),
+ error.
+
+
+ranges(L) ->
+ lists:reverse(ranges(lists:sort(L), [], [])).
+
+ranges([], Range, Ranges) ->
+ ranges2(Range, Ranges);
+ranges([S1|Sn], [S2|_] = Range, Ranges) when S1 == (S2+1) ->
+ ranges(Sn, [S1|Range], Ranges);
+ranges([S|Sn], Range, Ranges) ->
+ ranges(Sn, [S], ranges2(Range, Ranges)).
+
+ranges2([], Ranges) ->
+ Ranges;
+ranges2([S], Ranges) ->
+ [{S,S}|Ranges];
+ranges2(Range0, Ranges) ->
+ Range = lists:reverse(Range0),
+ [{hd(Range),lists:last(Range)}|Ranges].
+
+
+make_acks([], Acks) ->
+ lists:reverse(Acks);
+make_acks([{S,S}|SerialRanges], Acks) ->
+ TRA = #'TransactionAck'{firstAck = S},
+ make_acks(SerialRanges, [TRA|Acks]);
+make_acks([{F,L}|SerialRanges], Acks) ->
+ TRA = #'TransactionAck'{firstAck = F, lastAck = L},
+ make_acks(SerialRanges, [TRA|Acks]).
+
+
+
+%%%-----------------------------------------------------------------
+
+to(To, Start) ->
+ To - (t() - Start).
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+warning_msg(F, A) ->
+ ?megaco_warning("Transaction sender: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Transaction sender: " ++ F, A).
+
+
+%%%-----------------------------------------------------------------
+%%% System messages handled here
+%%%-----------------------------------------------------------------
+
+system_continue(_Parent, _Dbg, {S,To}) ->
+ loop(S, To).
+
+system_terminate(Reason, _Parent, _Dbg, {S, _}) ->
+ #state{conn_handle = CH, reqs = Reqs, acks = Acks} = S,
+ send_msg(CH, Reqs, Acks),
+ exit(Reason).
+
+system_code_change(S, _Module, _OLdVsn, _Extra) ->
+ ?d("system_code_change -> entry", []),
+ {ok, S}.
diff --git a/lib/megaco/src/engine/megaco_trans_sup.erl b/lib/megaco/src/engine/megaco_trans_sup.erl
new file mode 100644
index 0000000000..6c4a0b7145
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_trans_sup.erl
@@ -0,0 +1,88 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: The supervisor for the Megaco/H.248 transaction sender
+%% processes.
+%%----------------------------------------------------------------------
+
+-module(megaco_trans_sup).
+
+-behaviour(supervisor).
+
+%% public
+-export([start/0, stop/1, init/1]).
+-export([start_trans_sender/5]).
+
+%% -define(d(F,A), io:format("~p~p:" ++ F ++ "~n", [self(),?MODULE|A])).
+-define(d(F,A), ok).
+
+start() ->
+ ?d("start -> entry",[]),
+ SupName = {local,?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop(_StartArgs) ->
+ ok.
+
+init([]) ->
+ init();
+init(BadArg) ->
+ {error, {badarg, BadArg}}.
+
+init() ->
+ ?d("init -> entry",[]),
+ Flags = {one_for_one, 500, 100},
+ Workers = [],
+ ?d("init -> done",[]),
+ {ok, {Flags, Workers}}.
+
+
+%%----------------------------------------------------------------------
+%% Function: start_ack_sender/3
+%% Description: Starts a transient worker (child) process
+%%----------------------------------------------------------------------
+
+start_trans_sender(CH, To, ReqsMaxSz, ReqsMax, AcksMax) ->
+ ?d("start_ack_sender -> entry with"
+ "~n CH: ~p"
+ "~n To: ~p"
+ "~n ReqsMaxSz: ~p"
+ "~n ReqsMax: ~p"
+ "~n AxksMax: ~p", [CH, To, ReqsMaxSz, ReqsMax, AcksMax]),
+ M = megaco_trans_sender,
+ F = start_link,
+ A = [CH, To, ReqsMaxSz, ReqsMax, AcksMax],
+ N = {M,CH},
+ Spec = {N,
+ {M,F,A},
+ temporary, timer:seconds(1), worker, [M,gen_server]},
+ case supervisor:start_child(?MODULE, Spec) of
+ {error, already_present} ->
+ supervisor:restart_child(?MODULE, N);
+ Else ->
+ Else
+ end.
+
+
+
+
+
+
diff --git a/lib/megaco/src/engine/megaco_transport.erl b/lib/megaco/src/engine/megaco_transport.erl
new file mode 100644
index 0000000000..79cec8781c
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_transport.erl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Megaco transport behaviour module
+%%----------------------------------------------------------------------
+
+-module(megaco_transport).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{send_message,2}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/megaco/src/engine/megaco_user_default.erl b/lib/megaco/src/engine/megaco_user_default.erl
new file mode 100644
index 0000000000..ff98107d57
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_user_default.erl
@@ -0,0 +1,185 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Default implementation of user callbacks
+%%----------------------------------------------------------------------
+
+-module(megaco_user_default).
+
+-behaviour(megaco_user).
+
+-export([
+ handle_connect/2, handle_connect/3,
+ handle_disconnect/3,
+ handle_syntax_error/3, handle_syntax_error/4,
+ handle_message_error/3, handle_message_error/4,
+ handle_trans_request/3, handle_trans_request/4,
+ handle_trans_long_request/3, handle_trans_long_request/4,
+ handle_trans_reply/4, handle_trans_reply/5,
+ handle_trans_ack/4, handle_trans_ack/5,
+ handle_unexpected_trans/3, handle_unexpected_trans/4,
+ handle_trans_request_abort/4, handle_trans_request_abort/5,
+ handle_segment_reply/5, handle_segment_reply/6
+ ]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a new connection is established
+%%----------------------------------------------------------------------
+
+handle_connect(_ConnHandle, _ProtocolVersion) ->
+ ok.
+
+handle_connect(_ConnHandle, _ProtocolVersion, _ConnectInfo) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a connection is teared down
+%%----------------------------------------------------------------------
+
+handle_disconnect(ConnHandle, _ProtocolVersion, Reason) ->
+ megaco:cancel(ConnHandle, Reason), % Cancel the outstanding messages
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message had syntax errors
+%%----------------------------------------------------------------------
+
+handle_syntax_error(_ReceiveHandle, _ProtocolVersion, _ErrorDescriptor) ->
+ reply.
+
+handle_syntax_error(_ReceiveHandle, _ProtocolVersion, _ErrorDescriptor, _Extra) ->
+ reply.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when a received message contained no transactions
+%%----------------------------------------------------------------------
+
+handle_message_error(_ConnHandle, _ProtocolVersion, _ErrorDescriptor) ->
+ no_reply.
+
+handle_message_error(_ConnHandle, _ProtocolVersion, _ErrorDescriptor, _Extra) ->
+ no_reply.
+
+
+%%----------------------------------------------------------------------
+%% Invoked for each transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra).
+
+handle_trans_request(_ConnHandle, ProtocolVersion, _ActionRequests, _Extra) ->
+ case ProtocolVersion of
+ 1 ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Trans requests not handled"},
+ {discard_ack, ED};
+ _ ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_version_not_supported,
+ errorText = "Only version 1 is supported"},
+ {discard_ack, ED}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a time consuming transaction request
+%%----------------------------------------------------------------------
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Extra).
+
+handle_trans_long_request(_ConnHandle, _ProtocolVersion, _ReqData, _Extra) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long trans requests not handled"},
+ {discard_ack, ED}.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction reply
+%%----------------------------------------------------------------------
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData) ->
+ Extra = ?default_user_callback_extra,
+ handle_trans_reply(ConnHandle, ProtocolVersion,
+ ActualReply, ReplyData, Extra).
+
+handle_trans_reply(ConnHandle, _, {error, {send_message_failed, Reason}}, _, _Extra) ->
+ megaco:disconnect(ConnHandle, {send_message_failed, Reason}),
+ ok;
+handle_trans_reply(_ConnHandle, _ProtocolVersion, _ActualReply, _ReplyData, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Optionally invoked for a transaction acknowledgement
+%%----------------------------------------------------------------------
+
+handle_trans_ack(_ConnHandle, _ProtocolVersion, _AckStatus, _AckData) ->
+ ok.
+
+handle_trans_ack(_ConnHandle, _ProtocolVersion, _AckStatus, _AckData, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an unexpected message has been received
+%%----------------------------------------------------------------------
+
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans) ->
+ ok.
+
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked when an transaction has been aborted
+%% This happens when the originating pending limit has been exceeded
+%%----------------------------------------------------------------------
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid) ->
+ ok.
+
+handle_trans_request_abort(_ConnHandle, _ProtocolVersion, _TransId, _Pid, _Extra) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Invoked a segment reply has been received and the user has set
+%% config option segment_reply_ind = true.
+%%----------------------------------------------------------------------
+
+handle_segment_reply(_ConnHandle, _ProtocolVersion, _TransId, _SN, _SC) ->
+ ok.
+
+handle_segment_reply(_ConnHandle, _ProtocolVersion, _TransId, _SN, _SC, _Extra) ->
+ ok.
+
diff --git a/lib/megaco/src/engine/modules.mk b/lib/megaco/src/engine/modules.mk
new file mode 100644
index 0000000000..44bcadc37b
--- /dev/null
+++ b/lib/megaco/src/engine/modules.mk
@@ -0,0 +1,47 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+BEHAVIOUR_MODULES = \
+ megaco_edist_compress \
+ megaco_encoder \
+ megaco_transport
+
+MODULES = \
+ $(BEHAVIOUR_MODULES) \
+ megaco_config \
+ megaco_digit_map \
+ megaco_erl_dist_encoder \
+ megaco_erl_dist_encoder_mc \
+ megaco_filter \
+ megaco_messenger \
+ megaco_messenger_misc \
+ megaco_misc_sup \
+ megaco_monitor \
+ megaco_sdp \
+ megaco_sup \
+ megaco_stats \
+ megaco_timer \
+ megaco_trans_sender \
+ megaco_trans_sup \
+ megaco_user_default
+
+INTERNAL_HRL_FILES = \
+ megaco_message_internal.hrl
+
+
diff --git a/lib/megaco/src/flex/Makefile b/lib/megaco/src/flex/Makefile
new file mode 100644
index 0000000000..ab8183e548
--- /dev/null
+++ b/lib/megaco/src/flex/Makefile
@@ -0,0 +1,43 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# Invoke with GNU make or clearmake -C gnu.
+#
+
+include $(ERL_TOP)/make/run_make.mk
+include modules.mk
+
+conf:
+ cd ../..; $(MAKE) conf
+
+dconf:
+ $(MAKE) FLEX_SCANNER_REENTRANT=disable conf
+
+econf:
+ $(MAKE) FLEX_SCANNER_REENTRANT=enable conf
+
+setup:
+ (cd ../../priv/lib && \
+ rm -f $(STD_DRV).so $(MT_DRV).so && \
+ ln -s $(TARGET)/$(STD_DRV).so && \
+ ln -s $(TARGET)/$(MT_DRV).so )
+
+info:
+ $(MAKE) -f $(TARGET)/Makefile $@
+
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
new file mode 100644
index 0000000000..782d6a4807
--- /dev/null
+++ b/lib/megaco/src/flex/Makefile.in
@@ -0,0 +1,396 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# The following variables differ on different systems, we set
+# reasonable defaults, if something different is needed it should
+# be set for that system only.
+# ----------------------------------------------------
+
+FLEX_VSN = $(shell flex --version)
+
+TMP_CFLAGS = @DED_CFLAGS@
+ifeq ($(TYPE),valgrind)
+CFLAGS = $(subst -O2, , $(TMP_CFLAGS)) -DVALGRIND
+else
+CFLAGS = $(TMP_CFLAGS)
+endif
+CC = @CC@
+CFLAGS_MT = $(CFLAGS) -D_THREAD_SAFE -D_REENTRANT
+LD = @DED_LD@
+LDFLAGS = @DED_LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+PERL = @PERL@
+ERLANG_OSTYPE = @ERLANG_OSTYPE@
+
+# Shall we build the flex scanner or not.
+# We assume that it does not exist on windows...
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),)
+ifeq ($(findstring win32,$(TARGET)), win32)
+ENABLE_MEGACO_FLEX_SCANNER = false
+ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = false
+else
+ENABLE_MEGACO_FLEX_SCANNER = @ENABLE_MEGACO_FLEX_SCANNER@
+ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = @ENABLE_REENTRANT_MEGACO_FLEX_SCANNER@
+endif
+endif
+ERL_COMPILE_FLAGS += -DENABLE_MEGACO_FLEX_SCANNER=$(ENABLE_MEGACO_FLEX_SCANNER)
+
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+CFLAGS_MT += -DMEGACO_REENTRANT_FLEX_SCANNER
+MT_LEX_FLAGS += -R
+ERL_COMPILE_FLAGS += -DMEGACO_REENTRANT_FLEX_SCANNER=true
+else
+ERL_COMPILE_FLAGS += -DMEGACO_REENTRANT_FLEX_SCANNER=false
+endif
+
+# Shall the library be built with line-number checks or without
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),)
+# This is not really needed in this case (since we don't support
+# this for windows), but just to ensure that the variable _has_
+# a value...
+ifeq ($(findstring win32,$(TARGET)), win32)
+ENABLE_MEGACO_FLEX_SCANNER_LINENO = true
+else
+ENABLE_MEGACO_FLEX_SCANNER_LINENO = @ENABLE_MEGACO_FLEX_SCANNER_LINENO@
+endif
+endif
+
+
+SYSINCLUDE = -I$(ERL_TOP)/erts/emulator/beam \
+ -I$(ERL_TOP)/erts/emulator/sys/$(ERLANG_OSTYPE)
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+ SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks
+endif
+
+DRIVER_INCLUDES = $(SYSINCLUDE)
+
+PRIVDIR = ../../priv
+LIBDIR = $(PRIVDIR)/lib/$(TARGET)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+FLEX_SRC = $(FLEX_MODULES:%=%.flex.src)
+FLEX_FILES = $(STD_DRV).flex $(MT_DRV).flex
+
+C_TARGETS = $(STD_DRV).c $(MT_DRV).c
+
+
+# ----------------------------------------------------
+# Misc Macros
+# ----------------------------------------------------
+
+STD_DRV_NAME=-DMEGACO_DRV_NAME=\"$(STD_DRV)\"
+MT_DRV_NAME=-DMEGACO_DRV_NAME=\"$(MT_DRV)\"
+
+ifeq ($(findstring win32,$(TARGET)), win32)
+FLEX_SCANNER_SO =
+SOLIBS = $(FLEX_SCANNER_SO)
+else
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+FLEX_SCANNER_SO =
+SOLIBS = $(FLEX_SCANNER_SO)
+else
+FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).so
+FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).so
+SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO)
+endif
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+ifeq ($(MFS_DEBUG),true)
+CFLAGS += -DMFS_DEBUG=true
+endif
+
+ifeq ($(MFS_FLEX_PERF),true)
+STD_LEX_FLAGS += -p
+MT_LEX_FLAGS += -p
+endif
+
+ifeq ($(MFS_FLEX_DEBUG),true)
+CFLAGS += -DMFS_FLEX_DEBUG=1
+STD_LEX_FLAGS += -d
+MT_LEX_FLAGS += -d
+else
+CFLAGS += -DMFS_FLEX_DEBUG=0
+endif
+
+CFLAGS += $(DRIVER_INCLUDES) $(DRV_FLAGS) -funroll-loops -Wall
+
+#ifneq ($(FLEX_VSN),)
+#CFLAGS += -DFLEX_VERSION="$(FLEX_VSN)"
+#else
+#CFLAGS += -DFLEX_VERSION=unknown
+#endif
+
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+CFLAGS += -DMEGACO_LINENO
+STD_LEX_FLAGS += -Ca
+MT_LEX_FLAGS += -Ca
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+MT_LEX_FLAGS += --yylineno
+endif
+else
+CFLAGS += -DMEGACO_TOKENCNT
+STD_LEX_FLAGS += -Cfe
+MT_LEX_FLAGS += -Cfe
+endif
+
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
+debug opt: $(TARGET_FILES) $(C_TARGETS) solibs
+else
+debug opt: $(TARGET_FILES)
+endif
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f $(FLEX_FILES)
+ rm -f $(C_TARGETS)
+ rm -f $(SOLIBS)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "ENABLE_MEGACO_FLEX_SCANNER = $(ENABLE_MEGACO_FLEX_SCANNER)"
+ @echo "ENABLE_MEGACO_FLEX_SCANNER_LINENO = $(ENABLE_MEGACO_FLEX_SCANNER_LINENO)"
+ @echo "ENABLE_REENTRANT_MEGACO_FLEX_SCANNER = $(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER)"
+ @echo ""
+ @echo "FLEX_VSN = $(FLEX_VSN)"
+ @echo ""
+ @echo "CFLAGS = $(CFLAGS)"
+ @echo "CFLAGS_MT = $(CFLAGS_MT)"
+ @echo "DRV_FLAGS = $(DRV_FLAGS)"
+ @echo "STD_LEX_FLAGS = $(STD_LEX_FLAGS)"
+ @echo "MT_LEX_FLAGS = $(MT_LEX_FLAGS)"
+ @echo ""
+ @echo "MODULES = $(MODULES)"
+ @echo "ERL_FILES = $(ERL_FILES)"
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "FLEX_MODULES = $(FLEX_MODULES)"
+ @echo "FLEX_SRC = $(FLEX_SRC)"
+ @echo "FLEX_FILES = $(FLEX_FILES)"
+ @echo ""
+ @echo "C_TARGETS = $(C_TARGETS)"
+ @echo ""
+ @echo "LIBDIR = $(LIBDIR)"
+ @echo "LEXLIB = $(LEXLIB)"
+ @echo ""
+ @echo "STD_DRV = $(STD_DRV)"
+ @echo "MT_DRV = $(MT_DRV)"
+ @echo ""
+ @echo "STD_DRV_NAME = $(STD_DRV_NAME)"
+ @echo "MT_DRV_NAME = $(MT_DRV_NAME)"
+ @echo ""
+ @echo "SOLIBS = $(SOLIBS)"
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/flex
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/lib
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/flex
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true)
+ $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex
+ $(INSTALL_DATA) $(SOLIBS) $(RELSYSDIR)/priv/lib
+endif
+
+
+release_docs_spec:
+
+# megaco_flex_scanner_drv.flex: megaco_flex_scanner_drv.flex.src
+# ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+# ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+# @printf "\treentrant [flex] scanner lineno enabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+# < $< > $@
+# else
+# @printf "\tnon-reentrant [flex] scanner lineno enabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+# < $< > $@
+# endif
+# else
+# ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+# @printf "\treentrant [flex] scanner lineno disabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; - REENTRANT SCANNER*\//' \
+# < $< > $@
+# else
+# @printf "\tnon-reentrant [flex] scanner lineno disabled\n"
+# $(PERL) -p -e \
+# 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+# s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+# s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+# s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+# < $< > $@
+# endif
+# endif
+#
+
+$(STD_DRV).flex: megaco_flex_scanner_drv.flex.src
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+ @printf "std [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+else
+ @printf "std [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+ < $< > $@
+endif
+
+$(MT_DRV).flex: megaco_flex_scanner_drv.flex.src
+ifeq ($(ENABLE_MEGACO_FLEX_SCANNER_LINENO),true)
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+ @printf "multi-threaded reentrant [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+else
+ @printf "multi-threaded non-reentrant [flex] scanner - lineno enabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/%option yylineno/ ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; *\//' \
+ < $< > $@
+endif
+else
+ifeq ($(ENABLE_REENTRANT_MEGACO_FLEX_SCANNER),true)
+ @printf "multi-threaded reentrant [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/%option reentrant/ ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/\/* static int yylineno = 1; - REENTRANT SCANNER*\//' \
+ < $< > $@
+else
+ @printf "multi-threaded non-reentrant [flex] scanner - lineno disabled\n"
+ $(PERL) -p -e \
+ 's/%FLEX_VERSION%/$(FLEX_VSN)/ ; \
+ s/%MEGACO_YY_LINENO_OPTION%/\/\* %option yylineno \*\// ; \
+ s/%MEGACO_YY_REENTRANT_OPTION%/\/\* %option reentrant \*\// ; \
+ s/%MEGACO_DUMMY_DECL_YY_LINENO%/static int yylineno = 1;/' \
+ < $< > $@
+endif
+endif
+
+# megaco_flex_scanner_drv.c: megaco_flex_scanner_drv.flex
+# $(LEX) $(LEX_FLAGS) -P$* -o$@ $<
+$(STD_DRV).c: $(STD_DRV).flex
+ $(LEX) $(STD_LEX_FLAGS) -P$* -o$@ $<
+$(MT_DRV).c: $(MT_DRV).flex
+ $(LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
+
+solibs: $(LIBDIR) $(SOLIBS)
+
+# No need to link with -lfl as we have also defined %option noyywrap -
+# and having -lfl doesn't work under Darwin for some reason. - Sean
+$(LIBDIR)/$(STD_DRV).so: $(STD_DRV).c
+ @echo "std driver:"
+ $(CC) $(STD_DRV_NAME) $(CFLAGS) $(LDFLAGS) -o $(LIBDIR)/$(STD_DRV).so $<
+
+$(LIBDIR)/$(MT_DRV).so: $(MT_DRV).c
+ @echo "multi-threaded driver:"
+ $(CC) $(MT_DRV_NAME) $(CFLAGS_MT) $(LDFLAGS) -o $(LIBDIR)/$(MT_DRV).so $<
+
+$(LIBDIR):
+ -mkdir -p $(LIBDIR)
+
diff --git a/lib/megaco/src/flex/megaco_flex_scanner.erl b/lib/megaco/src/flex/megaco_flex_scanner.erl
new file mode 100644
index 0000000000..e471412c13
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner.erl
@@ -0,0 +1,230 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose : Scanner for text encoded Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_scanner).
+
+-export([is_enabled/0, is_reentrant_enabled/0, is_scanner_port/2]).
+-export([start/0, start/1, stop/1, scan/2]).
+
+-define(NUM_SCHED(), erlang:system_info(schedulers)).
+-define(SCHED_ID(), erlang:system_info(scheduler_id)).
+-define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)).
+
+is_enabled() ->
+ case ?ENABLE_MEGACO_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_reentrant_enabled() ->
+ case ?MEGACO_REENTRANT_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_scanner_port(Port, Port) when is_port(Port) ->
+ true;
+is_scanner_port(Port, Ports) when is_tuple(Ports) ->
+ is_own_port(Port, Ports);
+is_scanner_port(_, _) ->
+ false.
+
+is_own_port(Port, Ports) ->
+ is_own_port(Port, size(Ports), Ports).
+
+is_own_port(_Port, 0, _Ports) ->
+ false;
+is_own_port(Port, N, Ports) when (N > 0) ->
+ case element(N, Ports) of
+ Port ->
+ true;
+ _ ->
+ is_own_port(Port, N-1, Ports)
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Start the flex scanner
+%%----------------------------------------------------------------------
+
+start() ->
+ start(?SMP_SUPPORT_DEFAULT()).
+
+start(SMP) when ((SMP =:= true) orelse (SMP =:= false)) ->
+ (catch do_start(is_reentrant_enabled() andalso SMP)).
+
+do_start(SMP) ->
+ Path = lib_dir(),
+ erl_ddll:start(),
+ load_driver(Path),
+ PortOrPorts = open_drv_port(SMP),
+ {ok, PortOrPorts}.
+
+
+lib_dir() ->
+ case code:priv_dir(megaco) of
+ {error, Reason} ->
+ throw({error, {priv_dir, Reason}});
+ P when is_list(P) ->
+ P ++ "/lib"
+ end.
+
+
+load_driver(Path) ->
+ case erl_ddll:load_driver(Path, drv_name()) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ case (catch erl_ddll:format_error(Reason)) of
+ FormatReason when is_list(FormatReason) ->
+ throw({error, {load_driver, FormatReason}});
+ _ ->
+ throw({error, {load_driver, Reason}})
+ end
+ end.
+
+
+open_drv_port(true) ->
+ open_drv_ports(?NUM_SCHED(), []);
+open_drv_port(_) ->
+ open_drv_port().
+
+open_drv_ports(0, Acc) ->
+ list_to_tuple(Acc);
+open_drv_ports(N, Acc) when is_integer(N) andalso (N > 0) ->
+ Port = open_drv_port(),
+ open_drv_ports(N-1, [Port | Acc]).
+
+open_drv_port() ->
+ case (catch erlang:open_port({spawn, drv_name()}, [binary])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', Reason} ->
+ erl_ddll:unload_driver(drv_name()),
+ throw({error, {open_port, Reason}})
+ end.
+
+drv_name() ->
+ case erlang:system_info(threads) of
+ true ->
+ "megaco_flex_scanner_drv_mt";
+ false ->
+ "megaco_flex_scanner_drv"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Stop the flex scanner
+%%----------------------------------------------------------------------
+
+stop(Port) when is_port(Port) ->
+ erlang:port_close(Port),
+ erl_ddll:unload_driver(drv_name()),
+ stopped;
+stop(Ports) when is_tuple(Ports) ->
+ stop(tuple_to_list(Ports));
+stop(Ports) when is_list(Ports) ->
+ lists:foreach(fun(Port) -> erlang:port_close(Port) end, Ports),
+ erl_ddll:unload_driver(drv_name()),
+ stopped.
+
+
+%%----------------------------------------------------------------------
+%% Scan a message
+%%----------------------------------------------------------------------
+
+scan(Binary, Port) when is_port(Port) ->
+ do_scan(Binary, Port);
+scan(Binary, Ports) when is_tuple(Ports) ->
+%% p("scan -> entry with"
+%% "~n Ports: ~p", [Ports]),
+ do_scan(Binary, select_port(Ports)).
+
+do_scan(Binary, Port) ->
+%% p("do_scan -> entry with"
+%% "~n Port: ~p", [Port]),
+ case erlang:port_control(Port, $s, Binary) of
+ [] ->
+ receive
+ {tokens, Tokens, LatestLine} ->
+%% p("do_scan -> OK with:"
+%% "~n length(Tokens): ~p"
+%% "~n LatestLine: ~p", [length(Tokens), LatestLine]),
+ Vsn = version(Tokens),
+ {ok, Tokens, Vsn, LatestLine}
+ after 5000 ->
+%% p("do_scan -> ERROR", []),
+ {error, "Driver term send failure", 1}
+ end;
+ Reason ->
+%% p("do_scan -> port control failed: "
+%% "~n Reason: ~p", [Reason]),
+ {error, Reason, 1}
+ end.
+
+select_port(Ports) ->
+ SchedId = ?SCHED_ID(),
+ %% lists:nth(SchedId, Ports).
+ element(SchedId, Ports).
+
+version([]) ->
+ 99; % Let the parser deal with this
+version([{'SafeChars',_,"!/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"megaco/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"!/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"megaco/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"!/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,"megaco/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,[$!, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([{'SafeChars',_,[$m, $e, $g, $a, $c, $o, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([_|T]) ->
+ version(T).
+
+
+guess_version([C]) when (48 =< C) and (C =< 57) ->
+ C-48;
+guess_version(Str) when is_list(Str) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ 99 % Let the parser deal with this
+ end;
+guess_version(_) ->
+ 99. % Let the parser deal with this
+
+
+%% p(F, A) ->
+%% io:format("~w [~p,~p] " ++ F ++ "~n", [?MODULE, self(), ?SCHED_ID() | A]).
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
new file mode 100644
index 0000000000..b96a69415d
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
@@ -0,0 +1,1943 @@
+ /*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+ * ----------------------------------------------------------------------
+ * Purpose : Scanner for text encoded Megaco/H.248 messages
+ * ----------------------------------------------------------------------
+ *
+ * Throughout this file the prefix mfs is used for megaco_flex_scanner.
+ * The reason is to get shorter function and variable names.
+ */
+
+%option case-insensitive
+
+ /* MEGACO_YY_LINENO_OPTION
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_DUMMY_DECL_YY_LINENO and
+ * MEGACO_LINENO_OR_TOKENCOUNTER below.
+ */
+%MEGACO_YY_LINENO_OPTION%
+
+%MEGACO_YY_REENTRANT_OPTION%
+%option noyywrap
+%option noinput
+%option nounput
+%{
+
+#define HAVE_UIO_H
+#include "erl_driver.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define TRUE 1
+#define FALSE 0
+#define SP 0x20
+#define HTAB 0x09
+#define CR 0x0d
+#define LF 0x0a
+#define SEMI_COLON 0x3b
+#define BACKSLASH 0x5c
+#define RBRKT 0x7b
+#define NUL 0x0
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ #define MEGACO_EXTENDED_MARKER ERL_DRV_EXTENDED_MARKER
+ #define MEGACO_DRIVER_FLAGS ERL_DRV_FLAG_USE_PORT_LOCKING
+ #define MEGACO_EXTENDED_MAJOR_VERSION ERL_DRV_EXTENDED_MAJOR_VERSION
+ #define MEGACO_EXTENDED_MINOR_VERSION ERL_DRV_EXTENDED_MINOR_VERSION
+#else
+ #define MEGACO_EXTENDED_MARKER 0
+ #define MEGACO_DRIVER_FLAGS 0
+ #define MEGACO_EXTENDED_MAJOR_VERSION 0
+ #define MEGACO_EXTENDED_MINOR_VERSION 0
+#endif
+
+
+#define FREE(bufP) driver_free(bufP)
+#define ALLOC(sz) driver_alloc(sz)
+#define REALLOC(bufP, sz) driver_realloc(bufP, sz)
+
+#define YY_MAIN false
+
+// #define YY_FATAL_ERROR(msg) mfs_fatal_error(msg)
+
+
+typedef struct {
+ ErlDrvPort port;
+ char* digit_map_name_ptr;
+ int digit_map_name_len;
+ char* digit_map_value_ptr;
+ int digit_map_value_len;
+ char* digit_map_start_ptr;
+ char* digit_map_short_ptr;
+ char* digit_map_long_ptr;
+ char* digit_map_duration_ptr;
+ int error;
+ char error_msg[512];
+ char* text_buf;
+ char* text_ptr;
+ ErlDrvTermData* term_spec;
+ int term_spec_size;
+ int term_spec_index;
+ int token_counter;
+} MfsErlDrvData;
+
+#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static MfsErlDrvData mfs_drv_data;
+#endif
+
+char flex_version[] = "%FLEX_VERSION%";
+
+static ErlDrvTermData mfs_AddToken = 0;
+static ErlDrvTermData mfs_AndAUDITSelectToken = 0; /* v3 */
+static ErlDrvTermData mfs_AuditCapToken = 0;
+static ErlDrvTermData mfs_AuditToken = 0;
+static ErlDrvTermData mfs_AuditValueToken = 0;
+static ErlDrvTermData mfs_AuthToken = 0;
+static ErlDrvTermData mfs_BothToken = 0; /* v3 */
+static ErlDrvTermData mfs_BothwayToken = 0;
+static ErlDrvTermData mfs_BriefToken = 0;
+static ErlDrvTermData mfs_BufferToken = 0;
+static ErlDrvTermData mfs_COLON = 0;
+static ErlDrvTermData mfs_COMMA = 0;
+static ErlDrvTermData mfs_ContextAttrToken = 0; /* v3 */
+static ErlDrvTermData mfs_ContextAuditToken = 0;
+static ErlDrvTermData mfs_ContextListToken = 0; /* v3 */
+static ErlDrvTermData mfs_CtxToken = 0;
+static ErlDrvTermData mfs_DelayToken = 0;
+static ErlDrvTermData mfs_DeleteToken = 0;
+static ErlDrvTermData mfs_DigitMapDescriptor = 0;
+static ErlDrvTermData mfs_DigitMapDescriptorToken = 0;
+static ErlDrvTermData mfs_DigitMapToken = 0;
+static ErlDrvTermData mfs_DigitMapValue = 0;
+static ErlDrvTermData mfs_DirectionToken = 0; /* v3 */
+static ErlDrvTermData mfs_DiscardToken = 0;
+static ErlDrvTermData mfs_DisconnectedToken = 0;
+static ErlDrvTermData mfs_DurationToken = 0;
+static ErlDrvTermData mfs_EQUAL = 0;
+static ErlDrvTermData mfs_EmbedToken = 0;
+static ErlDrvTermData mfs_EmergencyToken = 0;
+static ErlDrvTermData mfs_EmergencyOffToken = 0; /* v3 */
+static ErlDrvTermData mfs_EmergencyValueToken = 0; /* v3 */
+static ErlDrvTermData mfs_ErrorToken = 0;
+static ErlDrvTermData mfs_EventBufferToken = 0;
+static ErlDrvTermData mfs_EventsToken = 0;
+static ErlDrvTermData mfs_ExternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_FailoverToken = 0;
+static ErlDrvTermData mfs_ForcedToken = 0;
+static ErlDrvTermData mfs_GREATER = 0;
+static ErlDrvTermData mfs_GracefulToken = 0;
+static ErlDrvTermData mfs_H221Token = 0;
+static ErlDrvTermData mfs_H223Token = 0;
+static ErlDrvTermData mfs_H226Token = 0;
+static ErlDrvTermData mfs_HandOffToken = 0;
+static ErlDrvTermData mfs_IEPSToken = 0; /* v3 */
+static ErlDrvTermData mfs_IllegalChar = 0;
+static ErlDrvTermData mfs_ImmAckRequiredToken = 0;
+static ErlDrvTermData mfs_InactiveToken = 0;
+static ErlDrvTermData mfs_InSvcToken = 0;
+static ErlDrvTermData mfs_IntsigDelayToken = 0; /* v3 */
+static ErlDrvTermData mfs_InternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_InterruptByEventToken = 0;
+static ErlDrvTermData mfs_InterruptByNewSignalsDescrToken = 0;
+static ErlDrvTermData mfs_IsolateToken = 0;
+static ErlDrvTermData mfs_IterationToken = 0; /* v3 */
+static ErlDrvTermData mfs_KeepActiveToken = 0;
+static ErlDrvTermData mfs_LBRKT = 0;
+static ErlDrvTermData mfs_LESSER = 0;
+static ErlDrvTermData mfs_LSBRKT = 0;
+static ErlDrvTermData mfs_LocalControlToken = 0;
+static ErlDrvTermData mfs_LocalDescriptorToken = 0;
+static ErlDrvTermData mfs_LocalToken = 0;
+static ErlDrvTermData mfs_LockStepToken = 0;
+static ErlDrvTermData mfs_LoopbackToken = 0;
+static ErlDrvTermData mfs_MediaToken = 0;
+static ErlDrvTermData mfs_MegacopToken = 0;
+static ErlDrvTermData mfs_MethodToken = 0;
+static ErlDrvTermData mfs_MessageSegmentToken = 0;
+static ErlDrvTermData mfs_MgcIdToken = 0;
+static ErlDrvTermData mfs_ModeToken = 0;
+static ErlDrvTermData mfs_ModemToken = 0;
+static ErlDrvTermData mfs_ModifyToken = 0;
+static ErlDrvTermData mfs_MoveToken = 0;
+static ErlDrvTermData mfs_MtpAddressToken = 0;
+static ErlDrvTermData mfs_MuxToken = 0;
+static ErlDrvTermData mfs_NEQUAL = 0;
+static ErlDrvTermData mfs_NeverNotifyToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyCompletionToken = 0;
+static ErlDrvTermData mfs_NotifyImmediateToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyRegulatedToken = 0; /* v3 */
+static ErlDrvTermData mfs_NotifyToken = 0;
+static ErlDrvTermData mfs_Nx64kToken = 0;
+static ErlDrvTermData mfs_ObservedEventsToken = 0;
+static ErlDrvTermData mfs_OffToken = 0;
+static ErlDrvTermData mfs_OnOffToken = 0;
+static ErlDrvTermData mfs_OnToken = 0;
+static ErlDrvTermData mfs_OnewayToken = 0;
+static ErlDrvTermData mfs_OnewayBothToken = 0; /* v3 */
+static ErlDrvTermData mfs_OnewayExternalToken = 0; /* v3 */
+static ErlDrvTermData mfs_OrAUDITselectToken = 0; /* v3 */
+static ErlDrvTermData mfs_OtherReasonToken = 0;
+static ErlDrvTermData mfs_OutOfSvcToken = 0;
+static ErlDrvTermData mfs_PackagesToken = 0;
+static ErlDrvTermData mfs_PendingToken = 0;
+static ErlDrvTermData mfs_PriorityToken = 0;
+static ErlDrvTermData mfs_ProfileToken = 0;
+static ErlDrvTermData mfs_QuotedChars = 0;
+static ErlDrvTermData mfs_RBRKT = 0;
+static ErlDrvTermData mfs_RSBRKT = 0;
+static ErlDrvTermData mfs_ReasonToken = 0;
+static ErlDrvTermData mfs_RecvonlyToken = 0;
+static ErlDrvTermData mfs_RemoteDescriptorToken = 0;
+static ErlDrvTermData mfs_RemoteToken = 0;
+static ErlDrvTermData mfs_RequestIDToken = 0; /* v3 */
+static ErlDrvTermData mfs_ReplyToken = 0;
+static ErlDrvTermData mfs_ReservedGroupToken = 0;
+static ErlDrvTermData mfs_ReservedValueToken = 0;
+static ErlDrvTermData mfs_ResetEventsDescriptorToken = 0; /* v3 */
+static ErlDrvTermData mfs_ResponseAckToken = 0;
+static ErlDrvTermData mfs_RestartToken = 0;
+static ErlDrvTermData mfs_SEP = 0;
+static ErlDrvTermData mfs_SafeChars = 0;
+static ErlDrvTermData mfs_SegmentationCompleteToken = 0; /* v3 */
+static ErlDrvTermData mfs_SendonlyToken = 0;
+static ErlDrvTermData mfs_SendrecvToken = 0;
+static ErlDrvTermData mfs_ServiceChangeAddressToken = 0;
+static ErlDrvTermData mfs_ServiceChangeIncompleteToken = 0; /* v3 */
+static ErlDrvTermData mfs_ServiceChangeToken = 0;
+static ErlDrvTermData mfs_ServiceStatesToken = 0;
+static ErlDrvTermData mfs_ServicesToken = 0;
+static ErlDrvTermData mfs_SignalListToken = 0;
+static ErlDrvTermData mfs_SignalTypeToken = 0;
+static ErlDrvTermData mfs_SignalsToken = 0;
+static ErlDrvTermData mfs_StatsToken = 0;
+static ErlDrvTermData mfs_StreamToken = 0;
+static ErlDrvTermData mfs_SubtractToken = 0;
+static ErlDrvTermData mfs_SynchISDNToken = 0;
+static ErlDrvTermData mfs_TerminationStateToken = 0;
+static ErlDrvTermData mfs_TestToken = 0;
+static ErlDrvTermData mfs_TimeOutToken = 0;
+static ErlDrvTermData mfs_TimeStampToken = 0; /* OTP-5042 */
+static ErlDrvTermData mfs_TopologyToken = 0;
+static ErlDrvTermData mfs_TransToken = 0;
+static ErlDrvTermData mfs_V18Token = 0;
+static ErlDrvTermData mfs_V22Token = 0;
+static ErlDrvTermData mfs_V22bisToken = 0;
+static ErlDrvTermData mfs_V32Token = 0;
+static ErlDrvTermData mfs_V32bisToken = 0;
+static ErlDrvTermData mfs_V34Token = 0;
+static ErlDrvTermData mfs_V76Token = 0;
+static ErlDrvTermData mfs_V90Token = 0;
+static ErlDrvTermData mfs_V91Token = 0;
+static ErlDrvTermData mfs_VersionToken = 0;
+static ErlDrvTermData mfs_asn1_NOVALUE = 0;
+static ErlDrvTermData mfs_endOfMessage = 0;
+static ErlDrvTermData mfs_PropertyParm = 0;
+static ErlDrvTermData mfs_ErrorDescriptor = 0;
+
+/* MEGACO_DUMMY_DECL_YY_LINENO
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_YY_LINENO_OPTION above and
+ * MEGACO_LINENO_OR_TOKENCOUNTER below.
+ */
+#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
+%MEGACO_DUMMY_DECL_YY_LINENO%
+#endif
+
+/*
+static ErlDrvPort mfs_port = 0;
+static char* mfs_digit_map_name_ptr = 0;
+static int mfs_digit_map_name_len = 0;
+static char* mfs_digit_map_value_ptr = 0;
+static int mfs_digit_map_value_len = 0;
+static char* mfs_digit_map_start_ptr = 0;
+static char* mfs_digit_map_short_ptr = 0;
+static char* mfs_digit_map_long_ptr = 0;
+static char* mfs_digit_map_duration_ptr = 0;
+static int mfs_error = FALSE;
+static char mfs_error_msg[512];
+static char* mfs_text_buf = 0;
+static char* mfs_text_ptr = 0;
+static ErlDrvTermData* mfs_term_spec = 0;
+static int mfs_term_spec_size = 0;
+static int mfs_term_spec_index = 0;
+static int mfs_token_counter = 0;
+*/
+
+
+static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz);
+static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg);
+static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+static void mfs_short_load_token(ErlDrvTermData token_tag,
+ yyscan_t yyscanner);
+static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty,
+ yyscan_t yyscanner);
+static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty,
+ yyscan_t yyscanner);
+static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner);
+static void mfs_load_map_name(yyscan_t yyscanner);
+static void mfs_load_map_value(yyscan_t yyscanner);
+static void mfs_load_map_timer(yyscan_t yyscanner);
+static void mfs_load_map_token(yyscan_t yyscanner);
+
+#else
+
+static void mfs_short_load_token(ErlDrvTermData token_tag);
+static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty);
+static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty);
+static void mfs_load_property_groups(MfsErlDrvData* dataP);
+static void mfs_load_map_name();
+static void mfs_load_map_value();
+static void mfs_load_map_timer();
+static void mfs_load_map_token();
+
+#endif
+
+static ErlDrvData mfs_start(ErlDrvPort port, char *buf);
+static void mfs_stop(ErlDrvData handle);
+static void mfs_command(ErlDrvData handle,
+ char *buf, int buf_len);
+static int mfs_control(ErlDrvData handle,
+ unsigned int command,
+ char *buf, int buf_len,
+ char **res_buf, int res_buf_len);
+static void mfs_finish(void);
+
+/*
+ * The driver entry
+ */
+
+static ErlDrvEntry mfs_entry = {
+ NULL, /* init, always NULL for dynamic drivers */
+ mfs_start, /* start, called when port is opened */
+ mfs_stop, /* stop, called when port is closed */
+ mfs_command, /* output, called when erlang has sent */
+ NULL, /* ready_input, called when input descriptor ready */
+ NULL, /* ready_output, called when output descriptor ready */
+ MEGACO_DRV_NAME, /* char *driver_name, the arg to open_port */
+ mfs_finish, /* finish, called when unloaded */
+ NULL, /* void * that is not used (BC) */
+ mfs_control, /* control, port_control callback */
+ NULL, /* timeout, called on timeouts */
+ NULL, /* outputv, vector output interface */
+ NULL, /* ready_async, called after an asynchronous call has completed */
+ NULL, /* flush, port is about to be closed */
+ NULL, /* call, a syncronous call into the driver */
+ NULL, /* event, event selected by driver_event() has occurred */
+ MEGACO_EXTENDED_MARKER, /* extended_marker, which we use if reentrant */
+ MEGACO_EXTENDED_MAJOR_VERSION, /* major_version, ... */
+ MEGACO_EXTENDED_MINOR_VERSION, /* minor_version, ... */
+ MEGACO_DRIVER_FLAGS, /* driver_flags, used for port lock indication */
+ NULL, /* handle2, emulator internal use */
+ NULL /* process_exit, Called when a process monitor fires */
+#if defined(MEGACO_DRV_ENTRY_HAS_STOP_SELECT)
+ ,NULL /* stop_select, Called to close an event object */
+#endif
+};
+
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+#define LOAD_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, FALSE, yyscanner)
+#define LOAD_EMPTY_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, TRUE, yyscanner)
+#define LOAD_SHORT_TOKEN(TokenTag) mfs_short_load_token(TokenTag, yyscanner)
+#define LOAD_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, FALSE, yyscanner)
+#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE, yyscanner)
+#define LOAD_MAP_NAME() mfs_load_map_name(yyscanner)
+#define LOAD_MAP_TIMER() mfs_load_map_timer(yyscanner)
+#define LOAD_MAP_TOKEN() mfs_load_map_token(yyscanner)
+#define LOAD_MAP_VALUE() mfs_load_map_value(yyscanner)
+#define LOAD_PROP_GRPS(dataP) mfs_load_property_groups(dataP, yyscanner)
+
+#else
+
+#define LOAD_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, FALSE)
+#define LOAD_EMPTY_TOKEN(TokenTag) mfs_lower_load_token(TokenTag, TRUE)
+#define LOAD_SHORT_TOKEN(TokenTag) mfs_short_load_token(TokenTag)
+#define LOAD_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, FALSE)
+#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE)
+#define LOAD_MAP_NAME() mfs_load_map_name()
+#define LOAD_MAP_TIMER() mfs_load_map_timer()
+#define LOAD_MAP_TOKEN() mfs_load_map_token()
+#define LOAD_MAP_VALUE() mfs_load_map_value()
+#define LOAD_PROP_GRPS(dataP) mfs_load_property_groups(dataP)
+
+#endif
+
+/* OTP-4236 */
+#define ASSIGN_TERM_SPEC(dataP, what) \
+{ \
+ if (dataP->term_spec != NULL) { \
+ dataP->term_spec[dataP->term_spec_index++] = what; \
+ } \
+}
+
+%}
+
+%x SKIP_RBRKT MTP_HEXDIG LOCAL_OCTETS REMOTE_OCTETS
+%x MAP_NAME MAP_OPT_LBRKT MAP_VALUE MAP_SKIP_COMMA MAP_BODY
+%x QUOTED_CHARS SKIP_DQUOTE
+
+digit ([0-9])
+alpha ([a-zA-Z])
+hexdig ([0-9a-fA-F])
+sp (\x20)
+htab (\x09)
+cr (\x0D)
+lf (\x0A)
+slash (\/)
+dquote (\")
+colon (\:)
+dot (\.)
+wsp ({sp}|{htab})
+eol ({cr}|({cr}{lf})|{lf})
+safechar ({digit}|{alpha}|[\+\-\&\!\_\/\'\?\@\^\`\~\*\$\\\(\)\%\|\.])
+restchar ([\;\[\]\{\}\:\,\#\<\>\=])
+octet ((\\\})|[\x01-\x7C\x7E-\xFF])
+
+comment (\;({safechar}|{restchar}|{wsp}|\x22)*{eol})
+lwsp ({wsp}|{comment}|{eol})*
+
+equal ({lwsp}\={lwsp})
+nequal ({lwsp}\#{lwsp})
+lesser ({lwsp}\<{lwsp})
+greater ({lwsp}\>{lwsp})
+lbrkt ({lwsp}\{{lwsp})
+rbrkt ({lwsp}\}{lwsp})
+lsbrkt ({lwsp}\[{lwsp})
+rsbrkt ({lwsp}\]{lwsp})
+lpar ({lwsp}\({lwsp})
+rpar ({lwsp}\){lwsp})
+vbar ({lwsp}\|{lwsp})
+comma ({lwsp}\,{lwsp})
+sep (({wsp}|{eol}|{comment}){lwsp})+
+opt ((o\-)?)
+wild ((w\-)?)
+
+%%
+
+<SKIP_RBRKT>{rbrkt} BEGIN(INITIAL);
+
+{digit}{8,8}t{digit}{8,8} LOAD_TOKEN(mfs_TimeStampToken); /* OTP-5042 */
+
+(MTP){lbrkt} BEGIN(MTP_HEXDIG);
+<MTP_HEXDIG>{hexdig}{4,8} {LOAD_TOKEN(mfs_MtpAddressToken); BEGIN(SKIP_RBRKT);}
+
+((Local)|L){lbrkt} BEGIN(LOCAL_OCTETS);
+<LOCAL_OCTETS>{rbrkt} {LOAD_EMPTY_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(INITIAL);}
+<LOCAL_OCTETS>{octet}+ {LOAD_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(SKIP_RBRKT);}
+
+((Remote)|R){lbrkt} BEGIN(REMOTE_OCTETS);
+<REMOTE_OCTETS>{rbrkt} {LOAD_EMPTY_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(INITIAL);}
+<REMOTE_OCTETS>{octet}+ {LOAD_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(SKIP_RBRKT);}
+
+((DigitMap)|DM) LOAD_TOKEN(mfs_DigitMapToken);
+((DigitMap)|DM){equal} BEGIN(MAP_NAME);
+((DigitMap)|DM){equal}{lbrkt} BEGIN(MAP_VALUE);
+((DigitMap)|DM){lbrkt} BEGIN(MAP_VALUE);
+
+<MAP_NAME>{safechar}+ {LOAD_MAP_NAME(); BEGIN(MAP_OPT_LBRKT);}
+
+<MAP_OPT_LBRKT>{lbrkt} BEGIN(MAP_VALUE);
+<MAP_OPT_LBRKT><<EOF>> {LOAD_MAP_TOKEN(); LOAD_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
+<MAP_OPT_LBRKT>.|\n {LOAD_MAP_TOKEN(); yyless(0); BEGIN(INITIAL);}
+
+<MAP_VALUE>t{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>s{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>l{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>z{colon}{digit}{1,2} {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
+<MAP_VALUE>.|\n {yyless(0); BEGIN(MAP_BODY);}
+
+<MAP_SKIP_COMMA>{comma} BEGIN(MAP_VALUE);
+
+<MAP_BODY>{octet}+ {LOAD_MAP_VALUE(); LOAD_MAP_TOKEN(); BEGIN(SKIP_RBRKT);}
+
+{equal} LOAD_SHORT_TOKEN(mfs_EQUAL);
+{colon} LOAD_SHORT_TOKEN(mfs_COLON);
+{lbrkt} LOAD_SHORT_TOKEN(mfs_LBRKT);
+{rbrkt} LOAD_SHORT_TOKEN(mfs_RBRKT);
+{lsbrkt} LOAD_SHORT_TOKEN(mfs_LSBRKT);
+{rsbrkt} LOAD_SHORT_TOKEN(mfs_RSBRKT);
+{comma} LOAD_SHORT_TOKEN(mfs_COMMA);
+{nequal} LOAD_SHORT_TOKEN(mfs_NEQUAL);
+{lesser} LOAD_SHORT_TOKEN(mfs_LESSER);
+{greater} LOAD_SHORT_TOKEN(mfs_GREATER);
+{sep} LOAD_SHORT_TOKEN(mfs_SEP);
+
+{dquote} BEGIN(QUOTED_CHARS);
+
+<QUOTED_CHARS>{dquote} {LOAD_EMPTY_TOKEN(mfs_QuotedChars); BEGIN(INITIAL);}
+<QUOTED_CHARS>({safechar}|{restchar}|{wsp})+ {LOAD_TOKEN(mfs_QuotedChars); BEGIN(SKIP_DQUOTE);}
+
+<SKIP_DQUOTE>{dquote} BEGIN(INITIAL);
+
+{opt}{wild}add LOAD_TOKEN(mfs_AddToken);
+{opt}{wild}a LOAD_TOKEN(mfs_AddToken);
+andlgc LOAD_TOKEN(mfs_AndAUDITSelectToken);
+audit LOAD_TOKEN(mfs_AuditToken);
+at LOAD_TOKEN(mfs_AuditToken);
+{opt}{wild}auditcapability LOAD_TOKEN(mfs_AuditCapToken);
+{opt}{wild}ac LOAD_TOKEN(mfs_AuditCapToken);
+{opt}{wild}auditvalue LOAD_TOKEN(mfs_AuditValueToken);
+{opt}{wild}av LOAD_TOKEN(mfs_AuditValueToken);
+authentication LOAD_TOKEN(mfs_AuthToken);
+au LOAD_TOKEN(mfs_AuthToken);
+both LOAD_TOKEN(mfs_BothToken);
+b LOAD_TOKEN(mfs_BothToken);
+bothway LOAD_TOKEN(mfs_BothwayToken);
+bw LOAD_TOKEN(mfs_BothwayToken);
+brief LOAD_TOKEN(mfs_BriefToken);
+br LOAD_TOKEN(mfs_BriefToken);
+buffer LOAD_TOKEN(mfs_BufferToken);
+bf LOAD_TOKEN(mfs_BufferToken);
+context LOAD_TOKEN(mfs_CtxToken);
+c LOAD_TOKEN(mfs_CtxToken);
+contextattr LOAD_TOKEN(mfs_ContextAttrToken);
+ct LOAD_TOKEN(mfs_ContextAttrToken);
+contextaudit LOAD_TOKEN(mfs_ContextAuditToken);
+ca LOAD_TOKEN(mfs_ContextAuditToken);
+contextlist LOAD_TOKEN(mfs_ContextListToken);
+clt LOAD_TOKEN(mfs_ContextListToken);
+spadirection LOAD_TOKEN(mfs_DirectionToken);
+direction LOAD_TOKEN(mfs_DirectionToken);
+spadi LOAD_TOKEN(mfs_DirectionToken);
+di LOAD_TOKEN(mfs_DirectionToken);
+discard LOAD_TOKEN(mfs_DiscardToken);
+ds LOAD_TOKEN(mfs_DiscardToken);
+disconnected LOAD_TOKEN(mfs_DisconnectedToken);
+dc LOAD_TOKEN(mfs_DisconnectedToken);
+delay LOAD_TOKEN(mfs_DelayToken);
+dl LOAD_TOKEN(mfs_DelayToken);
+delete LOAD_TOKEN(mfs_DeleteToken);
+de LOAD_TOKEN(mfs_DeleteToken);
+duration LOAD_TOKEN(mfs_DurationToken);
+dr LOAD_TOKEN(mfs_DurationToken);
+embed LOAD_TOKEN(mfs_EmbedToken);
+em LOAD_TOKEN(mfs_EmbedToken);
+emergency LOAD_TOKEN(mfs_EmergencyToken);
+eg LOAD_TOKEN(mfs_EmergencyToken);
+emergencyoff LOAD_TOKEN(mfs_EmergencyOffToken);
+emergencyofftoken LOAD_TOKEN(mfs_EmergencyOffToken);
+ego LOAD_TOKEN(mfs_EmergencyOffToken);
+emergencyvalue LOAD_TOKEN(mfs_EmergencyValueToken);
+egv LOAD_TOKEN(mfs_EmergencyValueToken);
+error LOAD_TOKEN(mfs_ErrorToken);
+er LOAD_TOKEN(mfs_ErrorToken);
+eventbuffer LOAD_TOKEN(mfs_EventBufferToken);
+eb LOAD_TOKEN(mfs_EventBufferToken);
+events LOAD_TOKEN(mfs_EventsToken);
+e LOAD_TOKEN(mfs_EventsToken);
+external LOAD_TOKEN(mfs_ExternalToken);
+ex LOAD_TOKEN(mfs_ExternalToken);
+failover LOAD_TOKEN(mfs_FailoverToken);
+fl LOAD_TOKEN(mfs_FailoverToken);
+forced LOAD_TOKEN(mfs_ForcedToken);
+fo LOAD_TOKEN(mfs_ForcedToken);
+graceful LOAD_TOKEN(mfs_GracefulToken);
+gr LOAD_TOKEN(mfs_GracefulToken);
+h221 LOAD_TOKEN(mfs_H221Token);
+h223 LOAD_TOKEN(mfs_H223Token);
+h226 LOAD_TOKEN(mfs_H226Token);
+handoff LOAD_TOKEN(mfs_HandOffToken);
+ho LOAD_TOKEN(mfs_HandOffToken);
+iepscall LOAD_TOKEN(mfs_IEPSToken);
+ieps LOAD_TOKEN(mfs_IEPSToken);
+inactive LOAD_TOKEN(mfs_InactiveToken);
+in LOAD_TOKEN(mfs_InactiveToken);
+immackrequired LOAD_TOKEN(mfs_ImmAckRequiredToken);
+ia LOAD_TOKEN(mfs_ImmAckRequiredToken);
+inservice LOAD_TOKEN(mfs_InSvcToken);
+iv LOAD_TOKEN(mfs_InSvcToken);
+internal LOAD_TOKEN(mfs_InternalToken);
+it LOAD_TOKEN(mfs_InternalToken);
+intersignal LOAD_TOKEN(mfs_IntsigDelayToken);
+spais LOAD_TOKEN(mfs_IntsigDelayToken);
+isolate LOAD_TOKEN(mfs_IsolateToken);
+is LOAD_TOKEN(mfs_IsolateToken);
+intbyevent LOAD_TOKEN(mfs_InterruptByEventToken);
+ibe LOAD_TOKEN(mfs_InterruptByEventToken);
+intbysigdescr LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
+ibs LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
+iteration LOAD_TOKEN(mfs_IterationToken);
+ir LOAD_TOKEN(mfs_IterationToken);
+keepactive LOAD_TOKEN(mfs_KeepActiveToken);
+ka LOAD_TOKEN(mfs_KeepActiveToken);
+local LOAD_TOKEN(mfs_LocalToken);
+l LOAD_TOKEN(mfs_LocalToken);
+localcontrol LOAD_TOKEN(mfs_LocalControlToken);
+lockstep LOAD_TOKEN(mfs_LockStepToken);
+sp LOAD_TOKEN(mfs_LockStepToken);
+o LOAD_TOKEN(mfs_LocalControlToken);
+loopback LOAD_TOKEN(mfs_LoopbackToken);
+lb LOAD_TOKEN(mfs_LoopbackToken);
+media LOAD_TOKEN(mfs_MediaToken);
+m LOAD_TOKEN(mfs_MediaToken);
+megaco LOAD_TOKEN(mfs_MegacopToken);
+! LOAD_TOKEN(mfs_MegacopToken);
+segment LOAD_TOKEN(mfs_MessageSegmentToken);
+sm LOAD_TOKEN(mfs_MessageSegmentToken);
+method LOAD_TOKEN(mfs_MethodToken);
+mt LOAD_TOKEN(mfs_MethodToken);
+mgcidtotry LOAD_TOKEN(mfs_MgcIdToken);
+mg LOAD_TOKEN(mfs_MgcIdToken);
+mode LOAD_TOKEN(mfs_ModeToken);
+mo LOAD_TOKEN(mfs_ModeToken);
+{opt}modify LOAD_TOKEN(mfs_ModifyToken);
+{opt}mf LOAD_TOKEN(mfs_ModifyToken);
+modem LOAD_TOKEN(mfs_ModemToken);
+md LOAD_TOKEN(mfs_ModemToken);
+{opt}move LOAD_TOKEN(mfs_MoveToken);
+{opt}mv LOAD_TOKEN(mfs_MoveToken);
+mux LOAD_TOKEN(mfs_MuxToken);
+mx LOAD_TOKEN(mfs_MuxToken);
+nevernotify LOAD_TOKEN(mfs_NeverNotifyToken);
+nbnn LOAD_TOKEN(mfs_NeverNotifyToken);
+{opt}{wild}notify LOAD_TOKEN(mfs_NotifyToken);
+{opt}{wild}n LOAD_TOKEN(mfs_NotifyToken);
+notifycompletion LOAD_TOKEN(mfs_NotifyCompletionToken);
+nc LOAD_TOKEN(mfs_NotifyCompletionToken);
+immediatenotify LOAD_TOKEN(mfs_NotifyImmediateToken);
+nbin LOAD_TOKEN(mfs_NotifyImmediateToken);
+regulatednotify LOAD_TOKEN(mfs_NotifyRegulatedToken);
+nbrn LOAD_TOKEN(mfs_NotifyRegulatedToken);
+nx64kservice LOAD_TOKEN(mfs_Nx64kToken);
+n64 LOAD_TOKEN(mfs_Nx64kToken);
+observedevents LOAD_TOKEN(mfs_ObservedEventsToken);
+oe LOAD_TOKEN(mfs_ObservedEventsToken);
+oneway LOAD_TOKEN(mfs_OnewayToken);
+ow LOAD_TOKEN(mfs_OnewayToken);
+onewayboth LOAD_TOKEN(mfs_OnewayBothToken);
+owb LOAD_TOKEN(mfs_OnewayBothToken);
+onewayexternal LOAD_TOKEN(mfs_OnewayExternalToken);
+owe LOAD_TOKEN(mfs_OnewayExternalToken);
+off LOAD_TOKEN(mfs_OffToken);
+on LOAD_TOKEN(mfs_OnToken);
+onoff LOAD_TOKEN(mfs_OnOffToken);
+oo LOAD_TOKEN(mfs_OnOffToken);
+orlgc LOAD_TOKEN(mfs_OrAUDITselectToken);
+otherreason LOAD_TOKEN(mfs_OtherReasonToken);
+or LOAD_TOKEN(mfs_OtherReasonToken);
+outofservice LOAD_TOKEN(mfs_OutOfSvcToken);
+os LOAD_TOKEN(mfs_OutOfSvcToken);
+packages LOAD_TOKEN(mfs_PackagesToken);
+pg LOAD_TOKEN(mfs_PackagesToken);
+pending LOAD_TOKEN(mfs_PendingToken);
+pn LOAD_TOKEN(mfs_PendingToken);
+priority LOAD_TOKEN(mfs_PriorityToken);
+pr LOAD_TOKEN(mfs_PriorityToken);
+profile LOAD_TOKEN(mfs_ProfileToken);
+pf LOAD_TOKEN(mfs_ProfileToken);
+reason LOAD_TOKEN(mfs_ReasonToken);
+re LOAD_TOKEN(mfs_ReasonToken);
+receiveonly LOAD_TOKEN(mfs_RecvonlyToken);
+rc LOAD_TOKEN(mfs_RecvonlyToken);
+reply LOAD_TOKEN(mfs_ReplyToken);
+p LOAD_TOKEN(mfs_ReplyToken);
+reseteventsdescriptor LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
+rse LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
+transactionresponseack LOAD_TOKEN(mfs_ResponseAckToken);
+k LOAD_TOKEN(mfs_ResponseAckToken);
+restart LOAD_TOKEN(mfs_RestartToken);
+rs LOAD_TOKEN(mfs_RestartToken);
+remote LOAD_TOKEN(mfs_RemoteToken);
+r LOAD_TOKEN(mfs_RemoteToken);
+sparequestid LOAD_TOKEN(mfs_RequestIDToken);
+requestid LOAD_TOKEN(mfs_RequestIDToken);
+sparq LOAD_TOKEN(mfs_RequestIDToken);
+rq LOAD_TOKEN(mfs_RequestIDToken);
+reservedgroup LOAD_TOKEN(mfs_ReservedGroupToken);
+rg LOAD_TOKEN(mfs_ReservedGroupToken);
+reservedvalue LOAD_TOKEN(mfs_ReservedValueToken);
+rv LOAD_TOKEN(mfs_ReservedValueToken);
+end LOAD_TOKEN(mfs_SegmentationCompleteToken);
+& LOAD_TOKEN(mfs_SegmentationCompleteToken);
+sendonly LOAD_TOKEN(mfs_SendonlyToken);
+so LOAD_TOKEN(mfs_SendonlyToken);
+sendreceive LOAD_TOKEN(mfs_SendrecvToken);
+sr LOAD_TOKEN(mfs_SendrecvToken);
+services LOAD_TOKEN(mfs_ServicesToken);
+sv LOAD_TOKEN(mfs_ServicesToken);
+servicestates LOAD_TOKEN(mfs_ServiceStatesToken);
+si LOAD_TOKEN(mfs_ServiceStatesToken);
+{opt}{wild}servicechange LOAD_TOKEN(mfs_ServiceChangeToken);
+{opt}{wild}sc LOAD_TOKEN(mfs_ServiceChangeToken);
+servicechangeaddress LOAD_TOKEN(mfs_ServiceChangeAddressToken);
+ad LOAD_TOKEN(mfs_ServiceChangeAddressToken);
+servicechangeinc LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
+sic LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
+signallist LOAD_TOKEN(mfs_SignalListToken);
+sl LOAD_TOKEN(mfs_SignalListToken);
+signals LOAD_TOKEN(mfs_SignalsToken);
+sg LOAD_TOKEN(mfs_SignalsToken);
+signaltype LOAD_TOKEN(mfs_SignalTypeToken);
+sy LOAD_TOKEN(mfs_SignalTypeToken);
+statistics LOAD_TOKEN(mfs_StatsToken);
+sa LOAD_TOKEN(mfs_StatsToken);
+stream LOAD_TOKEN(mfs_StreamToken);
+st LOAD_TOKEN(mfs_StreamToken);
+{opt}{wild}subtract LOAD_TOKEN(mfs_SubtractToken);
+{opt}{wild}s LOAD_TOKEN(mfs_SubtractToken);
+synchisdn LOAD_TOKEN(mfs_SynchISDNToken);
+sn LOAD_TOKEN(mfs_SynchISDNToken);
+terminationstate LOAD_TOKEN(mfs_TerminationStateToken);
+ts LOAD_TOKEN(mfs_TerminationStateToken);
+test LOAD_TOKEN(mfs_TestToken);
+te LOAD_TOKEN(mfs_TestToken);
+timeout LOAD_TOKEN(mfs_TimeOutToken);
+to LOAD_TOKEN(mfs_TimeOutToken);
+topology LOAD_TOKEN(mfs_TopologyToken);
+tp LOAD_TOKEN(mfs_TopologyToken);
+transaction LOAD_TOKEN(mfs_TransToken);
+t LOAD_TOKEN(mfs_TransToken);
+v18 LOAD_TOKEN(mfs_V18Token);
+v22 LOAD_TOKEN(mfs_V22Token);
+v22b LOAD_TOKEN(mfs_V22bisToken);
+v32 LOAD_TOKEN(mfs_V32Token);
+v32b LOAD_TOKEN(mfs_V32bisToken);
+v34 LOAD_TOKEN(mfs_V34Token);
+v76 LOAD_TOKEN(mfs_V76Token);
+v90 LOAD_TOKEN(mfs_V90Token);
+v91 LOAD_TOKEN(mfs_V91Token);
+version LOAD_TOKEN(mfs_VersionToken);
+v LOAD_TOKEN(mfs_VersionToken);
+({safechar})+ LOAD_TOKEN(mfs_SafeChars);
+
+<<EOF>> {LOAD_SHORT_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
+<*>.|\n {LOAD_TOKEN(mfs_IllegalChar); BEGIN(INITIAL); yyterminate();}
+
+%%
+
+/* MEGACO_LINENO_OR_TOKENCOUNTER
+ * Note that this construction is intended to make it
+ * possible to generate flex files that either reports
+ * line-number or one that don't.
+ * See MEGACO_YY_LINENO_OPTION and
+ * MEGACO_DUMMY_DECL_YY_LINENO above.
+ */
+
+#if defined(MEGACO_LINENO)
+#define LINENO_OR_TOKENCNT(P) yylineno
+#else
+#define LINENO_OR_TOKENCNT(P) P->token_counter
+#endif
+
+
+/* #define MFS_DEBUG true */ /* temporary */
+#if defined(MFS_DEBUG)
+# define DBG( proto ) printf proto
+# define DBG_BUF(func, bufName, buf, bufSz) mfs_dbg_buf_print(func, bufName, buf, bufSz)
+#else
+# define DBG( proto ) ((void) 0)
+# define DBG_BUF(func, bufName, buf, bufSz) ((void) 0)
+#endif /* if defined(MFS_DEBUG) */
+
+
+#if defined(MFS_DEBUG)
+
+#define CHUNK 16
+
+static void hexdump(unsigned char *buf, int bufsz)
+{
+ int i,j;
+ int count;
+
+ /* do this in chunks of CHUNK bytes */
+ for (i=0; i<bufsz; i+=CHUNK) {
+ /* show the offset */
+ printf("0x%06x ", i);
+
+ /* max of CHUNK or remaining bytes */
+ count = ((bufsz-i) > CHUNK ? CHUNK : bufsz-i);
+
+ /* show the bytes */
+ for (j=0; j<count; j++) {
+ if (j==CHUNK/2) printf(" ");
+ printf("%02x ",buf[i+j]);
+ }
+
+ /* pad with spaces if less than CHUNK */
+ for (j=count; j<CHUNK; j++) {
+ if (j==CHUNK/2) printf(" ");
+ printf(" ");
+ }
+
+ /* divider between hex and ascii */
+ printf(" ");
+
+ for (j=0; j<count; j++)
+ printf("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));
+
+ printf("\n");
+ }
+}
+
+static void mfs_dbg_buf_print(char* func, char* bufName, char* buf, int len)
+{
+ printf("%s -> %s (%d):\n", func, bufName, len);
+ hexdump((unsigned char*) buf, len);
+}
+
+
+#endif /* if defined(MFS_DEBUG) */
+
+static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz)
+{
+ /*
+ * Make sure we are not allready in error state
+ */
+ if (!dataP->error) {
+
+ /*
+ * Make sure that there is room in the buffer:
+ * length of msg + 10 chars for the ' of %d bytes'
+ * + 10 chars for the size value...
+ * This is really overkill since the msg string is never
+ * longer then 50 chars, but sinze this function is
+ * called when we have run out of memory...
+ */
+
+ int msg_len = strlen(msg);
+ if ((10 + 10 + msg_len) < sizeof(dataP->error_msg)) {
+ if (0 >= sprintf(dataP->error_msg, "%s of %d bytes", msg, sz)) {
+ mfs_fatal_error(dataP, msg);
+ }
+ } else {
+ mfs_fatal_error(dataP, msg);
+ }
+ dataP->error = TRUE;
+ }
+}
+
+
+static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size)
+{
+ DBG( ("mfs_ensure_term_spec -> entry with"
+ "\n size: %d"
+ "\nwhen"
+ "\n spec_index: %d"
+ "\n spec_size: %d"
+ "\n", size, dataP->term_spec_index, dataP->term_spec_size) );
+
+ /* OTP-4236 - BEGIN */
+ if ((dataP->term_spec_index + size) >= dataP->term_spec_size) {
+ void *tmp;
+
+ DBG( ("mfs_ensure_term_spec -> allocate more memory when"
+ "\n term_spec_index: %d"
+ "\n term_spec_size: %d\n",
+ dataP->term_spec_index, dataP->term_spec_size) );
+
+ dataP->term_spec_size = (dataP->term_spec_size * 2) + size;
+
+ DBG( ("mfs_ensure_term_spec -> "
+ "term_spec is at 0x%X, new term_spec_size is %d\n",
+ (unsigned int) dataP->term_spec, dataP->term_spec_size) );
+
+ tmp = REALLOC(dataP->term_spec,
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ if (tmp == NULL) {
+ /*
+ * Ouch, we did'nt get any new memory.
+ * Just give ut. I.e. free the memory we have (note that
+ * the assign macro tests the buffer before assigning).
+ */
+ FREE(dataP->term_spec);
+ dataP->term_spec = NULL;
+
+ mfs_alloc_failed(dataP, "failed reallocating term spec buffer",
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ } else {
+ dataP->term_spec = tmp;
+ }
+
+ DBG( ("mfs_ensure_term_spec -> new term_spec is at 0x%X\n",
+ (unsigned int) dataP->term_spec) );
+ }
+ /* OTP-4236 - END */
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_short_load_token(ErlDrvTermData TokenTag, yyscan_t yyscanner)
+#else
+static void mfs_short_load_token(ErlDrvTermData TokenTag)
+#endif
+{
+ /* Build a {TokenTag, LineNumber} tuple */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ /*
+ DBG( ("mfs_short_load_token -> entry with"
+ "\n TokenTag: %ld\n", TokenTag) );
+ */
+
+ mfs_ensure_term_spec(dataP, 6);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 2);
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty,
+ yyscan_t yyscanner)
+#else
+static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty)
+#endif
+{
+ /* Build a {TokenTag, LineNumber, String} tuple */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_octet_load_token -> entry with"
+ "\n TokenTag: %d"
+ "\n is_empty: %d"
+ "\n yyleng: %d"
+ "\n", (int) TokenTag, is_empty, yyleng) );
+
+ mfs_ensure_term_spec(dataP, 9);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+
+ if (is_empty) {
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+
+ } else {
+
+ LOAD_PROP_GRPS(dataP);
+
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty,
+ yyscan_t yyscanner)
+#else
+static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty)
+#endif
+{
+ /* Build a {TokenTag, LineNumber, LowerCaseString} tuple */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_lower_load_token -> entry with"
+ "\n TokenTag: %ld"
+ "\n is_empty: %d"
+ "\n", TokenTag, is_empty) );
+
+ mfs_ensure_term_spec(dataP, 9);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, TokenTag);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+
+ if (is_empty) {
+
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData)"");
+ ASSIGN_TERM_SPEC(dataP, 0);
+
+ } else {
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ DBG_BUF("mfs_lower_load_token", "dataP->text_ptr",
+ dataP->text_ptr, yyleng);
+
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->text_ptr);
+ dataP->text_ptr += yyleng;
+ ASSIGN_TERM_SPEC(dataP, yyleng);
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+}
+
+#define PG_ERR_PRE "bad_property_parm:"
+#define PG_ERR1 "Could not find property parm value for"
+#define PG_ERR2 "Could not find proper property parm name"
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner)
+#else
+static void mfs_load_property_groups(MfsErlDrvData* dataP)
+#endif
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ // MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ // MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ /*
+ * Process the property groups string
+ * v= is a property group delimiter
+ */
+
+ /*
+ * For each string, look for the first '='.
+ * Everything to the left is the name and
+ * everything to the right is the value.
+ */
+
+ int i = 0; // loop counter
+ int numGroups = 0; // Number of property groups
+ int numPps = 0; // Number of property parms (in the group)
+ char* name; // Pointer to the name buffer
+ int nameStart = 0; // Start position of the property parm name
+ int nameLen; // Length of the name part
+ char* value; // Pointer to the value buffer
+ int valueStart = 0; // Start position of the property parm name
+ int valueLen = 0; // Length of the value part
+
+ DBG( ("mfs_load_property_groups -> entry\n") );
+
+ mfs_ensure_term_spec(dataP, 10); /*�Just in case... */
+
+ while (i <= yyleng) {
+
+ /* Skip white-spaces and end-of-line */
+
+ DBG( ("mfs_load_property_groups -> "
+ "skip white-spaces and end-of-line: i = %d\n", i) );
+
+ if ((yytext[i] != SP) &&
+ (yytext[i] != HTAB) &&
+ (yytext[i] != LF) &&
+ (yytext[i] != CR) &&
+ (yytext[i] != NUL)) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "start looking for delimiter ('=')\n") );
+
+ /* Start looking for '=' */
+ nameStart = i;
+ nameLen = 0;
+ while (i <= yyleng) {
+
+ /* Is it a name-value delimiter? */
+ if (yytext[i] == '=') {
+
+ /*
+ * Found the name/value delimiter
+ */
+ nameLen = i-nameStart;
+
+ DBG( ("mfs_load_property_groups -> "
+ "found delimiter at %d (name length = %d)\n", i, nameLen) );
+
+ /*
+ * "v=" is the start of a new group.
+ * So, check if this maybe is the beginning of
+ * the first group or not. If not, we need to
+ * "terminate" the previous group.
+ */
+ if (0 == strncmp("v", &yytext[nameStart], nameLen)) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "found a 'v' when group count is %d\n", numGroups) );
+
+ if (numGroups > 0) {
+ /*
+ * End the previous group
+ * (only if this is not the first group)
+ */
+
+ DBG( ("mfs_load_property_groups -> "
+ "start of new group - terminate previous group\n") );
+
+ mfs_ensure_term_spec(dataP, 3);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST); // List
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1); // Length of (group) list
+ numPps = 0; /* reset for next group */
+ } // if ...
+ numGroups++;
+ } // if ...
+ numPps++;
+ i++;
+
+ /*
+ * Now, look for the end of the value string,
+ * which is an EOL = (CR [LF] / LF )
+ */
+
+ DBG( ("mfs_load_property_groups -> "
+ "start looking for end of value\n") );
+ valueStart = i;
+ valueLen = 0;
+ while (i <= yyleng) {
+ if ((yytext[i] == CR) || (yytext[i] == LF)) {
+ valueLen = i-valueStart;
+ DBG( ("mfs_load_property_groups -> "
+ "found end of value at %d\n", i) );
+ break;
+ } else {
+ i++;
+ } // if ...
+ } // while ...
+
+ /* Name */
+ name = dataP->text_ptr;
+ strncpy(name, &yytext[nameStart], nameLen);
+ name[nameLen] = 0;
+ dataP->text_ptr += (nameLen + 1); // Make room for the NULL termination
+
+ /* Check that we actually got a proper value */
+ if (valueLen == 0) {
+ /* Invalid property parm value */
+ DBG( ("mfs_load_property_groups -> "
+ "property parm value not found\n") );
+
+ /**********************************************
+ * -record('ErrorDescriptor',
+ * {
+ * errorCode,
+ * errorText = asn1_NOVALUE
+ * }).
+ */
+
+ if (0 >= sprintf(dataP->error_msg, "%s %s %s",
+ PG_ERR_PRE, PG_ERR1, name)) {
+ mfs_fatal_error(dataP, PG_ERR1);
+ }
+ dataP->error = TRUE;
+
+ DBG( ("mfs_load_property_groups -> "
+ "done after value error (%s)\n", name) );
+
+ return; // Bail out
+
+ } else {
+
+
+ /***************************************
+ * -record('PropertyParm',
+ * {
+ * name,
+ * value,
+ * extraInfo = asn1_NOVALUE
+ * }). % with extension mark
+ */
+
+ mfs_ensure_term_spec(dataP, 15); // 2 + 3 + 6 + 2 + 2
+
+ DBG( ("mfs_load_property_groups -> "
+ "insert PropertyParm record name\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_PropertyParm);
+
+ /* Name */
+ DBG( ("mfs_load_property_groups -> insert name field\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) name);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) nameLen);
+
+ /*
+ * value, which is actually a list of length 1
+ * where the "actual value" is the (only) element
+ */
+ DBG( ("mfs_load_property_groups -> "
+ "insert value field (length = %d)\n", valueLen) );
+ value = dataP->text_ptr;
+ strncpy(value, &yytext[valueStart], valueLen);
+ dataP->text_ptr += valueLen;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) value);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) valueLen);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of value list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 1 + 1); // Length of (group) list
+
+ /* extraInfo - never used */
+ DBG( ("mfs_load_property_groups -> "
+ "insert the extraInfo field\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_asn1_NOVALUE);
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate PropertyParm tuple\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 4);
+ break;
+
+ } // if (valueLen == 0) ...
+
+ } else {
+ DBG( ("mfs_load_property_groups -> "
+ "b) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
+ i++;
+ } // if (yytext[i] == '=')
+
+ } // while (i <= yyleng)
+
+ /* Check that we actually got a proper name */
+ if (nameLen == 0) {
+ /* Invalid property parm name */
+ DBG( ("mfs_load_property_groups -> "
+ "property parm name not found when "
+ "nameStart = %d\n", nameStart) );
+
+ if (0 >= sprintf(dataP->error_msg, "%s %s (name start at %d)",
+ PG_ERR_PRE, PG_ERR2, nameStart)) {
+ mfs_fatal_error(dataP, PG_ERR2);
+ }
+
+ dataP->error = TRUE;
+
+ DBG( ("mfs_load_property_groups -> done after name error\n") );
+
+ return; // Bail out
+
+ } // if (nameLen == 0) ...
+
+ } else {
+ DBG( ("mfs_load_property_groups -> "
+ "a) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
+ i++; // next
+ } // if ((yytext[i] != SP)...
+ } // while ...
+
+ mfs_ensure_term_spec(dataP, 4); // 2 + 2 just in case
+
+ /* Make sure we actually have some groups */
+
+ if (numGroups > 0) {
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate group (list of properties) list (length = %d)\n",
+ numPps) );
+
+ /* Terminate the final group */
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1); // Length of (group) list
+
+ }
+
+ DBG( ("mfs_load_property_groups -> "
+ "terminate groups (list of property groups) list (length = %d)\n",
+ numGroups) );
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL); // End of list
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numGroups + 1); // Length of (groups) list
+
+ DBG( ("mfs_load_property_groups -> done\n") );
+}
+
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_name(yyscan_t yyscanner)
+#else
+static void mfs_load_map_name()
+#endif
+{
+ /* Copy digit map name as lower case */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ dataP->digit_map_name_ptr = dataP->text_ptr;
+ dataP->digit_map_name_len = yyleng;
+ dataP->text_ptr += yyleng;
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_value(yyscan_t yyscanner)
+#else
+static void mfs_load_map_value()
+#endif
+{
+ /* Copy digit map value as lower case */
+ int i;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ for ( i = 0; i < yyleng; ++i ) {
+ dataP->text_ptr[i] = tolower(yytext[i]);
+ }
+
+ dataP->digit_map_value_ptr = dataP->text_ptr;
+ dataP->digit_map_value_len = yyleng;
+ dataP->text_ptr += yyleng;
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_timer(yyscan_t yyscanner)
+#else
+static void mfs_load_map_timer()
+#endif
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+ int timer_len = yyleng - 2;
+
+ /* The digit map timer consists of 3 or 4 characters:
+ * z and Z are actually version 2 only
+ * 0 - the kind of timer (t|T|s|S|l|L|z|Z)
+ * 1 - a colon
+ * 2 - mandatory digit
+ * 3 - optional digit
+ */
+
+ /*
+ DBG( ("mfs_load_map_timer -> entry when yyleng: %d\n", yyleng) );
+ DBG( ("mfs_load_map_timer -> yytext: 0x%x\n", yytext) );
+
+ DBG( ("mfs_load_map_timer -> yytext[0]: %u (%c)\n", yytext[0], yytext[0]) );
+ DBG( ("mfs_load_map_timer -> yytext[1]: %u (%c)\n", yytext[1], yytext[1]) );
+ DBG( ("mfs_load_map_timer -> yytext[2]: %u (%c)\n", yytext[2], yytext[2]) );
+ DBG( ("mfs_load_map_timer -> yytext[3]: %u (%c)\n", yytext[3], yytext[3]) );
+ */
+
+ /* Pad with leading zero */
+
+ if (timer_len == 1) {
+ dataP->text_ptr[0] = '0';
+ dataP->text_ptr[1] = yytext[2];
+ } else if (timer_len == 2) {
+ dataP->text_ptr[0] = yytext[2];
+ dataP->text_ptr[1] = yytext[3];
+ }
+
+ /*
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr[0]: %u (%c)\n",
+ dataP->text_ptr[0], dataP->text_ptr[0]) );
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr[1]: %u (%c)\n",
+ dataP->text_ptr[1], dataP->text_ptr[1]) );
+
+ DBG( ("mfs_load_map_timer -> dataP->text_ptr: 0x%x\n",
+ dataP->text_ptr) );
+ */
+
+ switch (yytext[0]) {
+ case 't':
+ case 'T':
+ dataP->digit_map_start_ptr = dataP->text_ptr;
+ break;;
+ case 's':
+ case 'S':
+ dataP->digit_map_short_ptr = dataP->text_ptr;
+ break;;
+ case 'l':
+ case 'L':
+ dataP->digit_map_long_ptr = dataP->text_ptr;
+ break;;
+ case 'z':
+ case 'Z':
+ dataP->digit_map_duration_ptr = dataP->text_ptr;
+ break;;
+ }
+
+ /* We pad when there is only one digit, so it will always be two */
+ dataP->text_ptr += 2;
+
+}
+
+static void mfs_load_timer_field(MfsErlDrvData* dataP, char* text)
+{
+ mfs_ensure_term_spec(dataP, 2); /* OTP-4236 */
+ if (text == NULL) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, ((text[0] - '0') * 10) + (text[1] - '0'));
+ }
+}
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+static void mfs_load_map_token(yyscan_t yyscanner)
+#else
+static void mfs_load_map_token()
+#endif
+{
+ /*
+ * Build a {'DigitMapDescriptorToken', LineNumber,
+ * {'DigitMapDescriptor', DigitMapName, DigitMapValue}} tuple
+ */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ mfs_ensure_term_spec(dataP, 20);
+ dataP->token_counter++;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptorToken);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptor);
+
+ if (dataP->digit_map_name_ptr == 0) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_name_ptr);
+ ASSIGN_TERM_SPEC(dataP, dataP->digit_map_name_len);
+ dataP->digit_map_name_ptr = NULL;
+ }
+
+ if (dataP->digit_map_value_ptr == NULL) {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
+ } else {
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, mfs_DigitMapValue);
+
+ /* Take care of timer values */
+ mfs_load_timer_field(dataP, dataP->digit_map_start_ptr);
+ dataP->digit_map_start_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_short_ptr);
+ dataP->digit_map_short_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_long_ptr);
+ dataP->digit_map_long_ptr = NULL;
+
+ mfs_load_timer_field(dataP, dataP->digit_map_duration_ptr);
+ dataP->digit_map_duration_ptr = NULL;
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
+ ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_value_ptr);
+ ASSIGN_TERM_SPEC(dataP, dataP->digit_map_value_len);
+ dataP->digit_map_value_ptr = NULL;
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 6);
+ }
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+}
+
+
+DRIVER_INIT(mfs_drv)
+{
+ DBG( ("DRIVER_INIT(mfs_drv) -> entry\n") );
+
+ return &mfs_entry;
+}
+
+static ErlDrvData mfs_start(ErlDrvPort port, char *buf)
+{
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ MfsErlDrvData* dataP = ALLOC(sizeof(MfsErlDrvData));
+#else
+ MfsErlDrvData* dataP = &mfs_drv_data;
+#endif
+
+ DBG( ("mfs_start -> entry\n") );
+
+ dataP->port = port;
+ dataP->digit_map_name_ptr = NULL;
+ dataP->digit_map_name_len = 0;
+ dataP->digit_map_value_ptr = NULL;
+ dataP->digit_map_value_len = 0;
+ dataP->digit_map_start_ptr = NULL;
+ dataP->digit_map_short_ptr = NULL;
+ dataP->digit_map_long_ptr = NULL;
+ dataP->digit_map_duration_ptr = NULL;
+ dataP->error = FALSE;
+ /* dataP->error_msg[512]; */
+ dataP->text_buf = NULL;
+ dataP->text_ptr = NULL;
+ dataP->term_spec = NULL;
+ dataP->term_spec_size = 0;
+ dataP->term_spec_index = 0;
+ dataP->token_counter = 0;
+
+ mfs_AddToken = driver_mk_atom("AddToken");
+ mfs_AndAUDITSelectToken = driver_mk_atom("AndAUDITSelectToken");
+ mfs_AuditCapToken = driver_mk_atom("AuditCapToken");
+ mfs_AuditToken = driver_mk_atom("AuditToken");
+ mfs_AuditValueToken = driver_mk_atom("AuditValueToken");
+ mfs_AuthToken = driver_mk_atom("AuthToken");
+ mfs_BothToken = driver_mk_atom("BothToken");
+ mfs_BothwayToken = driver_mk_atom("BothwayToken");
+ mfs_BriefToken = driver_mk_atom("BriefToken");
+ mfs_BufferToken = driver_mk_atom("BufferToken");
+ mfs_COLON = driver_mk_atom("COLON");
+ mfs_COMMA = driver_mk_atom("COMMA");
+ mfs_ContextAttrToken = driver_mk_atom("ContextAttrToken");
+ mfs_ContextAuditToken = driver_mk_atom("ContextAuditToken");
+ mfs_ContextListToken = driver_mk_atom("ContextListToken");
+ mfs_CtxToken = driver_mk_atom("CtxToken");
+ mfs_DelayToken = driver_mk_atom("DelayToken");
+ mfs_DeleteToken = driver_mk_atom("DeleteToken");
+ mfs_DigitMapDescriptor = driver_mk_atom("DigitMapDescriptor");
+ mfs_DigitMapDescriptorToken = driver_mk_atom("DigitMapDescriptorToken");
+ mfs_DigitMapToken = driver_mk_atom("DigitMapToken");
+ mfs_DigitMapValue = driver_mk_atom("DigitMapValue");
+ mfs_DirectionToken = driver_mk_atom("DirectionToken");
+ mfs_DiscardToken = driver_mk_atom("DiscardToken");
+ mfs_DisconnectedToken = driver_mk_atom("DisconnectedToken");
+ mfs_DurationToken = driver_mk_atom("DurationToken");
+ mfs_EQUAL = driver_mk_atom("EQUAL");
+ mfs_EmbedToken = driver_mk_atom("EmbedToken");
+ mfs_EmergencyToken = driver_mk_atom("EmergencyToken");
+ mfs_EmergencyOffToken = driver_mk_atom("EmergencyOffToken");
+ mfs_EmergencyValueToken = driver_mk_atom("EmergencyValueToken");
+ mfs_ErrorToken = driver_mk_atom("ErrorToken");
+ mfs_EventBufferToken = driver_mk_atom("EventBufferToken");
+ mfs_EventsToken = driver_mk_atom("EventsToken");
+ mfs_ExternalToken = driver_mk_atom("ExternalToken");
+ mfs_FailoverToken = driver_mk_atom("FailoverToken");
+ mfs_ForcedToken = driver_mk_atom("ForcedToken");
+ mfs_GREATER = driver_mk_atom("GREATER");
+ mfs_GracefulToken = driver_mk_atom("GracefulToken");
+ mfs_H221Token = driver_mk_atom("H221Token");
+ mfs_H223Token = driver_mk_atom("H223Token");
+ mfs_H226Token = driver_mk_atom("H226Token");
+ mfs_HandOffToken = driver_mk_atom("HandOffToken");
+ mfs_IEPSToken = driver_mk_atom("IEPSToken");
+ mfs_IllegalChar = driver_mk_atom("IllegalChar");
+ mfs_ImmAckRequiredToken = driver_mk_atom("ImmAckRequiredToken");
+ mfs_InSvcToken = driver_mk_atom("InSvcToken");
+ mfs_InactiveToken = driver_mk_atom("InactiveToken");
+ mfs_InternalToken = driver_mk_atom("InternalToken");
+ mfs_InterruptByEventToken = driver_mk_atom("InterruptByEventToken");
+ mfs_InterruptByNewSignalsDescrToken = driver_mk_atom("InterruptByNewSignalsDescrToken");
+ mfs_IntsigDelayToken = driver_mk_atom("IntsigDelayToken");
+ mfs_IsolateToken = driver_mk_atom("IsolateToken");
+ mfs_IterationToken = driver_mk_atom("IterationToken");
+ mfs_KeepActiveToken = driver_mk_atom("KeepActiveToken");
+ mfs_LBRKT = driver_mk_atom("LBRKT");
+ mfs_LESSER = driver_mk_atom("LESSER");
+ mfs_LSBRKT = driver_mk_atom("LSBRKT");
+ mfs_LocalControlToken = driver_mk_atom("LocalControlToken");
+ mfs_LocalDescriptorToken = driver_mk_atom("LocalDescriptorToken");
+ mfs_LocalToken = driver_mk_atom("LocalToken");
+ mfs_LockStepToken = driver_mk_atom("LockStepToken");
+ mfs_LoopbackToken = driver_mk_atom("LoopbackToken");
+ mfs_MediaToken = driver_mk_atom("MediaToken");
+ mfs_MegacopToken = driver_mk_atom("MegacopToken");
+ mfs_MessageSegmentToken = driver_mk_atom("MessageSegmentToken");
+ mfs_MethodToken = driver_mk_atom("MethodToken");
+ mfs_MgcIdToken = driver_mk_atom("MgcIdToken");
+ mfs_ModeToken = driver_mk_atom("ModeToken");
+ mfs_ModemToken = driver_mk_atom("ModemToken");
+ mfs_ModifyToken = driver_mk_atom("ModifyToken");
+ mfs_MoveToken = driver_mk_atom("MoveToken");
+ mfs_MtpAddressToken = driver_mk_atom("MtpAddressToken");
+ mfs_MuxToken = driver_mk_atom("MuxToken");
+ mfs_NEQUAL = driver_mk_atom("NEQUAL");
+ mfs_NotifyCompletionToken = driver_mk_atom("NotifyCompletionToken");
+ mfs_NotifyImmediateToken = driver_mk_atom("NotifyImmediateToken");
+ mfs_NotifyRegulatedToken = driver_mk_atom("NotifyRegulatedToken");
+ mfs_NeverNotifyToken = driver_mk_atom("NeverNotifyToken");
+ mfs_NotifyToken = driver_mk_atom("NotifyToken");
+ mfs_Nx64kToken = driver_mk_atom("Nx64kToken");
+ mfs_ObservedEventsToken = driver_mk_atom("ObservedEventsToken");
+ mfs_OffToken = driver_mk_atom("OffToken");
+ mfs_OnOffToken = driver_mk_atom("OnOffToken");
+ mfs_OnToken = driver_mk_atom("OnToken");
+ mfs_OnewayToken = driver_mk_atom("OnewayToken");
+ mfs_OnewayBothToken = driver_mk_atom("OnewayBothToken");
+ mfs_OnewayExternalToken = driver_mk_atom("OnewayExternalToken");
+ mfs_OrAUDITselectToken = driver_mk_atom("OrAUDITselectToken");
+ mfs_OtherReasonToken = driver_mk_atom("OtherReasonToken");
+ mfs_OutOfSvcToken = driver_mk_atom("OutOfSvcToken");
+ mfs_PackagesToken = driver_mk_atom("PackagesToken");
+ mfs_PendingToken = driver_mk_atom("PendingToken");
+ mfs_PriorityToken = driver_mk_atom("PriorityToken");
+ mfs_ProfileToken = driver_mk_atom("ProfileToken");
+ mfs_QuotedChars = driver_mk_atom("QuotedChars");
+ mfs_RBRKT = driver_mk_atom("RBRKT");
+ mfs_RSBRKT = driver_mk_atom("RSBRKT");
+ mfs_ReasonToken = driver_mk_atom("ReasonToken");
+ mfs_RecvonlyToken = driver_mk_atom("RecvonlyToken");
+ mfs_RemoteDescriptorToken = driver_mk_atom("RemoteDescriptorToken");
+ mfs_RemoteToken = driver_mk_atom("RemoteToken");
+ mfs_ReplyToken = driver_mk_atom("ReplyToken");
+ mfs_RequestIDToken = driver_mk_atom("RequestIDToken");
+ mfs_ReservedGroupToken = driver_mk_atom("ReservedGroupToken");
+ mfs_ReservedValueToken = driver_mk_atom("ReservedValueToken");
+ mfs_ResetEventsDescriptorToken = driver_mk_atom("ResetEventsDescriptorToken");
+ mfs_ResponseAckToken = driver_mk_atom("ResponseAckToken");
+ mfs_RestartToken = driver_mk_atom("RestartToken");
+ mfs_SEP = driver_mk_atom("SEP");
+ mfs_SafeChars = driver_mk_atom("SafeChars");
+ mfs_SegmentationCompleteToken = driver_mk_atom("SegmentationCompleteToken");
+ mfs_SendonlyToken = driver_mk_atom("SendonlyToken");
+ mfs_SendrecvToken = driver_mk_atom("SendrecvToken");
+ mfs_ServiceChangeAddressToken = driver_mk_atom("ServiceChangeAddressToken");
+ mfs_ServiceChangeIncompleteToken = driver_mk_atom("ServiceChangeIncompleteToken");
+ mfs_ServiceChangeToken = driver_mk_atom("ServiceChangeToken");
+ mfs_ServiceStatesToken = driver_mk_atom("ServiceStatesToken");
+ mfs_ServicesToken = driver_mk_atom("ServicesToken");
+ mfs_SignalListToken = driver_mk_atom("SignalListToken");
+ mfs_SignalTypeToken = driver_mk_atom("SignalTypeToken");
+ mfs_SignalsToken = driver_mk_atom("SignalsToken");
+ mfs_StatsToken = driver_mk_atom("StatsToken");
+ mfs_StreamToken = driver_mk_atom("StreamToken");
+ mfs_SubtractToken = driver_mk_atom("SubtractToken");
+ mfs_SynchISDNToken = driver_mk_atom("SynchISDNToken");
+ mfs_TerminationStateToken = driver_mk_atom("TerminationStateToken");
+ mfs_TestToken = driver_mk_atom("TestToken");
+ mfs_TimeOutToken = driver_mk_atom("TimeOutToken");
+ mfs_TimeStampToken = driver_mk_atom("TimeStampToken"); /* OTP-5042 */
+ mfs_TopologyToken = driver_mk_atom("TopologyToken");
+ mfs_TransToken = driver_mk_atom("TransToken");
+ mfs_V18Token = driver_mk_atom("V18Token");
+ mfs_V22Token = driver_mk_atom("V22Token");
+ mfs_V22bisToken = driver_mk_atom("V22bisToken");
+ mfs_V32Token = driver_mk_atom("V32Token");
+ mfs_V32bisToken = driver_mk_atom("V32bisToken");
+ mfs_V34Token = driver_mk_atom("V34Token");
+ mfs_V76Token = driver_mk_atom("V76Token");
+ mfs_V90Token = driver_mk_atom("V90Token");
+ mfs_V91Token = driver_mk_atom("V91Token");
+ mfs_VersionToken = driver_mk_atom("VersionToken");
+ mfs_asn1_NOVALUE = driver_mk_atom("asn1_NOVALUE");
+ mfs_endOfMessage = driver_mk_atom("endOfMessage");
+ mfs_PropertyParm = driver_mk_atom("PropertyParm");
+ mfs_ErrorDescriptor = driver_mk_atom("ErrorDescriptor");
+
+ DBG( ("mfs_start -> exit\n") );
+
+ return (ErlDrvData) dataP;
+}
+
+static void mfs_stop(ErlDrvData handle)
+{
+ MfsErlDrvData* dataP = (MfsErlDrvData*) handle;
+
+ dataP->port = 0;
+
+ DBG( ("mfs_stop -> exit\n") );
+
+ return;
+}
+
+static void mfs_command(ErlDrvData handle,
+ char *buf, int buf_len)
+{
+ driver_failure_atom(((MfsErlDrvData*) handle)->port, "bad_usage");
+
+ return;
+}
+
+static int mfs_control(ErlDrvData handle,
+ unsigned int command,
+ char *buf, int buf_len,
+ char **res_buf, int res_buf_len)
+{
+ MfsErlDrvData* dataP = (MfsErlDrvData*) handle;
+ char* tmp;
+ YY_BUFFER_STATE state;
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ yyscan_t scanner;
+ /* struct yyguts_t * yyg = (struct yyguts_t*) scanner; */
+#endif
+
+ DBG( ("mfs_control -> entry with"
+ "\n command: %d"
+ "\n buf_len: %d"
+ "\n res_buf_len: %d\n", command, buf_len, res_buf_len) );
+
+ if (NULL == (tmp = ALLOC(buf_len))) {
+ int len;
+ mfs_alloc_failed(dataP, "failed allocating text buffer", buf_len);
+
+ len = strlen(dataP->error_msg);
+
+ if (res_buf_len < len) {
+ /*
+ * Since we failed the memory allocation in the first place,
+ * there is no point in trying to get more memory for the
+ * error code...
+ */
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ return len;
+ }
+ dataP->text_buf = tmp;
+ dataP->text_ptr = tmp;
+
+ dataP->term_spec_size = 1000 + buf_len; /* OTP-4237 */
+
+ DBG( ("mfs_control -> allocate term-spec buffer: "
+ "\n term_spec_size: %d\n", dataP->term_spec_size) );
+
+ dataP->term_spec = ALLOC(dataP->term_spec_size * sizeof(ErlDrvTermData));
+ if (NULL == dataP->term_spec) {
+ int len;
+ mfs_alloc_failed(dataP, "failed allocating term spec buffer",
+ dataP->term_spec_size * sizeof(ErlDrvTermData));
+
+ len = strlen(dataP->error_msg);
+
+ if (res_buf_len < len) {
+ /*
+ * Since we failed the memory allocation in the first place,
+ * there is no point in trying to get more memory for the
+ * error code...
+ */
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ FREE(dataP->text_buf);
+
+ return len;
+ }
+ dataP->term_spec_index = 0;
+ dataP->token_counter = 0;
+ dataP->error = FALSE;
+
+ /* Prepare the first field in the {tokens, TokenList, LastLine} tuple */
+ DBG( ("mfs_control -> prepare the first field in the tokens tuple\n") );
+ mfs_ensure_term_spec(dataP, 2);
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
+ ASSIGN_TERM_SPEC(dataP, driver_mk_atom("tokens"));
+
+ /* Perform the actual scan */
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> initiate scanner\n") );
+ yylex_init(&scanner);
+
+ DBG( ("mfs_control -> maybe enable flex debug\n") );
+ yyset_debug(MFS_FLEX_DEBUG, scanner);
+
+ DBG( ("mfs_control -> set my extra data (ErlDrvData)\n") );
+ yyset_extra(dataP, scanner);
+
+ DBG( ("mfs_control -> scan bytes\n") );
+ state = yy_scan_bytes(buf, buf_len, scanner);
+
+ DBG( ("mfs_control -> set initial line-no (1) when state is at 0x%x\n",
+ (unsigned int) state) );
+ yyset_lineno(1, scanner);
+
+ DBG( ("mfs_control -> do the actual scan\n") );
+ yylex(scanner);
+
+#else
+
+ /*
+ * N o n - R e e n t r a n t s c a n n e r
+ */
+
+ yylineno = 1;
+ state = yy_scan_bytes(buf, buf_len);
+ yylex();
+ yy_delete_buffer(state);
+
+#endif
+
+ DBG( ("mfs_control -> scan done - now check if ok or not (%d)\n", dataP->error) );
+ if (!dataP->error) {
+
+ /*
+ * Prepare the rest of the {tokens, TokenList, LastLine} tuple
+ * and send it as message top caller.
+ */
+
+ DBG( ("mfs_control -> ensure term spec(7)\n") );
+
+ mfs_ensure_term_spec(dataP, 7);
+ DBG( ("mfs_control -> assign nil\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);
+ DBG( ("mfs_control -> assign type list\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
+ DBG( ("mfs_control -> assign size of list: %d\n", dataP->token_counter + 1) );
+ ASSIGN_TERM_SPEC(dataP, dataP->token_counter + 1);
+ DBG( ("mfs_control -> assign type int\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+ DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", yyget_lineno(scanner)) );
+ // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
+ ASSIGN_TERM_SPEC(dataP, yyget_lineno(scanner));
+#else
+ DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", LINENO_OR_TOKENCNT(dataP)) );
+ // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
+ ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
+#endif
+ // ASSIGN_TERM_SPEC(1);
+ DBG( ("mfs_control -> assign tuple\n") );
+ ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
+ DBG( ("mfs_control -> assign size 3\n") );
+ ASSIGN_TERM_SPEC(dataP, 3);
+
+ DBG( ("mfs_control -> send the term when"
+ "\n term_spec_index: %d"
+ "\n term_spec_size: %d\n",
+ dataP->term_spec_index, dataP->term_spec_size) );
+
+ driver_send_term(dataP->port,
+ driver_caller(dataP->port),
+ dataP->term_spec,
+ dataP->term_spec_index);
+
+ if (dataP->text_buf != NULL) FREE(dataP->text_buf);
+ if (dataP->term_spec != NULL) FREE(dataP->term_spec);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> delete buffer\n") );
+ yy_delete_buffer(state, scanner);
+
+ DBG( ("mfs_control -> destroy scanner\n") );
+ yylex_destroy(scanner);
+
+#endif
+
+ DBG( ("mfs_control -> done (0)\n") );
+
+ return 0;
+
+ } else {
+ /*
+ * Return the error message
+ */
+ int len = strlen(dataP->error_msg);
+
+ DBG( ("mfs_control -> return the error message: \n%s\n\n",
+ dataP->error_msg) );
+
+ /*
+ * If we fail to alloc a bigger block of memory
+ * we have to make do with what we got
+ */
+ if (res_buf_len < len) {
+ void *tmp = ALLOC(len);
+ if (tmp != NULL)
+ *res_buf = tmp;
+ else
+ len = res_buf_len;
+ }
+
+ strncpy(*res_buf, dataP->error_msg, len);
+
+ if (dataP->text_buf != NULL) FREE(dataP->text_buf);
+ if (dataP->term_spec != NULL) FREE(dataP->term_spec);
+
+#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
+
+ /*
+ * R e e n t r a n t s c a n n e r
+ */
+
+ DBG( ("mfs_control -> delete buffer\n") );
+ yy_delete_buffer(state, scanner);
+
+ DBG( ("mfs_control -> destroy scanner\n") );
+ yylex_destroy(scanner);
+
+#endif
+
+ DBG( ("mfs_control -> done (%d)\n", len) );
+
+ return len;
+ }
+}
+
+static void mfs_finish(void)
+{
+ return;
+}
+
+static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg)
+{
+ if (!dataP->error) {
+ int len = strlen(msg);
+
+ if (len >= sizeof(dataP->error_msg))
+ len = sizeof(dataP->error_msg) - 1;
+
+ strncpy(dataP->error_msg, msg, len);
+ dataP->error_msg[len] = '\0';
+ dataP->error = TRUE;
+ }
+}
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
new file mode 100644
index 0000000000..d09e0c6fff
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
@@ -0,0 +1,232 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Handle the flex scanner
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_scanner_handler).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%% External exports
+-export([
+ start_link/0, start_link/1,
+ stop/1,
+ get_config/1
+ ]).
+
+%% gen_server callbacks
+-export([
+ init/1,
+ handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+-record(state, {conf}).
+
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+start_link() ->
+ start_link([]).
+
+start_link(Opts) ->
+ case gen_server:start_link(?MODULE, Opts, []) of
+ {ok, Pid} ->
+ Conf = get_config(Pid),
+ {ok, Pid, Conf};
+ Else ->
+ Else
+ end.
+
+stop(Pid) ->
+ gen_server:call(Pid, stop).
+
+get_config(Pid) ->
+ gen_server:call(Pid, get_config).
+
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+init(_Opts) ->
+ process_flag(trap_exit, true),
+ case start_flex_scanners() of
+ {ok, PortOrPorts} ->
+ {ok, #state{conf = {flex, PortOrPorts}}};
+ {error, Reason} ->
+ %% {stop, {failed_starting_scanner, Reason, Opts}};
+ {stop, {failed_starting_scanner, Reason, []}};
+ Else ->
+ {stop, {failed_starting_scanner, Else}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_call(get_config, _From, #state{conf = Conf} = S) ->
+ {reply, Conf, S};
+
+handle_call(stop, _From, #state{conf = {flex, PortOrPorts}} = S) ->
+ megaco_flex_scanner:stop(PortOrPorts),
+ Reason = normal,
+ Reply = ok,
+ {stop, Reason, Reply, S};
+
+handle_call(Req, From, S) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {unknown_request, Req}}, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_cast(Msg, S) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%----------------------------------------------------------------------
+handle_info({'EXIT', Port, Error}, #state{conf = {flex, PortOrPorts}} = S) ->
+ case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
+ true ->
+ error_msg("Port [~p] exited:"
+ "~n~w", [Port, Error]),
+ {stop, {port_exit, Port, Error}, S};
+ false ->
+ {noreply, S}
+ end;
+
+handle_info({'EXIT', Port, _Error}, S) when is_port(Port) ->
+ %% This is propably the old flex scanner,
+ %% terminating after a code change...
+ {noreply, S};
+
+handle_info({'EXIT', Id, Error}, S) ->
+ warning_msg("received unexpected 'EXIT' signal from ~p:"
+ "~n~w", [Id, Error]),
+ {noreply, S};
+
+handle_info(Info, S) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, S}.
+
+
+%%----------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%----------------------------------------------------------------------
+terminate(_Reason, _S) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Called to change the internal state
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+%% code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_8) ->
+%% Port = downgrade_flex_scanner(Conf),
+%% {ok, State#state{conf = {flex, Port}}};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+%% downgrade_flex_scanner({flex, Port}) when is_port(Port) ->
+%% Port;
+%% downgrade_flex_scanner({flex, [Port]}) when is_port(Port) ->
+%% Port;
+%% downgrade_flex_scanner({flex, Ports}) when is_list(Ports) ->
+%% megaco_flex_scanner:stop(Ports),
+%% case megaco_flex_scanner:start() of
+%% {ok, Port} ->
+%% Port;
+%% Error ->
+%% exit(Error)
+%% end;
+%% downgrade_flex_scanner(BadConfig) ->
+%% exit({invalid_config, BadConfig}).
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+start_flex_scanners() ->
+ megaco_flex_scanner:start().
+
+
+%% get_env(Key, Opts, Default) ->
+%% case lists:keysearch(Key, 1, Opts) of
+%% {value, {Key, Value}} ->
+%% Value;
+%% false ->
+%% Default
+%% end.
+
+warning_msg(F, A) ->
+ ?megaco_warning("Flex scanner handler: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("Flex scanner handler: " ++ F, A).
+
+
+
+% d(F, A) ->
+% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/megaco/src/flex/modules.mk b/lib/megaco/src/flex/modules.mk
new file mode 100644
index 0000000000..fb9957cffd
--- /dev/null
+++ b/lib/megaco/src/flex/modules.mk
@@ -0,0 +1,27 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco_flex_scanner \
+ megaco_flex_scanner_handler
+
+FLEX_MODULES = megaco_flex_scanner_drv
+
+STD_DRV = megaco_flex_scanner_drv
+MT_DRV = megaco_flex_scanner_drv_mt
diff --git a/lib/megaco/src/flex/prebuild.skip b/lib/megaco/src/flex/prebuild.skip
new file mode 100644
index 0000000000..9c558e357c
--- /dev/null
+++ b/lib/megaco/src/flex/prebuild.skip
@@ -0,0 +1 @@
+.
diff --git a/lib/megaco/src/rules.mk b/lib/megaco/src/rules.mk
new file mode 100644
index 0000000000..20fbed2a76
--- /dev/null
+++ b/lib/megaco/src/rules.mk
@@ -0,0 +1,100 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+.SUFFIXES: .erl .jam .beam .yrl .hrl .sgml .html .so .c .flex .flex.src
+
+
+CC = gcc
+CFLAGS = -g -O2 -funroll-loops -Wall -fPIC
+FLEX = flex
+PERL = perl
+
+# ----------------------------------------------------
+# Erlang language section
+# ----------------------------------------------------
+EMULATOR = beam
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+# VxWorks jam object files should be compressed
+ERL_COMPILE_FLAGS += +compressed
+endif
+ERLC_WFLAGS = -W
+ERLC = erlc $(ERLC_WFLAGS) $(ERLC_FLAGS)
+ERL.beam = erl.beam -boot start_clean
+ERL.jam = erl -boot start_clean
+ERL = $(ERL.$(EMULATOR))
+
+ifndef EBIN
+EBIN = ../ebin
+endif
+
+ifndef ESRC
+ESRC = .
+endif
+
+$(EBIN)/%.jam: $(ESRC)/%.erl
+ $(ERLC) -bjam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+$(EBIN)/%.beam: $(ESRC)/%.erl
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+.erl.jam:
+ $(ERLC) -bjam $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
+
+.erl.beam:
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(dir $@) $<
+
+#
+# When .erl files are automatically created GNU make removes them if
+# they were the result of a chain of implicit rules. To prevent this
+# we say that all .erl files are "precious".
+#
+.PRECIOUS: %.erl
+
+## Uncomment these lines and add .idl to suffixes above to have erlc
+## eat IDL files
+##.idl.erl:
+## $(ERLC) $(IDL_FLAGS) $<
+
+.yrl.erl:
+ $(ERLC) $(YRL_FLAGS) $<
+
+.xrl.erl:
+ $(ERLC) $(XRL_FLAGS) $<
+
+## generating app files
+
+$(EBIN)/%.app: $(ESRC)/%.app.src $(VSN_FILE)
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(EBIN)/%.appup: $(ESRC)/%.appup.src $(VSN_FILE)
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+
+.c.so:
+ $(CC) $(CFLAGS) -fpic -shared -o $*.so $< -lfl
+
+
+# ----------------------------------------------------
+# Command macros
+# ----------------------------------------------------
+INSTALL = /usr/ucb/install -c
+INSTALL_DIR = /usr/ucb/install -c -d
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
diff --git a/lib/megaco/src/subdirs.mk b/lib/megaco/src/subdirs.mk
new file mode 100644
index 0000000000..af1a679561
--- /dev/null
+++ b/lib/megaco/src/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+SUB_DIRECTORIES = app engine text flex binary tcp udp
+
diff --git a/lib/megaco/src/tcp/Makefile b/lib/megaco/src/tcp/Makefile
new file mode 100644
index 0000000000..0bd4b7c4ee
--- /dev/null
+++ b/lib/megaco/src/tcp/Makefile
@@ -0,0 +1,107 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/tcp
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/tcp
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/tcp/depend.mk b/lib/megaco/src/tcp/depend.mk
new file mode 100644
index 0000000000..27b0feec94
--- /dev/null
+++ b/lib/megaco/src/tcp/depend.mk
@@ -0,0 +1,42 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+$(EBIN)/megaco_tcp.$(EMULATOR): megaco_tcp.erl \
+ megaco_tcp.hrl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_accept.$(EMULATOR): megaco_tcp_accept.erl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_connection.$(EMULATOR): megaco_tcp_connection.erl \
+ megaco_tcp.hrl \
+ ../app/megaco_internal.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_sup.$(EMULATOR): megaco_tcp_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_connection_sup.$(EMULATOR): megaco_tcp_connection_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_tcp_accept_sup.$(EMULATOR): megaco_tcp_accept_sup.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl
+
diff --git a/lib/megaco/src/tcp/megaco_tcp.erl b/lib/megaco/src/tcp/megaco_tcp.erl
new file mode 100644
index 0000000000..45fd35eabc
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp.erl
@@ -0,0 +1,692 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%%
+%% Purpose:
+%% Interface the TPKT (TCP/IP) transport module for Megaco/H.248
+%%
+%%-----------------------------------------------------------------
+-module(megaco_tcp).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
+-define(d2(F), ?d1(F, [])).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_transport/0, %% Start TPKT transport service
+ stop_transport/1, %% Stop TPKT transport service
+ listen/2, %% Starts a new listener socket
+ connect/2, %% Used on client side to connect server
+ socket/1, %% Returns the inet socket
+ send_message/2, %% Used to send data on connection
+ block/1, %% Used to block the socket for incomming
+ %% messages
+ unblock/1, %% Used to unblock the node
+ close/1, %% Used on both sides to close connection
+
+ upgrade_receive_handle/2
+ ]).
+
+%% Statistics exports
+-export([
+ get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1, %% Start TCP/IP net server
+ init/1, %%
+ terminate/2,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ start_connection/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Server state record
+%%-----------------------------------------------------------------
+-record(state, {supervisor_pid, linkdb}).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_stats:get_stats(megaco_tcp_stats).
+
+get_stats(Socket) ->
+ megaco_stats:get_stats(megaco_tcp_stats, Socket).
+
+get_stats(Socket, Counter) ->
+ megaco_stats:get_stats(megaco_tcp_stats, Socket, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_tcp_stats).
+
+reset_stats(Socket) ->
+ megaco_stats:reset_stats(megaco_tcp_stats, Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_transport/0
+%% Description: Starts the TPKT transport service
+%%-----------------------------------------------------------------
+start_transport() ->
+ ?d2("start_transport -> entry"),
+ (catch megaco_stats:init(megaco_tcp_stats)),
+ megaco_tcp_sup:start_link().
+
+
+%%-----------------------------------------------------------------
+%% Func: stop_transport/1, 2
+%% Description: Stop the TPKT transport service
+%%-----------------------------------------------------------------
+stop_transport(Pid) ->
+ (catch unlink(Pid)),
+ stop_transport(Pid, shutdown).
+
+stop_transport(Pid, Reason) ->
+ ?d1("stop_transport -> entry with"
+ "~n Pid: ~p"
+ "~n Reason: ~p", [Pid, Reason]),
+ exit(Pid, Reason).
+
+
+%%-----------------------------------------------------------------
+%% Func: listen/2
+%% Description: Starts new TPKT listener sockets
+%%-----------------------------------------------------------------
+listen(SupPid, Parameters) ->
+ ?d1("listen -> entry with"
+ "~n SupPid: ~p"
+ "~n Parameters: ~p", [SupPid, Parameters]),
+ ProcList = supervisor:which_children(SupPid),
+ case lists:keysearch(megaco_tcp, 1, ProcList) of
+ {value, {_Name, Pid, _Type, _Modules}} ->
+ ?d1("listen -> found listener: "
+ "~n Pid: ~p", [Pid]),
+ call(Pid, {add_listener, Parameters});
+ false ->
+ {error, no_tcp_server}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: connect
+%% Description: Function is used when opening an TCP socket
+%% at the MG side when trying to connect an MGC
+%%-----------------------------------------------------------------
+connect(SupPid, Parameters) ->
+ ?d1("connect -> entry with"
+ "~n SupPid: ~p"
+ "~n Parameters: ~p", [SupPid, Parameters]),
+ Mand = [host, port, receive_handle],
+ case parse_options(Parameters, #megaco_tcp{}, Mand) of
+ {ok, Rec} ->
+
+ ?d1("connect -> options parsed: "
+ "~n Rec: ~p", [Rec]),
+
+ #megaco_tcp{host = Host,
+ port = Port,
+ options = Options} = Rec,
+
+ IpOpt = [binary, {packet, tpkt}, {active, once} | Options],
+
+ %%------------------------------------------------------
+ %% Connect the other side
+ case (catch gen_tcp:connect(Host, Port, IpOpt)) of
+ {ok, Socket} ->
+ ?d1("connect -> connected: "
+ "~n Socket: ~p", [Socket]),
+ %%----------------------------------------------
+ %% Socket up start a new control process
+ Rec2 = Rec#megaco_tcp{socket = Socket},
+ case start_connection(SupPid, Rec2) of
+ {ok, Pid} ->
+ ?d1("connect -> connection started: "
+ "~n Pid: ~p", [Pid]),
+ gen_tcp:controlling_process(Socket, Pid),
+ ?d2("connect -> control transferred"),
+ {ok, Socket, Pid};
+ {error, Reason} ->
+ ?d1("connect -> failed starting connection: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end;
+
+ {error, Reason} ->
+ ?d1("connect -> failed connecting: "
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {gen_tcp_connect, Reason}},
+ ?tcp_debug(Rec, "tcp connect failed", [Error]),
+ Error;
+
+ {'EXIT', _Reason} = Exit ->
+ ?d1("connect -> connect exited: "
+ "~n Exit: ~p", [Exit]),
+ Error = {error, {gen_tcp_connect, Exit}},
+ ?tcp_debug(Rec, "tcp connect failed", [Error]),
+ Error
+
+ end;
+
+ {error, _Reason} = Error ->
+ ?d1("connect -> failed parsing options: "
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(#megaco_tcp{}, "tcp connect failed",
+ [Error, {options, Parameters}]),
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: send_message
+%% Description: Function is used for sending data on the TCP socket
+%%-----------------------------------------------------------------
+send_message(Socket, Data) ->
+ ?d1("send_message -> entry with"
+ "~n Socket: ~p"
+ "~n size(Data): ~p", [Socket, sz(Data)]),
+ {Size, NewData} = add_tpkt_header(Data),
+ Res = gen_tcp:send(Socket, NewData),
+ case Res of
+ ok ->
+ incNumOutMessages(Socket),
+ incNumOutOctets(Socket, Size);
+ _ ->
+ ok
+ end,
+ Res.
+
+-ifdef(megaco_debug).
+sz(Bin) when is_binary(Bin) ->
+ size(Bin);
+sz(List) when is_list(List) ->
+ length(List).
+-endif.
+
+
+%%-----------------------------------------------------------------
+%% Func: block
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+block(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp block", []),
+ inet:setopts(Socket, [{active, false}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: unblock
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+unblock(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp unblock", []),
+ inet:setopts(Socket, [{active, once}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: close
+%% Description: Function is used for closing the TCP socket
+%%-----------------------------------------------------------------
+close(Socket) ->
+ ?tcp_debug({socket, Socket}, "tcp close", []),
+ gen_tcp:close(Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: socket
+%% Description: Returns the inet socket
+%%-----------------------------------------------------------------
+socket(Socket) ->
+ Socket.
+
+upgrade_receive_handle(Pid, NewHandle)
+ when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) ->
+ megaco_tcp_connection:upgrade_receive_handle(Pid, NewHandle).
+
+
+%%-----------------------------------------------------------------
+%% Internal Interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the net server
+%%-----------------------------------------------------------------
+start_link(Args) ->
+ gen_server:start_link(?MODULE, Args, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_connection
+%% Description: Function is used for starting up a connection
+%% process
+%%-----------------------------------------------------------------
+start_connection(SupPid, #megaco_tcp{socket = Socket} = TcpRec) ->
+ ?d1("start_connection -> entry with"
+ "~n SupPid: ~p"
+ "~n Socket: ~p", [SupPid, Socket]),
+
+ case connection_sup(SupPid) of
+ {ok, ConnSupPid} ->
+ ?d1("start_connection -> found connection supervisor: "
+ "~n ConnSupPid: ~p", [ConnSupPid]),
+ ?tcp_debug(TcpRec, "tcp connect", []),
+ case create_connection(ConnSupPid, TcpRec) of
+ {ok, Pid} ->
+ ?d1("start_connection -> started: "
+ "~n Pid: ~p", [Pid]),
+ ?tcp_debug(TcpRec, "connect handler started", [Pid]),
+ create_snmp_counters(Socket),
+ {ok, Pid};
+ {error, Reason} ->
+ ?d1("start_connection -> failed starting: "
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {controlling_process_not_started, Reason}},
+ ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
+ Error
+ end;
+ {error, _Reason} ->
+ ?d2("start_connection -> could not find connection supervisor"),
+ Error = {error, no_connection_supervisor},
+ ?tcp_debug(TcpRec, "tcp connect failed", [Error]),
+ Error
+ end.
+
+connection_sup(Pid) ->
+ megaco_tcp_sup:which_connection_sup(Pid).
+
+create_connection(Pid, Rec) ->
+ megaco_tcp_connection_sup:start_child(Pid, Rec).
+
+create_snmp_counters(Socket) ->
+ Counters = [medGwyGatewayNumInMessages,
+ medGwyGatewayNumInOctets,
+ medGwyGatewayNumOutMessages,
+ medGwyGatewayNumOutOctets,
+ medGwyGatewayNumErrors],
+ create_snmp_counters(Socket, Counters).
+
+create_snmp_counters(_Socket, []) ->
+ ok;
+create_snmp_counters(Socket, [Counter|Counters]) ->
+ Key = {Socket, Counter},
+ ets:insert(megaco_tcp_stats, {Key, 0}),
+ create_snmp_counters(Socket, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init({SupPid, _}) ->
+ process_flag(trap_exit, true),
+ {ok, #state{supervisor_pid = SupPid}}.
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Internal Functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_tcp_listener/2
+%% Description: Function which parses the list of transport layers
+%% to start
+%%-----------------------------------------------------------------
+start_tcp_listener(P, State) ->
+ ?d1("start_tcp_listener -> entry with"
+ "~n P: ~p", [P]),
+ case setup(State#state.supervisor_pid, P) of
+ {ok, Pid, Data} ->
+ ?d1("start_tcp_listener -> setup ok"
+ "~n Pid: ~p"
+ "~n Data: ~p", [Pid, Data]),
+ link(Pid),
+ {reply, ok,
+ State#state{linkdb=[{Pid, Data} | State#state.linkdb]}};
+ {error, Reason} ->
+ ?d1("start_tcp_listener -> setup failed"
+ "~n Reason: ~p", [Reason]),
+ {reply, {error, {could_not_start_listener, Reason}}, State}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just garbage)
+%%-----------------------------------------------------------------
+handle_call({add_listener, Parameters}, _From, State) ->
+ ?d1("handle_call(add_listener) -> entry with"
+ "~n Parameters: ~p", [Parameters]),
+ start_tcp_listener(Parameters, State);
+handle_call(Req, From, State) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {noreply, State}.
+
+
+%%------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just garbage)
+%%------------------------------------------------------------
+handle_cast(Msg, State) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, State}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages, eg exit messages
+%%-----------------------------------------------------------------
+handle_info({'EXIT', Pid, Reason}, State) when is_pid(Pid) ->
+ %% Accept process died
+ NewState = resetup(Pid, Reason, State),
+ {noreply, NewState};
+handle_info(Info, State) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, State}.
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: setup/2
+%% Description: Function is used when setting up an TCP listen
+%% socket in the MGC
+%%-----------------------------------------------------------------
+setup(SupPid, Options) ->
+ ?d1("setup -> entry with"
+ "~n SupPid: ~p"
+ "~n Options: ~p", [SupPid, Options]),
+ Mand = [port, receive_handle],
+ case parse_options(Options, #megaco_tcp{}, Mand) of
+ {ok, TcpRec} ->
+
+ ?d1("setup -> options parsed"
+ "~n TcpRec: ~p", [TcpRec]),
+
+ %%------------------------------------------------------
+ %% Setup the listen socket
+ IpOpts = [binary, {packet, tpkt}, {active, once},
+ {reuseaddr, true} | TcpRec#megaco_tcp.options],
+ case catch gen_tcp:listen(TcpRec#megaco_tcp.port, IpOpts) of
+ {ok, Listen} ->
+
+ ?d1("setup -> listen ok"
+ "~n Listen: ~p", [Listen]),
+
+ %%-----------------------------------------------
+ %% Startup the accept process that will wait for
+ %% connect attempts
+ case start_accept(SupPid, TcpRec, Listen) of
+ {ok, Pid} ->
+
+ ?d1("setup -> accept process started"
+ "~n Pid: ~p", [Pid]),
+
+ ?tcp_debug(TcpRec, "tcp listen setup", []),
+ {ok, Pid, {TcpRec, Listen}};
+ {error, _Reason} = Error ->
+ ?d1("setup -> failed starting accept process"
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(TcpRec, "tcp listen setup failed",
+ [Error]),
+ Error
+ end;
+ {error, Reason} ->
+ ?d1("setup -> listen failed"
+ "~n Reason: ~p", [Reason]),
+ Error = {error, {gen_tcp_listen, Reason}},
+ ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
+ Error;
+ {'EXIT', _Reason} = Exit ->
+ ?d1("setup -> listen exited"
+ "~n Exit: ~p", [Exit]),
+ Error = {error, {gen_tcp_listen, Exit}},
+ ?tcp_debug(TcpRec, "tcp listen setup failed", [Error]),
+ Error
+ end;
+ {error, _Reason} = Error ->
+ ?d1("setup -> failed parsing options"
+ "~n Error: ~p", [Error]),
+ ?tcp_debug(#megaco_tcp{}, "tcp listen setup failed",
+ [Error, {options, Options}]),
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: resetup
+%% Description: Function is used when restarting the accept process
+%% if it died for some reason.
+%%-----------------------------------------------------------------
+
+resetup(Pid, Reason, State) ->
+ ?d1("resetup -> entry with"
+ "~n Pid: ~p"
+ "~n Reason: ~p", [Pid, Reason]),
+ case lists:keysearch(Pid, 1, State#state.linkdb) of
+ {value, {Pid, {TcpRec, Listener}}} ->
+ ?d1("resetup -> found accept process: "
+ "~n TcpRec: ~p"
+ "~n Listener: ~p", [TcpRec, Listener]),
+ ?tcp_debug(TcpRec, "tcp listen resetup", [{error, Reason}]),
+ unlink(Pid),
+ warning_msg("received unexpected 'EXIT' signal "
+ "from accept process ~p: "
+ "~n~w", [Pid, Reason]),
+ case start_accept(State#state.supervisor_pid, TcpRec, Listener) of
+ {ok, NewPid} ->
+ ?d1("resetup -> start new accept process ok: "
+ "~n NewPid: ~p", [NewPid]),
+ link(NewPid),
+ NewList = lists:keyreplace(Pid, 1, State#state.linkdb,
+ {NewPid, {TcpRec, Listener}}),
+ State#state{linkdb = NewList};
+ {error, Reason} ->
+ ?d1("resetup -> failed starting new accept process: "
+ "~n :Reason ~p", [Reason]),
+ ?tcp_debug(TcpRec,
+ "tcp listen resetup failed", [{error, Reason}]),
+ State
+ end;
+ false ->
+ warning_msg("received unexpected 'EXIT' signal from ~p: "
+ "~n~w", [Pid, Reason]),
+ State
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: start_accept
+%% Description: Function is used for starting up an TCP accept
+%% process
+%%-----------------------------------------------------------------
+start_accept(SupPid, TcpRec, Listen) ->
+ ?d1("start_accept -> entry with"
+ "~n SupPid: ~p"
+ "~n TcpRec: ~p"
+ "~n Reason: ~p", [SupPid, TcpRec, Listen]),
+ case accept_sup(SupPid) of
+ {ok, AcceptSupPid} ->
+ ?d1("start_accept -> found accept supervisor"
+ "~n AcceptSupPid: ~p", [AcceptSupPid]),
+ case create_acceptor(AcceptSupPid, TcpRec, SupPid, Listen) of
+ {ok, Pid} ->
+ ?d1("start_accept -> accept process started"
+ "~n Pid: ~p", [Pid]),
+ {ok, Pid};
+ {error, Reason} ->
+ ?d1("start_accept -> failed starting accept process: "
+ "~n Reason: ~p", [Reason]),
+ {error, {accept_not_started, Reason}}
+ end;
+ {error, Reason} ->
+ ?d1("start_accept -> could not find acceept supervisor: "
+ "~n Reason: ~p", [Reason]),
+ {error, {no_tcp_accept_sup, Reason}}
+ end.
+
+accept_sup(Pid) ->
+ megaco_tcp_sup:which_accept_sup(Pid).
+
+create_acceptor(Pid, Rec, TopSup, Listen) ->
+ megaco_tcp_accept_sup:start_child(Pid, Rec, TopSup, Listen).
+
+
+%%-----------------------------------------------------------------
+%% Func: add_tpkt_header
+%% Description: Function is used to add the TPKT header
+%%-----------------------------------------------------------------
+add_tpkt_header(Data) when is_binary(Data) ->
+ L = size(Data) + 4,
+ {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff ,Data]};
+add_tpkt_header(IOList) when is_list(IOList) ->
+ Binary = list_to_binary(IOList),
+ L = size(Binary) + 4,
+ {L, [3, 0, ((L) bsr 8) band 16#ff, (L) band 16#ff , Binary]}.
+
+%%-----------------------------------------------------------------
+%% Func: parse_options
+%% Description: Function that parses the options sent to the TCP
+%% module.
+%%-----------------------------------------------------------------
+parse_options([{Tag, Val} | T], TcpRec, Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ Mand2 = Mand -- [Tag],
+ case Tag of
+ port ->
+ parse_options(T, TcpRec#megaco_tcp{port = Val}, Mand2);
+ host ->
+ parse_options(T, TcpRec#megaco_tcp{host = Val}, Mand2);
+ tcp_options when is_list(Val) ->
+ parse_options(T, TcpRec#megaco_tcp{options = Val}, Mand2);
+ receive_handle ->
+ parse_options(T, TcpRec#megaco_tcp{receive_handle = Val}, Mand2);
+ module when is_atom(Val) ->
+ parse_options(T, TcpRec#megaco_tcp{module = Val}, Mand2);
+ serialize when (Val =:= true) orelse (Val =:= false) ->
+ parse_options(T, TcpRec#megaco_tcp{serialize = Val}, Mand2);
+ Bad ->
+ ?d1("parse_options -> bad option: "
+ "~n Tag: ~p", [Tag]),
+ {error, {bad_option, Bad}}
+ end;
+parse_options([], TcpRec, []) ->
+ ?d2("parse_options -> done"),
+ {ok, TcpRec};
+parse_options([], _TcpRec, Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n Mand: ~p", [Mand]),
+ {error, {missing_options, Mand}};
+parse_options(BadList, _TcpRec, _Mand) ->
+ ?d1("parse_options -> entry with"
+ "~n BadList: ~p", [BadList]),
+ {error, {bad_option_list, BadList}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumOutMessages(Socket) ->
+ incCounter({Socket, medGwyGatewayNumOutMessages}, 1).
+
+incNumOutOctets(Socket, NumOctets) ->
+ incCounter({Socket, medGwyGatewayNumOutOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_tcp_stats, Key, Inc).
+
+% incNumErrors(Socket) ->
+% ets:update_counter(megaco_tcp_stats,
+% {Socket, medGwyGatewayNumErrors}, 1).
+
+
+%%-----------------------------------------------------------------
+
+
+warning_msg(F, A) ->
+ ?megaco_warning("TCP server: " ++ F, A).
+
+%% error_msg(F, A) ->
+%% ?megaco_error("TCP server: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
diff --git a/lib/megaco/src/tcp/megaco_tcp.hrl b/lib/megaco/src/tcp/megaco_tcp.hrl
new file mode 100644
index 0000000000..5de1dd9070
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp.hrl
@@ -0,0 +1,68 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Define the protocol options for Megaco/H.248 IP connections
+%%-----------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% IP options
+%%----------------------------------------------------------------------
+-record(megaco_tcp,
+ {host,
+ port,
+ options = [],
+ socket,
+ proxy_pid,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+
+
+-define(GC_MSG_LIMIT,1000).
+-define(HEAP_SIZE(S),5000 + 2*(S)).
+
+
+%%----------------------------------------------------------------------
+%% Event Trace
+%%----------------------------------------------------------------------
+
+-define(tcp_report(Level, TcpRec, From, To, Label, Contents),
+ megaco:report_event(Level, From, To, Label,
+ [{line, ?MODULE, ?LINE}, TcpRec | Contents])).
+
+-define(tcp_debug(TcpRec, Label, Contents),
+ ?tcp_report_debug(TcpRec,
+ megaco_tcp,
+ megaco_tcp,
+ Label,
+ Contents)).
+
+-define(tcp_report_important(C, From, To, Label, Contents),
+ ?tcp_report(20, C, From, To, Label, Contents)).
+-define(tcp_report_verbose(C, From, To, Label, Contents),
+ ?tcp_report(40, C, From, To, Label, Contents)).
+-define(tcp_report_debug(C, From, To, Label, Contents),
+ ?tcp_report(60, C, From, To, Label, Contents)).
+-define(tcp_report_trace(C, From, To, Label, Contents),
+ ?tcp_report(80, C, From, To, Label, Contents)).
+
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_accept.erl b/lib/megaco/src/tcp/megaco_tcp_accept.erl
new file mode 100644
index 0000000000..68bda8a340
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_accept.erl
@@ -0,0 +1,123 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Waiting in accept for new connections.
+%%-----------------------------------------------------------------
+-module(megaco_tcp_accept).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
+-define(d2(F), ?d1(F, [])).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ net_accept/4
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start
+%% Description: Starts the proces that makes the accept call.
+%%-----------------------------------------------------------------
+start_link({TcpRec, SupPid, Listen}) ->
+ Args = [TcpRec, SupPid, Listen, self()],
+ Pid = proc_lib:spawn_link(?MODULE, net_accept, Args),
+ {ok, Pid}.
+
+%%-----------------------------------------------------------------
+%% Internal Interface Functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: net_accept
+%% Description: Loop function which calls accept and
+%% spawns a connection process when there is an initial
+%% contact.
+%%-----------------------------------------------------------------
+net_accept(TcpRec, SupPid, ListenFd, Parent) ->
+ do_accept(TcpRec, SupPid, ListenFd),
+ net_accept(TcpRec, SupPid, ListenFd, Parent).
+
+do_accept(Tcp, Sup, Fd) ->
+ case gen_tcp:accept(Fd) of
+ {ok, S} ->
+ ?d1("do_accept -> accepted: "
+ "~n S: ~p", [S]),
+ case megaco_tcp:start_connection(Sup,
+ Tcp#megaco_tcp{socket = S}) of
+ {ok, Pid} ->
+ ?d1("do_accept -> connection started"
+ "~n Pid: ~p", [Pid]),
+ case gen_tcp:controlling_process(S, Pid) of
+ ok ->
+ ?d2("do_accept -> control transferred"),
+ ok;
+ {error, _Reason} ->
+ ?d1("do_accept -> "
+ "failed changing controlling process: "
+ "n _Reason: ~p", [_Reason]),
+ tcp_clear(S),
+ gen_tcp:close(S)
+ end;
+
+ {error, _Reason} ->
+ ?d1("do_accept -> failed starting connection: "
+ "~n _Reason: ~p", [_Reason]),
+ tcp_clear(S),
+ gen_tcp:close(S)
+ end;
+ {error, _Reason} ->
+ ?d1("do_accept -> accept failed: "
+ "~n _Reason: ~p", [_Reason]),
+ ok
+ end.
+
+
+tcp_clear(Socket) ->
+ receive
+ {tcp, Socket, _Data} ->
+ tcp_clear(Socket);
+ {tcp_closed, Socket} ->
+ tcp_clear(Socket);
+ {tcp_error, Socket} ->
+ tcp_clear(Socket)
+ after 0 ->
+ ok
+ end.
diff --git a/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl b/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl
new file mode 100644
index 0000000000..a601f32558
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_accept_sup.erl
@@ -0,0 +1,95 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Supervisor for the tcp "accept" processes.
+%%-----------------------------------------------------------------
+-module(megaco_tcp_accept_sup).
+
+-behaviour(supervisor).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/4
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the process that keeps track of the TCP
+%% accept processes
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the acceptor process (the TCP accept
+%% processes)
+%%-----------------------------------------------------------------
+start_child(Pid, Rec, Ref, Listen) ->
+ ChildSpec = [{Rec, Ref, Listen}], % Simple one-for-one
+ supervisor:start_child(Pid, ChildSpec).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_Options) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_accept,
+ {megaco_tcp_accept, start_link, []},
+ temporary, 10000, worker, []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_connection.erl b/lib/megaco/src/tcp/megaco_tcp_connection.erl
new file mode 100644
index 0000000000..614edf513a
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_connection.erl
@@ -0,0 +1,275 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%%
+%% Purpose: Handles the Megaco/H.248 TCP connections.
+%%
+%%-----------------------------------------------------------------
+-module(megaco_tcp_connection).
+
+-behaviour(gen_server).
+
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1,
+ stop/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ terminate/2,
+
+ handle_received_message/5
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the proces that keeps track of an TCP
+%% connection.
+%%-----------------------------------------------------------------
+
+start_link(Arg) ->
+ gen_server:start_link(?MODULE, Arg, []).
+
+
+stop(Pid) ->
+ call(Pid, stop).
+
+
+upgrade_receive_handle(Pid, NewHandle) ->
+ call(Pid, {upgrade_receive_handle, NewHandle}).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the generic server
+%%-----------------------------------------------------------------
+init(Arg) ->
+ %% process_flag(trap_exit, true),
+ ?tcp_debug(Arg, "tcp connection handler starting", [self()]),
+%% info_msg("starting with"
+%% "~n Arg: ~p", [Arg]),
+ {ok, Arg}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_call(stop, _From, TcpRec) ->
+ {stop, shutdown, ok, TcpRec};
+handle_call({upgrade_receive_handle, NewHandle}, _From, TcpRec) ->
+ {reply, ok, TcpRec#megaco_tcp{receive_handle = NewHandle}};
+handle_call(Req, From, TcpRec) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~w", [From, Req]),
+ {reply, {error, {invalid_request, Req}}, TcpRec}.
+
+
+%%-----------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_cast(stop, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_cast(Msg, TcpRec) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, TcpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages. Incomming messages
+%% from the socket and exit messages.
+%%-----------------------------------------------------------------
+handle_info({tcp_closed, _Socket}, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_info({tcp_error, _Socket}, TcpRec) ->
+ {stop, shutdown, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = false} = TcpRec)
+ when Length < ?GC_MSG_LIMIT ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ apply(Mod, receive_message, [RH, self(), Socket, Msg]),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = false} = TcpRec) ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ receive_message(Mod, RH, Socket, Length, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, <<3:8, _X:8, _Length:16, Msg/binary>>},
+ #megaco_tcp{socket = Socket, serialize = true} = TcpRec) ->
+ #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
+ incNumInMessages(Socket),
+ incNumInOctets(Socket, 4+size(Msg)),
+ process_received_message(Mod, RH, Socket, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, TcpRec};
+handle_info({tcp, Socket, Msg}, TcpRec) ->
+ incNumErrors(Socket),
+ error_msg("received bad tpkt packet: "
+ "~n~w", [Msg]),
+ {noreply, TcpRec};
+handle_info(Info, TcpRec) ->
+ warning_msg("received unexpected info: "
+ "~n~p", [Info]),
+ {noreply, TcpRec}.
+
+
+process_received_message(Mod, RH, SH, Msg) ->
+ case (catch Mod:process_received_message(RH, self(), SH, Msg)) of
+ ok ->
+ ok;
+ Error ->
+ error_msg("failed processing received message: "
+ "~n~p", [Error]),
+ ok
+ end.
+
+
+receive_message(Mod, RH, SendHandle, Length, Msg) ->
+ Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}],
+ spawn_opt(?MODULE, handle_received_message,
+ [Mod, RH, self(), SendHandle, Msg], Opts),
+ ok.
+
+
+handle_received_message(Mod, RH, Parent, SH, Msg) ->
+ Mod:process_received_message(RH, Parent, SH, Msg),
+ unlink(Parent),
+ exit(normal).
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(shutdown = _Reason, TcpRec) ->
+ ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(),_Reason]),
+ ok;
+
+terminate(Reason, TcpRec) ->
+ ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(), Reason]),
+ SchedId = erlang:system_info(scheduler_id),
+ SchedNum = erlang:system_info(schedulers),
+ ProcCount = erlang:system_info(process_count),
+ ProcLimit = erlang:system_info(process_limit),
+ ProcMemUsed = erlang:memory(processes_used),
+ ProcMemAlloc = erlang:memory(processes),
+ MemTot = erlang:memory(total),
+ error_msg("abormal termination: "
+ "~n Scheduler id: ~p"
+ "~n Num scheduler: ~p"
+ "~n Process count: ~p"
+ "~n Process limit: ~p"
+ "~n Memory used by erlang processes: ~p"
+ "~n Memory allocated by erlang processes: ~p"
+ "~n The total amount of memory allocated: ~p"
+ "~n~p",
+ [SchedId, SchedNum, ProcCount, ProcLimit,
+ ProcMemUsed, ProcMemAlloc, MemTot, Reason]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_OldVsn, S, _Extra) ->
+ ?d("code_change -> entry with"
+ "~n OldVsn: ~p"
+ "~n S: ~p"
+ "~n Extra: ~p", [_OldVsn, S, _Extra]),
+ {ok, S}.
+
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumInMessages(Socket) ->
+ incCounter({Socket, medGwyGatewayNumInMessages}, 1).
+
+incNumInOctets(Socket, NumOctets) ->
+ incCounter({Socket, medGwyGatewayNumInOctets}, NumOctets).
+
+incNumErrors(Socket) ->
+ incCounter({Socket, medGwyGatewayNumErrors}, 1).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_tcp_stats, Key, Inc).
+
+
+%% info_msg(F, A) ->
+%% ?megaco_info("TCP connection handler " ++ F, A).
+
+warning_msg(F, A) ->
+ ?megaco_warning("TCP connection handler: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("TCP connection handler: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
+
diff --git a/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl b/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl
new file mode 100644
index 0000000000..0ca8697418
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_connection_sup.erl
@@ -0,0 +1,114 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Supervisor for all active connections
+%% independent of transport protocol.
+%%-----------------------------------------------------------------
+
+-module(megaco_tcp_connection_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2,
+ start_connection/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link
+%% Description: Starts the connection supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, [[]]).
+
+
+%% -----------------------------------------------------------------
+%% Func: start_child/2
+%% DEscription: Start a child (the connection) process
+%% -----------------------------------------------------------------
+start_child(Pid, TcpRec) ->
+ supervisor:start_child(Pid, [TcpRec]).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_connection/1
+%% Description: Function which the supervisor calls to start a child
+%%-----------------------------------------------------------------
+start_connection(Args) ->
+ megaco_tcp_connection:start_link(Args).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_tcp_connection,
+ {?MODULE, start_connection, []},
+ temporary,
+ 10000,
+ worker,
+ []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
diff --git a/lib/megaco/src/tcp/megaco_tcp_sup.erl b/lib/megaco/src/tcp/megaco_tcp_sup.erl
new file mode 100644
index 0000000000..6afc7582ec
--- /dev/null
+++ b/lib/megaco/src/tcp/megaco_tcp_sup.erl
@@ -0,0 +1,145 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Supervisor
+%%-----------------------------------------------------------------
+-module(megaco_tcp_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ which_accept_sup/1,
+ which_connection_sup/1,
+ start_accept_child/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Start an megaco net element supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+
+%%-----------------------------------------------------------------
+%% Func: which_accept_sup/1
+%% Description: Get the pid() of the accept supervisor process
+%%-----------------------------------------------------------------
+which_accept_sup(Pid) ->
+ which_child(Pid, megaco_tcp_accept_sup).
+
+
+%%-----------------------------------------------------------------
+%% Func: which_connection_sup/1
+%% Description: Get the pid() of the connection supervisor process
+%%-----------------------------------------------------------------
+which_connection_sup(Pid) ->
+ which_child(Pid, megaco_tcp_connection_sup).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_accept_child/1
+%% Description: Starts the process that keeps track of the TCP
+%% accept processes
+%%-----------------------------------------------------------------
+start_accept_child(SupPid, Data) ->
+ case supervisor:start_child(SupPid,
+ {megaco_tcp_accept,
+ {megaco_tcp_accept, start_link, [Data]},
+ temporary, 10000, worker,
+ [megaco_tcp_accept]}) of
+ {ok, ChildPid} ->
+ ChildPid;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init([]) ->
+ SupFlags = {one_for_one, 5, 1000}, % Max 5 restarts in 1 second
+ ChildSpec = [sup_spec(megaco_tcp_accept_sup, []),
+ sup_spec(megaco_tcp_connection_sup,[]),
+ worker_spec(megaco_tcp, [{self(), []}], [gen_server])],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Local functions
+%%-----------------------------------------------------------------
+
+which_child(Pid, Name) ->
+ ProcList = supervisor:which_children(Pid),
+ %% ProcList of type [{Name, Pid, Type, Modules}]
+ case lists:keysearch(Name, 1, ProcList) of
+ {value, {_Name, ChildPid, _Type, _Modules}} ->
+ {ok, ChildPid};
+ false ->
+ {error, no_such_process}
+ end.
+
+
+sup_spec(Name, Args) ->
+ {Name,
+ {Name, start_link, Args},
+ permanent, 10000, supervisor, [Name, supervisor]}.
+
+worker_spec(Name, Args, Mods) ->
+ {Name, {Name, start_link, Args},
+ permanent, 10000, worker, [Name] ++ Mods}.
+
diff --git a/lib/megaco/src/tcp/modules.mk b/lib/megaco/src/tcp/modules.mk
new file mode 100644
index 0000000000..505bd67792
--- /dev/null
+++ b/lib/megaco/src/tcp/modules.mk
@@ -0,0 +1,33 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco_tcp \
+ megaco_tcp_sup \
+ megaco_tcp_accept \
+ megaco_tcp_accept_sup \
+ megaco_tcp_connection \
+ megaco_tcp_connection_sup
+
+
+INTERNAL_HRL_FILES = \
+ megaco_tcp.hrl
+
+
+
diff --git a/lib/megaco/src/text/Makefile b/lib/megaco/src/text/Makefile
new file mode 100644
index 0000000000..b2e8e762dd
--- /dev/null
+++ b/lib/megaco/src/text/Makefile
@@ -0,0 +1,148 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = \
+ $(MODULES:%=%.erl) \
+ $(INTERNAL_YRL_FILES:%.yrl=%.erl)
+
+ERL_TARGET_FILES = \
+ $(INTERNAL_YRL_FILES:%.yrl=%.erl)
+
+BEAM_TARGET_FILES = \
+ $(INTERNAL_YRL_FILES:%.yrl=$(EBIN)/%.$(EMULATOR)) \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+TARGET_FILES = $(ERL_TARGET_FILES) $(BEAM_TARGET_FILES)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+# YRL_FLAGS += -pa /clearcase/otp/tools/parsetools/ebin
+
+ifeq ($(YRL_VERBOSE),true)
+YRL_FLAGS += -v
+endif
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo ""
+ @echo "ERL_FILES = $(ERL_FILES)"
+ @echo ""
+ @echo "ERL_TARGET_FILES = $(ERL_TARGET_FILES)"
+ @echo ""
+ @echo "BEAM_TARGET_FILES = $(BEAM_TARGET_FILES)"
+ @echo ""
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "INTERNAL_YRL_FILES = $(INTERNAL_YRL_FILES)"
+ @echo ""
+ @echo "INTERNAL_HRL_FILES = $(INTERNAL_HRL_FILES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+parser: parser_v1 parser_v2 parser_prev3a parser_prev3b
+
+parser_v1: megaco_text_parser_v1.$(EMULATOR)
+
+parser_v2: megaco_text_parser_v2.$(EMULATOR)
+
+parser_prev3a: megaco_text_parser_prev3a.$(EMULATOR)
+
+parser_prev3b: megaco_text_parser_prev3b.$(EMULATOR)
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(BEAM_TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/text
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_YRL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/text
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+include depend.mk
+
diff --git a/lib/megaco/src/text/depend.mk b/lib/megaco/src/text/depend.mk
new file mode 100644
index 0000000000..62d0811692
--- /dev/null
+++ b/lib/megaco/src/text/depend.mk
@@ -0,0 +1,187 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+megaco_text_parser_v1.erl: \
+ megaco_text_parser_v1.yrl \
+ megaco_text_parser_v1.hrl
+megaco_text_parser_v2.erl: \
+ megaco_text_parser_v2.yrl \
+ megaco_text_parser_v2.hrl
+megaco_text_parser_v3.erl: \
+ megaco_text_parser_v3.yrl \
+ megaco_text_parser_v3.hrl
+megaco_text_parser_prev3a.erl: \
+ megaco_text_parser_prev3a.yrl \
+ megaco_text_parser_prev3a.hrl
+megaco_text_parser_prev3b.erl: \
+ megaco_text_parser_prev3b.yrl \
+ megaco_text_parser_prev3b.hrl
+megaco_text_parser_prev3c.erl: \
+ megaco_text_parser_prev3c.yrl \
+ megaco_text_parser_prev3c.hrl
+
+megaco_text_mini_parser.erl: \
+ megaco_text_mini_parser.yrl \
+ megaco_text_mini_parser.hrl
+
+$(EBIN)/megaco_compact_text_encoder.$(EMULATOR): \
+ megaco_compact_text_encoder.erl
+
+$(EBIN)/megaco_compact_text_encoder.$(EMULATOR): \
+ megaco_compact_text_encoder.erl
+
+$(EBIN)/megaco_compact_text_encoder_v1.$(EMULATOR): \
+ megaco_compact_text_encoder_v1.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v1.hrl
+
+$(EBIN)/megaco_compact_text_encoder_v2.$(EMULATOR): \
+ megaco_compact_text_encoder_v2.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v2.hrl
+
+$(EBIN)/megaco_compact_text_encoder_v3.$(EMULATOR): \
+ megaco_compact_text_encoder_v3.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v3.hrl
+
+$(EBIN)/megaco_compact_text_encoder_prev3a.$(EMULATOR): \
+ megaco_compact_text_encoder_prev3a.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3a.hrl
+
+$(EBIN)/megaco_compact_text_encoder_prev3b.$(EMULATOR): \
+ megaco_compact_text_encoder_prev3b.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3b.hrl
+
+$(EBIN)/megaco_compact_text_encoder_prev3c.$(EMULATOR): \
+ megaco_compact_text_encoder_prev3c.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3c.hrl
+
+$(EBIN)/megaco_pretty_text_encoder.$(EMULATOR): \
+ megaco_pretty_text_encoder.erl
+
+$(EBIN)/megaco_pretty_text_encoder_v1.$(EMULATOR): \
+ megaco_pretty_text_encoder_v1.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v1.hrl
+
+$(EBIN)/megaco_pretty_text_encoder_v2.$(EMULATOR): \
+ megaco_pretty_text_encoder_v2.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v2.hrl
+
+$(EBIN)/megaco_pretty_text_encoder_v3.$(EMULATOR): \
+ megaco_pretty_text_encoder_v3.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_v3.hrl
+
+$(EBIN)/megaco_pretty_text_encoder_prev3a.$(EMULATOR): \
+ megaco_pretty_text_encoder_prev3a.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3a.hrl
+
+$(EBIN)/megaco_pretty_text_encoder_prev3b.$(EMULATOR): \
+ megaco_pretty_text_encoder_prev3b.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3b.hrl
+
+$(EBIN)/megaco_pretty_text_encoder_prev3c.$(EMULATOR): \
+ megaco_pretty_text_encoder_prev3c.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_gen_prev3c.hrl
+
+$(EBIN)/megaco_text_parser_v1.$(EMULATOR): \
+ megaco_text_parser_v1.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v1.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_v1.hrl
+
+$(EBIN)/megaco_text_parser_v2.$(EMULATOR): \
+ megaco_text_parser_v2.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v2.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_v2.hrl
+
+$(EBIN)/megaco_text_parser_v3.$(EMULATOR): \
+ megaco_text_parser_v3.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_v3.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_v3.hrl
+
+$(EBIN)/megaco_text_parser_prev3a.$(EMULATOR): \
+ megaco_text_parser_prev3a.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3a.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_prev3a.hrl
+
+$(EBIN)/megaco_text_parser_prev3b.$(EMULATOR): \
+ megaco_text_parser_prev3b.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3b.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_prev3b.hrl
+
+$(EBIN)/megaco_text_parser_prev3c.$(EMULATOR): \
+ megaco_text_parser_prev3c.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ $(MEGACO_INCLUDEDIR)/megaco_message_prev3c.hrl \
+ megaco_text_tokens.hrl \
+ megaco_text_parser_prev3c.hrl
+
+$(EBIN)/megaco_text_scanner.$(EMULATOR): megaco_text_scanner.erl \
+ $(MEGACO_INCLUDEDIR)/megaco.hrl \
+ ../engine/megaco_message_internal.hrl \
+ megaco_text_tokens.hrl
+
+$(EBIN)/megaco_text_mini_decoder.$(EMULATOR): \
+ megaco_text_mini_decoder.erl \
+ ../engine/megaco_message_internal.hrl \
+ megaco_text_tokens.hrl
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder.erl b/lib/megaco/src/text/megaco_compact_text_encoder.erl
new file mode 100644
index 0000000000..f5195bda14
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder.erl
@@ -0,0 +1,560 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ version_of/2,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_command_request/3,
+ encode_action_reply/3]).
+
+-export([token_tag2string/1, token_tag2string/2]).
+
+%% Backward compatible funcs:
+-export([encode_message/2, decode_message/2]).
+
+
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_PARSE_MOD, megaco_text_parser_v1).
+-define(V2_PARSE_MOD, megaco_text_parser_v2).
+-define(V3_PARSE_MOD, megaco_text_parser_v3).
+-define(PREV3A_PARSE_MOD, megaco_text_parser_prev3a).
+-define(PREV3B_PARSE_MOD, megaco_text_parser_prev3b).
+-define(PREV3C_PARSE_MOD, megaco_text_parser_prev3c).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EncodingConfig,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EncodingConfig, V, MegaMsg).
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg);
+encode_message(EC, 1, MegaMsg) ->
+ megaco_compact_text_encoder_v1:encode_message(EC, MegaMsg);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg);
+encode_message(EC, 2, MegaMsg) ->
+ megaco_compact_text_encoder_v2:encode_message(EC, MegaMsg);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ megaco_compact_text_encoder_prev3c:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ megaco_compact_text_encoder_prev3b:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ megaco_compact_text_encoder_prev3a:encode_message(EC, MegaMsg);
+encode_message(EC, 3, MegaMsg) ->
+ megaco_compact_text_encoder_v3:encode_message(EC, MegaMsg);
+encode_message(_EC, V, _MegaMsg) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(_EC, Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, _Tokens, V, _LastLine} ->
+ {ok, V};
+ {error, Reason, Line} ->
+ {error, {decode_failed, Reason, Line}}
+ end.
+
+decode_message(EC, Bin) ->
+ %% d("decode_message -> entry with"
+ %% "~n EC: ~p", [EC]),
+ decode_message(EC, dynamic, Bin).
+
+decode_message([], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message([]) -> entry"),
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,v3}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(v3) -> entry"),
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3c}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3c) -> entry"),
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3b}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3b) -> entry"),
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3a}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3a) -> entry"),
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{flex, Port}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(flex) -> entry"),
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,v3},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(v3,flex) -> entry"),
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3c},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3c,flex) -> entry"),
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} ->
+ scan_error(Reason, Line, Bin)
+ end;
+decode_message([{version3,prev3b},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3b,flex) -> entry"),
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3a},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ %% d("decode_message(prev3a,flex) -> entry"),
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message(EC, _, Bin) when is_binary(Bin) ->
+ {error, {bad_encoding_config, EC}};
+decode_message(_EC, _, _BadBin) ->
+ {error, bad_binary}.
+
+
+do_decode_message(ParseMod, Tokens, Bin) ->
+%% d("do_decode_message -> entry with"
+%% "~n ParseMod: ~p"
+%% "~n Tokens: ~p", [ParseMod, Tokens]),
+ case (catch ParseMod:parse(Tokens)) of
+ {ok, MegacoMessage} ->
+%% d("do_decode_message -> "
+%% "~n MegacoMessage: ~p", [MegacoMessage]),
+ {ok, MegacoMessage};
+ {error, Reason} ->
+ parse_error(Reason, Tokens, Bin);
+
+ %% OTP-4007
+ {'EXIT', Reason} ->
+ parse_error(Reason, Tokens, Bin)
+ end.
+
+
+decode_mini_message(EC, _, Bin) when is_binary(Bin) ->
+ megaco_text_mini_decoder:decode_message(EC, Bin).
+
+
+scan_error(Reason, Line, Bin) ->
+ scan_error(Reason, Line, [], Bin).
+
+scan_error("bad_property_parm: " ++ Reason, _Line, _Tokens, _Bin) ->
+ {error, {bad_property_parm, Reason}};
+scan_error(Reason, Line, Tokens, Bin) ->
+ %% io:format("scanner error: "
+ %% "~n Reason: ~p"
+ %% "~n Line: ~p"
+ %% "~n Tokens: ~p"
+ %% "~n Bin: ~p"
+ %% "~n", [Reason, Line, Tokens, Bin]),
+ {error, [{reason, Reason, Line}, {token, Tokens}, {chars, Bin}]}.
+
+parse_error(Reason, Tokens, Chars) ->
+ %% io:format("parser error -> entry with"
+ %% "~n Reason: ~p"
+ %% "~n Tokens: ~p"
+ %% "~n", [Reason, Tokens]),
+ case Reason of
+ {Line, Mod, [Prefix, [$[, TokenStringRaw, $]]]} when
+ is_integer(Line) andalso
+ is_atom(Mod) andalso
+ is_list(Prefix) andalso
+ is_list(TokenStringRaw) ->
+ TokenString = [l2i(X) || X <- TokenStringRaw, is_list(X)],
+ ReasonStr = Prefix ++ TokenString,
+ {error, [{reason, ReasonStr, Line}, {tokens, Tokens}, {chars, Chars}, {module, Mod}]};
+ _ ->
+ {error, [{reason, Reason}, {token, Tokens}, {chars, Chars}]}
+ end.
+
+
+l2i(L) when is_list(L) ->
+ case (catch list_to_integer(L)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ L
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction([{version3,_}|EC], 1, Trans) ->
+ megaco_compact_text_encoder_v1:encode_transaction(EC, Trans);
+encode_transaction(EC, 1, Trans) ->
+ megaco_compact_text_encoder_v1:encode_transaction(EC, Trans);
+encode_transaction([{version3,_}|EC], 2, Trans) ->
+ megaco_compact_text_encoder_v2:encode_transaction(EC, Trans);
+encode_transaction(EC, 2, Trans) ->
+ megaco_compact_text_encoder_v2:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3c}|EC], 3, Trans) ->
+ megaco_compact_text_encoder_prev3c:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3b}|EC], 3, Trans) ->
+ megaco_compact_text_encoder_prev3b:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3a}|EC], 3, Trans) ->
+ megaco_compact_text_encoder_prev3a:encode_transaction(EC, Trans);
+encode_transaction([{version3,v3}|EC], 3, Trans) ->
+ megaco_compact_text_encoder_v3:encode_transaction(EC, Trans);
+encode_transaction(EC, 3, Trans) ->
+ megaco_compact_text_encoder_v3:encode_transaction(EC, Trans);
+encode_transaction(_EC, V, _Trans) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([{version3,_}|EC], 1, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v1:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,_}|EC], 2, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v2:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3c}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_prev3c:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3b}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_prev3b:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3a}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_prev3a:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,v3}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ megaco_compact_text_encoder_v3:encode_action_requests(EC, ActReqs);
+encode_action_requests(_EC, V, _ActReqs) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3,_}|EC], 1, ActReq) ->
+ megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq);
+encode_action_request(EC, 1, ActReq) ->
+ megaco_compact_text_encoder_v1:encode_action_request(EC, ActReq);
+encode_action_request([{version3,_}|EC], 2, ActReq) ->
+ megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq);
+encode_action_request(EC, 2, ActReq) ->
+ megaco_compact_text_encoder_v2:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3c}|EC], 3, ActReq) ->
+ megaco_compact_text_encoder_prev3c:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3b}|EC], 3, ActReq) ->
+ megaco_compact_text_encoder_prev3b:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3a}|EC], 3, ActReq) ->
+ megaco_compact_text_encoder_prev3a:encode_action_request(EC, ActReq);
+encode_action_request([{version3,v3}|EC], 3, ActReq) ->
+ megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq);
+encode_action_request(EC, 3, ActReq) ->
+ megaco_compact_text_encoder_v3:encode_action_request(EC, ActReq);
+encode_action_request(_EC, V, _ActReq) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request([{version3,_}|EC], 1, CmdReq) ->
+ megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 1, CmdReq) ->
+ megaco_compact_text_encoder_v1:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,_}|EC], 2, CmdReq) ->
+ megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 2, CmdReq) ->
+ megaco_compact_text_encoder_v2:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3c}|EC], 3, CmdReq) ->
+ megaco_compact_text_encoder_prev3c:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3b}|EC], 3, CmdReq) ->
+ megaco_compact_text_encoder_prev3b:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3a}|EC], 3, CmdReq) ->
+ megaco_compact_text_encoder_prev3a:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,v3}|EC], 3, CmdReq) ->
+ megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 3, CmdReq) ->
+ megaco_compact_text_encoder_v3:encode_command_request(EC, CmdReq);
+encode_command_request(_EC, V, _CmdReq) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply([{version3,_}|EC], 1, ActRep) ->
+ megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 1, ActRep) ->
+ megaco_compact_text_encoder_v1:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,_}|EC], 2, ActRep) ->
+ megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 2, ActRep) ->
+ megaco_compact_text_encoder_v2:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3c}|EC], 3, ActRep) ->
+ megaco_compact_text_encoder_prev3c:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3b}|EC], 3, ActRep) ->
+ megaco_compact_text_encoder_prev3b:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3a}|EC], 3, ActRep) ->
+ megaco_compact_text_encoder_prev3a:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,v3}|EC], 3, ActRep) ->
+ megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 3, ActRep) ->
+ megaco_compact_text_encoder_v3:encode_action_reply(EC, ActRep);
+encode_action_reply(_EC, V, _ActRep) ->
+ {error, {bad_version, V}}.
+
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+-define(TT2S_BEST_VERSION, v3).
+
+token_tag2string(Tag) ->
+ token_tag2string(Tag, ?TT2S_BEST_VERSION).
+
+token_tag2string(Tag, 1) ->
+ token_tag2string(Tag, v1);
+token_tag2string(Tag, v1) ->
+ megaco_compact_text_encoder_v1:token_tag2string(Tag);
+token_tag2string(Tag, 2) ->
+ token_tag2string(Tag, v2);
+token_tag2string(Tag, v2) ->
+ megaco_compact_text_encoder_v2:token_tag2string(Tag);
+token_tag2string(Tag, 3) ->
+ token_tag2string(Tag, v3);
+token_tag2string(Tag, v3) ->
+ megaco_compact_text_encoder_v3:token_tag2string(Tag);
+token_tag2string(Tag, prev3b) ->
+ megaco_compact_text_encoder_prev3b:token_tag2string(Tag);
+token_tag2string(Tag, prev3c) ->
+ megaco_compact_text_encoder_prev3c:token_tag2string(Tag);
+token_tag2string(Tag, _Vsn) ->
+ token_tag2string(Tag, ?TT2S_BEST_VERSION).
+
+
+%% d(F) ->
+%% d(F, []).
+
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl
new file mode 100644
index 0000000000..a45d35cc43
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3a.erl
@@ -0,0 +1,297 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_prev3a).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(LSBRKT_INDENT(_State), [?LsbrktToken]).
+-define(RSBRKT_INDENT(_State), [?RsbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothToken , ?CompactBothToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(ContextAttrToken , ?CompactContextAttrToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DirectionToken , ?CompactDirectionToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(EmergencyOffToken , ?CompactEmergencyOffToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(ExternalToken , ?CompactExternalToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(IEPSToken , ?CompactIEPSToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InternalToken , ?CompactInternalToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(Nx64kToken , ?CompactNx64kToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(RequestIDToken , ?CompactRequestIDToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3a.hrl").
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl
new file mode 100644
index 0000000000..63f76040ce
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3b.erl
@@ -0,0 +1,432 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_prev3b).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(both) -> ?CompactBothToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAttrToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+%% token_tag2string(X) -> ?CompactContextListToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDirectionToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+%% token_tag2string(X) -> ?CompactEmergencyOffToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+token_tag2string(external) -> ?CompactExternalToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+token_tag2string(iepsCallind) -> ?CompactIEPSToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(internal) -> ?CompactInternalToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+%% token_tag2string(X) -> ?CompactNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+%% token_tag2string(X) -> ?CompactRequestIDToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(LSBRKT_INDENT(_State), [?LsbrktToken]).
+-define(RSBRKT_INDENT(_State), [?RsbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothToken , ?CompactBothToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(ContextAttrToken , ?CompactContextAttrToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DirectionToken , ?CompactDirectionToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(EmergencyOffToken , ?CompactEmergencyOffToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(ExternalToken , ?CompactExternalToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(IEPSToken , ?CompactIEPSToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InternalToken , ?CompactInternalToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(Nx64kToken , ?CompactNx64kToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(RequestIDToken , ?CompactRequestIDToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3b.hrl").
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl b/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl
new file mode 100644
index 0000000000..10d7b7e732
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_prev3c.erl
@@ -0,0 +1,455 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_prev3c).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+%% token_tag2string(X) -> ?CompactAndAUDITSelectToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(both) -> ?CompactBothToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+%% token_tag2string(X) -> ?CompactContextAttrToken;
+%% token_tag2string(X) -> ?CompactContextListToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDirectionToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+%% token_tag2string(X) -> ?CompactEmergencyOffToken;
+%% token_tag2string(X) -> ?CompactEmergencyValueToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+token_tag2string(external) -> ?CompactExternalToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+token_tag2string(iepsCallind) -> ?CompactIEPSToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(internal) -> ?CompactInternalToken;
+%% token_tag2string(X) -> ?CompactIntsigDelayToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(iteration) -> ?CompactIterationToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+%% token_tag2string(X) -> ?CompactNeverNotifyToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+%% token_tag2string(X) -> ?CompactNotifyImmediateToken;
+%% token_tag2string(X) -> ?CompactNotifyRegulatedToken;
+%% token_tag2string(X) -> ?CompactNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onewayboth) -> ?CompactOnewayBothToken;
+token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+%% token_tag2string(X) -> ?CompactOrAUDITselectToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken;
+%% token_tag2string(X) -> ?CompactRequestIDToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(LSBRKT_INDENT(_State), [?LsbrktToken]).
+-define(RSBRKT_INDENT(_State), [?RsbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AndAUDITSelectToken , ?CompactAndAUDITSelectToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothToken , ?CompactBothToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(ContextAttrToken , ?CompactContextAttrToken).
+-define(ContextListToken , ?CompactContextListToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DirectionToken , ?CompactDirectionToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(EmergencyOffToken , ?CompactEmergencyOffToken).
+-define(EmergencyValueToken , ?CompactEmergencyValueToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(ExternalToken , ?CompactExternalToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(IEPSToken , ?CompactIEPSToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InternalToken , ?CompactInternalToken).
+-define(IntsigDelayToken , ?CompactIntsigDelayToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IterationToken , ?CompactIterationToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+%% -define(MessageSegmentToken , ?CompactMessageSegmentToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NeverNotifyToken , ?CompactNeverNotifyToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(NotifyImmediateToken , ?CompactNotifyImmediateToken).
+-define(NotifyRegulatedToken , ?CompactNotifyRegulatedToken).
+-define(Nx64kToken , ?CompactNx64kToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnewayBothToken , ?CompactOnewayBothToken).
+-define(OnewayExternalToken , ?CompactOnewayExternalToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OrAUDITselectToken , ?CompactOrAUDITselectToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResetEventsDescriptorToken , ?CompactResetEventsDescriptorToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(RequestIDToken , ?CompactRequestIDToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+%% -define(SegmentationCompleteToken , ?CompactSegmentationCompleteToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3c.hrl").
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl
new file mode 100644
index 0000000000..c1b454dc0f
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_v1.erl
@@ -0,0 +1,407 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_v1).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v1.hrl").
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl
new file mode 100644
index 0000000000..ac0877da2f
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_v2.erl
@@ -0,0 +1,413 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_v2).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+%% token_tag2string(X) -> ?CompactEmergencyOffToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+%% token_tag2string(X) -> ?CompactNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(EmergencyOffToken , ?CompactEmergencyOffToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(Nx64kToken , ?CompactNx64kToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v2.hrl").
+
diff --git a/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl b/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl
new file mode 100644
index 0000000000..5dd239222b
--- /dev/null
+++ b/lib/megaco/src/text/megaco_compact_text_encoder_v3.erl
@@ -0,0 +1,455 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode COMPACT Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_compact_text_encoder_v3).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+%% token_tag2string(X) -> ?CompactAndAUDITSelectToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(both) -> ?CompactBothToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+%% token_tag2string(X) -> ?CompactContextAttrToken;
+%% token_tag2string(X) -> ?CompactContextListToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDirectionToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+%% token_tag2string(X) -> ?CompactEmergencyOffToken;
+%% token_tag2string(X) -> ?CompactEmergencyValueToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+token_tag2string(external) -> ?CompactExternalToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+token_tag2string(iepsCallind) -> ?CompactIEPSToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(internal) -> ?CompactInternalToken;
+%% token_tag2string(X) -> ?CompactIntsigDelayToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(iteration) -> ?CompactIterationToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+%% token_tag2string(X) -> ?CompactNeverNotifyToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+%% token_tag2string(X) -> ?CompactNotifyImmediateToken;
+%% token_tag2string(X) -> ?CompactNotifyRegulatedToken;
+%% token_tag2string(X) -> ?CompactNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onewayboth) -> ?CompactOnewayBothToken;
+token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+%% token_tag2string(X) -> ?CompactOrAUDITselectToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken;
+%% token_tag2string(X) -> ?CompactRequestIDToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?EqualToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?LbrktToken]).
+-define(RBRKT, [?RbrktToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), State).
+-define(INDENT(State), State).
+-define(LBRKT_INDENT(_State), [?LbrktToken]).
+-define(RBRKT_INDENT(_State), [?RbrktToken]).
+-define(LSBRKT_INDENT(_State), [?LsbrktToken]).
+-define(RSBRKT_INDENT(_State), [?RsbrktToken]).
+-define(COMMA_INDENT(_State), [?CommaToken]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?CompactAddToken).
+-define(AndAUDITSelectToken , ?CompactAndAUDITSelectToken).
+-define(AuditToken , ?CompactAuditToken).
+-define(AuditCapToken , ?CompactAuditCapToken).
+-define(AuditValueToken , ?CompactAuditValueToken).
+-define(AuthToken , ?CompactAuthToken).
+-define(BothToken , ?CompactBothToken).
+-define(BothwayToken , ?CompactBothwayToken).
+-define(BriefToken , ?CompactBriefToken).
+-define(BufferToken , ?CompactBufferToken).
+-define(CtxToken , ?CompactCtxToken).
+-define(ContextAuditToken , ?CompactContextAuditToken).
+-define(ContextAttrToken , ?CompactContextAttrToken).
+-define(ContextListToken , ?CompactContextListToken).
+-define(DigitMapToken , ?CompactDigitMapToken).
+-define(DirectionToken , ?CompactDirectionToken).
+-define(DiscardToken , ?CompactDiscardToken).
+-define(DisconnectedToken , ?CompactDisconnectedToken).
+-define(DelayToken , ?CompactDelayToken).
+-define(DeleteToken , ?CompactDeleteToken).
+-define(DurationToken , ?CompactDurationToken).
+-define(EmbedToken , ?CompactEmbedToken).
+-define(EmergencyToken , ?CompactEmergencyToken).
+-define(EmergencyOffToken , ?CompactEmergencyOffToken).
+-define(EmergencyValueToken , ?CompactEmergencyValueToken).
+-define(ErrorToken , ?CompactErrorToken).
+-define(EventBufferToken , ?CompactEventBufferToken).
+-define(EventsToken , ?CompactEventsToken).
+-define(ExternalToken , ?CompactExternalToken).
+-define(FailoverToken , ?CompactFailoverToken).
+-define(ForcedToken , ?CompactForcedToken).
+-define(GracefulToken , ?CompactGracefulToken).
+-define(H221Token , ?CompactH221Token).
+-define(H223Token , ?CompactH223Token).
+-define(H226Token , ?CompactH226Token).
+-define(HandOffToken , ?CompactHandOffToken).
+-define(IEPSToken , ?CompactIEPSToken).
+-define(ImmAckRequiredToken , ?CompactImmAckRequiredToken).
+-define(InactiveToken , ?CompactInactiveToken).
+-define(InternalToken , ?CompactInternalToken).
+-define(IntsigDelayToken , ?CompactIntsigDelayToken).
+-define(IsolateToken , ?CompactIsolateToken).
+-define(InSvcToken , ?CompactInSvcToken).
+-define(InterruptByEventToken , ?CompactInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?CompactInterruptByNewSignalsDescrToken).
+-define(IterationToken , ?CompactIterationToken).
+-define(KeepActiveToken , ?CompactKeepActiveToken).
+-define(LocalToken , ?CompactLocalToken).
+-define(LocalControlToken , ?CompactLocalControlToken).
+-define(LockStepToken , ?CompactLockStepToken).
+-define(LoopbackToken , ?CompactLoopbackToken).
+-define(MediaToken , ?CompactMediaToken).
+-define(MegacopToken , ?CompactMegacopToken).
+-define(MessageSegmentToken , ?CompactMessageSegmentToken).
+-define(MethodToken , ?CompactMethodToken).
+-define(MgcIdToken , ?CompactMgcIdToken).
+-define(ModeToken , ?CompactModeToken).
+-define(ModifyToken , ?CompactModifyToken).
+-define(ModemToken , ?CompactModemToken).
+-define(MoveToken , ?CompactMoveToken).
+-define(MtpToken , ?CompactMtpToken).
+-define(MuxToken , ?CompactMuxToken).
+-define(NeverNotifyToken , ?CompactNeverNotifyToken).
+-define(NotifyToken , ?CompactNotifyToken).
+-define(NotifyCompletionToken , ?CompactNotifyCompletionToken).
+-define(NotifyImmediateToken , ?CompactNotifyImmediateToken).
+-define(NotifyRegulatedToken , ?CompactNotifyRegulatedToken).
+-define(Nx64kToken , ?CompactNx64kToken).
+-define(ObservedEventsToken , ?CompactObservedEventsToken).
+-define(OffToken , ?CompactOffToken).
+-define(OnewayToken , ?CompactOnewayToken).
+-define(OnewayBothToken , ?CompactOnewayBothToken).
+-define(OnewayExternalToken , ?CompactOnewayExternalToken).
+-define(OnOffToken , ?CompactOnOffToken).
+-define(OnToken , ?CompactOnToken).
+-define(OrAUDITselectToken , ?CompactOrAUDITselectToken).
+-define(OtherReasonToken , ?CompactOtherReasonToken).
+-define(OutOfSvcToken , ?CompactOutOfSvcToken).
+-define(PackagesToken , ?CompactPackagesToken).
+-define(PendingToken , ?CompactPendingToken).
+-define(PriorityToken , ?CompactPriorityToken).
+-define(ProfileToken , ?CompactProfileToken).
+-define(ReasonToken , ?CompactReasonToken).
+-define(RecvonlyToken , ?CompactRecvonlyToken).
+-define(ReplyToken , ?CompactReplyToken).
+-define(ResetEventsDescriptorToken , ?CompactResetEventsDescriptorToken).
+-define(ResponseAckToken , ?CompactResponseAckToken).
+-define(RestartToken , ?CompactRestartToken).
+-define(RemoteToken , ?CompactRemoteToken).
+-define(RequestIDToken , ?CompactRequestIDToken).
+-define(ReservedGroupToken , ?CompactReservedGroupToken).
+-define(ReservedValueToken , ?CompactReservedValueToken).
+-define(SegmentationCompleteToken , ?CompactSegmentationCompleteToken).
+-define(SendonlyToken , ?CompactSendonlyToken).
+-define(SendrecvToken , ?CompactSendrecvToken).
+-define(ServicesToken , ?CompactServicesToken).
+-define(ServiceStatesToken , ?CompactServiceStatesToken).
+-define(ServiceChangeToken , ?CompactServiceChangeToken).
+-define(ServiceChangeAddressToken , ?CompactServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?CompactServiceChangeIncompleteToken).
+-define(SignalListToken , ?CompactSignalListToken).
+-define(SignalsToken , ?CompactSignalsToken).
+-define(SignalTypeToken , ?CompactSignalTypeToken).
+-define(StatsToken , ?CompactStatsToken).
+-define(StreamToken , ?CompactStreamToken).
+-define(SubtractToken , ?CompactSubtractToken).
+-define(SynchISDNToken , ?CompactSynchISDNToken).
+-define(TerminationStateToken , ?CompactTerminationStateToken).
+-define(TestToken , ?CompactTestToken).
+-define(TimeOutToken , ?CompactTimeOutToken).
+-define(TopologyToken , ?CompactTopologyToken).
+-define(TransToken , ?CompactTransToken).
+-define(V18Token , ?CompactV18Token).
+-define(V22Token , ?CompactV22Token).
+-define(V22bisToken , ?CompactV22bisToken).
+-define(V32Token , ?CompactV32Token).
+-define(V32bisToken , ?CompactV32bisToken).
+-define(V34Token , ?CompactV34Token).
+-define(V76Token , ?CompactV76Token).
+-define(V90Token , ?CompactV90Token).
+-define(V91Token , ?CompactV91Token).
+-define(VersionToken , ?CompactVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v3.hrl").
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder.erl b/lib/megaco/src/text/megaco_pretty_text_encoder.erl
new file mode 100644
index 0000000000..6a9a7df041
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder.erl
@@ -0,0 +1,613 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder).
+
+-behaviour(megaco_encoder).
+
+-export([encode_message/3, decode_message/3,
+ decode_mini_message/3,
+
+ version_of/2,
+
+ encode_transaction/3,
+ encode_action_requests/3,
+ encode_action_request/3,
+ encode_command_request/3,
+ encode_action_reply/3]).
+
+%% Backward compatible funcs:
+-export([encode_message/2, decode_message/2,
+
+ encode_transaction/1,
+ encode_command_request/1,
+ encode_action_reply/1]).
+
+%% Do we need these here?
+-export([trim_quoted_string/1,
+ term_to_compact_string/1,
+ term_to_pretty_string/1]).
+
+-export([token_tag2string/1, token_tag2string/2]).
+
+
+-include("megaco_text_tokens.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+-define(V1_PARSE_MOD, megaco_text_parser_v1).
+-define(V2_PARSE_MOD, megaco_text_parser_v2).
+-define(V3_PARSE_MOD, megaco_text_parser_v3).
+-define(PREV3A_PARSE_MOD, megaco_text_parser_prev3a).
+-define(PREV3B_PARSE_MOD, megaco_text_parser_prev3b).
+-define(PREV3C_PARSE_MOD, megaco_text_parser_prev3c).
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EncodingConfig,
+ #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) ->
+ encode_message(EncodingConfig, V, MegaMsg).
+
+
+encode_message([{version3,_}|EC], 1, MegaMsg) ->
+ megaco_pretty_text_encoder_v1:encode_message(EC, MegaMsg);
+encode_message(EC, 1, MegaMsg) ->
+ megaco_pretty_text_encoder_v1:encode_message(EC, MegaMsg);
+encode_message([{version3,_}|EC], 2, MegaMsg) ->
+ megaco_pretty_text_encoder_v2:encode_message(EC, MegaMsg);
+encode_message(EC, 2, MegaMsg) ->
+ megaco_pretty_text_encoder_v2:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3c}|EC], 3, MegaMsg) ->
+ megaco_pretty_text_encoder_prev3c:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3b}|EC], 3, MegaMsg) ->
+ megaco_pretty_text_encoder_prev3b:encode_message(EC, MegaMsg);
+encode_message([{version3,prev3a}|EC], 3, MegaMsg) ->
+ megaco_pretty_text_encoder_prev3a:encode_message(EC, MegaMsg);
+encode_message([{version3,v3}|EC], 3, MegaMsg) ->
+ megaco_pretty_text_encoder_v3:encode_message(EC, MegaMsg);
+encode_message(EC, 3, MegaMsg) ->
+ megaco_pretty_text_encoder_v3:encode_message(EC, MegaMsg);
+encode_message(_EC, V, _MegaMsg) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+version_of(_EC, Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, _Tokens, V, _LastLine} ->
+ {ok, V};
+ {error, Reason, Line} ->
+ {error, {decode_failed, Reason, Line}}
+ end.
+
+
+decode_message(EC, Bin) ->
+ decode_message(EC, dynamic, Bin).
+
+decode_message([], _, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,v3}], _, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3c}], _, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} ->
+ scan_error(Reason, Line, Bin)
+ end;
+decode_message([{version3,prev3b}], _, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3a}], _, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ {error, Reason, Tokens, Line} ->
+ scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{flex, Port}], _, Bin) when is_binary(Bin) ->
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,v3},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?V3_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3c},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3C_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3b},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3B_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message([{version3,prev3a},{flex, Port}], _, Bin) when is_binary(Bin) ->
+ case megaco_flex_scanner:scan(Bin, Port) of
+ {ok, Tokens, 1, _LastLine} ->
+ do_decode_message(?V1_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 2, _LastLine} ->
+ do_decode_message(?V2_PARSE_MOD, Tokens, Bin);
+
+ {ok, Tokens, 3, _LastLine} ->
+ do_decode_message(?PREV3A_PARSE_MOD, Tokens, Bin);
+
+ {ok, _Tokens, V, _LastLine} ->
+ {error, {unsupported_version, V}};
+
+ %% {error, Reason, Tokens, Line} ->
+ %% scan_error(Reason, Line, Tokens, Bin);
+
+ {error, Reason, Line} -> %% OTP-4007
+ scan_error(Reason, Line, Bin) %% OTP-4007
+ end;
+decode_message(EC, _, Bin) when is_binary(Bin) ->
+ {error, {bad_encoding_config, EC}};
+decode_message(_EC, _, _BadBin) ->
+ {error, bad_binary}.
+
+
+do_decode_message(ParseMod, Tokens, Bin) ->
+ case (catch ParseMod:parse(Tokens)) of
+ {ok, MegacoMessage} ->
+ {ok, MegacoMessage};
+ {error, Reason} ->
+ parse_error(Reason, Tokens, Bin);
+
+ %% OTP-4007
+ {'EXIT', Reason} ->
+ parse_error(Reason, Tokens, Bin)
+ end.
+
+
+decode_mini_message(EC, _, Bin) when is_binary(Bin) ->
+ megaco_text_mini_decoder:decode_message(EC, Bin).
+
+
+scan_error(Reason, Line, Bin) ->
+ scan_error(Reason, Line, [], Bin).
+
+scan_error("bad_property_parm: " ++ Reason, _Line, _Tokens, _Bin) ->
+ {error, {bad_property_parm, Reason}};
+scan_error(Reason, Line, Tokens, Bin) ->
+ %% io:format("scanner error: "
+ %% "~n Reason: ~p"
+ %% "~n Line: ~p"
+ %% "~n Tokens: ~p"
+ %% "~n Bin: ~p"
+ %% "~n", [Reason, Line, Tokens, Bin]),
+ {error, [{reason, Reason, Line}, {token, Tokens}, {chars, Bin}]}.
+
+parse_error(Reason, Tokens, Chars) ->
+%% io:format("parse_error -> entry with"
+%% "~n Reason: ~p"
+%% "~n Tokens: ~p"
+%% "~n Chars: ~p"
+%% "~n", [Reason, Tokens, Chars]),
+ case Reason of
+ {Line, Mod, [Prefix, [$[, TokenStringRaw, $]]]} when
+ is_integer(Line) andalso
+ is_atom(Mod) andalso
+ is_list(Prefix) andalso
+ is_list(TokenStringRaw) ->
+ TokenString = [l2i(X) || X <- TokenStringRaw, is_list(X)],
+ ReasonStr = Prefix ++ TokenString,
+ {error, [{reason, ReasonStr, Line}, {tokens, Tokens}, {chars, Chars}, {module, Mod}]};
+ _ ->
+ {error, [{reason, Reason}, {token, Tokens}, {chars, Chars}]}
+ end.
+
+
+l2i(L) when is_list(L) ->
+ case (catch list_to_integer(L)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ L
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a binary
+%% Return {ok, Bin} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(Trans) ->
+ encode_transaction([], 1, Trans).
+
+encode_transaction([{version3,_}|EC], 1, Trans) ->
+ megaco_pretty_text_encoder_v1:encode_transaction(EC, Trans);
+encode_transaction(EC, 1, Trans) ->
+ megaco_pretty_text_encoder_v1:encode_transaction(EC, Trans);
+encode_transaction([{version3,_}|EC], 2, Trans) ->
+ megaco_pretty_text_encoder_v2:encode_transaction(EC, Trans);
+encode_transaction(EC, 2, Trans) ->
+ megaco_pretty_text_encoder_v2:encode_transaction(EC, Trans);
+encode_transaction([{version3,v3}|EC], 3, Trans) ->
+ megaco_pretty_text_encoder_v3:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3c}|EC], 3, Trans) ->
+ megaco_pretty_text_encoder_prev3c:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3b}|EC], 3, Trans) ->
+ megaco_pretty_text_encoder_prev3b:encode_transaction(EC, Trans);
+encode_transaction([{version3,prev3a}|EC], 3, Trans) ->
+ megaco_pretty_text_encoder_prev3a:encode_transaction(EC, Trans);
+encode_transaction(EC, 3, Trans) ->
+ megaco_pretty_text_encoder_v3:encode_transaction(EC, Trans);
+encode_transaction(_EC, V, _Trans) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests([{version3,_}|EC], 1, ActReqs) when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v1:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 1, ActReqs) when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v1:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,_}|EC], 2, ActReqs) when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v2:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 2, ActReqs) when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v2:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,v3}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v3:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3c}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_prev3c:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3b}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_prev3b:encode_action_requests(EC, ActReqs);
+encode_action_requests([{version3,prev3a}|EC], 3, ActReqs)
+ when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_prev3a:encode_action_requests(EC, ActReqs);
+encode_action_requests(EC, 3, ActReqs) when is_list(ActReqs) ->
+ megaco_pretty_text_encoder_v3:encode_action_requests(EC, ActReqs);
+encode_action_requests(_EC, V, _ActReqs) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request([{version3,_}|EC], 1, ActReq) ->
+ megaco_pretty_text_encoder_v1:encode_action_request(EC, ActReq);
+encode_action_request(EC, 1, ActReq) ->
+ megaco_pretty_text_encoder_v1:encode_action_request(EC, ActReq);
+encode_action_request([{version3,_}|EC], 2, ActReq) ->
+ megaco_pretty_text_encoder_v2:encode_action_request(EC, ActReq);
+encode_action_request(EC, 2, ActReq) ->
+ megaco_pretty_text_encoder_v2:encode_action_request(EC, ActReq);
+encode_action_request([{version3,v3}|EC], 3, ActReq) ->
+ megaco_pretty_text_encoder_v3:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3c}|EC], 3, ActReq) ->
+ megaco_pretty_text_encoder_prev3c:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3b}|EC], 3, ActReq) ->
+ megaco_pretty_text_encoder_prev3b:encode_action_request(EC, ActReq);
+encode_action_request([{version3,prev3a}|EC], 3, ActReq) ->
+ megaco_pretty_text_encoder_prev3a:encode_action_request(EC, ActReq);
+encode_action_request(EC, 3, ActReq) ->
+ megaco_pretty_text_encoder_v3:encode_action_request(EC, ActReq);
+encode_action_request(_EC, V, _ActReq) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(CmdReq) ->
+ encode_command_request([], 1, CmdReq).
+
+encode_command_request([{version3,_}|EC], 1, CmdReq) ->
+ megaco_pretty_text_encoder_v1:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 1, CmdReq) ->
+ megaco_pretty_text_encoder_v1:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,_}|EC], 2, CmdReq) ->
+ megaco_pretty_text_encoder_v2:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 2, CmdReq) ->
+ megaco_pretty_text_encoder_v2:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,v3}|EC], 3, CmdReq) ->
+ megaco_pretty_text_encoder_v3:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3c}|EC], 3, CmdReq) ->
+ megaco_pretty_text_encoder_prev3c:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3b}|EC], 3, CmdReq) ->
+ megaco_pretty_text_encoder_prev3b:encode_command_request(EC, CmdReq);
+encode_command_request([{version3,prev3a}|EC], 3, CmdReq) ->
+ megaco_pretty_text_encoder_prev3a:encode_command_request(EC, CmdReq);
+encode_command_request(EC, 3, CmdReq) ->
+ megaco_pretty_text_encoder_v3:encode_command_request(EC, CmdReq);
+encode_command_request(_EC, V, _CmdReq) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(ActRep) ->
+%% io:format("~p:encode_action_reply -> entry with"
+%% "~n ActRep: ~p"
+%% "~n", [?MODULE, ActRep]),
+ encode_action_reply([], 1, ActRep).
+
+encode_action_reply([{version3,_}|EC], 1, ActRep) ->
+ megaco_pretty_text_encoder_v1:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 1, ActRep) ->
+ megaco_pretty_text_encoder_v1:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,_}|EC], 2, ActRep) ->
+ megaco_pretty_text_encoder_v2:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 2, ActRep) ->
+ megaco_pretty_text_encoder_v2:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,v3}|EC], 3, ActRep) ->
+ megaco_pretty_text_encoder_v3:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3c}|EC], 3, ActRep) ->
+ megaco_pretty_text_encoder_prev3c:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3b}|EC], 3, ActRep) ->
+ megaco_pretty_text_encoder_prev3b:encode_action_reply(EC, ActRep);
+encode_action_reply([{version3,prev3a}|EC], 3, ActRep) ->
+ megaco_pretty_text_encoder_prev3a:encode_action_reply(EC, ActRep);
+encode_action_reply(EC, 3, ActRep) ->
+ megaco_pretty_text_encoder_v3:encode_action_reply(EC, ActRep);
+encode_action_reply(_EC, V, _ActRep) ->
+ {error, {bad_version, V}}.
+
+
+%%----------------------------------------------------------------------
+term_to_compact_string(Term) ->
+ case catch io_lib:format("~s", [Term]) of
+ {'EXIT', _} -> lists:flatten(io_lib:format("~w", [Term]));
+ GoodString -> lists:flatten(GoodString)
+ end.
+
+%%----------------------------------------------------------------------
+term_to_pretty_string(Term) ->
+ case catch io_lib:format("~s", [Term]) of
+ {'EXIT', _} -> lists:flatten(io_lib:format("~p", [Term]));
+ GoodString -> lists:flatten(GoodString)
+ end.
+
+%%----------------------------------------------------------------------
+trim_quoted_string([H | T]) ->
+ case ?classify_char(H) of
+ safe_char -> [H | trim_quoted_string(T)];
+ rest_char -> [H | trim_quoted_string(T)];
+ white_space -> [H | trim_quoted_string(T)];
+ _BadChar -> [$? | trim_quoted_string(T)]
+ end;
+trim_quoted_string([]) ->
+ [].
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+-define(TT2S_BEST_VERSION, v3).
+
+token_tag2string(Tag) ->
+ token_tag2string(Tag, ?TT2S_BEST_VERSION).
+
+token_tag2string(Tag, 1) ->
+ token_tag2string(Tag, v1);
+token_tag2string(Tag, v1) ->
+ megaco_pretty_text_encoder_v1:token_tag2string(Tag);
+token_tag2string(Tag, 2) ->
+ token_tag2string(Tag, v2);
+token_tag2string(Tag, v2) ->
+ megaco_pretty_text_encoder_v2:token_tag2string(Tag);
+token_tag2string(Tag, 3) ->
+ token_tag2string(Tag, v3);
+token_tag2string(Tag, v3) ->
+ megaco_pretty_text_encoder_v3:token_tag2string(Tag);
+token_tag2string(Tag, prev3b) ->
+ megaco_pretty_text_encoder_prev3b:token_tag2string(Tag);
+token_tag2string(Tag, prev3c) ->
+ megaco_pretty_text_encoder_prev3c:token_tag2string(Tag);
+token_tag2string(Tag, _Vsn) ->
+ token_tag2string(Tag, ?TT2S_BEST_VERSION).
+
+
+
+%% d(F) ->
+%% d(F, []).
+
+%% d(F, A) ->
+%% %% d(get(dbg), F, A).
+%% d(true, F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.
+
+%% p(F, A) ->
+%% io:format("*** [~s] ***"
+%% "~n " ++ F ++ "~n", [formated_timestamp() | A]),
+%% sleep(5000),
+%% ok.
+
+%% sleep(X) -> receive after X -> ok end.
+
+%% formated_timestamp() ->
+%% format_timestamp(now()).
+
+%% format_timestamp({_N1, _N2, N3} = Now) ->
+%% {Date, Time} = calendar:now_to_datetime(Now),
+%% {YYYY,MM,DD} = Date,
+%% {Hour,Min,Sec} = Time,
+%% FormatDate =
+%% io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+%% [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+%% lists:flatten(FormatDate).
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl
new file mode 100644
index 0000000000..6f42bf963c
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3a.erl
@@ -0,0 +1,303 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_prev3a).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%
+%% See megaco_pretty_text_encoder:decode_message/2
+%%
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]).
+-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothToken , ?PrettyBothToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(ContextAttrToken , ?PrettyContextAttrToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DirectionToken , ?PrettyDirectionToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(EmergencyOffToken , ?PrettyEmergencyOffToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(ExternalToken , ?PrettyExternalToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(IEPSToken , ?PrettyIEPSToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(InternalToken , ?PrettyInternalToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(RequestIDToken , ?PrettyRequestIDToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3a.hrl").
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl
new file mode 100644
index 0000000000..44bdc4690d
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3b.erl
@@ -0,0 +1,437 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_prev3b).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%
+%% See megaco_pretty_text_encoder:decode_message/2
+%%
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?PrettyAddToken;
+token_tag2string(addReply) -> ?PrettyAddToken;
+token_tag2string(auditDescriptor) -> ?PrettyAuditToken;
+token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken;
+token_tag2string(auditCapReply) -> ?PrettyAuditCapToken;
+token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken;
+token_tag2string(auditValueReply) -> ?PrettyAuditValueToken;
+%% token_tag2string(X) -> ?PrettyAuthToken;
+token_tag2string(both) -> ?PrettyBothToken;
+token_tag2string(bothway) -> ?PrettyBothwayToken;
+token_tag2string(brief) -> ?PrettyBriefToken;
+%% token_tag2string(X) -> ?PrettyBufferToken;
+%% token_tag2string(X) -> ?PrettyCtxToken;
+%% token_tag2string(X) -> ?PrettyContextAttrToken;
+%% token_tag2string(X) -> ?PrettyContextAuditToken;
+%% token_tag2string(X) -> ?PrettyContextListToken;
+token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken;
+token_tag2string(digitMapToken) -> ?PrettyDigitMapToken;
+%% token_tag2string(X) -> ?PrettyDirectionToken;
+%% token_tag2string(X) -> ?PrettyDiscardToken;
+%% token_tag2string(X) -> ?PrettyDisconnectedToken;
+%% token_tag2string(X) -> ?PrettyDelayToken;
+token_tag2string(duration) -> ?PrettyDurationToken;
+%% token_tag2string(X) -> ?PrettyEmbedToken;
+token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken;
+%% token_tag2string(X) -> ?PrettyEmergencyOffToken;
+token_tag2string(errorDescriptor) -> ?PrettyErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken;
+token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?PrettyEventsToken;
+token_tag2string(eventsToken) -> ?PrettyEventsToken;
+token_tag2string(external) -> ?PrettyExternalToken;
+%% token_tag2string(X) -> ?PrettyFailoverToken;
+%% token_tag2string(X) -> ?PrettyForcedToken;
+%% token_tag2string(X) -> ?PrettyGracefulToken;
+%% token_tag2string(X) -> ?PrettyH221Token;
+%% token_tag2string(X) -> ?PrettyH223Token;
+%% token_tag2string(X) -> ?PrettyH226Token;
+%% token_tag2string(X) -> ?PrettyHandOffToken;
+token_tag2string(iepsCallind) -> ?PrettyIEPSToken;
+%% token_tag2string(X) -> ?PrettyImmAckRequiredToken;
+token_tag2string(inactive) -> ?PrettyInactiveToken;
+token_tag2string(internal) -> ?PrettyInternalToken;
+token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?PrettyIsolateToken;
+token_tag2string(inSvc) -> ?PrettyInSvcToken;
+token_tag2string(keepActive) -> ?PrettyKeepActiveToken;
+token_tag2string(localDescriptor) -> ?PrettyLocalToken;
+token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken;
+token_tag2string(lockStep) -> ?PrettyLockStepToken;
+token_tag2string(loopBack) -> ?PrettyLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?PrettyMediaToken;
+token_tag2string(mediaToken) -> ?PrettyMediaToken;
+%% token_tag2string(X) -> ?PrettyMegacopToken;
+%% token_tag2string(X) -> ?PrettyMethodToken;
+%% token_tag2string(X) -> ?PrettyMgcIdToken;
+%% token_tag2string(X) -> ?PrettyModeToken;
+token_tag2string(modReq) -> ?PrettyModifyToken;
+token_tag2string(modReply) -> ?PrettyModifyToken;
+token_tag2string(modemDescriptor) -> ?PrettyModemToken;
+token_tag2string(modemToken) -> ?PrettyModemToken;
+token_tag2string(moveReq) -> ?PrettyMoveToken;
+token_tag2string(moveReply) -> ?PrettyMoveToken;
+%% token_tag2string(X) -> ?PrettyMtpToken;
+token_tag2string(muxDescriptor) -> ?PrettyMuxToken;
+token_tag2string(muxToken) -> ?PrettyMuxToken;
+token_tag2string(notifyReq) -> ?PrettyNotifyToken;
+%% token_tag2string(X) -> ?PrettyNotifyCompletionToken;
+%% token_tag2string(X) -> ?PrettyNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken;
+token_tag2string(false) -> ?PrettyOffToken;
+token_tag2string(off) -> ?PrettyOffToken;
+token_tag2string(oneway) -> ?PrettyOnewayToken;
+token_tag2string(onOff) -> ?PrettyOnOffToken;
+token_tag2string(true) -> ?PrettyOnToken;
+token_tag2string(otherReason) -> ?PrettyOtherReasonToken;
+token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken;
+token_tag2string(packagesToken) -> ?PrettyPackagesToken;
+%% token_tag2string(X) -> ?PrettyPendingToken;
+token_tag2string(priorityAudit) -> ?PrettyPriorityToken;
+%% token_tag2string(X) -> ?PrettyProfileToken;
+%% token_tag2string(X) -> ?PrettyReasonToken;
+token_tag2string(recvOnly) -> ?PrettyRecvonlyToken;
+%% token_tag2string(X) -> ?PrettyReplyToken;
+%% token_tag2string(X) -> ?PrettyRequestIDToken;
+%% token_tag2string(X) -> ?PrettyResponseAckToken;
+%% token_tag2string(X) -> ?PrettyRestartToken;
+token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken;
+%% token_tag2string(X) -> ?PrettyReservedGroupToken;
+%% token_tag2string(X) -> ?PrettyReservedValueToken;
+token_tag2string(sendOnly) -> ?PrettySendonlyToken;
+token_tag2string(sendRecv) -> ?PrettySendrecvToken;
+%% token_tag2string(X) -> ?PrettyServicesToken;
+%% token_tag2string(X) -> ?PrettyServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken;
+%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?PrettyServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?PrettySignalListToken;
+token_tag2string(signalsDescriptor) -> ?PrettySignalsToken;
+token_tag2string(signalsToken) -> ?PrettySignalsToken;
+%% token_tag2string(X) -> ?PrettySignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken;
+token_tag2string(statsToken) -> ?PrettyStatsToken;
+%% token_tag2string(X) -> ?PrettyStreamToken;
+token_tag2string(subtractReq) -> ?PrettySubtractToken;
+token_tag2string(subtractReply) -> ?PrettySubtractToken;
+%% token_tag2string(X) -> ?PrettySynchISDNToken;
+%% token_tag2string(X) -> ?PrettyTerminationStateToken;
+token_tag2string(test) -> ?PrettyTestToken;
+token_tag2string(timeOut) -> ?PrettyTimeOutToken;
+token_tag2string(onTimeOut) -> ?PrettyTimeOutToken;
+token_tag2string(topologyAudit) -> ?PrettyTopologyToken;
+%% token_tag2string(X) -> ?PrettyTransToken;
+%% token_tag2string(X) -> ?PrettyV18Token;
+%% token_tag2string(X) -> ?PrettyV22Token;
+%% token_tag2string(X) -> ?PrettyV22bisToken;
+%% token_tag2string(X) -> ?PrettyV32Token;
+%% token_tag2string(X) -> ?PrettyV32bisToken;
+%% token_tag2string(X) -> ?PrettyV34Token;
+%% token_tag2string(X) -> ?PrettyV76Token;
+%% token_tag2string(X) -> ?PrettyV90Token;
+%% token_tag2string(X) -> ?PrettyV91Token;
+%% token_tag2string(X) -> ?PrettyVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]).
+-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothToken , ?PrettyBothToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(ContextAttrToken , ?PrettyContextAttrToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DirectionToken , ?PrettyDirectionToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(EmergencyOffToken , ?PrettyEmergencyOffToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(ExternalToken , ?PrettyExternalToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(IEPSToken , ?PrettyIEPSToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(InternalToken , ?PrettyInternalToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(RequestIDToken , ?PrettyRequestIDToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3b.hrl").
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl
new file mode 100644
index 0000000000..1511056f00
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_prev3c.erl
@@ -0,0 +1,483 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_prev3c).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-export([test/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include("megaco_text_tokens.hrl").
+
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%
+%% See megaco_pretty_text_encoder:decode_message/2
+%%
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?PrettyAddToken;
+token_tag2string(addReply) -> ?PrettyAddToken;
+%% token_tag2string(X) -> ?PrettyAndAUDITSelectToken;
+token_tag2string(auditDescriptor) -> ?PrettyAuditToken;
+token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken;
+token_tag2string(auditCapReply) -> ?PrettyAuditCapToken;
+token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken;
+token_tag2string(auditValueReply) -> ?PrettyAuditValueToken;
+%% token_tag2string(X) -> ?PrettyAuthToken;
+token_tag2string(both) -> ?PrettyBothToken;
+token_tag2string(bothway) -> ?PrettyBothwayToken;
+token_tag2string(brief) -> ?PrettyBriefToken;
+%% token_tag2string(X) -> ?PrettyBufferToken;
+%% token_tag2string(X) -> ?PrettyCtxToken;
+%% token_tag2string(X) -> ?PrettyContextAuditToken;
+%% token_tag2string(X) -> ?PrettyContextAttrToken;
+%% token_tag2string(X) -> ?PrettyContextListToken;
+token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken;
+token_tag2string(digitMapToken) -> ?PrettyDigitMapToken;
+%% token_tag2string(X) -> ?PrettyDirectionToken;
+%% token_tag2string(X) -> ?PrettyDiscardToken;
+%% token_tag2string(X) -> ?PrettyDisconnectedToken;
+%% token_tag2string(X) -> ?PrettyDelayToken;
+token_tag2string(duration) -> ?PrettyDurationToken;
+%% token_tag2string(X) -> ?PrettyEmbedToken;
+token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken;
+%% token_tag2string(X) -> ?PrettyEmergencyOffToken;
+%% token_tag2string(X) -> ?PrettyEmergencyValueToken;
+token_tag2string(errorDescriptor) -> ?PrettyErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken;
+token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?PrettyEventsToken;
+token_tag2string(eventsToken) -> ?PrettyEventsToken;
+token_tag2string(external) -> ?PrettyExternalToken;
+%% token_tag2string(X) -> ?PrettyFailoverToken;
+%% token_tag2string(X) -> ?PrettyForcedToken;
+%% token_tag2string(X) -> ?PrettyGracefulToken;
+%% token_tag2string(X) -> ?PrettyH221Token;
+%% token_tag2string(X) -> ?PrettyH223Token;
+%% token_tag2string(X) -> ?PrettyH226Token;
+%% token_tag2string(X) -> ?PrettyHandOffToken;
+token_tag2string(iepsCallind) -> ?PrettyIEPSToken;
+%% token_tag2string(X) -> ?PrettyImmAckRequiredToken;
+token_tag2string(inactive) -> ?PrettyInactiveToken;
+token_tag2string(internal) -> ?PrettyInternalToken;
+%% token_tag2string(X) -> ?PrettyIntsigDelayToken;
+token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?PrettyIsolateToken;
+token_tag2string(inSvc) -> ?PrettyInSvcToken;
+token_tag2string(iteration) -> ?PrettyIterationToken;
+token_tag2string(keepActive) -> ?PrettyKeepActiveToken;
+token_tag2string(localDescriptor) -> ?PrettyLocalToken;
+token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken;
+token_tag2string(lockStep) -> ?PrettyLockStepToken;
+token_tag2string(loopBack) -> ?PrettyLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?PrettyMediaToken;
+token_tag2string(mediaToken) -> ?PrettyMediaToken;
+%% token_tag2string(X) -> ?PrettyMegacopToken;
+%% token_tag2string(X) -> ?PrettyMethodToken;
+%% token_tag2string(X) -> ?PrettyMgcIdToken;
+%% token_tag2string(X) -> ?PrettyModeToken;
+token_tag2string(modReq) -> ?PrettyModifyToken;
+token_tag2string(modReply) -> ?PrettyModifyToken;
+token_tag2string(modemDescriptor) -> ?PrettyModemToken;
+token_tag2string(modemToken) -> ?PrettyModemToken;
+token_tag2string(moveReq) -> ?PrettyMoveToken;
+token_tag2string(moveReply) -> ?PrettyMoveToken;
+%% token_tag2string(X) -> ?PrettyMtpToken;
+token_tag2string(muxDescriptor) -> ?PrettyMuxToken;
+token_tag2string(muxToken) -> ?PrettyMuxToken;
+%% token_tag2string(X) -> ?PrettyNeverNotifyToken;
+token_tag2string(notifyReq) -> ?PrettyNotifyToken;
+%% token_tag2string(X) -> ?PrettyNotifyCompletionToken;
+%% token_tag2string(X) -> ?PrettyNotifyImmediateToken;
+%% token_tag2string(X) -> ?PrettyNotifyRegulatedToken;
+%% token_tag2string(X) -> ?PrettyNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken;
+token_tag2string(false) -> ?PrettyOffToken;
+token_tag2string(off) -> ?PrettyOffToken;
+token_tag2string(oneway) -> ?PrettyOnewayToken;
+token_tag2string(onewayboth) -> ?PrettyOnewayBothToken;
+token_tag2string(onewayexternal) -> ?PrettyOnewayExternalToken;
+token_tag2string(onOff) -> ?PrettyOnOffToken;
+%% token_tag2string(X) -> ?PrettyOrAUDITselectToken;
+token_tag2string(true) -> ?PrettyOnToken;
+token_tag2string(otherReason) -> ?PrettyOtherReasonToken;
+token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken;
+token_tag2string(packagesToken) -> ?PrettyPackagesToken;
+%% token_tag2string(X) -> ?PrettyPendingToken;
+token_tag2string(priorityAudit) -> ?PrettyPriorityToken;
+%% token_tag2string(X) -> ?PrettyProfileToken;
+%% token_tag2string(X) -> ?PrettyReasonToken;
+token_tag2string(recvOnly) -> ?PrettyRecvonlyToken;
+%% token_tag2string(X) -> ?PrettyReplyToken;
+token_tag2string(resetEventsDescriptor) -> ?PrettyResetEventsDescriptorToken;
+%% token_tag2string(X) -> ?PrettyRequestIDToken;
+%% token_tag2string(X) -> ?PrettyResponseAckToken;
+%% token_tag2string(X) -> ?PrettyRestartToken;
+token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken;
+%% token_tag2string(X) -> ?PrettyReservedGroupToken;
+%% token_tag2string(X) -> ?PrettyReservedValueToken;
+token_tag2string(sendOnly) -> ?PrettySendonlyToken;
+token_tag2string(sendRecv) -> ?PrettySendrecvToken;
+%% token_tag2string(X) -> ?PrettyServicesToken;
+%% token_tag2string(X) -> ?PrettyServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken;
+%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?PrettyServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?PrettySignalListToken;
+token_tag2string(signalsDescriptor) -> ?PrettySignalsToken;
+token_tag2string(signalsToken) -> ?PrettySignalsToken;
+%% token_tag2string(X) -> ?PrettySignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken;
+token_tag2string(statsToken) -> ?PrettyStatsToken;
+%% token_tag2string(X) -> ?PrettyStreamToken;
+token_tag2string(subtractReq) -> ?PrettySubtractToken;
+token_tag2string(subtractReply) -> ?PrettySubtractToken;
+%% token_tag2string(X) -> ?PrettySynchISDNToken;
+%% token_tag2string(X) -> ?PrettyTerminationStateToken;
+token_tag2string(test) -> ?PrettyTestToken;
+token_tag2string(timeOut) -> ?PrettyTimeOutToken;
+token_tag2string(onTimeOut) -> ?PrettyTimeOutToken;
+token_tag2string(topologyAudit) -> ?PrettyTopologyToken;
+%% token_tag2string(X) -> ?PrettyTransToken;
+%% token_tag2string(X) -> ?PrettyV18Token;
+%% token_tag2string(X) -> ?PrettyV22Token;
+%% token_tag2string(X) -> ?PrettyV22bisToken;
+%% token_tag2string(X) -> ?PrettyV32Token;
+%% token_tag2string(X) -> ?PrettyV32bisToken;
+%% token_tag2string(X) -> ?PrettyV34Token;
+%% token_tag2string(X) -> ?PrettyV76Token;
+%% token_tag2string(X) -> ?PrettyV90Token;
+%% token_tag2string(X) -> ?PrettyV91Token;
+%% token_tag2string(X) -> ?PrettyVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]).
+-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AndAUDITSelectToken , ?PrettytAndAUDITSelectToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothToken , ?PrettyBothToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(ContextAttrToken , ?PrettyContextAttrToken).
+-define(ContextListToken , ?PrettyContextListToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DirectionToken , ?PrettyDirectionToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(EmergencyOffToken , ?PrettyEmergencyOffToken).
+-define(EmergencyValueToken , ?PrettyEmergencyValueToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(ExternalToken , ?PrettyExternalToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(IEPSToken , ?PrettyIEPSToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(InternalToken , ?PrettyInternalToken).
+-define(IntsigDelayToken , ?PrettyIntsigDelayToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(IterationToken , ?PrettyIterationToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+%% -define(MessageSegmentToken , ?PrettyMessageSegmentToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NeverNotifyToken , ?PrettyNeverNotifyToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(NotifyImmediateToken , ?PrettyNotifyImmediateToken).
+-define(NotifyRegulatedToken , ?PrettyNotifyRegulatedToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnewayBothToken , ?PrettyOnewayBothToken).
+-define(OnewayExternalToken , ?PrettyOnewayExternalToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OrAUDITselectToken , ?PrettyOrAUDITselectToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(ResetEventsDescriptorToken , ?PrettyResetEventsDescriptorToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(RequestIDToken , ?PrettyRequestIDToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+%% -define(SegmentationCompleteToken , ?PrettySegmentationCompleteToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_prev3c.hrl").
+
+%% start() ->
+%% Fun = fun() ->
+%% Val = lists:flatten([$", $e, $r, $i, $c, $s, $s, $o, $n, $"]),
+%% %% Val = [$e, $r, $i, $c, $s, $s, $o, $n],
+%% PP = {'PropertyParm',"ipdc/realm",[Val],asn1_NOVALUE},
+%% enc_PropertyParm(PP, [])
+%% end,
+%% test(Fun).
+
+%% start() ->
+%% Fun = fun() ->
+%% PP = {'PropertyParm',"ipdc/realm",["ericsson"],asn1_NOVALUE},
+%% enc_PropertyParm(PP, [])
+%% end,
+%% test(Fun).
+
+test(Fun) when is_function(Fun) ->
+ Fun().
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl
new file mode 100644
index 0000000000..6f65bc7337
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v1.erl
@@ -0,0 +1,407 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_v1).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EC, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EC}};
+encode_message(_EC, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?PrettyAddToken;
+token_tag2string(addReply) -> ?PrettyAddToken;
+token_tag2string(auditDescriptor) -> ?PrettyAuditToken;
+token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken;
+token_tag2string(auditCapReply) -> ?PrettyAuditCapToken;
+token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken;
+token_tag2string(auditValueReply) -> ?PrettyAuditValueToken;
+%% token_tag2string(X) -> ?PrettyAuthToken;
+token_tag2string(bothway) -> ?PrettyBothwayToken;
+token_tag2string(brief) -> ?PrettyBriefToken;
+%% token_tag2string(X) -> ?PrettyBufferToken;
+%% token_tag2string(X) -> ?PrettyCtxToken;
+%% token_tag2string(X) -> ?PrettyContextAuditToken;
+token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken;
+token_tag2string(digitMapToken) -> ?PrettyDigitMapToken;
+%% token_tag2string(X) -> ?PrettyDiscardToken;
+%% token_tag2string(X) -> ?PrettyDisconnectedToken;
+%% token_tag2string(X) -> ?PrettyDelayToken;
+token_tag2string(duration) -> ?PrettyDurationToken;
+%% token_tag2string(X) -> ?PrettyEmbedToken;
+token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken;
+token_tag2string(errorDescriptor) -> ?PrettyErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken;
+token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?PrettyEventsToken;
+token_tag2string(eventsToken) -> ?PrettyEventsToken;
+%% token_tag2string(X) -> ?PrettyFailoverToken;
+%% token_tag2string(X) -> ?PrettyForcedToken;
+%% token_tag2string(X) -> ?PrettyGracefulToken;
+%% token_tag2string(X) -> ?PrettyH221Token;
+%% token_tag2string(X) -> ?PrettyH223Token;
+%% token_tag2string(X) -> ?PrettyH226Token;
+%% token_tag2string(X) -> ?PrettyHandOffToken;
+%% token_tag2string(X) -> ?PrettyImmAckRequiredToken;
+token_tag2string(inactive) -> ?PrettyInactiveToken;
+token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?PrettyIsolateToken;
+token_tag2string(inSvc) -> ?PrettyInSvcToken;
+token_tag2string(keepActive) -> ?PrettyKeepActiveToken;
+token_tag2string(localDescriptor) -> ?PrettyLocalToken;
+token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken;
+token_tag2string(lockStep) -> ?PrettyLockStepToken;
+token_tag2string(loopBack) -> ?PrettyLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?PrettyMediaToken;
+token_tag2string(mediaToken) -> ?PrettyMediaToken;
+%% token_tag2string(X) -> ?PrettyMegacopToken;
+%% token_tag2string(X) -> ?PrettyMethodToken;
+%% token_tag2string(X) -> ?PrettyMgcIdToken;
+%% token_tag2string(X) -> ?PrettyModeToken;
+token_tag2string(modReq) -> ?PrettyModifyToken;
+token_tag2string(modReply) -> ?PrettyModifyToken;
+token_tag2string(modemDescriptor) -> ?PrettyModemToken;
+token_tag2string(modemToken) -> ?PrettyModemToken;
+token_tag2string(moveReq) -> ?PrettyMoveToken;
+token_tag2string(moveReply) -> ?PrettyMoveToken;
+%% token_tag2string(X) -> ?PrettyMtpToken;
+token_tag2string(muxDescriptor) -> ?PrettyMuxToken;
+token_tag2string(muxToken) -> ?PrettyMuxToken;
+token_tag2string(notifyReq) -> ?PrettyNotifyToken;
+%% token_tag2string(X) -> ?PrettyNotifyCompletionToken;
+token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken;
+token_tag2string(false) -> ?PrettyOffToken;
+token_tag2string(off) -> ?PrettyOffToken;
+token_tag2string(oneway) -> ?PrettyOnewayToken;
+token_tag2string(onOff) -> ?PrettyOnOffToken;
+token_tag2string(true) -> ?PrettyOnToken;
+token_tag2string(otherReason) -> ?PrettyOtherReasonToken;
+token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken;
+token_tag2string(packagesToken) -> ?PrettyPackagesToken;
+%% token_tag2string(X) -> ?PrettyPendingToken;
+token_tag2string(priorityAudit) -> ?PrettyPriorityToken;
+%% token_tag2string(X) -> ?PrettyProfileToken;
+%% token_tag2string(X) -> ?PrettyReasonToken;
+token_tag2string(recvOnly) -> ?PrettyRecvonlyToken;
+%% token_tag2string(X) -> ?PrettyReplyToken;
+%% token_tag2string(X) -> ?PrettyResponseAckToken;
+%% token_tag2string(X) -> ?PrettyRestartToken;
+token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken;
+%% token_tag2string(X) -> ?PrettyReservedGroupToken;
+%% token_tag2string(X) -> ?PrettyReservedValueToken;
+token_tag2string(sendOnly) -> ?PrettySendonlyToken;
+token_tag2string(sendRecv) -> ?PrettySendrecvToken;
+%% token_tag2string(X) -> ?PrettyServicesToken;
+%% token_tag2string(X) -> ?PrettyServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken;
+%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken;
+%% token_tag2string(X) -> ?PrettySignalListToken;
+token_tag2string(signalsDescriptor) -> ?PrettySignalsToken;
+token_tag2string(signalsToken) -> ?PrettySignalsToken;
+%% token_tag2string(X) -> ?PrettySignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken;
+token_tag2string(statsToken) -> ?PrettyStatsToken;
+%% token_tag2string(X) -> ?PrettyStreamToken;
+token_tag2string(subtractReq) -> ?PrettySubtractToken;
+token_tag2string(subtractReply) -> ?PrettySubtractToken;
+%% token_tag2string(X) -> ?PrettySynchISDNToken;
+%% token_tag2string(X) -> ?PrettyTerminationStateToken;
+token_tag2string(test) -> ?PrettyTestToken;
+token_tag2string(timeOut) -> ?PrettyTimeOutToken;
+token_tag2string(onTimeOut) -> ?PrettyTimeOutToken;
+token_tag2string(topologyAudit) -> ?PrettyTopologyToken;
+%% token_tag2string(X) -> ?PrettyTransToken;
+%% token_tag2string(X) -> ?PrettyV18Token;
+%% token_tag2string(X) -> ?PrettyV22Token;
+%% token_tag2string(X) -> ?PrettyV22bisToken;
+%% token_tag2string(X) -> ?PrettyV32Token;
+%% token_tag2string(X) -> ?PrettyV32bisToken;
+%% token_tag2string(X) -> ?PrettyV34Token;
+%% token_tag2string(X) -> ?PrettyV76Token;
+%% token_tag2string(X) -> ?PrettyV90Token;
+%% token_tag2string(X) -> ?PrettyV91Token;
+%% token_tag2string(X) -> ?PrettyVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v1.hrl").
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl
new file mode 100644
index 0000000000..37c067b937
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v2.erl
@@ -0,0 +1,430 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_v2).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+-export([test/1]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%
+%% See megaco_pretty_text_encoder:decode_message/2
+%%
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?PrettyAddToken;
+token_tag2string(addReply) -> ?PrettyAddToken;
+token_tag2string(auditDescriptor) -> ?PrettyAuditToken;
+token_tag2string(auditCapRequest) -> ?PrettyAuditCapToken;
+token_tag2string(auditCapReply) -> ?PrettyAuditCapToken;
+token_tag2string(auditValueRequest) -> ?PrettyAuditValueToken;
+token_tag2string(auditValueReply) -> ?PrettyAuditValueToken;
+%% token_tag2string(X) -> ?PrettyAuthToken;
+token_tag2string(bothway) -> ?PrettyBothwayToken;
+token_tag2string(brief) -> ?PrettyBriefToken;
+%% token_tag2string(X) -> ?PrettyBufferToken;
+%% token_tag2string(X) -> ?PrettyCtxToken;
+%% token_tag2string(X) -> ?PrettyContextAuditToken;
+token_tag2string(digitMapDescriptor) -> ?PrettyDigitMapToken;
+token_tag2string(digitMapToken) -> ?PrettyDigitMapToken;
+%% token_tag2string(X) -> ?PrettyDiscardToken;
+%% token_tag2string(X) -> ?PrettyDisconnectedToken;
+%% token_tag2string(X) -> ?PrettyDelayToken;
+token_tag2string(duration) -> ?PrettyDurationToken;
+%% token_tag2string(X) -> ?PrettyEmbedToken;
+token_tag2string(emergencyAudit) -> ?PrettyEmergencyToken;
+%% token_tag2string(X) -> ?PrettyEmergencyOffToken;
+token_tag2string(errorDescriptor) -> ?PrettyErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?PrettyEventBufferToken;
+token_tag2string(eventBufferToken) -> ?PrettyEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?PrettyEventsToken;
+token_tag2string(eventsToken) -> ?PrettyEventsToken;
+%% token_tag2string(X) -> ?PrettyFailoverToken;
+%% token_tag2string(X) -> ?PrettyForcedToken;
+%% token_tag2string(X) -> ?PrettyGracefulToken;
+%% token_tag2string(X) -> ?PrettyH221Token;
+%% token_tag2string(X) -> ?PrettyH223Token;
+%% token_tag2string(X) -> ?PrettyH226Token;
+%% token_tag2string(X) -> ?PrettyHandOffToken;
+%% token_tag2string(X) -> ?PrettyImmAckRequiredToken;
+token_tag2string(inactive) -> ?PrettyInactiveToken;
+token_tag2string(onInterruptByEvent) -> ?PrettyInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?PrettyInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?PrettyIsolateToken;
+token_tag2string(inSvc) -> ?PrettyInSvcToken;
+token_tag2string(keepActive) -> ?PrettyKeepActiveToken;
+token_tag2string(localDescriptor) -> ?PrettyLocalToken;
+token_tag2string(localControlDescriptor) -> ?PrettyLocalControlToken;
+token_tag2string(lockStep) -> ?PrettyLockStepToken;
+token_tag2string(loopBack) -> ?PrettyLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?PrettyMediaToken;
+token_tag2string(mediaToken) -> ?PrettyMediaToken;
+%% token_tag2string(X) -> ?PrettyMegacopToken;
+%% token_tag2string(X) -> ?PrettyMethodToken;
+%% token_tag2string(X) -> ?PrettyMgcIdToken;
+%% token_tag2string(X) -> ?PrettyModeToken;
+token_tag2string(modReq) -> ?PrettyModifyToken;
+token_tag2string(modReply) -> ?PrettyModifyToken;
+token_tag2string(modemDescriptor) -> ?PrettyModemToken;
+token_tag2string(modemToken) -> ?PrettyModemToken;
+token_tag2string(moveReq) -> ?PrettyMoveToken;
+token_tag2string(moveReply) -> ?PrettyMoveToken;
+%% token_tag2string(X) -> ?PrettyMtpToken;
+token_tag2string(muxDescriptor) -> ?PrettyMuxToken;
+token_tag2string(muxToken) -> ?PrettyMuxToken;
+token_tag2string(notifyReq) -> ?PrettyNotifyToken;
+%% token_tag2string(X) -> ?PrettyNotifyCompletionToken;
+%% token_tag2string(X) -> ?PrettyNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?PrettyObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?PrettyObservedEventsToken;
+token_tag2string(false) -> ?PrettyOffToken;
+token_tag2string(off) -> ?PrettyOffToken;
+token_tag2string(oneway) -> ?PrettyOnewayToken;
+token_tag2string(onOff) -> ?PrettyOnOffToken;
+token_tag2string(true) -> ?PrettyOnToken;
+token_tag2string(otherReason) -> ?PrettyOtherReasonToken;
+token_tag2string(outOfSvc) -> ?PrettyOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?PrettyPackagesToken;
+token_tag2string(packagesToken) -> ?PrettyPackagesToken;
+%% token_tag2string(X) -> ?PrettyPendingToken;
+token_tag2string(priorityAudit) -> ?PrettyPriorityToken;
+%% token_tag2string(X) -> ?PrettyProfileToken;
+%% token_tag2string(X) -> ?PrettyReasonToken;
+token_tag2string(recvOnly) -> ?PrettyRecvonlyToken;
+%% token_tag2string(X) -> ?PrettyReplyToken;
+%% token_tag2string(X) -> ?PrettyResponseAckToken;
+%% token_tag2string(X) -> ?PrettyRestartToken;
+token_tag2string(remoteDescriptor) -> ?PrettyRemoteToken;
+%% token_tag2string(X) -> ?PrettyReservedGroupToken;
+%% token_tag2string(X) -> ?PrettyReservedValueToken;
+token_tag2string(sendOnly) -> ?PrettySendonlyToken;
+token_tag2string(sendRecv) -> ?PrettySendrecvToken;
+%% token_tag2string(X) -> ?PrettyServicesToken;
+%% token_tag2string(X) -> ?PrettyServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?PrettyServiceChangeToken;
+%% token_tag2string(X) -> ?PrettyServiceChangeAddressToken;
+%% token_tag2string(X) -> ?PrettySignalListToken;
+token_tag2string(signalsDescriptor) -> ?PrettySignalsToken;
+token_tag2string(signalsToken) -> ?PrettySignalsToken;
+%% token_tag2string(X) -> ?PrettySignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?PrettyStatsToken;
+token_tag2string(statsToken) -> ?PrettyStatsToken;
+%% token_tag2string(X) -> ?PrettyStreamToken;
+token_tag2string(subtractReq) -> ?PrettySubtractToken;
+token_tag2string(subtractReply) -> ?PrettySubtractToken;
+%% token_tag2string(X) -> ?PrettySynchISDNToken;
+%% token_tag2string(X) -> ?PrettyTerminationStateToken;
+token_tag2string(test) -> ?PrettyTestToken;
+token_tag2string(timeOut) -> ?PrettyTimeOutToken;
+token_tag2string(onTimeOut) -> ?PrettyTimeOutToken;
+token_tag2string(topologyAudit) -> ?PrettyTopologyToken;
+%% token_tag2string(X) -> ?PrettyTransToken;
+%% token_tag2string(X) -> ?PrettyV18Token;
+%% token_tag2string(X) -> ?PrettyV22Token;
+%% token_tag2string(X) -> ?PrettyV22bisToken;
+%% token_tag2string(X) -> ?PrettyV32Token;
+%% token_tag2string(X) -> ?PrettyV32bisToken;
+%% token_tag2string(X) -> ?PrettyV34Token;
+%% token_tag2string(X) -> ?PrettyV76Token;
+%% token_tag2string(X) -> ?PrettyV90Token;
+%% token_tag2string(X) -> ?PrettyV91Token;
+%% token_tag2string(X) -> ?PrettyVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?LsbrktToken]).
+-define(RSBRKT, [?RsbrktToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(EmergencyOffToken , ?PrettyEmergencyOffToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v2.hrl").
+
+%% start() ->
+%% Fun = fun() ->
+%% PP = {'PropertyParm',"ipdc/realm",["ericsson"],asn1_NOVALUE},
+%% enc_PropertyParm(PP, [])
+%% end,
+%% test(Fun).
+
+test(Fun) when is_function(Fun) ->
+ Fun().
+
diff --git a/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl b/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl
new file mode 100644
index 0000000000..833b6ea00f
--- /dev/null
+++ b/lib/megaco/src/text/megaco_pretty_text_encoder_v3.erl
@@ -0,0 +1,462 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_pretty_text_encoder_v3).
+
+-export([encode_message/2,
+ encode_transaction/2,
+ encode_action_requests/2,
+ encode_action_request/2,
+ encode_command_request/2,
+ encode_action_reply/2]).
+
+-export([token_tag2string/1]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include("megaco_text_tokens.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a 'MegacoMessage' record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+
+encode_message(EC, MegaMsg)
+ when is_list(EC) andalso is_record(MegaMsg, 'MegacoMessage') ->
+ case (catch enc_MegacoMessage(MegaMsg)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end;
+encode_message(EncodingConfig, MegaMsg)
+ when is_record(MegaMsg, 'MegacoMessage') ->
+ {error, {bad_encoding_config, EncodingConfig}};
+encode_message(_EncodingConfig, _MegaMsg) ->
+ {error, bad_megaco_message}.
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%
+%% See megaco_pretty_text_encoder:decode_message/2
+%%
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Convert a transaction record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_transaction(_EC, Trans) ->
+ case (catch enc_Transaction(Trans)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a list of ActionRequest record's into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_requests(_EC, ActReqs) when is_list(ActReqs) ->
+ case (catch enc_ActionRequests(ActReqs)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a ActionRequest record into a binary
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_request(_EC, ActReq)
+ when is_record(ActReq, 'ActionRequest') ->
+ case (catch enc_ActionRequest(ActReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a CommandRequest record into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_command_request(_EC, CmdReq)
+ when is_record(CmdReq, 'CommandRequest') ->
+ case (catch enc_CommandRequest(CmdReq)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+%%----------------------------------------------------------------------
+%% Convert a action reply into a deep io list
+%% Return {ok, DeepIoList} | {error, Reason}
+%%----------------------------------------------------------------------
+encode_action_reply(_EC, ActRep)
+ when is_record(ActRep, 'ActionReply') ->
+ case (catch enc_ActionReply(ActRep)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ DeepIoList ->
+ Bin = erlang:list_to_binary(DeepIoList),
+ {ok, Bin}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% A utility function to pretty print the tags found in a megaco message
+%%----------------------------------------------------------------------
+
+token_tag2string(addReq) -> ?CompactAddToken;
+token_tag2string(addReply) -> ?CompactAddToken;
+%% token_tag2string(X) -> ?CompactAndAUDITSelectToken;
+token_tag2string(auditDescriptor) -> ?CompactAuditToken;
+token_tag2string(auditCapRequest) -> ?CompactAuditCapToken;
+token_tag2string(auditCapReply) -> ?CompactAuditCapToken;
+token_tag2string(auditValueRequest) -> ?CompactAuditValueToken;
+token_tag2string(auditValueReply) -> ?CompactAuditValueToken;
+%% token_tag2string(X) -> ?CompactAuthToken;
+token_tag2string(both) -> ?CompactBothToken;
+token_tag2string(bothway) -> ?CompactBothwayToken;
+token_tag2string(brief) -> ?CompactBriefToken;
+%% token_tag2string(X) -> ?CompactBufferToken;
+%% token_tag2string(X) -> ?CompactCtxToken;
+%% token_tag2string(X) -> ?CompactContextAuditToken;
+%% token_tag2string(X) -> ?CompactContextAttrToken;
+%% token_tag2string(X) -> ?CompactContextListToken;
+token_tag2string(digitMapDescriptor) -> ?CompactDigitMapToken;
+token_tag2string(digitMapToken) -> ?CompactDigitMapToken;
+%% token_tag2string(X) -> ?CompactDirectionToken;
+%% token_tag2string(X) -> ?CompactDiscardToken;
+%% token_tag2string(X) -> ?CompactDisconnectedToken;
+%% token_tag2string(X) -> ?CompactDelayToken;
+token_tag2string(duration) -> ?CompactDurationToken;
+%% token_tag2string(X) -> ?CompactEmbedToken;
+token_tag2string(emergencyAudit) -> ?CompactEmergencyToken;
+%% token_tag2string(X) -> ?CompactEmergencyOffToken;
+%% token_tag2string(X) -> ?CompactEmergencyValueToken;
+token_tag2string(errorDescriptor) -> ?CompactErrorToken;
+token_tag2string(eventBufferDescriptor) -> ?CompactEventBufferToken;
+token_tag2string(eventBufferToken) -> ?CompactEventBufferToken;
+token_tag2string(eventsDescriptor) -> ?CompactEventsToken;
+token_tag2string(eventsToken) -> ?CompactEventsToken;
+token_tag2string(external) -> ?CompactExternalToken;
+%% token_tag2string(X) -> ?CompactFailoverToken;
+%% token_tag2string(X) -> ?CompactForcedToken;
+%% token_tag2string(X) -> ?CompactGracefulToken;
+%% token_tag2string(X) -> ?CompactH221Token;
+%% token_tag2string(X) -> ?CompactH223Token;
+%% token_tag2string(X) -> ?CompactH226Token;
+%% token_tag2string(X) -> ?CompactHandOffToken;
+token_tag2string(iepsCallind) -> ?CompactIEPSToken;
+%% token_tag2string(X) -> ?CompactImmAckRequiredToken;
+token_tag2string(inactive) -> ?CompactInactiveToken;
+token_tag2string(internal) -> ?CompactInternalToken;
+%% token_tag2string(X) -> ?CompactIntsigDelayToken;
+token_tag2string(onInterruptByEvent) -> ?CompactInterruptByEventToken;
+token_tag2string(onInterruptByNewSignalDescr) -> ?CompactInterruptByNewSignalsDescrToken;
+token_tag2string(isolate) -> ?CompactIsolateToken;
+token_tag2string(inSvc) -> ?CompactInSvcToken;
+token_tag2string(iteration) -> ?CompactIterationToken;
+token_tag2string(keepActive) -> ?CompactKeepActiveToken;
+token_tag2string(localDescriptor) -> ?CompactLocalToken;
+token_tag2string(localControlDescriptor) -> ?CompactLocalControlToken;
+token_tag2string(lockStep) -> ?CompactLockStepToken;
+token_tag2string(loopBack) -> ?CompactLoopbackToken;
+token_tag2string(mediaDescriptor) -> ?CompactMediaToken;
+token_tag2string(mediaToken) -> ?CompactMediaToken;
+%% token_tag2string(X) -> ?CompactMegacopToken;
+%% token_tag2string(X) -> ?CompactMethodToken;
+%% token_tag2string(X) -> ?CompactMgcIdToken;
+%% token_tag2string(X) -> ?CompactModeToken;
+token_tag2string(modReq) -> ?CompactModifyToken;
+token_tag2string(modReply) -> ?CompactModifyToken;
+token_tag2string(modemDescriptor) -> ?CompactModemToken;
+token_tag2string(modemToken) -> ?CompactModemToken;
+token_tag2string(moveReq) -> ?CompactMoveToken;
+token_tag2string(moveReply) -> ?CompactMoveToken;
+%% token_tag2string(X) -> ?CompactMtpToken;
+token_tag2string(muxDescriptor) -> ?CompactMuxToken;
+token_tag2string(muxToken) -> ?CompactMuxToken;
+%% token_tag2string(X) -> ?CompactNeverNotifyToken;
+token_tag2string(notifyReq) -> ?CompactNotifyToken;
+%% token_tag2string(X) -> ?CompactNotifyCompletionToken;
+%% token_tag2string(X) -> ?CompactNotifyImmediateToken;
+%% token_tag2string(X) -> ?CompactNotifyRegulatedToken;
+%% token_tag2string(X) -> ?CompactNx64kToken;
+token_tag2string(observedEventsDescriptor) -> ?CompactObservedEventsToken;
+token_tag2string(observedEventsToken) -> ?CompactObservedEventsToken;
+token_tag2string(false) -> ?CompactOffToken;
+token_tag2string(off) -> ?CompactOffToken;
+token_tag2string(oneway) -> ?CompactOnewayToken;
+token_tag2string(onewayboth) -> ?CompactOnewayBothToken;
+token_tag2string(onewayexternal) -> ?CompactOnewayExternalToken;
+token_tag2string(onOff) -> ?CompactOnOffToken;
+%% token_tag2string(X) -> ?CompactOrAUDITselectToken;
+token_tag2string(true) -> ?CompactOnToken;
+token_tag2string(otherReason) -> ?CompactOtherReasonToken;
+token_tag2string(outOfSvc) -> ?CompactOutOfSvcToken;
+token_tag2string(packagesDescriptor) -> ?CompactPackagesToken;
+token_tag2string(packagesToken) -> ?CompactPackagesToken;
+%% token_tag2string(X) -> ?CompactPendingToken;
+token_tag2string(priorityAudit) -> ?CompactPriorityToken;
+%% token_tag2string(X) -> ?CompactProfileToken;
+%% token_tag2string(X) -> ?CompactReasonToken;
+token_tag2string(recvOnly) -> ?CompactRecvonlyToken;
+%% token_tag2string(X) -> ?CompactReplyToken;
+token_tag2string(resetEventsDescriptor) -> ?CompactResetEventsDescriptorToken;
+%% token_tag2string(X) -> ?CompactRequestIDToken;
+%% token_tag2string(X) -> ?CompactResponseAckToken;
+%% token_tag2string(X) -> ?CompactRestartToken;
+token_tag2string(remoteDescriptor) -> ?CompactRemoteToken;
+%% token_tag2string(X) -> ?CompactReservedGroupToken;
+%% token_tag2string(X) -> ?CompactReservedValueToken;
+token_tag2string(sendOnly) -> ?CompactSendonlyToken;
+token_tag2string(sendRecv) -> ?CompactSendrecvToken;
+%% token_tag2string(X) -> ?CompactServicesToken;
+%% token_tag2string(X) -> ?CompactServiceStatesToken;
+token_tag2string(serviceChangeReq) -> ?CompactServiceChangeToken;
+%% token_tag2string(X) -> ?CompactServiceChangeAddressToken;
+token_tag2string(incomplete) -> ?CompactServiceChangeIncompleteToken;
+%% token_tag2string(X) -> ?CompactSignalListToken;
+token_tag2string(signalsDescriptor) -> ?CompactSignalsToken;
+token_tag2string(signalsToken) -> ?CompactSignalsToken;
+%% token_tag2string(X) -> ?CompactSignalTypeToken;
+token_tag2string(statisticsDescriptor) -> ?CompactStatsToken;
+token_tag2string(statsToken) -> ?CompactStatsToken;
+%% token_tag2string(X) -> ?CompactStreamToken;
+token_tag2string(subtractReq) -> ?CompactSubtractToken;
+token_tag2string(subtractReply) -> ?CompactSubtractToken;
+%% token_tag2string(X) -> ?CompactSynchISDNToken;
+%% token_tag2string(X) -> ?CompactTerminationStateToken;
+token_tag2string(test) -> ?CompactTestToken;
+token_tag2string(timeOut) -> ?CompactTimeOutToken;
+token_tag2string(onTimeOut) -> ?CompactTimeOutToken;
+token_tag2string(topologyAudit) -> ?CompactTopologyToken;
+%% token_tag2string(X) -> ?CompactTransToken;
+%% token_tag2string(X) -> ?CompactV18Token;
+%% token_tag2string(X) -> ?CompactV22Token;
+%% token_tag2string(X) -> ?CompactV22bisToken;
+%% token_tag2string(X) -> ?CompactV32Token;
+%% token_tag2string(X) -> ?CompactV32bisToken;
+%% token_tag2string(X) -> ?CompactV34Token;
+%% token_tag2string(X) -> ?CompactV76Token;
+%% token_tag2string(X) -> ?CompactV90Token;
+%% token_tag2string(X) -> ?CompactV91Token;
+%% token_tag2string(X) -> ?CompactVersionToken;
+token_tag2string(_) -> [].
+
+
+%%----------------------------------------------------------------------
+%% Define various macros used by the actual generator code
+%%----------------------------------------------------------------------
+
+-define(EQUAL, [?SpToken, ?EqualToken, ?SpToken]).
+-define(COLON, [?ColonToken]).
+-define(LBRKT, [?SpToken, ?LbrktToken, ?SpToken]).
+-define(RBRKT, [?SpToken, ?RbrktToken, ?SpToken]).
+-define(LSBRKT, [?SpToken, ?LsbrktToken, ?SpToken]).
+-define(RSBRKT, [?SpToken, ?RsbrktToken, ?SpToken]).
+-define(COMMA, [?CommaToken, ?SpToken]).
+-define(DOT, [?DotToken]).
+-define(SLASH, [?SlashToken]).
+-define(DQUOTE, [?DoubleQuoteToken]).
+-define(SP, [?SpToken]).
+-define(HTAB, [?HtabToken]).
+-define(CR, [?CrToken]).
+-define(LF, [?LfToken]).
+-define(LWSP, []).
+-define(EOL, ?LF).
+-define(WSP, ?SP).
+-define(SEP, ?WSP).
+
+-define(INIT_INDENT, []).
+-define(INC_INDENT(State), [?HtabToken | State]).
+-define(INDENT(State), [?LfToken | State]).
+-define(LBRKT_INDENT(State), [?SpToken, ?LbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RBRKT_INDENT(State), [?INDENT(State), ?RbrktToken]).
+-define(LSBRKT_INDENT(State), [?SpToken, ?LsbrktToken, ?INDENT(?INC_INDENT(State))]).
+-define(RSBRKT_INDENT(State), [?INDENT(State), ?RsbrktToken]).
+-define(COMMA_INDENT(State), [?CommaToken, ?INDENT(State)]).
+-define(SEP_INDENT(_State), [?LfToken]).
+
+%%----------------------------------------------------------------------
+%% Define token macros
+%%----------------------------------------------------------------------
+
+-define(AddToken , ?PrettyAddToken).
+-define(AndAUDITSelectToken , ?PrettytAndAUDITSelectToken).
+-define(AuditToken , ?PrettyAuditToken).
+-define(AuditCapToken , ?PrettyAuditCapToken).
+-define(AuditValueToken , ?PrettyAuditValueToken).
+-define(AuthToken , ?PrettyAuthToken).
+-define(BothToken , ?PrettyBothToken).
+-define(BothwayToken , ?PrettyBothwayToken).
+-define(BriefToken , ?PrettyBriefToken).
+-define(BufferToken , ?PrettyBufferToken).
+-define(CtxToken , ?PrettyCtxToken).
+-define(ContextAuditToken , ?PrettyContextAuditToken).
+-define(ContextAttrToken , ?PrettyContextAttrToken).
+-define(ContextListToken , ?PrettyContextListToken).
+-define(DigitMapToken , ?PrettyDigitMapToken).
+-define(DirectionToken , ?PrettyDirectionToken).
+-define(DiscardToken , ?PrettyDiscardToken).
+-define(DisconnectedToken , ?PrettyDisconnectedToken).
+-define(DelayToken , ?PrettyDelayToken).
+-define(DeleteToken , ?PrettyDeleteToken).
+-define(DurationToken , ?PrettyDurationToken).
+-define(EmbedToken , ?PrettyEmbedToken).
+-define(EmergencyToken , ?PrettyEmergencyToken).
+-define(EmergencyOffToken , ?PrettyEmergencyOffToken).
+-define(EmergencyValueToken , ?PrettyEmergencyValueToken).
+-define(ErrorToken , ?PrettyErrorToken).
+-define(EventBufferToken , ?PrettyEventBufferToken).
+-define(EventsToken , ?PrettyEventsToken).
+-define(ExternalToken , ?PrettyExternalToken).
+-define(FailoverToken , ?PrettyFailoverToken).
+-define(ForcedToken , ?PrettyForcedToken).
+-define(GracefulToken , ?PrettyGracefulToken).
+-define(H221Token , ?PrettyH221Token).
+-define(H223Token , ?PrettyH223Token).
+-define(H226Token , ?PrettyH226Token).
+-define(HandOffToken , ?PrettyHandOffToken).
+-define(IEPSToken , ?PrettyIEPSToken).
+-define(ImmAckRequiredToken , ?PrettyImmAckRequiredToken).
+-define(InactiveToken , ?PrettyInactiveToken).
+-define(InternalToken , ?PrettyInternalToken).
+-define(IntsigDelayToken , ?PrettyIntsigDelayToken).
+-define(IsolateToken , ?PrettyIsolateToken).
+-define(InSvcToken , ?PrettyInSvcToken).
+-define(InterruptByEventToken , ?PrettyInterruptByEventToken).
+-define(InterruptByNewSignalsDescrToken, ?PrettyInterruptByNewSignalsDescrToken).
+-define(IterationToken , ?PrettyIterationToken).
+-define(KeepActiveToken , ?PrettyKeepActiveToken).
+-define(LocalToken , ?PrettyLocalToken).
+-define(LocalControlToken , ?PrettyLocalControlToken).
+-define(LockStepToken , ?PrettyLockStepToken).
+-define(LoopbackToken , ?PrettyLoopbackToken).
+-define(MediaToken , ?PrettyMediaToken).
+-define(MegacopToken , ?PrettyMegacopToken).
+-define(MessageSegmentToken , ?PrettyMessageSegmentToken).
+-define(MethodToken , ?PrettyMethodToken).
+-define(MgcIdToken , ?PrettyMgcIdToken).
+-define(ModeToken , ?PrettyModeToken).
+-define(ModifyToken , ?PrettyModifyToken).
+-define(ModemToken , ?PrettyModemToken).
+-define(MoveToken , ?PrettyMoveToken).
+-define(MtpToken , ?PrettyMtpToken).
+-define(MuxToken , ?PrettyMuxToken).
+-define(NeverNotifyToken , ?PrettyNeverNotifyToken).
+-define(NotifyToken , ?PrettyNotifyToken).
+-define(NotifyCompletionToken , ?PrettyNotifyCompletionToken).
+-define(NotifyImmediateToken , ?PrettyNotifyImmediateToken).
+-define(NotifyRegulatedToken , ?PrettyNotifyRegulatedToken).
+-define(Nx64kToken , ?PrettyNx64kToken).
+-define(ObservedEventsToken , ?PrettyObservedEventsToken).
+-define(OffToken , ?PrettyOffToken).
+-define(OnewayToken , ?PrettyOnewayToken).
+-define(OnewayBothToken , ?PrettyOnewayBothToken).
+-define(OnewayExternalToken , ?PrettyOnewayExternalToken).
+-define(OnOffToken , ?PrettyOnOffToken).
+-define(OnToken , ?PrettyOnToken).
+-define(OrAUDITselectToken , ?PrettyOrAUDITselectToken).
+-define(OtherReasonToken , ?PrettyOtherReasonToken).
+-define(OutOfSvcToken , ?PrettyOutOfSvcToken).
+-define(PackagesToken , ?PrettyPackagesToken).
+-define(PendingToken , ?PrettyPendingToken).
+-define(PriorityToken , ?PrettyPriorityToken).
+-define(ProfileToken , ?PrettyProfileToken).
+-define(ReasonToken , ?PrettyReasonToken).
+-define(RecvonlyToken , ?PrettyRecvonlyToken).
+-define(ReplyToken , ?PrettyReplyToken).
+-define(ResetEventsDescriptorToken , ?PrettyResetEventsDescriptorToken).
+-define(ResponseAckToken , ?PrettyResponseAckToken).
+-define(RestartToken , ?PrettyRestartToken).
+-define(RemoteToken , ?PrettyRemoteToken).
+-define(RequestIDToken , ?PrettyRequestIDToken).
+-define(ReservedGroupToken , ?PrettyReservedGroupToken).
+-define(ReservedValueToken , ?PrettyReservedValueToken).
+-define(SegmentationCompleteToken , ?PrettySegmentationCompleteToken).
+-define(SendonlyToken , ?PrettySendonlyToken).
+-define(SendrecvToken , ?PrettySendrecvToken).
+-define(ServicesToken , ?PrettyServicesToken).
+-define(ServiceStatesToken , ?PrettyServiceStatesToken).
+-define(ServiceChangeToken , ?PrettyServiceChangeToken).
+-define(ServiceChangeAddressToken , ?PrettyServiceChangeAddressToken).
+-define(ServiceChangeIncompleteToken , ?PrettyServiceChangeIncompleteToken).
+-define(SignalListToken , ?PrettySignalListToken).
+-define(SignalsToken , ?PrettySignalsToken).
+-define(SignalTypeToken , ?PrettySignalTypeToken).
+-define(StatsToken , ?PrettyStatsToken).
+-define(StreamToken , ?PrettyStreamToken).
+-define(SubtractToken , ?PrettySubtractToken).
+-define(SynchISDNToken , ?PrettySynchISDNToken).
+-define(TerminationStateToken , ?PrettyTerminationStateToken).
+-define(TestToken , ?PrettyTestToken).
+-define(TimeOutToken , ?PrettyTimeOutToken).
+-define(TopologyToken , ?PrettyTopologyToken).
+-define(TransToken , ?PrettyTransToken).
+-define(V18Token , ?PrettyV18Token).
+-define(V22Token , ?PrettyV22Token).
+-define(V22bisToken , ?PrettyV22bisToken).
+-define(V32Token , ?PrettyV32Token).
+-define(V32bisToken , ?PrettyV32bisToken).
+-define(V34Token , ?PrettyV34Token).
+-define(V76Token , ?PrettyV76Token).
+-define(V90Token , ?PrettyV90Token).
+-define(V91Token , ?PrettyV91Token).
+-define(VersionToken , ?PrettyVersionToken).
+
+%%----------------------------------------------------------------------
+%% Include the generator code
+%%----------------------------------------------------------------------
+
+-include("megaco_text_gen_v3.hrl").
+
diff --git a/lib/megaco/src/text/megaco_text_gen_prev3a.hrl b/lib/megaco/src/text/megaco_text_gen_prev3a.hrl
new file mode 100644
index 0000000000..b1ddb10a4e
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_prev3a.hrl
@@ -0,0 +1,2945 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode V2 Megaco/H.248 text messages from internal form
+%% The following was changed:
+%% - MuxType (Nx64kToken)
+%% - auditItem (terminationAudit)
+%% - serviceChangeParm (auditItem)
+%%
+%% The following was added:
+%% - All IndAud stuff
+%%----------------------------------------------------------------------
+
+%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])).
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) andalso (Val =/= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE},
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',
+ Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAAR,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {[CtxAAR], fun enc_ContextAttrAuditRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+% d("enc_ActionReply -> entry with"
+% "~n Id: ~p"
+% "~n ED: ~p"
+% "~n CtxRep: ~p"
+% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, [], State)
+ when CtxRep =/= asn1_NOVALUE ->
+% d("do_enc_ActionReply -> entry with"
+% "~n CtxRep: ~p", [CtxRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when CtxRep =/= asn1_NOVALUE, CmdRep =/= [] ->
+% d("do_enc_ActionReply -> entry with"
+% "~n CtxRep: ~p"
+% "~n CmdRep: ~p", [CtxRep, CmdRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State)
+ when CmdRep =/= [] ->
+% d("do_enc_ActionReply -> entry with"
+% "~n CmdRep: ~p", [CmdRep]),
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, [], State)
+ when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) ->
+% d("do_enc_ActionReply -> entry with"
+% "~n ED: ~p"
+% "~n CtxRep: ~p", [ED, CtxRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) ->
+% d("do_enc_ActionReply -> entry with"
+% "~n ED: ~p"
+% "~n CmdRep: ~p", [ED, CmdRep]),
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso
+ (CtxRep =/= asn1_NOVALUE) andalso
+ (CmdRep =/= []) ->
+% d("do_enc_ActionReply -> entry with"
+% "~n ED: ~p"
+% "~n CtxRep: ~p"
+% "~n CmdRep: ~p", [ED, CtxRep, CmdRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State)
+ when ED =/= asn1_NOVALUE ->
+% d("do_enc_ActionReply -> entry with"
+% "~n ED: ~p", [ED]),
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+enc_ContextRequest_priority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_priority(Val, _State) ->
+ {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextRequest_emergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_emergency(true, _State) ->
+ {[?EmergencyToken], fun(Elem, _) -> Elem end};
+enc_ContextRequest_emergency(false, _State) ->
+ {[?EmergencyOffToken], fun(Elem, _) -> Elem end}.
+
+enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ asn1_NOVALUE}, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ List}, _State) ->
+ {List, fun enc_TopologyRequest/2};
+enc_ContextRequest_topologyReq(List, _State) ->
+ {[List], fun enc_TopologyRequest/2}.
+
+enc_ContextRequest_iepsCallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_iepsCallind(false, _State) ->
+ {[], dummy};
+% enc_ContextRequest_iepsCallind(false, _State) ->
+% {[?IEPS_XXXX_Token], fun(Elem, _) -> Elem end};
+enc_ContextRequest_iepsCallind(true, _State) ->
+ {[?IEPSToken], fun(Elem, _) -> Elem end}.
+
+enc_ContextRequest_contextProp(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp([PP], _State) ->
+ {[PP], fun enc_PropertyParm/2};
+enc_ContextRequest_contextProp(PPs, _State) when is_list(PPs) ->
+ error({at_most_one_contextProp, PPs}).
+
+enc_ContextRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = [],
+ iepsCallind = asn1_NOVALUE,
+ contextProp = []}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TR,
+ iepsCallind = Ieps,
+ contextProp = CP}, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ enc_list([enc_ContextRequest_priority(Prio, State),
+ enc_ContextRequest_emergency(Em, State),
+ enc_ContextRequest_topologyReq(TR, State),
+ enc_ContextRequest_iepsCallind(Ieps, State),
+ enc_ContextRequest_contextProp(CP, State)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = []}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(CAAR, State) ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudContextAttrDescriptor(CAAR, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudContextAttrDescriptor(
+ #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepsCallind = Ieps,
+ contextPropAud = CPA}, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+ {[Em], fun('NULL', _) -> ?EmergencyToken end},
+ {[Prio], fun('NULL', _) -> ?PriorityToken end},
+ {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+ {CPA, fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+% d("enc_Command -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+% d("enc_CommandReply -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir}, State) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(Dir, State)
+ ].
+
+enc_TopologyDirection(bothway, _State) ->
+ ?BothwayToken;
+enc_TopologyDirection(isolate, _State) ->
+ ?IsolateToken;
+enc_TopologyDirection(oneway, _State) ->
+ ?OnewayToken;
+enc_TopologyDirection(Top, _State) ->
+ error({illegal_TopologyDirection, Top}).
+
+enc_AmmRequest(Val, State)
+ when is_record(Val, 'AmmRequest') ->
+% d("enc_AmmRequest -> entry with"
+% "~n Val: ~p", [Val]),
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State),
+ enc_opt_brackets(
+ enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+% d("enc_ammDescriptor -> entry with"
+% "~n Tag: ~p"
+% "~n Desc: ~p", [Tag, Desc]),
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = asn1_NOVALUE}, State) ->
+% d("enc_AmmsReply(asn1_NOVALUE) -> entry with"
+% "~n ID: ~p", [ID]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = []}, State) ->
+% d("enc_AmmsReply([]) -> entry with"
+% "~n ID: ~p", [ID]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = Res}, State) ->
+% d("enc_AmmsReply -> entry with"
+% "~n ID: ~p"
+% "~n Res: ~p", [ID, Res]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(Val, State)
+ when is_record(Val, 'SubtractRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State),
+ case Val#'SubtractRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_AuditRequest(Val, State)
+ when is_record(Val, 'AuditRequest') ->
+% d("enc_AuditRequest -> entry with"
+% "~n Val: ~p", [Val]),
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State),
+ case Val#'AuditRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+ case Tag of
+ contextAuditResult ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDListN(Val, State)
+ ];
+ error ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [],
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor([]) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = asn1_NOVALUE},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n List: ~p", [List]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+%% - v2 -
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = Prop},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n Prop: ~p", [Prop]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = Prop},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n List: ~p"
+% "~n Prop: ~p", [List, Prop]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+
+%% - v2 begin -
+
+enc_auditPropertyToken([], _State) ->
+ [];
+enc_auditPropertyToken([Param | Params], State) ->
+% d("enc_auditPropertyToken -> entry with",
+% "~n Param: ~p", [Param]),
+ [enc_IndAudauditReturnParameter(Param, State),
+ [[?COMMA_INDENT(State),
+ enc_IndAudauditReturnParameter(P, State)] || P <- Params]].
+
+
+enc_IndAudauditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ indAudMediaDescriptor ->
+ enc_IndAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ enc_IndAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ enc_IndAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ enc_IndAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ enc_IndAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ enc_IndAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ enc_IndAudPackagesDescriptor(Val, State);
+ _ ->
+ error({invalid_IndAudauditReturnParameter_tag, Tag})
+ end.
+
+%% The ASN.1 does not limit to just one of termStateDescr or streams,
+%% but the ABNF seams to do that...
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE,
+ streams = Streams}, State) ->
+% d("enc_IndAudMediaDescriptor -> entry with",
+% "~n Streams: ~p", [Streams]),
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = asn1_NOVALUE},
+ State) ->
+% d("enc_IndAudMediaDescriptor -> entry with",
+% "~n TSD: ~p", [TSD]),
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudMediaDescriptor_streams({Tag, Val}, State) ->
+% d("enc_IndAudMediaDescriptor_streams -> entry with",
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ oneStream ->
+ enc_IndAudStreamParms(Val, State);
+ multiStream ->
+ enc_IndAudMediaDescriptor_multiStream(Val, State);
+ _ ->
+ error({invalid_IndAudMediaDescriptor_streams_tag, Tag})
+ end.
+
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = 'NULL'}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?ServiceStatesToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = 'NULL',
+ serviceState = asn1_NOVALUE}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?BufferToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [Parms],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE}, State) ->
+ #'IndAudPropertyParm'{name = Name} = Parms,
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% In text, localDescriptor and remoteDescriptor are not allowed!!
+enc_IndAudStreamParms(
+ #'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+ statisticsDescriptor = SD}, State) ->
+% d("enc_IndAudStreamParms -> entry with"
+% "~n LCD: ~p"
+% "~n SD: ~p", [LCD, SD]),
+ [
+ enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2},
+ {[SD], fun enc_IndAudStatisticsDescriptor/2}],
+ ?INC_INDENT(State))
+ ].
+
+enc_IndAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'IndAudLocalControlDescriptor'.streamMode],
+ fun('NULL', _) -> ?ModeToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveValue],
+ fun('NULL', _) -> ?ReservedValueToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveGroup],
+ fun('NULL', _) -> ?ReservedGroupToken end},
+ {Val#'IndAudLocalControlDescriptor'.propertyParms,
+ fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = PkgdName}, State) ->
+ enc_PkgdName(PkgdName, State).
+
+enc_IndAudMediaDescriptor_multiStream([Val], State) ->
+% d("enc_IndAudMediaDescriptor_multiStream -> entry with"
+% "~n Val: ~p", [Val]),
+ [
+ enc_IndAudStreamDescriptor(Val, ?INC_INDENT(State))
+ ];
+enc_IndAudMediaDescriptor_multiStream(Vals, _State) when is_list(Vals) ->
+ error({invalid_IndAudMediaDescriptor_multiStream_length, Vals});
+enc_IndAudMediaDescriptor_multiStream(Val, _State) ->
+ error({invalid_IndAudMediaDescriptor_multiStream, Val}).
+
+enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms},
+ State) ->
+% d("enc_IndAudStreamDescriptor -> entry with"
+% "~n SID: ~p"
+% "~n Parms: ~p", [SID, Parms]),
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudStreamParms(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventBufferDescriptor') ->
+ #'IndAudEventBufferDescriptor'{eventName = EvName,
+ streamID = ID} = Val,
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(EvName, State),
+ enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) ->
+ [
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName},
+ State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_Name(ParamName, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec(ID, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventsDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventsDescriptor') ->
+ #'IndAudEventsDescriptor'{requestID = ReqID,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE} = Val,
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(ReqID, State),
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudSignalsDescriptor(Val, State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSignalsDescriptor_value({signal, Val}, State) ->
+ enc_IndAudSignal(Val, State);
+enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) ->
+ enc_IndAudSeqSigList(Val, State).
+
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ enc_SignalName(SignalName, State)
+ ].
+
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = Parm},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignal(Parm, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ].
+
+enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name},
+ State) ->
+% d("enc_IndAudStatisticsDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_Name(N, State),
+ "-",
+ enc_UINT16(V, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% - v2 end -
+
+
+enc_TerminationAudit({'TerminationAudit',Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([], _State) ->
+ [];
+enc_TerminationAudit([Mand | Opt], State) ->
+% d("enc_TerminationAudit -> entry with"
+% "~n Mand: ~p", [Mand]),
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+% d("enc_AuditReturnParameter -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({invalid_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+ enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)).
+
+
+enc_NotifyRequest(Val, State)
+ when is_record(Val, 'NotifyRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ case Val#'NotifyRequest'.errorDescriptor of
+ asn1_NOVALUE ->
+ OED = Val#'NotifyRequest'.observedEventsDescriptor,
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State));
+ ErrorDescr ->
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State))
+ end,
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(Val, State)
+ when is_record(Val, 'NotifyReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ case Val#'NotifyReply'.terminationID of
+ asn1_NOVALUE ->
+ error(asn1_not_compliant_with_abnf);
+ TermId ->
+ enc_TerminationIDList1(TermId, State)
+ end,
+ case Val#'NotifyReply'.errorDescriptor of
+ asn1_NOVALUE ->
+ [];
+ ErrorDescr ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_ObservedEventsDescriptor(Val, State)
+ when is_record(Val, 'ObservedEventsDescriptor') ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEventsDescriptors([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(Val, State)
+ when is_record(Val, 'ObservedEvent') ->
+ [
+ case Val#'ObservedEvent'.timeNotation of
+ asn1_NOVALUE ->
+ [];
+ TimeStamp ->
+ [
+ enc_TimeNotation(TimeStamp, State),
+ ?LWSP,
+ ?COLON
+ ]
+ end,
+ ?LWSP,
+ enc_EventName(Val#'ObservedEvent'.eventName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName',Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(Val, State)
+ when is_record(Val, 'ServiceChangeRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms,
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(Val, State)
+ when is_record(Val, 'ServiceChangeReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State),
+ enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({Tag, Val}, State) ->
+ case Tag of
+ errorDescriptor ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ serviceChangeResParms ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+ _ ->
+ error({invalid_ServiceChangeResult_tag, Tag})
+ end.
+
+%% Required length of termination ID list is 1
+enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList1(Val, State);
+enc_TerminationIDList1([Singleton], State) ->
+ enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDListN({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDListN(Val, State);
+enc_TerminationIDListN([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDListN(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(Val, State)
+ when is_record(Val, 'MediaDescriptor') ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'MediaDescriptor'.termStateDescr],
+ fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Val#'MediaDescriptor'.streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2},
+ {[Val#'StreamParms'.statisticsDescriptor],
+ fun enc_StatisticsDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name == "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EQUAL,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EQUAL,
+ ?LSBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RSBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token;
+ %% extensionParameter
+ nx64k -> ?Nx64kToken % v2
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(Val, State)
+ when is_record(Val, 'EventsDescriptor') ->
+ #'EventsDescriptor'{requestID = RequestId,
+ eventList = Events} = Val,
+ if
+ RequestId == asn1_NOVALUE, Events == [] ->
+ [
+ ?EventsToken
+ ];
+
+ RequestId /= asn1_NOVALUE, Events /= [] ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RequestId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Events, fun enc_RequestedEvent/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end.
+
+enc_RequestedEvent(Val, State)
+ when is_record(Val, 'RequestedEvent') ->
+ PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} |
+ decompose_requestedActions(Val#'RequestedEvent'.eventAction)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of KeepActiveToken , eventDM and eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (KA =/= true) andalso
+ (SD =/= asn1_NOVALUE) andalso
+ (SD =/= []) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ].
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) ->
+ %% d("enc_embedFirst -> entry with"
+ %% "~n RID: ~p"
+ %% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+ %% d("enc_embedFirst -> entry"),
+ [
+ ?EventsToken
+ ].
+
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL,
+ eventAction = EA}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list(
+ [{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(Val)
+ when is_record(Val, 'SecondRequestedActions') ->
+ [
+ {[Val#'SecondRequestedActions'.keepActive],
+ fun enc_keepActive/2},
+ {[Val#'SecondRequestedActions'.eventDM],
+ fun enc_EventDM/2},
+ {[Val#'SecondRequestedActions'.signalsDescriptor],
+ fun enc_embeddedSignalsDescriptor/2}
+ ].
+
+enc_embeddedSignalsDescriptor(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EventSpecs, State)
+ when is_list(EventSpecs) andalso (length(EventSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EventSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventBufferDescriptor(EventSpecs, _State) ->
+ error({bad_eventSpecs, EventSpecs}).
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(Name, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(List, State) when is_list(List) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(Val, State)
+ when is_record(Val, 'Signal') ->
+ [
+ enc_SignalName(Val#'Signal'.signalName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2},
+ {[Val#'Signal'.sigType], fun enc_sigSignalType/2},
+ {[Val#'Signal'.duration], fun enc_sigDuration/2},
+ {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2},
+ {[Val#'Signal'.keepActive], fun enc_keepActive/2},
+ {Val#'Signal'.sigParList, fun enc_sigOther/2},
+ {[Val#'Signal'.direction], fun enc_SignalDirection/2},
+ {[Val#'Signal'.requestID], fun enc_sigRequestID/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_SignalDirection({'SignalDirection', Val}, State) ->
+ enc_SignalDirection(Val, State);
+enc_SignalDirection(Val, _State) ->
+ [
+ ?DirectionToken,
+ ?EQUAL,
+ case Val of
+ internal -> ?InternalToken;
+ external -> ?ExternalToken;
+ both -> ?BothToken
+ end
+ ].
+
+enc_sigRequestID(Val, State) ->
+ [
+ ?RequestIDToken,
+ ?EQUAL,
+ enc_RequestID(Val, State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_ModemDescriptor(MD, _State) ->
+ error({deprecated, MD}).
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% 7.1.2: ...shall not be included as part of a transmitted content and,
+%% if received, shall either be ignored or processed at the option
+%% of the implementation. ...
+%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+%% mpl = [],
+%% nonStandardData = asn1_NOVALUE},
+%% State) ->
+%% [
+%% ?ModemToken,
+%% ?EQUAL,
+%% enc_ModemType(Val, State)
+%% ];
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% %% BUGBUG: Does never generate: EQUAL modemType
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% Corr1: See ModemDescriptor above
+%% enc_ModemType({'ModemType',Val}, State)->
+%% enc_ModemType(Val, State);
+%% enc_ModemType(Val, _State) ->
+%% %% BUGBUG: Does not handle extensionParameter
+%% case Val of
+%% v18 -> ?V18Token;
+%% v22 -> ?V22Token;
+%% v22bis -> ?V22bisToken;
+%% v32 -> ?V32Token;
+%% v32bis -> ?V32bisToken;
+%% v34 -> ?V34Token;
+%% v90 -> ?V90Token;
+%% v91 -> ?V91Token;
+%% synchISDN -> ?SynchISDNToken
+%% end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value} = Val,
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ error({invalid_DigitMapDescriptor, Val});
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE}) ->
+ true;
+is_empty_DigitMapValue(#'DigitMapValue'{}) ->
+ false.
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2},
+ {Val#'ServiceChangeParm'.serviceChangeInfo,
+ fun enc_AuditDescriptor/2},
+ {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag],
+ fun('NULL', _) -> ?ServiceChangeIncompleteToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken
+ end
+ %% BUGBUG: extension
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+ [String]
+ end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) andalso (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) andalso (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invalid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) andalso is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep =:= true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep =:= false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
+
diff --git a/lib/megaco/src/text/megaco_text_gen_prev3b.hrl b/lib/megaco/src/text/megaco_text_gen_prev3b.hrl
new file mode 100644
index 0000000000..8a4af877dc
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_prev3b.hrl
@@ -0,0 +1,2966 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode V2 Megaco/H.248 text messages from internal form
+%% The following was changed:
+%% - MuxType (Nx64kToken)
+%% - auditItem (terminationAudit)
+%% - serviceChangeParm (auditItem)
+%%
+%% The following was added:
+%% - All IndAud stuff
+%%----------------------------------------------------------------------
+
+%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])).
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) andalso (Val =/= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE},
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',
+ Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAAR,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {[CtxAAR], fun enc_ContextAttrAuditRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+%% d("enc_ActionReply -> entry with"
+%% "~n Id: ~p"
+%% "~n ED: ~p"
+%% "~n CtxRep: ~p"
+%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, [], State)
+ when (CtxRep =/= asn1_NOVALUE) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n CtxRep: ~p", [CtxRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) andalso (CmdRep =/= []) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n CtxRep: ~p"
+%% "~n CmdRep: ~p", [CtxRep, CmdRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State)
+ when (CmdRep =/= []) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n CmdRep: ~p", [CmdRep]),
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, [], State)
+ when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n ED: ~p"
+%% "~n CtxRep: ~p", [ED, CtxRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n ED: ~p"
+%% "~n CmdRep: ~p", [ED, CmdRep]),
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso
+ (CtxRep =/= asn1_NOVALUE) andalso
+ (CmdRep =/= []) ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n ED: ~p"
+%% "~n CtxRep: ~p"
+%% "~n CmdRep: ~p", [ED, CtxRep, CmdRep]),
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State)
+ when ED =/= asn1_NOVALUE ->
+%% d("do_enc_ActionReply -> entry with"
+%% "~n ED: ~p", [ED]),
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+enc_ContextRequest_priority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_priority(Val, _State) ->
+ {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextRequest_emergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_emergency(true, _State) ->
+ {[?EmergencyToken], fun(Elem, _) -> Elem end};
+enc_ContextRequest_emergency(false, _State) ->
+ {[?EmergencyOffToken], fun(Elem, _) -> Elem end}.
+
+enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ asn1_NOVALUE}, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ List}, _State) ->
+ {List, fun enc_TopologyRequest/2};
+enc_ContextRequest_topologyReq(List, _State) ->
+ {[List], fun enc_TopologyRequest/2}.
+
+enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_iepscallind(Bool, _State) ->
+ {[Bool], fun enc_iepsValue/2}.
+
+enc_ContextRequest_contextProp(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp(Props, _State) ->
+ {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}.
+
+enc_contextAttrDescriptor([Mand|Opt], contextProps, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ [enc_PropertyParm(Mand, State) |
+ [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = [],
+ iepscallind = asn1_NOVALUE,
+ contextProp = []}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TR,
+ iepscallind = Ieps,
+ contextProp = CP}, State) ->
+ [
+ enc_list([enc_ContextRequest_priority(Prio, State),
+ enc_ContextRequest_emergency(Em, State),
+ enc_ContextRequest_topologyReq(TR, State),
+ enc_ContextRequest_iepscallind(Ieps, State),
+ enc_ContextRequest_contextProp(CP, State)],
+ State)
+ ].
+
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = []}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(CAAR, State) ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudContextAttrDescriptor(CAAR, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudContextAttrDescriptor(
+ #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = CPA}, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+ {[Em], fun('NULL', _) -> ?EmergencyToken end},
+ {[Prio], fun('NULL', _) -> ?PriorityToken end},
+ {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+ {CPA, fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+% d("enc_Command -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+%% d("enc_CommandReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir}, State) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(Dir, State)
+ ].
+
+enc_TopologyDirection(bothway, _State) ->
+ ?BothwayToken;
+enc_TopologyDirection(isolate, _State) ->
+ ?IsolateToken;
+enc_TopologyDirection(oneway, _State) ->
+ ?OnewayToken;
+enc_TopologyDirection(Top, _State) ->
+ error({illegal_TopologyDirection, Top}).
+
+enc_iepsValue(Val, _State) ->
+ [
+ ?IEPSToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+
+
+enc_AmmRequest(Val, State)
+ when is_record(Val, 'AmmRequest') ->
+% d("enc_AmmRequest -> entry with"
+% "~n Val: ~p", [Val]),
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State),
+ enc_opt_brackets(
+ enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+% d("enc_ammDescriptor -> entry with"
+% "~n Tag: ~p"
+% "~n Desc: ~p", [Tag, Desc]),
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = asn1_NOVALUE}, State) ->
+% d("enc_AmmsReply(asn1_NOVALUE) -> entry with"
+% "~n ID: ~p", [ID]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = []}, State) ->
+% d("enc_AmmsReply([]) -> entry with"
+% "~n ID: ~p", [ID]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = Res}, State) ->
+% d("enc_AmmsReply -> entry with"
+% "~n ID: ~p"
+% "~n Res: ~p", [ID, Res]),
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(Val, State)
+ when is_record(Val, 'SubtractRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State),
+ case Val#'SubtractRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_AuditRequest(Val, State)
+ when is_record(Val, 'AuditRequest') ->
+ %% d("enc_AuditRequest -> entry with"
+ %% "~n Val: ~p", [Val]),
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State),
+ case Val#'AuditRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+%% d("enc_AuditReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ contextAuditResult ->
+ %% d("enc_AuditReply -> contextAuditResult"),
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDListN(Val, State)
+ ];
+ error ->
+ %% d("enc_AuditReply -> error"),
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ %% d("enc_AuditReply -> auditResult"),
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [],
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor([]) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = asn1_NOVALUE},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n List: ~p", [List]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+%% - v2 -
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = Prop},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n Prop: ~p", [Prop]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = Prop},
+ State) ->
+% d("enc_AuditDescriptor -> entry with",
+% "~n List: ~p"
+% "~n Prop: ~p", [List, Prop]),
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+
+%% - v2 begin -
+
+enc_auditPropertyToken([], _State) ->
+ [];
+enc_auditPropertyToken([Param | Params], State) ->
+% d("enc_auditPropertyToken -> entry with",
+% "~n Param: ~p", [Param]),
+ [enc_IndAudauditReturnParameter(Param, State),
+ [[?COMMA_INDENT(State),
+ enc_IndAudauditReturnParameter(P, State)] || P <- Params]].
+
+
+enc_IndAudauditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ indAudMediaDescriptor ->
+ enc_IndAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ enc_IndAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ enc_IndAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ enc_IndAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ enc_IndAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ enc_IndAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ enc_IndAudPackagesDescriptor(Val, State);
+ _ ->
+ error({invalid_IndAudauditReturnParameter_tag, Tag})
+ end.
+
+%% The ASN.1 does not limit to just one of termStateDescr or streams,
+%% but the ABNF seams to do that...
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE,
+ streams = Streams}, State) ->
+% d("enc_IndAudMediaDescriptor -> entry with",
+% "~n Streams: ~p", [Streams]),
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = asn1_NOVALUE},
+ State) ->
+% d("enc_IndAudMediaDescriptor -> entry with",
+% "~n TSD: ~p", [TSD]),
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudMediaDescriptor_streams({Tag, Val}, State) ->
+% d("enc_IndAudMediaDescriptor_streams -> entry with",
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ oneStream ->
+ enc_IndAudStreamParms(Val, State);
+ multiStream ->
+ enc_IndAudMediaDescriptor_multiStream(Val, State);
+ _ ->
+ error({invalid_IndAudMediaDescriptor_streams_tag, Tag})
+ end.
+
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = 'NULL'}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?ServiceStatesToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = 'NULL',
+ serviceState = asn1_NOVALUE}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?BufferToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [Parms],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE}, State) ->
+ #'IndAudPropertyParm'{name = Name} = Parms,
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% In text, localDescriptor and remoteDescriptor are not allowed!!
+enc_IndAudStreamParms(
+ #'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE,
+ statisticsDescriptor = SD}, State) ->
+% d("enc_IndAudStreamParms -> entry with"
+% "~n LCD: ~p"
+% "~n SD: ~p", [LCD, SD]),
+ [
+ enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2},
+ {[SD], fun enc_IndAudStatisticsDescriptor/2}],
+ ?INC_INDENT(State))
+ ].
+
+enc_IndAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'IndAudLocalControlDescriptor'.streamMode],
+ fun('NULL', _) -> ?ModeToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveValue],
+ fun('NULL', _) -> ?ReservedValueToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveGroup],
+ fun('NULL', _) -> ?ReservedGroupToken end},
+ {Val#'IndAudLocalControlDescriptor'.propertyParms,
+ fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = PkgdName}, State) ->
+ enc_PkgdName(PkgdName, State).
+
+enc_IndAudMediaDescriptor_multiStream([Val], State) ->
+ %% d("enc_IndAudMediaDescriptor_multiStream -> entry with"
+ %% "~n Val: ~p", [Val]),
+ [
+ enc_IndAudStreamDescriptor(Val, ?INC_INDENT(State))
+ ];
+enc_IndAudMediaDescriptor_multiStream(Vals, State) when is_list(Vals) ->
+%% d("enc_IndAudMediaDescriptor_multiStream -> entry with"
+%% "~n Vals: ~p", [Vals]),
+ [
+ enc_list([{Vals, fun enc_IndAudStreamDescriptor/2}], State)
+ ];
+enc_IndAudMediaDescriptor_multiStream(Val, _State) ->
+ error({invalid_IndAudMediaDescriptor_multiStream, Val}).
+
+enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms},
+ State) ->
+%% d("enc_IndAudStreamDescriptor -> entry with"
+%% "~n SID: ~p"
+%% "~n Parms: ~p", [SID, Parms]),
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudStreamParms(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventBufferDescriptor') ->
+ #'IndAudEventBufferDescriptor'{eventName = EvName,
+ streamID = ID} = Val,
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(EvName, State),
+ enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) ->
+ [
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName},
+ State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_Name(ParamName, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec(ID, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventsDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventsDescriptor') ->
+ #'IndAudEventsDescriptor'{requestID = ReqID,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE} = Val,
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(ReqID, State),
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudSignalsDescriptor(Val, State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSignalsDescriptor_value({signal, Val}, State) ->
+ enc_IndAudSignal(Val, State);
+enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) ->
+ enc_IndAudSeqSigList(Val, State).
+
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ enc_SignalName(SignalName, State)
+ ].
+
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = Parm},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignal(Parm, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ].
+
+enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name},
+ State) ->
+% d("enc_IndAudStatisticsDescriptor -> entry with"
+% "~n Name: ~p", [Name]),
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_Name(N, State),
+ "-",
+ enc_UINT16(V, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% - v2 end -
+
+
+enc_TerminationAudit({'TerminationAudit',Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([], _State) ->
+ [];
+enc_TerminationAudit([Mand | Opt], State) ->
+% d("enc_TerminationAudit -> entry with"
+% "~n Mand: ~p", [Mand]),
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+% d("enc_AuditReturnParameter -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({invalid_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+ enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)).
+
+
+enc_NotifyRequest(Val, State)
+ when is_record(Val, 'NotifyRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ case Val#'NotifyRequest'.errorDescriptor of
+ asn1_NOVALUE ->
+ OED = Val#'NotifyRequest'.observedEventsDescriptor,
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State));
+ ErrorDescr ->
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State))
+ end,
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(Val, State)
+ when is_record(Val, 'NotifyReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ case Val#'NotifyReply'.terminationID of
+ asn1_NOVALUE ->
+ error(asn1_not_compliant_with_abnf);
+ TermId ->
+ enc_TerminationIDList1(TermId, State)
+ end,
+ case Val#'NotifyReply'.errorDescriptor of
+ asn1_NOVALUE ->
+ [];
+ ErrorDescr ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_ObservedEventsDescriptor(Val, State)
+ when is_record(Val, 'ObservedEventsDescriptor') ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEventsDescriptors([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(Val, State)
+ when is_record(Val, 'ObservedEvent') ->
+ [
+ case Val#'ObservedEvent'.timeNotation of
+ asn1_NOVALUE ->
+ [];
+ TimeStamp ->
+ [
+ enc_TimeNotation(TimeStamp, State),
+ ?LWSP,
+ ?COLON
+ ]
+ end,
+ ?LWSP,
+ enc_EventName(Val#'ObservedEvent'.eventName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName',Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(Val, State)
+ when is_record(Val, 'ServiceChangeRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms,
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(Val, State)
+ when is_record(Val, 'ServiceChangeReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State),
+ enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({Tag, Val}, State) ->
+ case Tag of
+ errorDescriptor ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ serviceChangeResParms ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+ _ ->
+ error({invalid_ServiceChangeResult_tag, Tag})
+ end.
+
+%% Required length of termination ID list is 1
+enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList1(Val, State);
+enc_TerminationIDList1([Singleton], State) ->
+ enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDListN({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDListN(Val, State);
+enc_TerminationIDListN([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDListN(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(Val, State)
+ when is_record(Val, 'MediaDescriptor') ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'MediaDescriptor'.termStateDescr],
+ fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Val#'MediaDescriptor'.streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2},
+ {[Val#'StreamParms'.statisticsDescriptor],
+ fun enc_StatisticsDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EQUAL,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EQUAL,
+ ?LSBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RSBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token;
+ %% extensionParameter
+ nx64k -> ?Nx64kToken % v2
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(Val, State)
+ when is_record(Val, 'EventsDescriptor') ->
+ #'EventsDescriptor'{requestID = RequestId,
+ eventList = Events} = Val,
+ if
+ RequestId == asn1_NOVALUE, Events == [] ->
+ [
+ ?EventsToken
+ ];
+
+ RequestId /= asn1_NOVALUE, Events /= [] ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RequestId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Events, fun enc_RequestedEvent/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end.
+
+enc_RequestedEvent(Val, State)
+ when is_record(Val, 'RequestedEvent') ->
+ PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} |
+ decompose_requestedActions(Val#'RequestedEvent'.eventAction)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of KeepActiveToken , eventDM and eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (KA =/= true) andalso
+ (SD =/= asn1_NOVALUE) andalso
+ (SD =/= []) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ].
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) ->
+ %% d("enc_embedFirst -> entry with"
+ %% "~n RID: ~p"
+ %% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+ %% d("enc_embedFirst -> entry"),
+ [
+ ?EventsToken
+ ].
+
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL,
+ eventAction = EA}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list(
+ [{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(Val)
+ when is_record(Val, 'SecondRequestedActions') ->
+ [
+ {[Val#'SecondRequestedActions'.keepActive],
+ fun enc_keepActive/2},
+ {[Val#'SecondRequestedActions'.eventDM],
+ fun enc_EventDM/2},
+ {[Val#'SecondRequestedActions'.signalsDescriptor],
+ fun enc_embeddedSignalsDescriptor/2}
+ ].
+
+enc_embeddedSignalsDescriptor(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EventSpecs, State)
+ when is_list(EventSpecs) andalso (length(EventSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EventSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(Name, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(List, State) when is_list(List) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(Val, State)
+ when is_record(Val, 'Signal') ->
+ [
+ enc_SignalName(Val#'Signal'.signalName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2},
+ {[Val#'Signal'.sigType], fun enc_sigSignalType/2},
+ {[Val#'Signal'.duration], fun enc_sigDuration/2},
+ {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2},
+ {[Val#'Signal'.keepActive], fun enc_keepActive/2},
+ {Val#'Signal'.sigParList, fun enc_sigOther/2},
+ {[Val#'Signal'.direction], fun enc_SignalDirection/2},
+ {[Val#'Signal'.requestID], fun enc_sigRequestID/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_SignalDirection({'SignalDirection', Val}, State) ->
+ enc_SignalDirection(Val, State);
+enc_SignalDirection(Val, _State) ->
+ [
+ ?DirectionToken,
+ ?EQUAL,
+ case Val of
+ internal -> ?InternalToken;
+ external -> ?ExternalToken;
+ both -> ?BothToken
+ end
+ ].
+
+enc_sigRequestID(Val, State) ->
+ [
+ ?RequestIDToken,
+ ?EQUAL,
+ enc_RequestID(Val, State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_ModemDescriptor(MD, _State) ->
+ error({deprecated, MD}).
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% 7.1.2: ...shall not be included as part of a transmitted content and,
+%% if received, shall either be ignored or processed at the option
+%% of the implementation. ...
+%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+%% mpl = [],
+%% nonStandardData = asn1_NOVALUE},
+%% State) ->
+%% [
+%% ?ModemToken,
+%% ?EQUAL,
+%% enc_ModemType(Val, State)
+%% ];
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% %% BUGBUG: Does never generate: EQUAL modemType
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% Corr1: See ModemDescriptor above
+%% enc_ModemType({'ModemType',Val}, State)->
+%% enc_ModemType(Val, State);
+%% enc_ModemType(Val, _State) ->
+%% %% BUGBUG: Does not handle extensionParameter
+%% case Val of
+%% v18 -> ?V18Token;
+%% v22 -> ?V22Token;
+%% v22bis -> ?V22bisToken;
+%% v32 -> ?V32Token;
+%% v32bis -> ?V32bisToken;
+%% v34 -> ?V34Token;
+%% v90 -> ?V90Token;
+%% v91 -> ?V91Token;
+%% synchISDN -> ?SynchISDNToken
+%% end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value} = Val,
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ error({invalid_DigitMapDescriptor, Val});
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE}) ->
+ true;
+is_empty_DigitMapValue(#'DigitMapValue'{}) ->
+ false.
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2},
+ {Val#'ServiceChangeParm'.serviceChangeInfo,
+ fun enc_AuditDescriptor/2},
+ {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag],
+ fun('NULL', _) -> ?ServiceChangeIncompleteToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken
+ end
+ %% BUGBUG: extension
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+ [String]
+ end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) andalso (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) andalso (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invalid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) andalso is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep =:= true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep =:= false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+%%
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+%%
+
diff --git a/lib/megaco/src/text/megaco_text_gen_prev3c.hrl b/lib/megaco/src/text/megaco_text_gen_prev3c.hrl
new file mode 100644
index 0000000000..11db906846
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_prev3c.hrl
@@ -0,0 +1,3443 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode V3 Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])).
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) andalso (Val =/= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+%% segmentReply ->
+%% enc_SegmentReply(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res%% ,
+%% segmentationNumber = SegNo,
+%% segmentationComplete = SegCompl
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ %% These fields are actually not
+ %% supported in this implementation,
+ %% but because the messanger module
+ %% cannot see any diff between the
+ %% various v3 implementations...
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',
+ Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAAR,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {[CtxAAR], fun enc_ContextAttrAuditRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []},
+ State) ->
+%% d("enc_ActionReply -> entry with"
+%% "~n Id: ~p", [Id]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State)
+ ];
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+%% d("enc_ActionReply -> entry with"
+%% "~n Id: ~p"
+%% "~n ED: ~p"
+%% "~n CtxRep: ~p"
+%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, [], State)
+ when (CtxRep =/= asn1_NOVALUE) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) andalso (CmdRep =/= []) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State)
+ when (CmdRep =/= []) ->
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, [], State)
+ when (ED =/= asn1_NOVALUE) andalso (CtxRep =/= asn1_NOVALUE) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso (CmdRep =/= []) ->
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) andalso
+ (CtxRep =/= asn1_NOVALUE) andalso
+ (CmdRep =/= []) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State)
+ when (ED =/= asn1_NOVALUE) ->
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+enc_ContextRequest_priority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_priority(Val, _State) ->
+ {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextRequest_emergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_emergency(true, _State) ->
+ {[?EmergencyToken], fun(Elem, _) -> Elem end};
+enc_ContextRequest_emergency(false, _State) ->
+ {[?EmergencyOffToken], fun(Elem, _) -> Elem end}.
+
+enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ asn1_NOVALUE}, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ List}, _State) ->
+ {List, fun enc_TopologyRequest/2};
+enc_ContextRequest_topologyReq(List, _State) ->
+ {[List], fun enc_TopologyRequest/2}.
+
+enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_iepscallind(Bool, _State) ->
+ {[Bool], fun enc_iepsValue/2}.
+
+enc_ContextRequest_contextProp(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp(Props, _State) ->
+ {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}.
+
+enc_ContextRequest_contextList(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextList([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextList(Props, _State) ->
+ {[Props], fun(Elem, S) ->
+ enc_contextAttrDescriptor(Elem, contextList, S)
+ end}.
+
+enc_contextAttrDescriptor([Mand|Opt], contextProps, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ [enc_PropertyParm(Mand, State) |
+ [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ];
+enc_contextAttrDescriptor(CtxIdList, contextList, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ enc_contextIdList(CtxIdList, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_contextIdList([Mand|Opt], State) ->
+ State2 = ?INC_INDENT(State),
+ [
+ ?ContextListToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ [enc_ContextID(Mand, State2) |
+ [[?COMMA_INDENT(State2), enc_ContextID(Val, State2)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+ contextList = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = [],
+ iepscallind = asn1_NOVALUE,
+ contextProp = [],
+ contextList = []}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TR,
+ iepscallind = Ieps,
+ contextProp = CP,
+ contextList = CL}, State) ->
+ [
+ enc_list([enc_ContextRequest_priority(Prio, State),
+ enc_ContextRequest_emergency(Em, State),
+ enc_ContextRequest_topologyReq(TR, State),
+ enc_ContextRequest_iepscallind(Ieps, State),
+ enc_ContextRequest_contextProp(CP, State),
+ enc_ContextRequest_contextList(CL, State)],
+ State)
+ ].
+
+
+%% -- contextAudit --
+%% contextAudit = ContextAuditToken LBRKT
+%% (contextAuditProperties *(COMMA contextAuditProperties)) /
+%% indAudcontextAttrDesscriptor
+%% RBRKT
+%% contextAuditProperties =
+%% (TopologyToken / EmergencyToken / PriorityToken /
+%% IEPSToken / pkgdName / contextAuditSelect)
+%% contextAuditSelect =
+%% priority / emergencyValue / iepsValue /
+%% contextAttrDescriptor / auditSelectLogic
+%% indAudcontextAttrDesscriptor =
+%% ContextAttrToken LBRKT
+%% (contextAuditProperties *(COMMA contextAuditProperties))
+%% RBRKT
+%%
+%% This could actually either be
+%% a) a list of contextAuditProperties:
+%% contextAuditProperties *(COMMA contextAuditProperties)
+%% b) a indAudcontextAttrDescriptor
+%% But since b) actually has the same content as a) with
+%% the extra ContextAttrToken, there does not seem to be any
+%% reason for using it.
+enc_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = [],
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = CPA,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SIeps,
+ selectLogic = SL}, State) ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+ {[Em], fun('NULL', _) -> ?EmergencyToken end},
+ {[Prio], fun('NULL', _) -> ?PriorityToken end},
+ {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+ {CPA, fun enc_IndAudPropertyParm/2},
+ enc_ContextAttrAuditRequest_selectpriority(SPrio, State),
+ enc_ContextAttrAuditRequest_selectemergency(SEm, State),
+ enc_ContextAttrAuditRequest_selectiepscallind(SIeps, State),
+ enc_ContextAttrAuditRequest_selectLogic(SL, State)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectpriority(SPrio, _State) ->
+ {[SPrio], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectemergency(SEm, _State) ->
+ {[SEm], fun(X,S) -> enc_emergencyValue(X, S) end}.
+
+enc_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectiepscallind(SEm, _State) ->
+ {[SEm], fun(X,S) -> enc_iepsValue(X, S) end}.
+
+enc_ContextAttrAuditRequest_selectLogic(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectLogic({andAUDITSelect, 'NULL'}, _State) ->
+ {[], dummy}; % This is default so, there is no reason to add it
+enc_ContextAttrAuditRequest_selectLogic({orAUDITSelect, 'NULL'}, _State) ->
+ {[?OrAUDITselectToken], fun(Elem, _) -> Elem end}.
+
+enc_emergencyValue(true, _) ->
+ [?EmergencyValueToken,?EQUAL,?EmergencyToken];
+enc_emergencyValue(_, _) ->
+ [?EmergencyValueToken,?EQUAL,?EmergencyOffToken].
+
+
+%% enc_IndAudContextAttrDescriptor(
+%% #'ContextAttrAuditRequest'{topology = Top,
+%% emergency = Em,
+%% priority = Prio,
+%% iepscallind = Ieps,
+%% contextPropAud = CPA,
+%% selectpriority = SelPrio,
+%% selectemergency = SelEm,
+%% selectiepscallind = SelIeps,
+%% selectLogic = SelLog}, State) ->
+%% [
+%% ?ContextAttrToken,
+%% ?LBRKT_INDENT(State),
+%% enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+%% {[Em], fun('NULL', _) -> ?EmergencyToken end},
+%% {[Prio], fun('NULL', _) -> ?PriorityToken end},
+%% {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+%% {CPA, fun enc_IndAudPropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% ?RBRKT_INDENT(State)
+%% ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+%% d("enc_Command -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+%% d("enc_CommandReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = asn1_NOVALUE, % OPTIONAL
+ topologyDirectionExtension = asn1_NOVALUE % OPTIONAL
+ }, State) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID, % OPTIONAL
+ topologyDirectionExtension = asn1_NOVALUE}, % OPTIONAL
+ State) when (SID =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_StreamID(SID, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = asn1_NOVALUE, % OPTIONAL
+ topologyDirectionExtension = TDE}, % OPTIONAL
+ State) when (TDE =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirectionExtension(TDE, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID, % OPTIONAL
+ topologyDirectionExtension = TDE}, % OPTIONAL
+ State) when (SID =/= asn1_NOVALUE) andalso (TDE =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_StreamID(SID, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirectionExtension(TDE, State)
+ ].
+
+enc_TopologyDirection(bothway, _State) ->
+ ?BothwayToken;
+enc_TopologyDirection(isolate, _State) ->
+ ?IsolateToken;
+enc_TopologyDirection(oneway, _State) ->
+ ?OnewayToken.
+
+enc_TopologyDirectionExtension(onewayexternal, _State) ->
+ ?OnewayExternalToken;
+enc_TopologyDirectionExtension(onewayboth, _State) ->
+ ?OnewayBothToken.
+
+enc_iepsValue(Val, _State) ->
+ [
+ ?IEPSToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+
+
+enc_AmmRequest(#'AmmRequest'{terminationID = TIDs,
+ descriptors = Ds}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ enc_opt_brackets(
+ enc_list([{Ds, fun enc_ammDescriptor/2}], ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = []}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs,
+ auditDescriptor = asn1_NOVALUE},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs,
+ auditDescriptor = AD},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = [TID|_] = TIDList},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = TIDList},
+ _State) ->
+ error({invalid_terminationID, TID, TIDList});
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList([TID], State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = [TID|_] = TIDList},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDList, State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = _AD,
+ terminationIDList = TIDList},
+ _State) ->
+ error({invalid_terminationID, TID, TIDList}).
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+%% d("enc_AuditReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ contextAuditResult ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDList(Val, State)
+ ];
+ error ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ auditResultTermList ->
+ enc_TermListAuditResult(Val, State);
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+%% This is actually the same as AuditResult with the exception
+%% that instead of terminationID we have terminationIDList.
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p", [TIDList]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = []}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p", [TIDList]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p"
+%% "~n TAR: ~p", [TIDList, TAR]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State),
+ case lists:flatten(enc_TerminationAudit(TAR, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [],
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor([]) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = asn1_NOVALUE},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+%% - v2 -
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+
+%% - v2 begin -
+
+enc_auditPropertyToken([], _State) ->
+ [];
+enc_auditPropertyToken([Param | Params], State) ->
+ [enc_IndAudauditReturnParameter(Param, State),
+ [[?COMMA_INDENT(State),
+ enc_IndAudauditReturnParameter(P, State)] || P <- Params]].
+
+
+enc_IndAudauditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ indAudMediaDescriptor ->
+ enc_IndAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ enc_IndAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ enc_IndAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ enc_IndAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ enc_IndAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ enc_IndAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ enc_IndAudPackagesDescriptor(Val, State);
+ _ ->
+ error({invalid_IndAudauditReturnParameter_tag, Tag})
+ end.
+
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = asn1_NOVALUE}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudMediaDescriptor_streams({oneStream, Val}, State) ->
+ enc_IndAudStreamParms(Val, State);
+enc_IndAudMediaDescriptor_streams({multiStream, Val}, State) ->
+ enc_IndAudMediaDescriptor_multiStream(Val, State);
+enc_IndAudMediaDescriptor_streams({Tag, _Val}, _State) ->
+ error({invalid_IndAudMediaDescriptor_streams_tag, Tag}).
+
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = 'NULL',
+ serviceStateSel = asn1_NOVALUE},
+ _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?ServiceStatesToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = SSS},
+ State) when (SSS =/= asn1_NOVALUE) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_serviceState(SSS, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = 'NULL',
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = asn1_NOVALUE},
+ _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?BufferToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [Parms],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = asn1_NOVALUE},
+ State) ->
+ #'IndAudPropertyParm'{name = Name} = Parms,
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudStreamParms(
+ #'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}, State) ->
+ [
+ enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2},
+ {[LD], fun enc_remoteDescriptor/2},
+ {[RD], fun enc_localDescriptor/2},
+ {[SD], fun enc_IndAudStatisticsDescriptor/2}],
+ ?INC_INDENT(State))
+ ].
+
+enc_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = asn1_NOVALUE}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun('NULL', _) -> ?ModeToken end},
+ {[RV], fun('NULL', _) -> ?ReservedValueToken end},
+ {[RG], fun('NULL', _) -> ?ReservedGroupToken end},
+ {PP, fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[RV], fun('NULL', _) -> ?ReservedValueToken end},
+ {[RG], fun('NULL', _) -> ?ReservedGroupToken end},
+ { PP, fun enc_IndAudPropertyParm/2},
+ {[SMS], fun enc_StreamMode/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name, propertyParms = PP},
+ State) ->
+ [
+ enc_list([{[Name], fun enc_PkgdName/2},
+ {[PP], fun enc_PropertyParm/2}], State)
+ ].
+
+enc_IndAudMediaDescriptor_multiStream(Val, State) when is_list(Val) ->
+ [
+ enc_list([{Val, fun enc_IndAudStreamDescriptor/2}], State)
+ ];
+enc_IndAudMediaDescriptor_multiStream(Val, _State) ->
+ error({invalid_IndAudMediaDescriptor_multiStream, Val}).
+
+enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms},
+ State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudStreamParms(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = EvName,
+ streamID = ID}, State) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(EvName, State),
+ enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) ->
+ [
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName},
+ State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_Name(ParamName, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventStream, ID}, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec(ID, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventsDescriptor(
+ #'IndAudEventsDescriptor'{requestID = asn1_NOVALUE,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ ?EventsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventsDescriptor(
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudSignalsDescriptor(asn1_NOVALUE, _State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(_State),
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudSignalsDescriptor(Val, State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSignalsDescriptor_value({signal, Val}, State) ->
+ enc_IndAudSignal(Val, State);
+enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) ->
+ enc_IndAudSeqSigList(Val, State).
+
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = asn1_NOVALUE,
+ signalRequestID = asn1_NOVALUE}, State) ->
+ [
+ enc_SignalName(SignalName, State)
+ ];
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = SID,
+ signalRequestID = SRID}, State) ->
+ [
+ enc_SignalName(SignalName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_StreamID/2},
+ {[SRID], fun enc_sigRequestID/2}],
+ State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = asn1_NOVALUE},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State)
+ ];
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignal(SL, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ].
+
+enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name},
+ State) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_Name(N, State),
+ "-",
+ enc_UINT16(V, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% - v2 end -
+
+
+enc_TerminationAudit({'TerminationAudit', Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([Mand | Opt], State) ->
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+%% d("enc_AuditReturnParameter -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({invalid_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+%% d("enc_AuditReturnParameter -> entry with"
+%% "~n List: ~p", [List]),
+ enc_list([{List, fun enc_auditReturnItem/2}], State).
+
+
+enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs,
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)),
+ ?COMMA,
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(#'NotifyReply'{terminationID = TIDs,
+ errorDescriptor = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_NotifyReply(#'NotifyReply'{terminationID = TIDs,
+ errorDescriptor = ED}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}, State) ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEvents(OEL, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEvents([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(#'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = asn1_NOVALUE}, State) ->
+ [
+ ?LWSP,
+ enc_EventName(EN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ { EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ];
+enc_ObservedEvent(#'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}, State) ->
+ [
+ enc_TimeNotation(TN, State),
+ ?LWSP,
+ ?COLON,
+ ?LWSP,
+ enc_EventName(EN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName', Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = TIDs,
+ serviceChangeParms = Parms}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = TIDs,
+ serviceChangeResult = Res}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ enc_ServiceChangeResult(Res, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult', Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({errorDescriptor, Val}, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ServiceChangeResult({serviceChangeResParms, Val}, State) ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_ServiceChangeResult({Tag, _}, _State) ->
+ error({invalid_ServiceChangeResult_tag, Tag}).
+
+%% %% Required length of termination ID list is 1
+%% enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+%% enc_TerminationIDList1(Val, State);
+%% enc_TerminationIDList1([Singleton], State) ->
+%% enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDList({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList(Val, State);
+enc_TerminationIDList([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDList(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_termIDList({'TerminationIDList',Val}, State) ->
+ enc_termIDList(Val, State);
+enc_termIDList([Singleton], State) ->
+ enc_TerminationID(Singleton, State);
+enc_termIDList(TidList, State)
+ when is_list(TidList) andalso (length(TidList) > 1) ->
+%% d("enc_termIDList -> entry with"
+%% "~n TidList: ~p", [TidList]),
+ State2 = ?INC_INDENT(State),
+ [
+ ?LSBRKT_INDENT(State),
+ enc_list([{TidList, fun enc_TerminationID/2}], State2),
+ ?RSBRKT_INDENT(State)
+ ].
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[TSD], fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2},
+ {[Val#'StreamParms'.statisticsDescriptor],
+ fun enc_StatisticsDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+%% d("enc_PropertyParm -> entry with"
+%% "~n Val: ~p", [Val]),
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+%% d("enc_PropertyParmValues -> entry with"
+%% "~n Single: ~p", [Single]),
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+%% d("enc_PropertyParmValues -> entry with"
+%% "~n Single: ~p"
+%% "~n Rel: ~p", [Single, Rel]),
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EQUAL,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EQUAL,
+ ?LSBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RSBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDList(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token;
+ %% extensionParameter
+ nx64k -> ?Nx64kToken % v2
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []}, _State) ->
+ [
+ ?EventsToken
+ ];
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = Evs}, State)
+ when (RID =/= asn1_NOVALUE) andalso (Evs =/= []) ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_RequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = Evs}, _State) ->
+ error({invalid_EventsDescriptor, RID, Evs}).
+
+enc_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+enc_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_requestedActions(EA)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+decompose_requestedActions(
+ #'RequestedActions'{keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE}) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of
+%% - KeepActiveToken
+%% - notifyBehaviour
+%% - eventDM
+%% - ResetEventsDescriptor
+%% - eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (KA =/= true) andalso ((SD =/= asn1_NOVALUE) andalso (SD =/= [])) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ].
+
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) andalso (is_list(Evs) andalso (Evs =/= [])) ->
+ %% d("enc_embedFirst -> entry with"
+ %% "~n RID: ~p"
+ %% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+ %% d("enc_embedFirst -> entry"),
+ [
+ ?EventsToken
+ ].
+
+enc_notifyBehaviour({notifyImmediate, 'NULL'}, _State) ->
+ [?NotifyImmediateToken];
+enc_notifyBehaviour({notifyRegulated, Val}, State) ->
+ enc_RegulatedEmbeddedDescriptor(Val, State);
+enc_notifyBehaviour({neverNotify, 'NULL'}, _State) ->
+ [?NeverNotifyToken];
+enc_notifyBehaviour({Tag, Val}, _State) ->
+ error({invalid_notifyBehaviour, Tag, Val}).
+
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE}, _State) ->
+ [
+ ?NotifyRegulatedToken
+ ];
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = asn1_NOVALUE}, State) ->
+ [
+ ?NotifyRegulatedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedNoSig(SE, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ [
+ ?NotifyRegulatedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedWithSig({SE, SD}, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_RegulatedEmbeddedDescriptor(Val, _State) ->
+ error({invalid_RegulatedEmbeddedDescriptor, Val}).
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%%
+%% This in the ABNF:
+%% at-most-once each of
+%% - KeepActiveToken
+%% - notifyBehaviour
+%% - eventDM
+%% - ResetEventsDescriptor
+%% - eventStream
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE}) ->
+ [];
+
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (KA =/= true) andalso ((SD =/= asn1_NOVALUE) andalso (SD =/= [])) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[SD], fun enc_embedSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+decompose_secondRequestedActions(SRA) ->
+ error({invalid_SecondRequestedActions, SRA}).
+
+enc_embedSig(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EvSpecs, State)
+ when is_list(EvSpecs) andalso (length(EvSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EvSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventBufferDescriptor(EvSpecs, _State) ->
+ error({bad_eventSpecs, EvSpecs}).
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = N,
+ streamID = asn1_NOVALUE,
+ eventParList = []}, State) ->
+ [
+ enc_EventName(N, State)
+ ];
+enc_eventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(N, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2}, {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(SigRequests, State) when is_list(SigRequests) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{SigRequests, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(#'Signal'{signalName = SN,
+ streamID = SID,
+ sigType = ST,
+ duration = Du,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Di,
+ requestID = RID,
+ intersigDelay = ISD}, State) ->
+ [
+ enc_SignalName(SN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_sigStream/2},
+ {[ST], fun enc_sigSignalType/2},
+ {[Du], fun enc_sigDuration/2},
+ {[NC], fun enc_notifyCompletion/2},
+ {[KA], fun enc_keepActive/2},
+ {SPL, fun enc_sigOther/2},
+ {[Di], fun enc_SignalDirection/2},
+ {[RID], fun enc_sigRequestID/2},
+ {[ISD], fun enc_sigIntsigDelay/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken;
+ onIteration -> ?IterationToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_SignalDirection({'SignalDirection', Val}, State) ->
+ enc_SignalDirection(Val, State);
+enc_SignalDirection(Val, _State) ->
+ [
+ ?DirectionToken,
+ ?EQUAL,
+ case Val of
+ internal -> ?InternalToken;
+ external -> ?ExternalToken;
+ both -> ?BothToken
+ end
+ ].
+
+enc_sigRequestID(Val, State) ->
+ [
+ ?RequestIDToken,
+ ?EQUAL,
+ enc_RequestID(Val, State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_sigIntsigDelay(Val, State) ->
+ [
+ ?IntsigDelayToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_ModemDescriptor(MD, _State) ->
+ error({deprecated, MD}).
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% 7.1.2: ...shall not be included as part of a transmitted content and,
+%% if received, shall either be ignored or processed at the option
+%% of the implementation. ...
+%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+%% mpl = [],
+%% nonStandardData = asn1_NOVALUE},
+%% State) ->
+%% [
+%% ?ModemToken,
+%% ?EQUAL,
+%% enc_ModemType(Val, State)
+%% ];
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% %% BUGBUG: Does never generate: EQUAL modemType
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% Corr1: See ModemDescriptor above
+%% enc_ModemType({'ModemType',Val}, State)->
+%% enc_ModemType(Val, State);
+%% enc_ModemType(Val, _State) ->
+%% %% BUGBUG: Does not handle extensionParameter
+%% case Val of
+%% v18 -> ?V18Token;
+%% v22 -> ?V22Token;
+%% v22bis -> ?V22bisToken;
+%% v32 -> ?V32Token;
+%% v32bis -> ?V32bisToken;
+%% v34 -> ?V34Token;
+%% v90 -> ?V90Token;
+%% v91 -> ?V91Token;
+%% synchISDN -> ?SynchISDNToken
+%% end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value} = Val,
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ error({invalid_DigitMapDescriptor, Val});
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE}) ->
+ true;
+is_empty_DigitMapValue(#'DigitMapValue'{}) ->
+ false.
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2},
+ {Val#'ServiceChangeParm'.serviceChangeInfo,
+ fun enc_AuditDescriptor/2},
+ {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag],
+ fun('NULL', _) -> ?ServiceChangeIncompleteToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken;
+ _ ->
+ error({invalid_ServiceChangeMethod, Val})
+
+ end
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that the string must contain at least one
+%% BUGBUG: char. This violation of is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+%% d("enc_Value -> entry with"
+%% "~n String: ~p", [String]),
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+%% d("enc_Value -> 0"),
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+%% d("enc_Value -> false"),
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+%% d("enc_Value -> true"),
+ [String]
+ end.
+
+%% needs_quoting(String) ->
+%% case quoted_string_count(String, 0, true) of
+%% {_, 0} ->
+%% true;
+%% {false, _} ->
+%% true;
+%% {true, _} ->
+%% false
+%% end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+%% d("quoted_string_count -> entry with"
+%% "~n H: ~p"
+%% "~n Classified H: ~p"
+%% "~n Count: ~p"
+%% "~n IsSafe: ~p", [H, ?classify_char(H), Count, IsSafe]),
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) andalso (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) andalso (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+%% enc_list(asn1_NOVALUE, _State) ->
+%% [];
+%% enc_list([], _State) ->
+%% [];
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invalid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) andalso is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep =:= true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep =:= false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% %% d(get(dbg), F, A).
+%% d(true, F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
+
diff --git a/lib/megaco/src/text/megaco_text_gen_v1.hrl b/lib/megaco/src/text/megaco_text_gen_v1.hrl
new file mode 100644
index 0000000000..b150c9ba58
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_v1.hrl
@@ -0,0 +1,2404 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) andalso (Val =/= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State),
+ ?INC_INDENT(State),
+ enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res},
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res}, State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(Val, State)
+ when is_record(Val, 'ActionRequest') ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Val#'ActionRequest'.contextId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ActionRequest'.contextAttrAuditReq],
+ fun enc_ContextAttrAuditRequest/2}] ++
+ decompose_ContextRequest(Val#'ActionRequest'.contextRequest) ++
+ [{Val#'ActionRequest'.commandRequests,
+ fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) ->
+ [
+ enc_list(decompose_ContextRequest(CtxRep) ++
+ [{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) ->
+ [
+ enc_list(decompose_ContextRequest(CtxRep) ++
+ [{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State) ->
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+decompose_ContextRequest(asn1_NOVALUE) ->
+ [{[], dummy}] ;
+decompose_ContextRequest(Val)
+ when is_record(Val, 'ContextRequest') ->
+ OptPriority =
+ case Val#'ContextRequest'.priority of
+ asn1_NOVALUE -> {[], dummy};
+ Prio -> {[Prio], fun enc_priority/2}
+ end,
+ OptEmergency =
+ case Val#'ContextRequest'.emergency of
+ asn1_NOVALUE -> {[], dummy};
+ false -> {[], dummy};
+ true -> {[?EmergencyToken], fun(Elem, _) -> Elem end}
+ end,
+ OptTopologyReq =
+ case Val#'ContextRequest'.topologyReq of
+ asn1_NOVALUE ->
+ {[], dummy};
+ {'ContextRequest_topologyReq', asn1_NOVALUE} ->
+ {[], dummy};
+ {'ContextRequest_topologyReq', List} ->
+ {List, fun enc_TopologyRequest/2};
+ List ->
+ {[List], fun enc_TopologyRequest/2}
+ end,
+ [OptPriority, OptEmergency, OptTopologyReq].
+
+enc_priority(Val, State) ->
+ [
+ ?PriorityToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_ContextAttrAuditRequest(Val, State)
+ when is_record(Val, 'ContextAttrAuditRequest') ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ContextAttrAuditRequest'.topology],
+ fun('NULL', _) -> ?TopologyToken end},
+ {[Val#'ContextAttrAuditRequest'.emergency],
+ fun('NULL', _) -> ?EmergencyToken end},
+ {[Val#'ContextAttrAuditRequest'.priority],
+ fun('NULL', _) -> ?PriorityToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(Val, State)
+ when is_record(Val, 'TopologyRequest') ->
+ [
+ fun(S) ->
+ [
+ enc_TerminationID(Val#'TopologyRequest'.terminationFrom, S),
+ ?COMMA_INDENT(S),
+ enc_TerminationID(Val#'TopologyRequest'.terminationTo, S),
+ ?COMMA_INDENT(S),
+ case Val#'TopologyRequest'.topologyDirection of
+ bothway -> ?BothwayToken;
+ isolate -> ?IsolateToken;
+ oneway -> ?OnewayToken
+ end
+ ]
+ end(?INC_INDENT(State))
+ ].
+
+enc_AmmRequest(Val, State)
+ when is_record(Val, 'AmmRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State),
+ enc_opt_brackets(
+ enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(Val, State)
+ when is_record(Val, 'SubtractRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State),
+ case Val#'SubtractRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_AuditRequest(Val, State)
+ when is_record(Val, 'AuditRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State),
+ case Val#'AuditRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+ case Tag of
+ contextAuditResult ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDListN(Val, State)
+ ];
+ error ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE},
+ _State) ->
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = []},
+ _State) ->
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+enc_TerminationAudit({'TerminationAudit',Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([], _State) ->
+ [];
+enc_TerminationAudit([Mand | Opt], State) ->
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State),
+ enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({unknown_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+ enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)).
+
+
+enc_NotifyRequest(Val, State)
+ when is_record(Val, 'NotifyRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ case Val#'NotifyRequest'.errorDescriptor of
+ asn1_NOVALUE ->
+ OED = Val#'NotifyRequest'.observedEventsDescriptor,
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State));
+ ErrorDescr ->
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State))
+ end,
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(Val, State)
+ when is_record(Val, 'NotifyReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ case Val#'NotifyReply'.terminationID of
+ asn1_NOVALUE ->
+ error(asn1_not_compliant_with_abnf);
+ TermId ->
+ enc_TerminationIDList1(TermId, State)
+ end,
+ case Val#'NotifyReply'.errorDescriptor of
+ asn1_NOVALUE ->
+ [];
+ ErrorDescr ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_ObservedEventsDescriptor(Val, State)
+ when is_record(Val, 'ObservedEventsDescriptor') ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEventsDescriptors([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(Val, State)
+ when is_record(Val, 'ObservedEvent') ->
+ [
+ case Val#'ObservedEvent'.timeNotation of
+ asn1_NOVALUE ->
+ [];
+ TimeStamp ->
+ [
+ enc_TimeNotation(TimeStamp, State),
+ ?LWSP,
+ ?COLON
+ ]
+ end,
+ ?LWSP,
+ enc_EventName(Val#'ObservedEvent'.eventName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName',Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(Val, State)
+ when is_record(Val, 'ServiceChangeRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms,
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(Val, State)
+ when is_record(Val, 'ServiceChangeReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State),
+ enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({Tag, Val}, State) ->
+ case Tag of
+ errorDescriptor ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ serviceChangeResParms ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+ _ ->
+ error({invalid_ServiceChangeResult_tag, Tag})
+ end.
+
+%% Required length of termination ID list is 1
+enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList1(Val, State);
+enc_TerminationIDList1([Singleton], State) ->
+ enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDListN({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDListN(Val, State);
+enc_TerminationIDListN([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDListN(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(Val, State)
+ when is_record(Val, 'MediaDescriptor') ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'MediaDescriptor'.termStateDescr],
+ fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Val#'MediaDescriptor'.streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. <When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EqualToken,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EqualToken,
+ ?LSBRKT,
+ enc_list([{Values, fun enc_Value/2}], State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EqualToken,
+ ?LBRKT,
+ enc_list([{Values, fun enc_Value/2}], State),
+ ?RBRKT
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(Val, State)
+ when is_record(Val, 'EventsDescriptor') ->
+ #'EventsDescriptor'{requestID = RequestId,
+ eventList = Events} = Val,
+ if
+ RequestId == asn1_NOVALUE, Events == [] ->
+ [
+ ?EventsToken
+ ];
+
+ RequestId =/= asn1_NOVALUE, Events =/= [] ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RequestId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Events, fun enc_RequestedEvent/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end.
+
+enc_RequestedEvent(Val, State)
+ when is_record(Val, 'RequestedEvent') ->
+ PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} |
+ decompose_requestedActions(Val#'RequestedEvent'.eventAction)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of KeepActiveToken , eventDM and eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (KA =/= true) andalso
+ (SD =/= asn1_NOVALUE) andalso
+ (SD /= []) ->
+% d("decompose_requestedActions -> entry with"
+% "~n EDM: ~p"
+% "~n SE: ~p"
+% "~n SD: ~p", [EDM, SE, SD]),
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ].
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+ [
+ ?EventsToken
+ ].
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL,
+ eventAction = EA}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list(
+ [{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(Val)
+ when is_record(Val, 'SecondRequestedActions') ->
+ [
+ {[Val#'SecondRequestedActions'.keepActive],
+ fun enc_keepActive/2},
+ {[Val#'SecondRequestedActions'.eventDM],
+ fun enc_EventDM/2},
+ {[Val#'SecondRequestedActions'.signalsDescriptor],
+ fun enc_embeddedSignalsDescriptor/2}
+ ].
+
+enc_embeddedSignalsDescriptor(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EventSpecs, State)
+ when is_list(EventSpecs) andalso (length(EventSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EventSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventBufferDescriptor(EventSpecs, _State) ->
+ error({bad_eventSpecs, EventSpecs}).
+
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(Name, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(List, State) when is_list(List) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(Val, State)
+ when is_record(Val, 'Signal') ->
+ [
+ enc_SignalName(Val#'Signal'.signalName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2},
+ {[Val#'Signal'.sigType], fun enc_sigSignalType/2},
+ {[Val#'Signal'.duration], fun enc_sigDuration/2},
+ {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2},
+ {[Val#'Signal'.keepActive], fun enc_keepActive/2},
+ {Val#'Signal'.sigParList, fun enc_sigOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+ mpl = [],
+ nonStandardData = asn1_NOVALUE},
+ State) ->
+ [
+ ?ModemToken,
+ ?EQUAL,
+ enc_ModemType(Val, State)
+ ];
+enc_ModemDescriptor(Val, State)
+ when is_record(Val, 'ModemDescriptor') ->
+ [
+ ?ModemToken,
+ ?LSBRKT,
+ enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+ ?RSBRKT,
+ enc_opt_brackets(
+ enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+ ?INC_INDENT(State)),
+ State)
+ %% BUGBUG: Is PropertyParm == NAME parmValue?
+ ].
+
+
+enc_ModemType({'ModemType',Val}, State)->
+ enc_ModemType(Val, State);
+enc_ModemType(Val, _State) ->
+ %% BUGBUG: Does not handle extensionParameter
+ case Val of
+ v18 -> ?V18Token;
+ v22 -> ?V22Token;
+ v22bis -> ?V22bisToken;
+ v32 -> ?V32Token;
+ v32bis -> ?V32bisToken;
+ v34 -> ?V34Token;
+ v90 -> ?V90Token;
+ v91 -> ?V91Token;
+ synchISDN -> ?SynchISDNToken
+ end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value} = Val,
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ error({invalid_DigitMapDescriptor, Val});
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = []}) ->
+ true;
+is_empty_DigitMapValue(#'DigitMapValue'{}) ->
+ false.
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken
+ end
+ %% BUGBUG: extension
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+ [String]
+ end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) andalso (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) andalso (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invlid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) andalso is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep =:= true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep =:= false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+% d(F) ->
+% d(F, []).
+
+% d(F, A) ->
+% %% d(get(dbg), F, A).
+% d(true, F, A).
+
+% d(true, F, A) ->
+% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]);
+% d(_, _, _) ->
+% ok.
diff --git a/lib/megaco/src/text/megaco_text_gen_v2.hrl b/lib/megaco/src/text/megaco_text_gen_v2.hrl
new file mode 100644
index 0000000000..6cfcac8664
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_v2.hrl
@@ -0,0 +1,2794 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode V2 Megaco/H.248 text messages from internal form
+%% The following was changed:
+%% - MuxType (Nx64kToken)
+%% - auditItem (terminationAudit)
+%% - serviceChangeParm (auditItem)
+%%
+%% The following was added:
+%% - All IndAud stuff
+%%----------------------------------------------------------------------
+
+%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])).
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) andalso (Val =/= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) == 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) =:= 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res},
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res}, State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',
+ Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(Val, State)
+ when is_record(Val, 'ActionRequest') ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Val#'ActionRequest'.contextId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ActionRequest'.contextAttrAuditReq],
+ fun enc_ContextAttrAuditRequest/2}] ++
+ decompose_ContextRequest(Val#'ActionRequest'.contextRequest) ++
+ [{Val#'ActionRequest'.commandRequests,
+ fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) ->
+ [
+ enc_list(decompose_ContextRequest(CtxRep) ++
+ [{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) orelse (CmdRep =/= []) ->
+ [
+ enc_list(decompose_ContextRequest(CtxRep) ++
+ [{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State)
+ when (ED =/= asn1_NOVALUE) ->
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+decompose_ContextRequest(asn1_NOVALUE) ->
+ [{[], dummy}] ;
+decompose_ContextRequest(Val)
+ when is_record(Val, 'ContextRequest') ->
+ OptPriority =
+ case Val#'ContextRequest'.priority of
+ asn1_NOVALUE -> {[], dummy};
+ Prio -> {[Prio], fun enc_priority/2}
+ end,
+ OptEmergency =
+ case Val#'ContextRequest'.emergency of
+ asn1_NOVALUE -> {[], dummy};
+ false -> {[?EmergencyOffToken], fun(Elem, _) -> Elem end};
+ true -> {[?EmergencyToken], fun(Elem, _) -> Elem end}
+ end,
+ OptTopologyReq =
+ case Val#'ContextRequest'.topologyReq of
+ asn1_NOVALUE ->
+ {[], dummy};
+ {'ContextRequest_topologyReq', asn1_NOVALUE} ->
+ {[], dummy};
+ {'ContextRequest_topologyReq', List} ->
+ {List, fun enc_TopologyRequest/2};
+ List ->
+ {[List], fun enc_TopologyRequest/2}
+ end,
+ [OptPriority, OptEmergency, OptTopologyReq].
+
+enc_priority(Val, State) ->
+ [
+ ?PriorityToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_ContextAttrAuditRequest(Val, State)
+ when is_record(Val, 'ContextAttrAuditRequest') ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ContextAttrAuditRequest'.topology],
+ fun('NULL', _) -> ?TopologyToken end},
+ {[Val#'ContextAttrAuditRequest'.emergency],
+ fun('NULL', _) -> ?EmergencyToken end},
+ {[Val#'ContextAttrAuditRequest'.priority],
+ fun('NULL', _) -> ?PriorityToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}],?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = asn1_NOVALUE},
+ State) ->
+ [
+ fun(S) ->
+ [
+ enc_TerminationID(From, S),
+ ?COMMA_INDENT(S),
+ enc_TerminationID(To, S),
+ ?COMMA_INDENT(S),
+ case Dir of
+ bothway -> ?BothwayToken;
+ isolate -> ?IsolateToken;
+ oneway -> ?OnewayToken
+ end
+ ]
+ end(?INC_INDENT(State))
+ ];
+enc_TopologyRequest1(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID},
+ State) ->
+ [
+ fun(S) ->
+ [
+ enc_TerminationID(From, S),
+ ?COMMA_INDENT(S),
+ enc_TerminationID(To, S),
+ ?COMMA_INDENT(S),
+ case Dir of
+ bothway -> ?BothwayToken;
+ isolate -> ?IsolateToken;
+ oneway -> ?OnewayToken
+ end,
+ ?COMMA_INDENT(S),
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, S)
+ ]
+ end(?INC_INDENT(State))
+ ].
+
+enc_AmmRequest(Val, State)
+ when is_record(Val, 'AmmRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'AmmRequest'.terminationID, State),
+ enc_opt_brackets(
+ enc_list([{Val#'AmmRequest'.descriptors, fun enc_ammDescriptor/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationIDList1(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(Val, State)
+ when is_record(Val, 'SubtractRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'SubtractRequest'.terminationID, State),
+ case Val#'SubtractRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_AuditRequest(Val, State)
+ when is_record(Val, 'AuditRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1([Val#'AuditRequest'.terminationID], State),
+ case Val#'AuditRequest'.auditDescriptor of
+ asn1_NOVALUE ->
+ [];
+ AuditDescr ->
+ [
+ ?LBRKT_INDENT(State) ,
+ enc_AuditDescriptor(AuditDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+ case Tag of
+ contextAuditResult ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDListN(Val, State)
+ ];
+ error ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_TerminationID(ID, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [],
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = asn1_NOVALUE},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+%% - v2 -
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+
+%% - v2 begin -
+
+enc_auditPropertyToken([], _State) ->
+ [];
+enc_auditPropertyToken([Param | Params], State) ->
+ [enc_IndAudauditReturnParameter(Param, State),
+ [[?COMMA_INDENT(State),
+ enc_IndAudauditReturnParameter(P, State)] || P <- Params]].
+
+
+enc_IndAudauditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ indAudMediaDescriptor ->
+ enc_IndAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ enc_IndAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ enc_IndAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ enc_IndAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ enc_IndAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ enc_IndAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ enc_IndAudPackagesDescriptor(Val, State);
+ _ ->
+ error({invalid_IndAudauditReturnParameter_tag, Tag})
+ end.
+
+%% The ASN.1 does not limit to just one of termStateDescr or streams,
+%% but the ABNF seams to do that...
+enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE,
+ streams = Val}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = Val,
+ streams = asn1_NOVALUE},
+ State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudMediaDescriptor_streams({Tag, Val}, State) ->
+ case Tag of
+ oneStream ->
+ enc_IndAudStreamParms(Val, State);
+ multiStream ->
+ enc_IndAudMediaDescriptor_multiStream(Val, State);
+ _ ->
+ error({invalid_IndAudMediaDescriptor_streams_tag, Tag})
+ end.
+
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = 'NULL'}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?ServiceStatesToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = 'NULL',
+ serviceState = asn1_NOVALUE}, _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?BufferToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [Parms],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE}, State) ->
+ #'IndAudPropertyParm'{name = Name} = Parms,
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = Val,
+ localDescriptor = asn1_NOVALUE,
+ remoteDescriptor = asn1_NOVALUE},
+ State) ->
+ [
+ enc_IndAudLocalControlDescriptor(Val, ?INC_INDENT(State))
+ ].
+
+enc_IndAudLocalControlDescriptor(Val, State)
+ when is_record(Val, 'IndAudLocalControlDescriptor') ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'IndAudLocalControlDescriptor'.streamMode],
+ fun('NULL', _) -> ?ModeToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveValue],
+ fun('NULL', _) -> ?ReservedValueToken end},
+ {[Val#'IndAudLocalControlDescriptor'.reserveGroup],
+ fun('NULL', _) -> ?ReservedGroupToken end},
+ {Val#'IndAudLocalControlDescriptor'.propertyParms,
+ fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = PkgdName}, State) ->
+ enc_PkgdName(PkgdName, State).
+
+enc_IndAudMediaDescriptor_multiStream([Val], State) ->
+ [
+ enc_IndAudStreamDescriptor(Val, ?INC_INDENT(State))
+ ];
+enc_IndAudMediaDescriptor_multiStream(Vals, _State) when is_list(Vals) ->
+ error({invalid_IndAudMediaDescriptor_multiStream_length, Vals});
+enc_IndAudMediaDescriptor_multiStream(Val, _State) ->
+ error({invalid_IndAudMediaDescriptor_multiStream, Val}).
+
+enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms},
+ State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudStreamParms(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventBufferDescriptor') ->
+ #'IndAudEventBufferDescriptor'{eventName = EvName,
+ streamID = ID} = Val,
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(EvName, State),
+ enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) ->
+ [
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName},
+ State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_Name(ParamName, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec(ID, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventsDescriptor(Val, State)
+ when is_record(Val, 'IndAudEventsDescriptor') ->
+ #'IndAudEventsDescriptor'{requestID = ReqID,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE} = Val,
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(ReqID, State),
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudSignalsDescriptor(Val, State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSignalsDescriptor_value({signal, Val}, State) ->
+ enc_IndAudSignal(Val, State);
+enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) ->
+ enc_IndAudSeqSigList(Val, State).
+
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ enc_SignalName(SignalName, State)
+ ].
+
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = Parm},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignal(Parm, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ].
+
+enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name},
+ State) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_Name(N, State),
+ "-",
+ enc_UINT16(V, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% - v2 end -
+
+
+enc_TerminationAudit({'TerminationAudit',Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([], _State) ->
+ [];
+enc_TerminationAudit([Mand | Opt], State) ->
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({invalid_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+ enc_list([{List, fun enc_auditReturnItem/2}], ?INC_INDENT(State)).
+
+
+enc_NotifyRequest(Val, State)
+ when is_record(Val, 'NotifyRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'NotifyRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ %% BUGBUG: Mismatch between ASN.1 and ABNF
+ %% BUGBUG: The following ought to be a 'choice'
+ case Val#'NotifyRequest'.errorDescriptor of
+ asn1_NOVALUE ->
+ OED = Val#'NotifyRequest'.observedEventsDescriptor,
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State));
+ ErrorDescr ->
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State))
+ end,
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(Val, State)
+ when is_record(Val, 'NotifyReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ case Val#'NotifyReply'.terminationID of
+ asn1_NOVALUE ->
+ error(asn1_not_compliant_with_abnf);
+ TermId ->
+ enc_TerminationIDList1(TermId, State)
+ end,
+ case Val#'NotifyReply'.errorDescriptor of
+ asn1_NOVALUE ->
+ [];
+ ErrorDescr ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ErrorDescr, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_ObservedEventsDescriptor(Val, State)
+ when is_record(Val, 'ObservedEventsDescriptor') ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(Val#'ObservedEventsDescriptor'.requestId, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEventsDescriptors(Val#'ObservedEventsDescriptor'.observedEventLst, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEventsDescriptors([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(Val, State)
+ when is_record(Val, 'ObservedEvent') ->
+ [
+ case Val#'ObservedEvent'.timeNotation of
+ asn1_NOVALUE ->
+ [];
+ TimeStamp ->
+ [
+ enc_TimeNotation(TimeStamp, State),
+ ?LWSP,
+ ?COLON
+ ]
+ end,
+ ?LWSP,
+ enc_EventName(Val#'ObservedEvent'.eventName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'ObservedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'ObservedEvent'.eventParList, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName',Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(Val, State)
+ when is_record(Val, 'ServiceChangeRequest') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeRequest'.terminationID, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Val#'ServiceChangeRequest'.serviceChangeParms,
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(Val, State)
+ when is_record(Val, 'ServiceChangeReply') ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_TerminationIDList1(Val#'ServiceChangeReply'.terminationID, State),
+ enc_ServiceChangeResult(Val#'ServiceChangeReply'.serviceChangeResult, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult',Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({Tag, Val}, State) ->
+ case Tag of
+ errorDescriptor ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ serviceChangeResParms ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+ _ ->
+ error({invalid_ServiceChangeResult_tag, Tag})
+ end.
+
+%% Required length of termination ID list is 1
+enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList1(Val, State);
+enc_TerminationIDList1([Singleton], State) ->
+ enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDListN({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDListN(Val, State);
+enc_TerminationIDListN([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDListN(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(Val, State)
+ when is_record(Val, 'MediaDescriptor') ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'MediaDescriptor'.termStateDescr],
+ fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Val#'MediaDescriptor'.streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') andalso (H#'PropertyParm'.name =:= "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EqualToken,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EqualToken,
+ ?LSBRKT,
+ enc_list([{Values, fun enc_Value/2}], State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EqualToken,
+ ?LBRKT,
+ enc_list([{Values, fun enc_Value/2}], State),
+ ?RBRKT
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDListN(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token;
+ %% extensionParameter
+ nx64k -> ?Nx64kToken % v2
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(Val, State)
+ when is_record(Val, 'EventsDescriptor') ->
+ #'EventsDescriptor'{requestID = RequestId,
+ eventList = Events} = Val,
+ if
+ RequestId == asn1_NOVALUE, Events == [] ->
+ [
+ ?EventsToken
+ ];
+
+ RequestId /= asn1_NOVALUE, Events /= [] ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RequestId, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Events, fun enc_RequestedEvent/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end.
+
+enc_RequestedEvent(Val, State)
+ when is_record(Val, 'RequestedEvent') ->
+%% d("enc_RequestedEvent -> entry with"
+%% "~n Val: ~p", [Val]),
+ PkgdName = ?META_ENC(event, Val#'RequestedEvent'.pkgdName),
+%% d("enc_RequestedEvent -> entry with"
+%% "~n PkgdName: ~p", [PkgdName]),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'RequestedEvent'.streamID], fun enc_eventStream/2},
+ {Val#'RequestedEvent'.evParList, fun enc_eventOther/2} |
+ decompose_requestedActions(Val#'RequestedEvent'.eventAction)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of KeepActiveToken , eventDM and eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (KA =/= true) andalso
+ (SD =/= asn1_NOVALUE) andalso
+ (SD =/= []) ->
+%% d("decompose_requestedActions -> entry with"
+%% "~n EDM: ~p"
+%% "~n SE: ~p"
+%% "~n SD: ~p", [EDM, SE, SD]),
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD})
+ when (SD =:= asn1_NOVALUE) orelse (SD =:= []) ->
+%% d("decompose_requestedActions -> entry with"
+%% "~n KA: ~p"
+%% "~n EDM: ~p"
+%% "~n SE: ~p", [KA, EDM, SE]),
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+%% d("decompose_requestedActions -> entry with"
+%% "~n KA: ~p"
+%% "~n EDM: ~p"
+%% "~n SE: ~p"
+%% "~n SD: ~p", [KA, EDM, SE, SD]),
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2}
+ ].
+
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+%% d("enc_embedNoSig -> entry with"
+%% "~n RID: ~p"
+%% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+%% d("enc_embedWithSig -> entry with"
+%% "~n SD: ~p", [SD]),
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+%% d("enc_embedWithSig -> entry with"
+%% "~n RID: ~p"
+%% "~n Evs: ~p"
+%% "~n SD: ~p", [RID, Evs, SD]),
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+%% d("enc_keepActive -> entry with"
+%% "~n Val: ~p", [Val]),
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+%% d("enc_EventDM -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) andalso is_list(Evs) andalso (Evs =/= []) ->
+%% d("enc_embedFirst -> entry with"
+%% "~n RID: ~p"
+%% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+%% d("enc_embedFirst -> entry"),
+ [
+ ?EventsToken
+ ].
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL,
+ eventAction = EA},
+ State) ->
+%% d("enc_SecondRequestedEvent -> entry with"
+%% "~n N: ~p"
+%% "~n SID: ~p"
+%% "~n EPL: ~p"
+%% "~n EA: ~p", [N, SID, EPL, EA]),
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_opt_brackets(
+ enc_list(
+ [{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(Val)
+ when is_record(Val, 'SecondRequestedActions') ->
+%% d("decompose_secondRequestedActions -> entry with"
+%% "~n Val: ~p", [Val]),
+ [
+ {[Val#'SecondRequestedActions'.keepActive],
+ fun enc_keepActive/2},
+ {[Val#'SecondRequestedActions'.eventDM],
+ fun enc_EventDM/2},
+ {[Val#'SecondRequestedActions'.signalsDescriptor],
+ fun enc_embeddedSignalsDescriptor/2}
+ ].
+
+enc_embeddedSignalsDescriptor(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EventSpecs, State)
+ when is_list(EventSpecs) and (length(EventSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EventSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventBufferDescriptor(EventSpecs, _State) ->
+ error({bad_eventSpecs, EventSpecs}).
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(Name, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(List, State) when is_list(List) ->
+% d("enc_SignalsDescriptor -> entry with"
+% "~n List: ~p", [List]),
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+% d("enc_SignalsDescriptor -> entry with"
+% "~n Tag: ~p"
+% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(Val, State)
+ when is_record(Val, 'Signal') ->
+ [
+ enc_SignalName(Val#'Signal'.signalName, State),
+ enc_opt_brackets(
+ enc_list([{[Val#'Signal'.streamID], fun enc_sigStream/2},
+ {[Val#'Signal'.sigType], fun enc_sigSignalType/2},
+ {[Val#'Signal'.duration], fun enc_sigDuration/2},
+ {[Val#'Signal'.notifyCompletion], fun enc_notifyCompletion/2},
+ {[Val#'Signal'.keepActive], fun enc_keepActive/2},
+ {Val#'Signal'.sigParList, fun enc_sigOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when (Val =:= ?megaco_all_request_id) ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_ModemDescriptor(MD, _State) ->
+ error({deprecated, MD}).
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% 7.1.2: ...shall not be included as part of a transmitted content and,
+%% if received, shall either be ignored or processed at the option
+%% of the implementation. ...
+%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+%% mpl = [],
+%% nonStandardData = asn1_NOVALUE},
+%% State) ->
+%% [
+%% ?ModemToken,
+%% ?EQUAL,
+%% enc_ModemType(Val, State)
+%% ];
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% enc_ModemDescriptor(Val, State)
+%% when is_record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% %% BUGBUG: Does never generate: EQUAL modemType
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% Corr1: See ModemDescriptor above
+%% enc_ModemType({'ModemType',Val}, State)->
+%% enc_ModemType(Val, State);
+%% enc_ModemType(Val, _State) ->
+%% %% BUGBUG: Does not handle extensionParameter
+%% case Val of
+%% v18 -> ?V18Token;
+%% v22 -> ?V22Token;
+%% v22bis -> ?V22bisToken;
+%% v32 -> ?V32Token;
+%% v32bis -> ?V32bisToken;
+%% v34 -> ?V34Token;
+%% v90 -> ?V90Token;
+%% v91 -> ?V91Token;
+%% synchISDN -> ?SynchISDNToken
+%% end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value} = Val,
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ error({invalid_DigitMapDescriptor, Val});
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ case is_empty_DigitMapValue(Value) of
+ true ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+ false ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+is_empty_DigitMapValue(#'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE}) ->
+ true;
+is_empty_DigitMapValue(#'DigitMapValue'{}) ->
+ false.
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2},
+ {Val#'ServiceChangeParm'.serviceChangeInfo,
+ fun enc_AuditDescriptor/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken
+ end
+ %% BUGBUG: extension
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) andalso (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+ [String]
+ end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) andalso (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) andalso (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invlid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) andalso is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep =:= true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep =:= false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% %% d(true, F, A).
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
+
diff --git a/lib/megaco/src/text/megaco_text_gen_v3.hrl b/lib/megaco/src/text/megaco_text_gen_v3.hrl
new file mode 100644
index 0000000000..1c19a4aa8b
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_gen_v3.hrl
@@ -0,0 +1,3457 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Encode V3 Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+%% -define(d(F,A), io:format("~w:" ++ F ++ "~n", [?MODULE|A])).
+
+-define(META_ENC(Type, Item), Item) .
+%% -define(META_ENC(Type, Item), megaco_meta_package:encode(text, Type, Item)).
+%% -define(META_DEC(Type, Item), megaco_meta_package:decode(text, Type, Item)).
+
+enc_MegacoMessage(Val) ->
+ State = ?INIT_INDENT,
+ enc_MegacoMessage(Val, State).
+
+enc_MegacoMessage(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_Message(Mess, State)
+ ];
+enc_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}, State) ->
+ [
+ ?LWSP,
+ enc_AuthenticationHeader(Auth, State),
+ enc_Message(Mess, State)
+ ].
+
+%% Note that encoding the transaction this way
+%% make the message look a bit strange.
+enc_Transaction(Val) ->
+ State = ?INIT_INDENT,
+ enc_Transaction(Val, State).
+
+%% Note that encoding the action request's this way
+%% make the message look a bit strange.
+enc_ActionRequests(Val) ->
+ State = ?INIT_INDENT,
+ enc_TransactionRequest_actions(Val, State).
+
+%% Note that encoding the action request this way
+%% make the message look a bit strange.
+enc_ActionRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionRequest(Val, State).
+
+enc_CommandRequest(Val) ->
+ State = ?INIT_INDENT,
+ enc_CommandRequest(Val, State).
+
+enc_ActionReply(Val) ->
+ State = ?INIT_INDENT,
+ enc_ActionReply(Val, State).
+
+enc_AuthenticationHeader(asn1_NOVALUE, _State) ->
+ [];
+enc_AuthenticationHeader(Val, State)
+ when is_record(Val, 'AuthenticationHeader') ->
+ [
+ ?AuthToken,
+ ?EQUAL,
+ enc_SecurityParmIndex(Val#'AuthenticationHeader'.secParmIndex, State),
+ ?COLON,
+ enc_SequenceNum(Val#'AuthenticationHeader'.seqNum, State),
+ ?COLON,
+ enc_AuthData(Val#'AuthenticationHeader'.ad, State),
+ ?SEP_INDENT(State)
+ ].
+
+enc_SecurityParmIndex({'SecurityParmIndex',Val}, State) ->
+ enc_SecurityParmIndex(Val, State);
+enc_SecurityParmIndex(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_SequenceNum({'SequenceNum',Val}, State) ->
+ enc_SequenceNum(Val, State);
+enc_SequenceNum(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 8, 8)
+ ].
+
+enc_AuthData({'AuthData',Val}, State) ->
+ enc_AuthData(Val, State);
+enc_AuthData(Val, State) ->
+ [
+ "0x",
+ enc_HEXDIG(Val, State, 24, 64) %% OTP-4710
+ ].
+
+enc_Message(Val, State)
+ when is_record(Val, 'Message') ->
+ [
+ ?MegacopToken,
+ ?SLASH,
+ enc_version(Val#'Message'.version, State),
+ ?SEP,
+ enc_MId(Val#'Message'.mId, State),
+ ?SEP_INDENT(State),
+ enc_Message_messageBody(Val#'Message'.messageBody, State)
+ ].
+
+enc_version(Val, State) when is_integer(Val) and (Val >= 0) ->
+ enc_DIGIT(Val, State, 0, 99).
+
+enc_Message_messageBody({'Message_messageBody',Val}, State) ->
+ enc_Message_messageBody(Val, State);
+enc_Message_messageBody({Tag, Val}, State) ->
+ case Tag of
+ messageError ->
+ enc_ErrorDescriptor(Val, State);
+ transactions ->
+ enc_Message_messageBody_transactions(Val, State);
+ _ ->
+ error({invalid_messageBody_tag, Tag})
+ end.
+
+enc_Message_messageBody_transactions({'Message_messageBody_transactions',Val},
+ State) ->
+ enc_Message_messageBody_transactions(Val, State);
+enc_Message_messageBody_transactions(Val, State)
+ when is_list(Val) and (Val /= []) ->
+ [enc_Transaction(T, State) || T <- Val].
+
+enc_MId({'MId',Val}, State) ->
+ enc_MId(Val, State);
+enc_MId({Tag, Val}, State) ->
+ case Tag of
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_MId_tag, Tag})
+ end.
+
+enc_mtpAddress(Val, State) ->
+ [
+ ?MtpToken,
+ ?LBRKT,
+ enc_OCTET_STRING(Val, State, 2, 4),
+ ?RBRKT
+ ].
+
+enc_DomainName(#'DomainName'{portNumber = asn1_NOVALUE,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>
+ ];
+enc_DomainName(#'DomainName'{portNumber = PortNumber,
+ name = Name}, State) ->
+ [
+ $<,
+ %% BUGBUG: (ALPHA / DIGIT) *63(ALPHA / DIGIT / "-" / ".")
+ enc_STRING(Name, State, 1, 64),
+ $>,
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP4Address(#'IP4Address'{portNumber = asn1_NOVALUE,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $]
+ ];
+enc_IP4Address(#'IP4Address'{portNumber = PortNumber,
+ address = [A1, A2, A3, A4]}, State) ->
+ [
+ $[,
+ enc_V4hex(A1, State),
+ ?DOT,
+ enc_V4hex(A2, State),
+ ?DOT,
+ enc_V4hex(A3, State),
+ ?DOT,
+ enc_V4hex(A4, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_V4hex(Val, State) ->
+ enc_DIGIT(Val, State, 0, 255).
+
+enc_IP6Address(#'IP6Address'{portNumber = asn1_NOVALUE,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) == 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $]
+ ];
+enc_IP6Address(#'IP6Address'{portNumber = PortNumber,
+ address = Addr}, State)
+ when is_list(Addr) andalso (length(Addr) == 16) ->
+ [
+ $[,
+ enc_IP6Address_address(Addr, State),
+ $],
+ $:,
+ enc_portNumber(PortNumber, State)
+ ].
+
+enc_IP6Address_address([0, 0|Addr], State) ->
+ enc_IP6Address_address2(Addr, 1, false, true, State);
+enc_IP6Address_address(Addr, State) ->
+ enc_IP6Address_address2(Addr, 0, false, false, State).
+
+enc_IP6Address_address2([0,0], 0, _Padding, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([0,0], PadN, false, true, _State) when PadN > 0 ->
+ [$:, $:]; % Padding from the beginning (all zero's)
+enc_IP6Address_address2([0,0], PadN, false, false, _State) when PadN > 0 ->
+ [$:]; % Padding in the middle or end
+enc_IP6Address_address2([0,0], _, true, _First, _State) ->
+ [$0];
+enc_IP6Address_address2([N1,N2], 0, _Padding, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], 1, _Padding, _First, State) ->
+ [$0, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, true, State) when PadN > 1 ->
+ [$:, $:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], PadN, false, false, State) when PadN > 1 ->
+ [$:, enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([N1,N2], _PadN, true, _First, State) ->
+ [enc_hex4([N1, N2], State)];
+enc_IP6Address_address2([0, 0|Ns], PadN, false, First, State) ->
+ enc_IP6Address_address2(Ns, PadN+1, false, First, State);
+enc_IP6Address_address2([0, 0|Ns], _PadN, true, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 0, Padded, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], 1, Padded, _First, State) ->
+ [
+ $0,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, Padded, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, true, State) when PadN > 1 ->
+ %% Padding from the beginning
+ [
+ $:,
+ $:,
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], PadN, false, false, State)
+ when PadN > 1 ->
+ [
+ $:, %% The other ':' has already added
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ];
+enc_IP6Address_address2([N1, N2|Ns], _PadN, true, _First, State) ->
+ [
+ enc_hex4([N1, N2], State),
+ $:,
+ enc_IP6Address_address2(Ns, 0, true, false, State)
+ ].
+
+
+enc_hex4([0,0], _State) ->
+ $0;
+enc_hex4([0,N], _State) ->
+ hex(N);
+enc_hex4([N1, N2], _State) when N2 =< 15 ->
+ [hex(N1), $0, hex(N2)];
+enc_hex4([N1, N2], _State) ->
+ [hex(N1), hex(N2)].
+
+enc_PathName({'PathName',Val}, State) ->
+ enc_PathName(Val, State);
+enc_PathName(Val, State) ->
+ %% BUGBUG: ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+ %% BUGBUG: ["@" pathDomainName ]
+ enc_STRING(Val, State, 1, 64).
+
+enc_Transaction(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_Transaction({'Transaction',Val}, State) ->
+ enc_Transaction(Val, State);
+enc_Transaction({Tag, Val}, State) ->
+ case Tag of
+ transactionRequest ->
+ enc_TransactionRequest(Val, State);
+ transactionPending ->
+ enc_TransactionPending(Val, State);
+ transactionReply ->
+ enc_TransactionReply(Val, State);
+ transactionResponseAck ->
+ enc_TransactionResponseAck(Val, State);
+ segmentReply ->
+ enc_SegmentReply(Val, State);
+ _ ->
+ error({invalid_Transaction_tag, Tag})
+ end.
+
+enc_TransactionResponseAck([Mand], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State)],
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionResponseAck([Mand | Opt], State) ->
+ [
+ ?ResponseAckToken,
+ ?LBRKT_INDENT(State),
+ [enc_TransactionAck(Mand, State) |
+ [[?COMMA_INDENT(State), enc_TransactionAck(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TransactionAck(Val, State)
+ when is_record(Val, 'TransactionAck') ->
+ [
+ enc_TransactionId(Val#'TransactionAck'.firstAck, ?INC_INDENT(State)),
+ case Val#'TransactionAck'.lastAck of
+ asn1_NOVALUE ->
+ [];
+ LastAck ->
+ ["-",enc_TransactionId(LastAck, State)]
+ end
+ ].
+
+enc_TransactionId({'TransactionId',Val}, State) ->
+ enc_TransactionId(Val, State);
+enc_TransactionId(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_TransactionRequest(#'TransactionRequest'{transactionId = Tid,
+ actions = Acts}, State) ->
+ [
+ ?TransToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionRequest_actions(Acts, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionRequest_actions(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_TransactionRequest_actions({'TransactionRequest_actions',Val}, State) ->
+ enc_TransactionRequest_actions(Val, State);
+enc_TransactionRequest_actions([Mand], State) ->
+ [enc_ActionRequest(Mand, State)];
+enc_TransactionRequest_actions([Mand | Opt], State) ->
+ [enc_ActionRequest(Mand, State) |
+ [[?COMMA_INDENT(State), enc_ActionRequest(Val, State)] || Val <- Opt]].
+
+enc_TransactionPending(#'TransactionPending'{transactionId = Tid}, State) ->
+ [?PendingToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionPending(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res,
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ segmentNumber = asn1_NOVALUE,
+ segmentationComplete = asn1_NOVALUE
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ segmentNumber = SegNo,
+ segmentationComplete = asn1_NOVALUE
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?SLASH,
+ enc_SegmentNumber(SegNo, State),
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(#'TransactionReply'{transactionId = Tid,
+ immAckRequired = Req,
+ transactionResult = Res,
+ segmentNumber = SegNo,
+ segmentationComplete = 'NULL'
+ },
+ State) ->
+ [
+ ?ReplyToken,
+ ?EQUAL,
+ enc_TransactionId(Tid, State),
+ ?SLASH,
+ enc_SegmentNumber(SegNo, State),
+ ?SLASH,
+ ?SegmentationCompleteToken,
+ ?LBRKT_INDENT(State),
+ enc_immAckRequired(Req, State),
+ enc_TransactionReply_transactionResult(Res, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TransactionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_SegmentReply({'SegmentReply', SR}, State) ->
+ enc_SegmentReply(SR, State);
+enc_SegmentReply(#'SegmentReply'{transactionId = TID,
+ segmentNumber = SegNo,
+ segmentationComplete = asn1_NOVALUE
+ }, State) ->
+ [
+ ?MessageSegmentToken,
+ ?EQUAL,
+ enc_TransactionId(TID, State),
+ ?SLASH,
+ enc_SegmentNumber(SegNo, State)
+ ];
+enc_SegmentReply(#'SegmentReply'{transactionId = TID,
+ segmentNumber = SegNo,
+ segmentationComplete = 'NULL'
+ }, State) ->
+ [
+ ?MessageSegmentToken,
+ ?EQUAL,
+ enc_TransactionId(TID, State),
+ ?SLASH,
+ enc_SegmentNumber(SegNo, State),
+ ?SLASH,
+ ?SegmentationCompleteToken
+ ];
+enc_SegmentReply(Bin, _State) when is_binary(Bin) ->
+ [Bin].
+
+enc_SegmentNumber({'SegmentNumber', SN}, State) ->
+ enc_SegmentNumber(SN, State);
+enc_SegmentNumber(SN, State) ->
+ enc_UINT16(SN, State).
+
+enc_immAckRequired(Val, _State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ 'NULL' ->
+ [?ImmAckRequiredToken, ?COMMA_INDENT(?INC_INDENT(_State))]
+ end.
+
+enc_TransactionReply_transactionResult({'TransactionReply_transactionResult',
+ Val}, State) ->
+ enc_TransactionReply_transactionResult(Val, State);
+enc_TransactionReply_transactionResult({Tag, Val}, State) ->
+ case Tag of
+ transactionError ->
+ enc_ErrorDescriptor(Val, State);
+ actionReplies ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+ _ ->
+ error({invalid_TransactionReply_transactionResult_tag, Tag})
+ end.
+
+enc_TransactionReply_transactionResult_actionReplies({'TransactionReply_transactionResult_actionReplies',Val}, State) ->
+ enc_TransactionReply_transactionResult_actionReplies(Val, State);
+enc_TransactionReply_transactionResult_actionReplies([Mand], State) ->
+ [enc_ActionReply(Mand, State)];
+enc_TransactionReply_transactionResult_actionReplies([Mand | Opt], State) ->
+ [enc_ActionReply(Mand, State),
+ [[?COMMA_INDENT(State), enc_ActionReply(Val, State)] || Val <- Opt]].
+
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = asn1_NOVALUE,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ ?RBRKT
+ ];
+enc_ErrorDescriptor(#'ErrorDescriptor'{errorText = Text,
+ errorCode = Code}, State) ->
+ [
+ ?ErrorToken,
+ ?EQUAL,
+ enc_ErrorCode(Code, State),
+ ?LBRKT,
+ enc_ErrorText(Text, State),
+ ?RBRKT
+ ].
+
+enc_ErrorCode({'ErrorCode',Val}, State)->
+ enc_ErrorCode(Val, State);
+enc_ErrorCode(Val, State) ->
+ enc_DIGIT(Val, State, 0, 999).
+
+enc_ErrorText({'ErrorText',Val}, State) ->
+ enc_ErrorText(Val, State);
+enc_ErrorText(Val, State) ->
+ enc_QUOTED_STRING(Val, State).
+
+enc_ContextID({'ContextID',Val}, State) ->
+ enc_ContextID(Val, State);
+enc_ContextID(Val, State) ->
+ case Val of
+ ?megaco_all_context_id -> $*;
+ ?megaco_null_context_id -> $-;
+ ?megaco_choose_context_id -> $$;
+ Int when is_integer(Int) -> enc_UINT32(Int, State)
+ end.
+
+enc_ActionRequest(Bin, _State) when is_binary(Bin) ->
+ [Bin]; %% Already encoded...
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = asn1_NOVALUE,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = asn1_NOVALUE,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ActionRequest(#'ActionRequest'{contextId = CID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CtxAAR,
+ commandRequests = CmdReqs}, State) ->
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(CID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[CtxReq], fun enc_ContextRequest/2},
+ {[CtxAAR], fun enc_ContextAttrAuditRequest/2},
+ {CmdReqs, fun enc_CommandRequest/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ActionReply(Bin, _State) when is_binary(Bin) ->
+ [Bin]; % Already encoded...
+%% OTP-5085
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = []},
+ State) ->
+%% d("enc_ActionReply -> entry with"
+%% "~n Id: ~p", [Id]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State)
+ ];
+enc_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep},
+ State) ->
+%% d("enc_ActionReply -> entry with"
+%% "~n Id: ~p"
+%% "~n ED: ~p"
+%% "~n CtxRep: ~p"
+%% "~n CmdRep: ~p", [Id, ED, CtxRep, CmdRep]),
+ [
+ ?CtxToken,
+ ?EQUAL,
+ enc_ContextID(Id, State),
+ ?LBRKT_INDENT(State),
+ do_enc_ActionReply(ED, CtxRep, CmdRep, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, [], State)
+ when CtxRep =/= asn1_NOVALUE ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, CtxRep, CmdRep, State)
+ when (CtxRep =/= asn1_NOVALUE) and (CmdRep =/= []) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(asn1_NOVALUE, asn1_NOVALUE, CmdRep, State)
+ when CmdRep =/= [] ->
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2}],
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, [], State)
+ when (ED =/= asn1_NOVALUE) and (CtxRep =/= asn1_NOVALUE) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) and (CmdRep =/= []) ->
+ [
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, CtxRep, CmdRep, State)
+ when (ED =/= asn1_NOVALUE) and
+ (CtxRep =/= asn1_NOVALUE) and
+ (CmdRep =/= []) ->
+ [
+ enc_ContextRequest(CtxRep, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_list([{CmdRep, fun enc_CommandReply/2},
+ {[ED], fun enc_ErrorDescriptor/2}], % Indention cosmetics
+ ?INC_INDENT(State))
+ ];
+do_enc_ActionReply(ED, asn1_NOVALUE, [], State)
+ when ED =/= asn1_NOVALUE ->
+ [
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State))
+ ].
+
+
+enc_ContextRequest_priority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_priority(Val, _State) ->
+ {[Val], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextRequest_emergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_emergency(true, _State) ->
+ {[?EmergencyToken], fun(Elem, _) -> Elem end};
+enc_ContextRequest_emergency(false, _State) ->
+ {[?EmergencyOffToken], fun(Elem, _) -> Elem end}.
+
+enc_ContextRequest_topologyReq(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ asn1_NOVALUE}, _State) ->
+ {[], dummy};
+enc_ContextRequest_topologyReq({'ContextRequest_topologyReq',
+ List}, _State) ->
+ {List, fun enc_TopologyRequest/2};
+enc_ContextRequest_topologyReq(List, _State) ->
+ {[List], fun enc_TopologyRequest/2}.
+
+enc_ContextRequest_iepscallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_iepscallind(Bool, _State) ->
+ {[Bool], fun enc_iepsValue/2}.
+
+enc_ContextRequest_contextProp(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextProp(Props, _State) ->
+ {[Props], fun(Elem, S) -> enc_contextAttrDescriptor(Elem, contextProps, S) end}.
+
+enc_ContextRequest_contextList(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextRequest_contextList([], _State) ->
+ {[], dummy};
+enc_ContextRequest_contextList(Props, _State) ->
+ {[Props], fun(Elem, S) ->
+ enc_contextAttrDescriptor(Elem, contextList, S)
+ end}.
+
+enc_contextAttrDescriptor([Mand|Opt], contextProps, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ [enc_PropertyParm(Mand, State) |
+ [[?COMMA_INDENT(State), enc_PropertyParm(Val, State)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ];
+enc_contextAttrDescriptor(CtxIdList, contextList, State) ->
+ [
+ ?ContextAttrToken,
+ ?LBRKT_INDENT(State),
+ enc_contextIdList(CtxIdList, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_contextIdList([Mand|Opt], State) ->
+ State2 = ?INC_INDENT(State),
+ [
+ ?ContextListToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ [enc_ContextID(Mand, State2) |
+ [[?COMMA_INDENT(State2), enc_ContextID(Val, State2)] || Val <- Opt]],
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+ contextList = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = [],
+ iepscallind = asn1_NOVALUE,
+ contextProp = [],
+ contextList = []}, _State) ->
+ [];
+enc_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TR,
+ iepscallind = Ieps,
+ contextProp = CP,
+ contextList = CL}, State) ->
+ [
+ enc_list([enc_ContextRequest_priority(Prio, State),
+ enc_ContextRequest_emergency(Em, State),
+ enc_ContextRequest_topologyReq(TR, State),
+ enc_ContextRequest_iepscallind(Ieps, State),
+ enc_ContextRequest_contextProp(CP, State),
+ enc_ContextRequest_contextList(CL, State)],
+ State)
+ ].
+
+
+%% -- contextAudit --
+%% contextAudit = ContextAuditToken LBRKT
+%% (contextAuditProperties *(COMMA contextAuditProperties)) /
+%% indAudcontextAttrDesscriptor
+%% RBRKT
+%% contextAuditProperties =
+%% (TopologyToken / EmergencyToken / PriorityToken /
+%% IEPSToken / pkgdName / contextAuditSelect)
+%% contextAuditSelect =
+%% priority / emergencyValue / iepsValue /
+%% contextAttrDescriptor / auditSelectLogic
+%% indAudcontextAttrDesscriptor =
+%% ContextAttrToken LBRKT
+%% (contextAuditProperties *(COMMA contextAuditProperties))
+%% RBRKT
+%%
+%% This could actually either be
+%% a) a list of contextAuditProperties:
+%% contextAuditProperties *(COMMA contextAuditProperties)
+%% b) a indAudcontextAttrDescriptor
+%% But since b) actually has the same content as a) with
+%% the extra ContextAttrToken, there does not seem to be any
+%% reason for using it.
+enc_ContextAttrAuditRequest(asn1_NOVALUE, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = [],
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}, _State) ->
+ [];
+enc_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = CPA,
+ selectpriority = SPrio,
+ selectemergency = SEm,
+ selectiepscallind = SIeps,
+ selectLogic = SL}, State) ->
+ [
+ ?ContextAuditToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+ {[Em], fun('NULL', _) -> ?EmergencyToken end},
+ {[Prio], fun('NULL', _) -> ?PriorityToken end},
+ {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+ {CPA, fun enc_IndAudPropertyParm/2},
+ enc_ContextAttrAuditRequest_selectpriority(SPrio, State),
+ enc_ContextAttrAuditRequest_selectemergency(SEm, State),
+ enc_ContextAttrAuditRequest_selectiepscallind(SIeps, State),
+ enc_ContextAttrAuditRequest_selectLogic(SL, State)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectpriority(SPrio, _State) ->
+ {[SPrio], fun(X,S) -> [?PriorityToken,?EQUAL,enc_UINT16(X, S)] end}.
+
+enc_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectemergency(SEm, _State) ->
+ {[SEm], fun(X,S) -> enc_emergencyValue(X, S) end}.
+
+enc_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectiepscallind(SEm, _State) ->
+ {[SEm], fun(X,S) -> enc_iepsValue(X, S) end}.
+
+enc_ContextAttrAuditRequest_selectLogic(asn1_NOVALUE, _State) ->
+ {[], dummy};
+enc_ContextAttrAuditRequest_selectLogic({andAUDITSelect, 'NULL'}, _State) ->
+ {[], dummy}; % This is default so, there is no reason to add it
+enc_ContextAttrAuditRequest_selectLogic({orAUDITSelect, 'NULL'}, _State) ->
+ {[?OrAUDITselectToken], fun(Elem, _) -> Elem end}.
+
+enc_emergencyValue(true, _) ->
+ [?EmergencyValueToken,?EQUAL,?EmergencyToken];
+enc_emergencyValue(_, _) ->
+ [?EmergencyValueToken,?EQUAL,?EmergencyOffToken].
+
+
+%% enc_IndAudContextAttrDescriptor(
+%% #'ContextAttrAuditRequest'{topology = Top,
+%% emergency = Em,
+%% priority = Prio,
+%% iepscallind = Ieps,
+%% contextPropAud = CPA,
+%% selectpriority = SelPrio,
+%% selectemergency = SelEm,
+%% selectiepscallind = SelIeps,
+%% selectLogic = SelLog}, State) ->
+%% [
+%% ?ContextAttrToken,
+%% ?LBRKT_INDENT(State),
+%% enc_list([{[Top], fun('NULL', _) -> ?TopologyToken end},
+%% {[Em], fun('NULL', _) -> ?EmergencyToken end},
+%% {[Prio], fun('NULL', _) -> ?PriorityToken end},
+%% {[Ieps], fun('NULL', _) -> ?IEPSToken end},
+%% {CPA, fun enc_IndAudPropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% ?RBRKT_INDENT(State)
+%% ].
+
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = asn1_NOVALUE,
+ command = Cmd}, State) ->
+ [
+ "O-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = asn1_NOVALUE,
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "W-",
+ enc_Command(Cmd, State)
+ ];
+enc_CommandRequest(#'CommandRequest'{optional = 'NULL',
+ wildcardReturn = 'NULL',
+ command = Cmd}, State) ->
+ [
+ "O-",
+ "W-",
+ enc_Command(Cmd, State)
+ ].
+
+enc_Command({'Command',Val}, State) ->
+ enc_Command(Val, State);
+enc_Command({Tag, Val}, State) ->
+%% d("enc_Command -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReq ->
+ [?AddToken, enc_AmmRequest(Val, State)];
+ moveReq ->
+ [?MoveToken, enc_AmmRequest(Val, State)];
+ modReq ->
+ [?ModifyToken, enc_AmmRequest(Val, State)];
+ subtractReq ->
+ [?SubtractToken, enc_SubtractRequest(Val, State)];
+ auditCapRequest ->
+ [?AuditCapToken, enc_AuditRequest(Val, State)];
+ auditValueRequest ->
+ [?AuditValueToken, enc_AuditRequest(Val, State)];
+ notifyReq ->
+ [?NotifyToken, enc_NotifyRequest(Val, State)];
+ serviceChangeReq ->
+ [?ServiceChangeToken, enc_ServiceChangeRequest(Val, State)];
+ _ ->
+ error({invalid_Command_tag, Tag})
+ end.
+
+enc_CommandReply({'CommandReply',Val}, State) ->
+ enc_CommandReply(Val, State);
+enc_CommandReply({Tag, Val}, State) ->
+%% d("enc_CommandReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ addReply ->
+ [?AddToken, enc_AmmsReply(Val, State)];
+ moveReply ->
+ [?MoveToken, enc_AmmsReply(Val, State)];
+ modReply ->
+ [?ModifyToken, enc_AmmsReply(Val, State)];
+ subtractReply ->
+ [?SubtractToken, enc_AmmsReply(Val, State)];
+ auditCapReply ->
+ [?AuditCapToken, enc_AuditReply(Val, State)];
+ auditValueReply ->
+ [?AuditValueToken, enc_AuditReply(Val, State)];
+ notifyReply ->
+ [?NotifyToken, enc_NotifyReply(Val, State)];
+ serviceChangeReply ->
+ [?ServiceChangeToken, enc_ServiceChangeReply(Val, State)];
+ _ ->
+ error({invalid_CommandReply_tag, Tag})
+ end.
+
+enc_TopologyRequest(Val, State)
+ when is_list(Val) ->
+ [
+ ?TopologyToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_TopologyRequest1/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = asn1_NOVALUE, % OPTIONAL
+ topologyDirectionExtension = asn1_NOVALUE % OPTIONAL
+ }, State) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID, % OPTIONAL
+ topologyDirectionExtension = asn1_NOVALUE}, % OPTIONAL
+ State) when (SID =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_StreamID(SID, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = asn1_NOVALUE, % OPTIONAL
+ topologyDirectionExtension = TDE}, % OPTIONAL
+ State) when (TDE =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirectionExtension(TDE, State)
+ ];
+enc_TopologyRequest1(
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID, % OPTIONAL
+ topologyDirectionExtension = TDE}, % OPTIONAL
+ State) when (SID =/= asn1_NOVALUE) and (TDE =/= asn1_NOVALUE) ->
+ [
+ enc_TerminationID(From, State),
+ ?COMMA_INDENT(State),
+ enc_TerminationID(To, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirection(TD, State),
+ ?COMMA_INDENT(State),
+ enc_StreamID(SID, State),
+ ?COMMA_INDENT(State),
+ enc_TopologyDirectionExtension(TDE, State)
+ ].
+
+enc_TopologyDirection(bothway, _State) ->
+ ?BothwayToken;
+enc_TopologyDirection(isolate, _State) ->
+ ?IsolateToken;
+enc_TopologyDirection(oneway, _State) ->
+ ?OnewayToken.
+
+enc_TopologyDirectionExtension(onewayexternal, _State) ->
+ ?OnewayExternalToken;
+enc_TopologyDirectionExtension(onewayboth, _State) ->
+ ?OnewayBothToken.
+
+enc_iepsValue(Val, _State) ->
+ [
+ ?IEPSToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+
+
+enc_AmmRequest(#'AmmRequest'{terminationID = TIDs,
+ descriptors = Ds}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ enc_opt_brackets(
+ enc_list([{Ds, fun enc_ammDescriptor/2}], ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_ammDescriptor({Tag, Desc}, State) ->
+ case Tag of
+ mediaDescriptor -> enc_MediaDescriptor(Desc, State);
+ modemDescriptor -> enc_ModemDescriptor(Desc, State);
+ muxDescriptor -> enc_MuxDescriptor(Desc, State);
+ eventsDescriptor -> enc_EventsDescriptor(Desc, State);
+ eventBufferDescriptor -> enc_EventBufferDescriptor(Desc, State);
+ signalsDescriptor -> enc_SignalsDescriptor(Desc, State);
+ digitMapDescriptor -> enc_DigitMapDescriptor(Desc, State);
+ auditDescriptor -> enc_AuditDescriptor(Desc, State);
+ statisticsDescriptor -> enc_StatisticsDescriptor(Desc, State);
+ _ ->
+ error({invalid_ammDescriptor_tag, Tag})
+ end.
+
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = []}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_AmmsReply(#'AmmsReply'{terminationID = TIDs,
+ terminationAudit = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs,
+ auditDescriptor = asn1_NOVALUE},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_SubtractRequest(#'SubtractRequest'{terminationID = TIDs,
+ auditDescriptor = AD},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = [TID|_] = TIDList},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = asn1_NOVALUE,
+ terminationIDList = TIDList},
+ _State) ->
+ error({invalid_terminationID, TID, TIDList});
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList([TID], State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = [TID|_] = TIDList},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDList, State),
+ ?LBRKT_INDENT(State),
+ enc_AuditDescriptor(AD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = _AD,
+ terminationIDList = TIDList},
+ _State) ->
+ error({invalid_terminationID, TID, TIDList}).
+
+%% auditReply = (AuditValueToken / AuditCapToken )
+%% ( contextTerminationAudit / auditOther)
+%% auditOther = EQUAL TerminationID LBRKT
+%% terminationAudit RBRKT
+%% terminationAudit = auditReturnParameter *(COMMA auditReturnParameter)
+%%
+%% contextTerminationAudit = EQUAL CtxToken ( terminationIDList /
+%% LBRKT errorDescriptor RBRKT )
+enc_AuditReply({Tag, Val}, State) ->
+%% d("enc_AuditReply -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ contextAuditResult ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ enc_TerminationIDList(Val, State)
+ ];
+ error ->
+ [
+ ?EQUAL,
+ ?CtxToken,
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ auditResult when is_record(Val, 'AuditResult') ->
+ enc_auditOther(Val, State);
+ auditResult ->
+ error({invalid_auditResult, Val});
+ auditResultTermList ->
+ enc_TermListAuditResult(Val, State);
+ _ ->
+ error({invalid_AuditReply_tag, Tag})
+ end.
+
+%% This is actually the same as AuditResult with the exception
+%% that instead of terminationID we have terminationIDList.
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p", [TIDList]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = []}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p", [TIDList]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State)
+ ];
+enc_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDList,
+ terminationAuditResult = TAR}, State) ->
+%% d("enc_TermListAuditResult -> entry with"
+%% "~n TIDList: ~p"
+%% "~n TAR: ~p", [TIDList, TAR]),
+ [
+ ?EQUAL,
+ enc_termIDList(TIDList, State),
+ case lists:flatten(enc_TerminationAudit(TAR, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = asn1_NOVALUE}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = []}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State)
+ ];
+enc_auditOther(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = Res}, State) ->
+ [
+ ?EQUAL,
+ enc_termIDList([TID], State),
+ case lists:flatten(enc_TerminationAudit(Res, ?INC_INDENT(State))) of
+ [] ->
+ [];
+ L ->
+ [
+ ?LBRKT_INDENT(State),
+ L,
+ ?RBRKT_INDENT(State)
+ ]
+ end
+ ].
+
+
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor(asn1_NOVALUE) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = [],
+ auditPropertyToken = asn1_NOVALUE},
+ _State) ->
+% d("enc_AuditDescriptor([]) -> entry"),
+ [
+ ?AuditToken,
+ [?LBRKT, ?RBRKT]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = asn1_NOVALUE},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+%% - v2 -
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ ];
+enc_AuditDescriptor(#'AuditDescriptor'{auditToken = List,
+ auditPropertyToken = Prop},
+ State) ->
+ [
+ ?AuditToken,
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_auditItem/2}], ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_auditPropertyToken(Prop, ?INC_INDENT(State)), % v2
+ ?RBRKT_INDENT(State)
+ ]
+ ].
+
+enc_auditItem(signalsToken, _State) ->
+ ?SignalsToken;
+enc_auditItem(eventBufferToken, _State) ->
+ ?EventBufferToken;
+enc_auditItem(eventsToken, _State) ->
+ ?EventsToken;
+enc_auditItem(Val, State) ->
+ enc_auditReturnItem(Val, State).
+
+
+enc_auditReturnItem(muxToken, _State) ->
+ ?MuxToken;
+enc_auditReturnItem(modemToken, _State) ->
+ ?ModemToken;
+enc_auditReturnItem(mediaToken, _State) ->
+ ?MediaToken;
+enc_auditReturnItem(digitMapToken, _State) ->
+ ?DigitMapToken;
+enc_auditReturnItem(statsToken, _State) ->
+ ?StatsToken;
+enc_auditReturnItem(observedEventsToken, _State) ->
+ ?ObservedEventsToken;
+enc_auditReturnItem(packagesToken, _State) ->
+ ?PackagesToken.
+
+
+%% - v2 begin -
+
+enc_auditPropertyToken([], _State) ->
+ [];
+enc_auditPropertyToken([Param | Params], State) ->
+ [enc_IndAudauditReturnParameter(Param, State),
+ [[?COMMA_INDENT(State),
+ enc_IndAudauditReturnParameter(P, State)] || P <- Params]].
+
+
+enc_IndAudauditReturnParameter({Tag, Val}, State) ->
+ case Tag of
+ indAudMediaDescriptor ->
+ enc_IndAudMediaDescriptor(Val, State);
+ indAudEventsDescriptor ->
+ enc_IndAudEventsDescriptor(Val, State);
+ indAudSignalsDescriptor ->
+ enc_IndAudSignalsDescriptor(Val, State);
+ indAudDigitMapDescriptor ->
+ enc_IndAudDigitMapDescriptor(Val, State);
+ indAudEventBufferDescriptor ->
+ enc_IndAudEventBufferDescriptor(Val, State);
+ indAudStatisticsDescriptor ->
+ enc_IndAudStatisticsDescriptor(Val, State);
+ indAudPackagesDescriptor ->
+ enc_IndAudPackagesDescriptor(Val, State);
+ _ ->
+ error({invalid_IndAudauditReturnParameter_tag, Tag})
+ end.
+
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = asn1_NOVALUE,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = asn1_NOVALUE}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudMediaDescriptor(
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudTerminationStateDescriptor(TSD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(State),
+ enc_IndAudMediaDescriptor_streams(Streams, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudMediaDescriptor_streams({oneStream, Val}, State) ->
+ enc_IndAudStreamParms(Val, State);
+enc_IndAudMediaDescriptor_streams({multiStream, Val}, State) ->
+ enc_IndAudMediaDescriptor_multiStream(Val, State);
+enc_IndAudMediaDescriptor_streams({Tag, _Val}, _State) ->
+ error({invalid_IndAudMediaDescriptor_streams_tag, Tag}).
+
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = 'NULL',
+ serviceStateSel = asn1_NOVALUE},
+ _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?ServiceStatesToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = SSS},
+ State) when SSS =/= asn1_NOVALUE ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_serviceState(SSS, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [],
+ eventBufferControl = 'NULL',
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = asn1_NOVALUE},
+ _State) ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(_State),
+ ?BufferToken,
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = [Parms],
+ eventBufferControl = asn1_NOVALUE,
+ serviceState = asn1_NOVALUE,
+ serviceStateSel = asn1_NOVALUE},
+ State) ->
+ #'IndAudPropertyParm'{name = Name} = Parms,
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudStreamParms(
+ #'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}, State) ->
+ [
+ enc_list([{[LCD], fun enc_IndAudLocalControlDescriptor/2},
+ {[LD], fun enc_remoteDescriptor/2},
+ {[RD], fun enc_localDescriptor/2},
+ {[SD], fun enc_IndAudStatisticsDescriptor/2}],
+ ?INC_INDENT(State))
+ ].
+
+enc_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = asn1_NOVALUE}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun('NULL', _) -> ?ModeToken end},
+ {[RV], fun('NULL', _) -> ?ReservedValueToken end},
+ {[RG], fun('NULL', _) -> ?ReservedGroupToken end},
+ {PP, fun enc_IndAudPropertyParm/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[RV], fun('NULL', _) -> ?ReservedValueToken end},
+ {[RG], fun('NULL', _) -> ?ReservedGroupToken end},
+ { PP, fun enc_IndAudPropertyParm/2},
+ {[SMS], fun enc_StreamMode/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name, propertyParms = PP},
+ State) ->
+ [
+ enc_list([{[Name], fun enc_PkgdName/2},
+ {[PP], fun enc_PropertyParm/2}], State)
+ ].
+
+enc_IndAudMediaDescriptor_multiStream(Val, State) when is_list(Val) ->
+ [
+ enc_list([{Val, fun enc_IndAudStreamDescriptor/2}], State)
+ ];
+enc_IndAudMediaDescriptor_multiStream(Val, _State) ->
+ error({invalid_IndAudMediaDescriptor_multiStream, Val}).
+
+enc_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms},
+ State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(SID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudStreamParms(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = EvName,
+ streamID = ID}, State) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(EvName, State),
+ enc_IndAudEventBufferDescriptor_eventSpec(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventBufferDescriptor_eventSpec(asn1_NOVALUE, _State) ->
+ [
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventParameterName, ParamName},
+ State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_Name(ParamName, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec({eventStream, ID}, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventBufferDescriptor_eventSpec(ID, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_eventStream(ID, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudEventsDescriptor(
+ #'IndAudEventsDescriptor'{requestID = asn1_NOVALUE,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ ?EventsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_IndAudEventsDescriptor(
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = asn1_NOVALUE}, State) ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudSignalsDescriptor(asn1_NOVALUE, _State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(_State),
+ ?RBRKT_INDENT(_State)
+ ];
+enc_IndAudSignalsDescriptor(Val, State) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignalsDescriptor_value(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSignalsDescriptor_value({signal, Val}, State) ->
+ enc_IndAudSignal(Val, State);
+enc_IndAudSignalsDescriptor_value({seqSigList, Val}, State) ->
+ enc_IndAudSeqSigList(Val, State).
+
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = asn1_NOVALUE,
+ signalRequestID = asn1_NOVALUE}, State) ->
+ [
+ enc_SignalName(SignalName, State)
+ ];
+enc_IndAudSignal(#'IndAudSignal'{signalName = SignalName,
+ streamID = SID,
+ signalRequestID = SRID}, State) ->
+ [
+ enc_SignalName(SignalName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_StreamID/2},
+ {[SRID], fun enc_sigRequestID/2}],
+ State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = asn1_NOVALUE},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State)
+ ];
+enc_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL},
+ State) ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(ID, State),
+ ?LBRKT_INDENT(State),
+ enc_IndAudSignal(SL, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_IndAudDigitMapDescriptor(#'IndAudDigitMapDescriptor'{digitMapName = Name},
+ State) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ].
+
+enc_IndAudStatisticsDescriptor(#'IndAudStatisticsDescriptor'{statName = Name},
+ State) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_PkgdName(Name, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_IndAudPackagesDescriptor(#'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V},
+ State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_Name(N, State),
+ "-",
+ enc_UINT16(V, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+%% - v2 end -
+
+
+enc_TerminationAudit({'TerminationAudit', Val}, State) ->
+ enc_TerminationAudit(Val, State);
+enc_TerminationAudit([Mand | Opt], State) ->
+ [enc_AuditReturnParameter(Mand, State),
+ [[?COMMA_INDENT(State), enc_AuditReturnParameter(Val, State)] || Val <- Opt]].
+
+enc_AuditReturnParameter({'AuditReturnParameter',Val}, State) ->
+ enc_AuditReturnParameter(Val, State);
+enc_AuditReturnParameter({Tag, Val}, State) ->
+%% d("enc_AuditReturnParameter -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p", [Tag, Val]),
+ case Tag of
+ mediaDescriptor ->
+ enc_MediaDescriptor(Val, State);
+ modemDescriptor ->
+ enc_ModemDescriptor(Val, State);
+ muxDescriptor ->
+ enc_MuxDescriptor(Val, State);
+ eventsDescriptor ->
+ enc_EventsDescriptor(Val, State);
+ signalsDescriptor ->
+ enc_SignalsDescriptor(Val, State);
+ digitMapDescriptor ->
+ enc_DigitMapDescriptor(Val, State);
+ observedEventsDescriptor ->
+ enc_ObservedEventsDescriptor(Val, State);
+ eventBufferDescriptor ->
+ enc_EventBufferDescriptor(Val, State);
+ statisticsDescriptor ->
+ enc_StatisticsDescriptor(Val, State);
+ packagesDescriptor ->
+ enc_PackagesDescriptor(Val, State);
+ errorDescriptor ->
+ enc_ErrorDescriptor(Val, State);
+ emptyDescriptors ->
+ enc_EmptyDescriptors(Val, State);
+ _ ->
+ error({invalid_AuditReturnParameter_tag, Tag})
+ end.
+
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = asn1_NOVALUE}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = []}, _State) ->
+ [];
+enc_EmptyDescriptors(#'AuditDescriptor'{auditToken = List}, State) ->
+%% d("enc_AuditReturnParameter -> entry with"
+%% "~n List: ~p", [List]),
+ enc_list([{List, fun enc_auditReturnItem/2}], State).
+
+
+enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs,
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE},
+ State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_NotifyRequest(#'NotifyRequest'{terminationID = TIDs,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ObservedEventsDescriptor(OED, ?INC_INDENT(State)),
+ ?COMMA,
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_NotifyReply(#'NotifyReply'{terminationID = TIDs,
+ errorDescriptor = asn1_NOVALUE}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State)
+ ];
+enc_NotifyReply(#'NotifyReply'{terminationID = TIDs,
+ errorDescriptor = ED}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(ED, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}, State) ->
+ [
+ ?ObservedEventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_observedEvents(OEL, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_observedEvents([Mand | Opt], State) ->
+ [enc_ObservedEvent(Mand, State),
+ [[?COMMA_INDENT(State), enc_ObservedEvent(Val, State)] || Val <- Opt]].
+
+%% ;time per event, because it might be buffered
+%% observedEvent = [ TimeStamp LWSP COLON] LWSP
+%% pkgdName [ LBRKT observedEventParameter
+%% *(COMMA observedEventParameter) RBRKT ]
+%%
+%% ;at-most-once eventStream, every eventParameterName at most once
+%% observedEventParameter = eventStream / eventOther
+enc_ObservedEvent(#'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = asn1_NOVALUE}, State) ->
+ [
+ ?LWSP,
+ enc_EventName(EN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ { EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ];
+enc_ObservedEvent(#'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}, State) ->
+ [
+ enc_TimeNotation(TN, State),
+ ?LWSP,
+ ?COLON,
+ ?LWSP,
+ enc_EventName(EN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_EventName({'EventName', Val}, State) ->
+ enc_EventName(Val, State);
+enc_EventName(Val, State) ->
+ PkgdName = ?META_ENC(event, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_eventStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+%% The value is already encoded
+enc_eventOther(#megaco_event_parameter{name = Name,
+ value = Value}, State)
+ when is_list(Value) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ Value
+ ];
+%% Special treatment of the ds parameter of the dd/ce event
+enc_eventOther(#'EventParameter'{eventParameterName = "ds" = Name,
+ value = [DigitString],
+ extraInfo = asn1_NOVALUE}, State) ->
+ [
+ enc_Name(Name, State),
+ ?EqualToken,
+ enc_DigitString(DigitString, State)
+ ];
+enc_eventOther(#'EventParameter'{eventParameterName = Name,
+ value = Value,
+ extraInfo = Extra}, State) ->
+ [
+ enc_Name(Name, State),
+ enc_propertyParmValues(Value, Extra, State)
+ ].
+
+enc_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = TIDs,
+ serviceChangeParms = Parms}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ ?LBRKT_INDENT(State),
+ enc_ServiceChangeParm(Parms, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% serviceChangeReply = ServiceChangeToken EQUAL TerminationID
+%% [LBRKT (errorDescriptor /
+%% serviceChangeReplyDescriptor) RBRKT]
+%% serviceChangeReplyDescriptor = ServicesToken LBRKT
+%% servChgReplyParm *(COMMA servChgReplyParm) RBRKT
+%%
+%% ;at-most-once. Version is REQUIRED on first ServiceChange response
+%% servChgReplyParm = (serviceChangeAddress / serviceChangeMgcId /
+%% serviceChangeProfile / serviceChangeVersion )
+enc_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = TIDs,
+ serviceChangeResult = Res}, State) ->
+ [
+ %% Assume that Token is added elsewhere
+ ?EQUAL,
+ enc_termIDList(TIDs, State),
+ enc_ServiceChangeResult(Res, State)
+ ].
+
+enc_ServiceChangeResult({'ServiceChangeResult', Val}, State) ->
+ enc_ServiceChangeResult(Val, State);
+enc_ServiceChangeResult({errorDescriptor, Val}, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_ErrorDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_ServiceChangeResult({serviceChangeResParms, Val}, State) ->
+ case enc_ServiceChangeResParm(Val, ?INC_INDENT(?INC_INDENT(State))) of
+ [] ->
+ [];
+ ResParms ->
+ [
+ ?LBRKT_INDENT(State),
+ ?ServicesToken,
+ fun(_S) ->
+ [
+ ?LBRKT_INDENT(_S),
+ ResParms,
+ ?RBRKT_INDENT(_S)
+ ]
+ end(?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ]
+ end;
+enc_ServiceChangeResult({Tag, _}, _State) ->
+ error({invalid_ServiceChangeResult_tag, Tag}).
+
+%% Required length of termination ID list is 1
+%% enc_TerminationIDList1({'TerminationIDList',Val}, State) ->
+%% enc_TerminationIDList1(Val, State);
+%% enc_TerminationIDList1([Singleton], State) ->
+%% enc_TerminationID(Singleton, State).
+
+%% No required length of termination ID list
+enc_TerminationIDList({'TerminationIDList',Val}, State) ->
+ enc_TerminationIDList(Val, State);
+enc_TerminationIDList([TID], State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_TerminationID(TID, State),
+ ?RBRKT_INDENT(State)
+ ];
+enc_TerminationIDList(TIDs, State) ->
+ [
+ ?LBRKT_INDENT(State),
+ enc_list([{TIDs, fun enc_TerminationID/2}], State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_termIDList({'TerminationIDList',Val}, State) ->
+ enc_termIDList(Val, State);
+enc_termIDList([Singleton], State) ->
+ enc_TerminationID(Singleton, State);
+enc_termIDList(TidList, State)
+ when is_list(TidList) and (length(TidList) > 1) ->
+%% d("enc_termIDList -> entry with"
+%% "~n TidList: ~p", [TidList]),
+ State2 = ?INC_INDENT(State),
+ [
+ ?LSBRKT_INDENT(State),
+ enc_list([{TidList, fun enc_TerminationID/2}], State2),
+ ?RSBRKT_INDENT(State)
+ ].
+
+%% TerminationID = "ROOT" / pathNAME / "$" / "*"
+%% ; Total length of pathNAME must not exceed 64 chars.
+%% pathNAME = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+enc_TerminationID(Tid, State)
+ when is_record(Tid, megaco_term_id) ->
+ List = [{Tid#megaco_term_id.id, fun enc_tid_component/2 }],
+ enc_list(List, State, fun(_S) -> ?SLASH end, false).
+
+enc_tid_component(Component, State) when is_list(Component) ->
+ [enc_tid_sub_component(Sub, State) || Sub <- Component];
+enc_tid_component(Invalid, _State) ->
+ error({invalid_id_list_component, Invalid}).
+
+enc_tid_sub_component(all = _Sub, _State) ->
+ ?megaco_all;
+enc_tid_sub_component(choose = _Sub, _State) ->
+ ?megaco_choose;
+enc_tid_sub_component(Char, _State) when is_integer(Char) ->
+ Char;
+enc_tid_sub_component(Invalid, _State) ->
+ error({invalid_id_list_sub_component, Invalid}).
+
+%% enc_tid_sub_component(Sub, _State) ->
+%% case Sub of
+%% all -> ?megaco_all;
+%% choose -> ?megaco_choose;
+%% Char when is_integer(Char) -> Char
+%% end.
+
+%% mediaDescriptor = MediaToken LBRKT mediaParm *(COMMA mediaParm) RBRKT
+%% ; at-most-once per item
+%% ; and either streamParm or streamDescriptor but not both
+%% mediaParm = (streamParm / streamDescriptor /
+%% terminationStateDescriptor)
+%% ; at-most-once
+%% streamParm = ( localDescriptor / remoteDescriptor /
+%% localControlDescriptor )
+%% streamDescriptor = StreamToken EQUAL StreamID LBRKT streamParm
+%% *(COMMA streamParm) RBRKT
+enc_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}, State) ->
+ [
+ ?MediaToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[TSD], fun enc_TerminationStateDescriptor/2} |
+ decompose_streams(Streams)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_streams(asn1_NOVALUE) ->
+ [];
+decompose_streams({'MediaDescriptor_streams',Val}) ->
+ decompose_streams(Val);
+decompose_streams({Tag, Val}) ->
+ case Tag of
+ oneStream ->
+ decompose_StreamParms(Val);
+ multiStream ->
+ [{Val, fun enc_StreamDescriptor/2}];
+ _ ->
+ error({invalid_streams_tag, Tag})
+ end.
+
+decompose_StreamParms(Val)
+ when is_record(Val, 'StreamParms') ->
+ [
+ {[Val#'StreamParms'.localControlDescriptor],
+ fun enc_LocalControlDescriptor/2},
+ {[Val#'StreamParms'.localDescriptor],
+ fun enc_localDescriptor/2},
+ {[Val#'StreamParms'.remoteDescriptor],
+ fun enc_remoteDescriptor/2},
+ {[Val#'StreamParms'.statisticsDescriptor],
+ fun enc_StatisticsDescriptor/2}
+ ].
+
+enc_StreamDescriptor(Val, State)
+ when is_record(Val, 'StreamDescriptor') ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val#'StreamDescriptor'.streamID, State),
+ ?LBRKT_INDENT(State),
+ enc_list(decompose_StreamParms(Val#'StreamDescriptor'.streamParms),
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% localControlDescriptor = LocalControlToken LBRKT localParm
+%% *(COMMA localParm) RBRKT
+%%
+%% ; at-most-once per item
+%% localParm = ( streamMode / propertyParm /
+%% reservedValueMode / reservedGroupMode )
+%% reservedValueMode = ReservedValueToken EQUAL ( "ON" / "OFF" )
+%% reservedGroupMode = ReservedGroupToken EQUAL ( "ON" / "OFF" )
+%%
+%% reservedMode = ReservedToken EQUAL ( "ON" / "OFF" )
+%%
+%% streamMode = ModeToken EQUAL streamModes
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ reserveValue = asn1_NOVALUE,
+ reserveGroup = asn1_NOVALUE,
+ propertyParms = []}, _State) ->
+ error({invalid_LocalControlDescriptor, empty});
+enc_LocalControlDescriptor(
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}, State) ->
+ [
+ ?LocalControlToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[SM], fun enc_StreamMode/2},
+ {[RG], fun enc_reservedGroupMode/2},
+ {[RV], fun enc_reservedValueMode/2},
+ {PPs, fun enc_PropertyParm/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_reservedGroupMode(Val, _State) ->
+ [
+ ?ReservedGroupToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_reservedValueMode(Val, _State) ->
+ [
+ ?ReservedValueToken,
+ ?EQUAL,
+ case Val of
+ false -> ?OffToken;
+ true -> ?OnToken
+ end
+ ].
+
+enc_StreamMode({'StreamMode',Val}, State) ->
+ enc_StreamMode(Val, State);
+enc_StreamMode(Val, _State) ->
+ [
+ ?ModeToken,
+ ?EQUAL,
+ case Val of
+ sendOnly -> ?SendonlyToken;
+ recvOnly -> ?RecvonlyToken;
+ sendRecv -> ?SendrecvToken;
+ inactive -> ?InactiveToken;
+ loopBack -> ?LoopbackToken
+ end
+ ].
+
+enc_Name({'Name',Val}, State) ->
+ enc_Name(Val, State);
+enc_Name(Val, State) ->
+ %% BUGBUG: NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ enc_STRING(Val, State, 1, 64).
+
+enc_PkgdName({'PkgdName', Val}, State) ->
+ enc_PkgdName(Val, State);
+enc_PkgdName(Val, _State) ->
+ %% BUGBUG: pkgdName = (NAME / "*") SLASH (ItemID / "*" )
+ %% enc_OCTET_STRING(Val, _State, 1, 64).
+ if
+ is_list(Val) ->
+ Length = length(Val),
+ if
+ (Length >= 1) ->
+ if
+ (Length =< 64) ->
+ Val;
+ true ->
+ error({pkgdName_toolong, Length, 64})
+ end;
+ true ->
+ error({pkgdName_tooshort, Length, 1})
+ end;
+ true ->
+ error({invalid_PkgdName, Val})
+ end.
+
+enc_localDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?LocalToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_remoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ [
+ ?RemoteToken,
+ ?LBRKT,
+ enc_LocalRemoteDescriptor(Val, State),
+ ?RBRKT_INDENT(State)
+ ].
+
+%% When text encoding the protocol, the descriptors consist of session
+%% descriptions as defined in SDP (RFC2327), except that the "s=", "t="
+%% and "o=" lines are optional. When multiple session descriptions are
+%% provided in one descriptor, the "v=" lines are required as delimiters;
+%% otherwise they are optional. Implementations shall accept session
+%% descriptions that are fully conformant to RFC2327. When binary
+%% encoding the protocol the descriptor consists of groups of properties
+%% (tag-value pairs) as specified in Annex C. Each such group may
+%% contain the parameters of a session description.
+enc_LocalRemoteDescriptor(Val, State)
+ when is_record(Val, 'LocalRemoteDescriptor') ->
+ case Val#'LocalRemoteDescriptor'.propGrps of
+ [] ->
+ [];
+ [OptV | MandV] ->
+ [?LfToken,
+ enc_PropertyGroup(OptV, opt_v, State) |
+ [enc_PropertyGroup(M, mand_v, State) || M <- MandV]]
+ end.
+
+enc_PropertyGroup({'PropertyGroup',Val}, RequiresV, State) ->
+ enc_PropertyGroup(Val, RequiresV, State);
+enc_PropertyGroup([H | _T] = List, mand_v, State)
+ when is_record(H, 'PropertyParm') and (H#'PropertyParm'.name == "v") ->
+ enc_PropertyGroup(List, opt_v, State);
+enc_PropertyGroup(PG, opt_v, State) ->
+ [
+ [[enc_PropertyGroupParm(PP, State), ?CrToken, ?LfToken] || PP <- PG]
+ ].
+
+enc_PropertyGroupParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ [OctetString] = Val#'PropertyParm'.value,
+ [
+ enc_PkgdName(Val#'PropertyParm'.name, State),
+ ?EqualToken,
+ enc_OCTET_STRING(OctetString, State, 0, infinity)
+ ].
+
+%% propertyParm = pkgdName parmValue
+%% parmValue = (EQUAL alternativeValue/ INEQUAL VALUE)
+%% alternativeValue = ( VALUE / LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE DOT DOT VALUE RSBRKT )
+enc_PropertyParm(Val, State)
+ when is_record(Val, 'PropertyParm') ->
+ PkgdName = ?META_ENC(property, Val#'PropertyParm'.name),
+ [
+ enc_PkgdName(PkgdName, State),
+ enc_propertyParmValues(Val#'PropertyParm'.value,
+ Val#'PropertyParm'.extraInfo,
+ State)
+ ].
+
+enc_propertyParmValues([Single], asn1_NOVALUE, State) ->
+ [
+ ?EqualToken,
+ enc_Value(Single, State)
+ ];
+enc_propertyParmValues([Single], {relation, Rel}, State) ->
+ case Rel of
+ greaterThan -> [$>, enc_Value(Single, State)];
+ smallerThan -> [$<, enc_Value(Single, State)];
+ unequalTo -> [$#, enc_Value(Single, State)]
+ end;
+enc_propertyParmValues([Low, High], {range, true}, State)->
+ %% Exact two values
+ [
+ ?EQUAL,
+ ?LSBRKT,
+ enc_Value(Low, State),
+ ?COLON,
+ enc_Value(High, State),
+ ?RSBRKT
+ ];
+enc_propertyParmValues(Values, {sublist, true}, State)->
+ %% sublist (i.e. A AND B AND ...)
+ [
+ ?EQUAL,
+ ?LSBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RSBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(Values, {sublist, false}, State) ->
+ %% alternatives (i.e. A OR B OR ...)
+ [
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{Values, fun enc_Value/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_propertyParmValues(V, EI, _State) ->
+ error({invalid_property_parm_values, V, EI}).
+
+enc_TerminationStateDescriptor(Val, State)
+ when is_record(Val, 'TerminationStateDescriptor') ->
+ [
+ ?TerminationStateToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'TerminationStateDescriptor'.propertyParms,
+ fun enc_PropertyParm/2},
+ {[Val#'TerminationStateDescriptor'.eventBufferControl],
+ fun enc_eventBufferControl/2},
+ {[Val#'TerminationStateDescriptor'.serviceState],
+ fun enc_serviceState/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_eventBufferControl(Val, _State) ->
+ [
+
+ ?BufferToken,
+ ?EQUAL,
+ case Val of
+ off -> ?OffToken;
+ lockStep -> ?LockStepToken
+ end
+ ].
+
+enc_serviceState({'ServiceState',Val}, State) ->
+ enc_serviceState(Val, State);
+enc_serviceState(Val, _State) ->
+ [
+ ?ServiceStatesToken,
+ ?EQUAL,
+ case Val of
+ test -> ?TestToken;
+ outOfSvc -> ?OutOfSvcToken;
+ inSvc -> ?InSvcToken
+ end
+ ].
+
+enc_MuxDescriptor(Val, State)
+ when is_record(Val, 'MuxDescriptor') ->
+ [
+ ?MuxToken,
+ ?EQUAL,
+ enc_MuxType(Val#'MuxDescriptor'.muxType, State),
+ enc_TerminationIDList(Val#'MuxDescriptor'.termList, State)
+ ].
+
+enc_MuxType({'MuxType',Val}, State) ->
+ enc_MuxType(Val, State);
+enc_MuxType(Val, _State) ->
+ case Val of
+ h221 -> ?H221Token;
+ h223 -> ?H223Token;
+ h226 -> ?H226Token;
+ v76 -> ?V76Token;
+ %% extensionParameter
+ nx64k -> ?Nx64kToken % v2
+ end.
+
+enc_StreamID({'StreamID',Val}, State) ->
+ enc_StreamID(Val, State);
+enc_StreamID(Val, State) ->
+ enc_UINT16(Val, State).
+
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []}, _State) ->
+ [
+ ?EventsToken
+ ];
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = Evs}, State)
+ when (RID =/= asn1_NOVALUE) and (Evs =/= []) ->
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_RequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = Evs}, _State) ->
+ error({invalid_EventsDescriptor, RID, Evs}).
+
+enc_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+enc_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_requestedActions(EA)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+decompose_requestedActions(asn1_NOVALUE) ->
+ [];
+decompose_requestedActions(
+ #'RequestedActions'{keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE}) ->
+ [];
+
+%%
+%% This in the ABNF:
+%% at-most-once each of
+%% - KeepActiveToken
+%% - notifyBehaviour
+%% - eventDM
+%% - ResetEventsDescriptor
+%% - eventStream
+%% at most one of either embedWithSig or embedNoSig but not both
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+
+%% embedWithSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (KA =/= true) and ((SD =/= asn1_NOVALUE) and (SD =/= [])) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+
+%% embedNoSig
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (SD == asn1_NOVALUE) or (SD == []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[SE], fun enc_embedNoSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+
+%% Fallback, if everything else failes....
+decompose_requestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[{SE, SD}], fun enc_embedWithSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ].
+
+
+enc_embedNoSig(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_embedWithSig({asn1_NOVALUE, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedWithSig({#'SecondEventsDescriptor'{requestID = RID,
+ eventList = Evs}, SD}, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(SD, ?INC_INDENT(State)),
+ ?COMMA_INDENT(?INC_INDENT(State)),
+ enc_embedFirst(RID, Evs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_keepActive(Val, _State) ->
+ case Val of
+ true -> [?KeepActiveToken];
+ false -> []
+ end.
+
+enc_EventDM({'EventDM',Val}, State) ->
+ enc_EventDM(Val, State);
+enc_EventDM({Tag, Val}, State) ->
+ case Tag of
+ digitMapName ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Val, State)
+ ];
+ digitMapValue ->
+ [
+ ?DigitMapToken,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+ _ ->
+ error({invalid_EventDM_tag, Tag})
+ end.
+
+
+enc_embedFirst(RID, Evs, State)
+ when (RID =/= asn1_NOVALUE) and (is_list(Evs) and (Evs =/= [])) ->
+ %% d("enc_embedFirst -> entry with"
+ %% "~n RID: ~p"
+ %% "~n Evs: ~p", [RID, Evs]),
+ [
+ ?EventsToken,
+ ?EQUAL,
+ enc_RequestID(RID, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Evs, fun enc_SecondRequestedEvent/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_embedFirst(_RID, _Evs, _State) ->
+ %% d("enc_embedFirst -> entry"),
+ [
+ ?EventsToken
+ ].
+
+enc_notifyBehaviour({notifyImmediate, 'NULL'}, _State) ->
+ [?NotifyImmediateToken];
+enc_notifyBehaviour({notifyRegulated, Val}, State) ->
+ enc_RegulatedEmbeddedDescriptor(Val, State);
+enc_notifyBehaviour({neverNotify, 'NULL'}, _State) ->
+ [?NeverNotifyToken];
+enc_notifyBehaviour({Tag, Val}, _State) ->
+ error({invalid_notifyBehaviour, Tag, Val}).
+
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE}, _State) ->
+ [
+ ?NotifyRegulatedToken
+ ];
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = asn1_NOVALUE}, State) ->
+ [
+ ?NotifyRegulatedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedNoSig(SE, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}, State) ->
+ [
+ ?NotifyRegulatedToken,
+ ?LBRKT_INDENT(State),
+ enc_embedWithSig({SE, SD}, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_RegulatedEmbeddedDescriptor(Val, _State) ->
+ error({invalid_RegulatedEmbeddedDescriptor, Val}).
+
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = asn1_NOVALUE,
+ eventAction = asn1_NOVALUE,
+ evParList = []}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+enc_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}, State) ->
+ PkgdName = ?META_ENC(event, N),
+ [
+ enc_PkgdName(PkgdName, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2},
+ {EPL, fun enc_eventOther/2} |
+ decompose_secondRequestedActions(EA)],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+%%
+%% This in the ABNF:
+%% at-most-once each of
+%% - KeepActiveToken
+%% - notifyBehaviour
+%% - eventDM
+%% - ResetEventsDescriptor
+%% - eventStream
+%% KeepActiveToken and embedWithSig must not both be present
+%%
+decompose_secondRequestedActions(asn1_NOVALUE) ->
+ [];
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = asn1_NOVALUE,
+ eventDM = asn1_NOVALUE,
+ signalsDescriptor = asn1_NOVALUE,
+ notifyBehaviour = asn1_NOVALUE,
+ resetEventsDescriptor = asn1_NOVALUE}) ->
+ [];
+
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (KA =/= true) and ((SD =/= asn1_NOVALUE) and (SD =/= [])) ->
+ [
+ {[EDM], fun enc_EventDM/2},
+ {[SD], fun enc_embedSig/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+decompose_secondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED})
+ when (SD == asn1_NOVALUE) or (SD == []) ->
+ [
+ {[KA], fun enc_keepActive/2},
+ {[EDM], fun enc_EventDM/2},
+ {[NB], fun enc_notifyBehaviour/2},
+ {[RED], fun('NULL', _) -> ?ResetEventsDescriptorToken end}
+ ];
+decompose_secondRequestedActions(SRA) ->
+ error({invalid_SecondRequestedActions, SRA}).
+
+enc_embedSig(Val, State) ->
+ [
+ ?EmbedToken,
+ ?LBRKT_INDENT(State),
+ enc_SignalsDescriptor(Val, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_EventBufferDescriptor({'EventBufferDescriptor',Val}, State) ->
+ enc_EventBufferDescriptor(Val, State);
+enc_EventBufferDescriptor([], _State) ->
+ [
+ ?EventBufferToken
+ ];
+enc_EventBufferDescriptor(EvSpecs, State)
+ when is_list(EvSpecs) andalso (length(EvSpecs) >= 1) ->
+ [
+ ?EventBufferToken,
+ ?LBRKT_INDENT(State),
+ enc_eventSpecs(EvSpecs, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_EventBufferDescriptor(EvSpecs, _State) ->
+ error({bad_eventSpecs, EvSpecs}).
+
+enc_eventSpecs([Mand | Opt], State) ->
+ [enc_eventSpec(Mand, State),
+ [[?COMMA_INDENT(State), enc_eventSpec(Val, State)] || Val <- Opt]].
+
+enc_eventSpec(#'EventSpec'{eventName = N,
+ streamID = asn1_NOVALUE,
+ eventParList = []}, State) ->
+ [
+ enc_EventName(N, State)
+ ];
+enc_eventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}, State) ->
+ [
+ enc_EventName(N, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{[SID], fun enc_eventStream/2}, {EPL, fun enc_eventOther/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalsDescriptor({'SignalsDescriptor',Val}, State) ->
+ enc_SignalsDescriptor(Val, State);
+enc_SignalsDescriptor([], _State) ->
+ [
+ ?SignalsToken
+ ];
+enc_SignalsDescriptor(SigRequests, State) when is_list(SigRequests) ->
+ [
+ ?SignalsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{SigRequests, fun enc_SignalRequest/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_SignalRequest({'SignalRequest',Val}, State) ->
+ enc_SignalRequest(Val, State);
+enc_SignalRequest({Tag, Val}, State) ->
+ case Tag of
+ signal ->
+ enc_Signal(Val, State);
+ seqSigList ->
+ enc_SeqSigList(Val, State);
+ _ ->
+ error({invalid_SignalRequest_tag, Tag})
+ end.
+
+
+enc_SeqSigList(Val, State)
+ when is_record(Val, 'SeqSigList') ->
+ [
+ ?SignalListToken,
+ ?EQUAL,
+ enc_UINT16(Val#'SeqSigList'.id, State),
+ ?LBRKT_INDENT(State),
+ enc_list([{Val#'SeqSigList'.signalList, fun enc_Signal/2}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_Signal(#'Signal'{signalName = SN,
+ streamID = SID,
+ sigType = ST,
+ duration = Du,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Di,
+ requestID = RID,
+ intersigDelay = ISD}, State) ->
+ [
+ enc_SignalName(SN, State),
+ enc_opt_brackets(
+ enc_list([{[SID], fun enc_sigStream/2},
+ {[ST], fun enc_sigSignalType/2},
+ {[Du], fun enc_sigDuration/2},
+ {[NC], fun enc_notifyCompletion/2},
+ {[KA], fun enc_keepActive/2},
+ {SPL, fun enc_sigOther/2},
+ {[Di], fun enc_SignalDirection/2},
+ {[RID], fun enc_sigRequestID/2},
+ {[ISD], fun enc_sigIntsigDelay/2}],
+ ?INC_INDENT(State)),
+ State)
+ ].
+
+enc_sigStream(Val, State) ->
+ [
+ ?StreamToken,
+ ?EQUAL,
+ enc_StreamID(Val, State)
+ ].
+
+enc_sigSignalType(Val, State) ->
+ [
+ ?SignalTypeToken,
+ ?EQUAL,
+ enc_SignalType(Val, State)
+ ].
+
+enc_sigDuration(Val, State) ->
+ [
+ ?DurationToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_notifyCompletion(List, State) when is_list(List) ->
+ [
+ ?NotifyCompletionToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_notifyCompletionItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_notifyCompletionItem(Val, _State) ->
+ case Val of
+ onTimeOut -> ?TimeOutToken;
+ onInterruptByEvent -> ?InterruptByEventToken;
+ onInterruptByNewSignalDescr -> ?InterruptByNewSignalsDescrToken;
+ otherReason -> ?OtherReasonToken;
+ onIteration -> ?IterationToken
+ end.
+
+enc_SignalType({'SignalType',Val}, State) ->
+ enc_SignalType(Val, State);
+enc_SignalType(Val, _State) ->
+ case Val of
+ brief -> ?BriefToken;
+ onOff -> ?OnOffToken;
+ timeOut -> ?TimeOutToken
+ end.
+
+enc_SignalName({'SignalName',Val}, State)->
+ enc_SignalName(Val, State);
+enc_SignalName(Val, State) ->
+ PkgdName = ?META_ENC(signal, Val),
+ enc_PkgdName(PkgdName, State).
+
+enc_sigOther(Val, State)
+ when is_record(Val, 'SigParameter') ->
+ [
+ enc_Name(Val#'SigParameter'.sigParameterName, State),
+ enc_propertyParmValues(Val#'SigParameter'.value,
+ Val#'SigParameter'.extraInfo,
+ State)
+ ].
+
+enc_SignalDirection({'SignalDirection', Val}, State) ->
+ enc_SignalDirection(Val, State);
+enc_SignalDirection(Val, _State) ->
+ [
+ ?DirectionToken,
+ ?EQUAL,
+ case Val of
+ internal -> ?InternalToken;
+ external -> ?ExternalToken;
+ both -> ?BothToken
+ end
+ ].
+
+enc_sigRequestID(Val, State) ->
+ [
+ ?RequestIDToken,
+ ?EQUAL,
+ enc_RequestID(Val, State)
+ ].
+
+enc_RequestID({'RequestID',Val}, State) ->
+ enc_RequestID(Val, State);
+enc_RequestID(Val, _State) when Val == ?megaco_all_request_id ->
+ "*";
+enc_RequestID(Val, State) ->
+ enc_UINT32(Val, State).
+
+enc_sigIntsigDelay(Val, State) ->
+ [
+ ?IntsigDelayToken,
+ ?EQUAL,
+ enc_UINT16(Val, State)
+ ].
+
+enc_ModemDescriptor(MD, _State) ->
+ error({deprecated, MD}).
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% 7.1.2: ...shall not be included as part of a transmitted content and,
+%% if received, shall either be ignored or processed at the option
+%% of the implementation. ...
+%% enc_ModemDescriptor(#'ModemDescriptor'{mtl = [Val],
+%% mpl = [],
+%% nonStandardData = asn1_NOVALUE},
+%% State) ->
+%% [
+%% ?ModemToken,
+%% ?EQUAL,
+%% enc_ModemType(Val, State)
+%% ];
+%% enc_ModemDescriptor(Val, State)
+%% when record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% enc_ModemDescriptor(Val, State)
+%% when record(Val, 'ModemDescriptor') ->
+%% [
+%% ?ModemToken,
+%% %% BUGBUG: Does never generate: EQUAL modemType
+%% ?LSBRKT,
+%% enc_list([{Val#'ModemDescriptor'.mtl, fun enc_ModemType/2}], State),
+%% ?RSBRKT,
+%% enc_opt_brackets(
+%% enc_list([{Val#'ModemDescriptor'.mpl, fun enc_PropertyParm/2}],
+%% ?INC_INDENT(State)),
+%% State)
+%% %% BUGBUG: Is PropertyParm == NAME parmValue?
+%% ].
+
+%% Corr1: See ModemDescriptor above
+%% enc_ModemType({'ModemType',Val}, State)->
+%% enc_ModemType(Val, State);
+%% enc_ModemType(Val, _State) ->
+%% %% BUGBUG: Does not handle extensionParameter
+%% case Val of
+%% v18 -> ?V18Token;
+%% v22 -> ?V22Token;
+%% v22bis -> ?V22bisToken;
+%% v32 -> ?V32Token;
+%% v32bis -> ?V32bisToken;
+%% v34 -> ?V34Token;
+%% v90 -> ?V90Token;
+%% v91 -> ?V91Token;
+%% synchISDN -> ?SynchISDNToken
+%% end.
+
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = asn1_NOVALUE,
+ digitMapValue = Value},
+ State)
+ when (Value =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE},
+ State)
+ when (Name =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State)
+ ];
+enc_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ State)
+ when (Name =/= asn1_NOVALUE) andalso (Value =/= asn1_NOVALUE) ->
+ [
+ ?DigitMapToken,
+ ?EQUAL,
+ enc_DigitMapName(Name, State),
+ ?LBRKT_INDENT(State),
+ enc_DigitMapValue(Value, ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ];
+enc_DigitMapDescriptor(BadVal, _State) ->
+ error({invalid_DigitMapDescriptor, BadVal}).
+
+enc_DigitMapName({'DigitMapName',Val}, State) ->
+ enc_DigitMapName(Val, State);
+enc_DigitMapName(Val, State) ->
+ enc_Name(Val, State).
+
+enc_DigitMapValue(Val, State)
+ when is_record(Val, 'DigitMapValue') ->
+ [
+ enc_timer(Val#'DigitMapValue'.startTimer, $T, State),
+ enc_timer(Val#'DigitMapValue'.shortTimer, $S, State),
+ enc_timer(Val#'DigitMapValue'.longTimer, $L, State),
+ enc_timer(Val#'DigitMapValue'.durationTimer, $Z, State),
+ %% BUGBUG: digitMapBody not handled at all
+ enc_STRING(Val#'DigitMapValue'.digitMapBody, State, 0, infinity)
+ ].
+
+enc_timer(asn1_NOVALUE, _Prefix, _State) ->
+ [];
+enc_timer(Timer, Prefix, State) ->
+ [
+ Prefix,
+ ?COLON,
+ enc_DIGIT(Timer, State, 0, 99),
+ ?COMMA_INDENT(State)
+ ].
+
+enc_ServiceChangeParm(Val, State)
+ when is_record(Val, 'ServiceChangeParm') ->
+ [
+ ?ServicesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{[Val#'ServiceChangeParm'.serviceChangeMethod],
+ fun enc_ServiceChangeMethod/2},
+ {[Val#'ServiceChangeParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[{reason, Val#'ServiceChangeParm'.serviceChangeReason}],
+ fun enc_serviceChangeReason/2},
+ {[Val#'ServiceChangeParm'.serviceChangeDelay],
+ fun enc_serviceChangeDelay/2},
+ {[Val#'ServiceChangeParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeParm'.timeStamp],
+ fun enc_TimeNotation/2},
+ {Val#'ServiceChangeParm'.serviceChangeInfo,
+ fun enc_AuditDescriptor/2},
+ {[Val#'ServiceChangeParm'.serviceChangeIncompleteFlag],
+ fun('NULL', _) -> ?ServiceChangeIncompleteToken end}],
+ ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+
+enc_ServiceChangeMethod({'ServiceChangeMethod',Val}, State) ->
+ enc_ServiceChangeMethod(Val, State);
+enc_ServiceChangeMethod(Val, _State) ->
+ [
+ ?MethodToken,
+ ?EQUAL,
+ case Val of
+ failover -> ?FailoverToken;
+ forced -> ?ForcedToken;
+ graceful -> ?GracefulToken;
+ restart -> ?RestartToken;
+ disconnected -> ?DisconnectedToken;
+ handOff -> ?HandOffToken;
+ _ ->
+ error({invalid_ServiceChangeMethod, Val})
+
+ end
+ ].
+
+enc_ServiceChangeAddress({'ServiceChangeAddress',Val}, State) ->
+ enc_ServiceChangeAddress(Val, State);
+enc_ServiceChangeAddress({Tag, Val}, State) ->
+ [
+ ?ServiceChangeAddressToken,
+ ?EQUAL,
+ case Tag of
+ portNumber ->
+ enc_portNumber(Val, State);
+ ip4Address ->
+ enc_IP4Address(Val, State);
+ ip6Address ->
+ enc_IP6Address(Val, State);
+ domainName ->
+ enc_DomainName(Val, State);
+ deviceName ->
+ enc_PathName(Val, State);
+ mtpAddress ->
+ enc_mtpAddress(Val, State);
+ _ ->
+ error({invalid_ServiceChangeAddress_tag, Tag})
+ end
+ ].
+
+enc_serviceChangeVersion(Val, State) ->
+ [
+ ?VersionToken,
+ ?EQUAL,
+ enc_version(Val, State)
+ ].
+
+enc_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = Name,
+ version = Version},
+ State) ->
+ [
+ ?ProfileToken,
+ ?EQUAL,
+ enc_Name(Name, State),
+ ?SLASH,
+ enc_version(Version, State)
+ ].
+
+enc_serviceChangeReason({reason, Val}, State) ->
+ case Val of
+ asn1_NOVALUE ->
+ [];
+ [List] when is_list(List) ->
+ [
+ ?ReasonToken,
+ ?EQUAL,
+ enc_QUOTED_STRING(List,State) % OTP-4632 enc_Value(List, State)
+ ]
+ end.
+
+enc_serviceChangeDelay(Val, State) ->
+ [
+ ?DelayToken,
+ ?EQUAL,
+ enc_UINT32(Val, State)
+ ].
+
+enc_serviceChangeMgcId(Val, State) ->
+ [
+ ?MgcIdToken,
+ ?EQUAL,
+ enc_MId(Val, State)
+ ].
+
+enc_portNumber(Val, State) when is_integer(Val) and (Val >= 0) ->
+ enc_UINT16(Val, State).
+
+enc_ServiceChangeResParm(Val, State)
+ when is_record(Val, 'ServiceChangeResParm') ->
+ enc_list([{[Val#'ServiceChangeResParm'.serviceChangeAddress],
+ fun enc_ServiceChangeAddress/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeVersion],
+ fun enc_serviceChangeVersion/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeProfile],
+ fun enc_ServiceChangeProfile/2},
+ {[Val#'ServiceChangeResParm'.serviceChangeMgcId],
+ fun enc_serviceChangeMgcId/2},
+ {[Val#'ServiceChangeResParm'.timeStamp],
+ fun enc_TimeNotation/2}],
+ State).
+
+enc_PackagesDescriptor({'PackagesDescriptor',Val}, State) ->
+ enc_PackagesDescriptor(Val, State);
+enc_PackagesDescriptor(Val, State) ->
+ [
+ ?PackagesToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{Val, fun enc_PackagesItem/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_PackagesItem(Val, State)
+ when is_record(Val, 'PackagesItem') ->
+ PkgdName = ?META_ENC(package, Val#'PackagesItem'.packageName),
+ [
+ enc_Name(PkgdName, State),
+ "-",
+ enc_UINT16(Val#'PackagesItem'.packageVersion, State)
+ ].
+
+enc_StatisticsDescriptor({'StatisticsDescriptor',Val}, State) ->
+ enc_StatisticsDescriptor(Val, State);
+enc_StatisticsDescriptor(List, State) when is_list(List) ->
+ [
+ ?StatsToken,
+ ?LBRKT_INDENT(State),
+ enc_list([{List, fun enc_StatisticsParameter/2}], ?INC_INDENT(State)),
+ ?RBRKT_INDENT(State)
+ ].
+
+enc_StatisticsParameter(Val, State)
+ when is_record(Val, 'StatisticsParameter') ->
+ PkgdName = ?META_ENC(statistics, Val#'StatisticsParameter'.statName),
+ case Val#'StatisticsParameter'.statValue of
+ asn1_NOVALUE ->
+ [
+ enc_PkgdName(PkgdName, State)
+ ];
+ [StatVal] when is_list(StatVal) ->
+ [
+ enc_PkgdName(PkgdName, State),
+ ?EQUAL,
+ enc_Value(StatVal, State)
+ ]
+ end.
+
+enc_TimeNotation(Val, State)
+ when is_record(Val, 'TimeNotation') ->
+ [
+ enc_STRING(Val#'TimeNotation'.date, State, 8, 8), % "yyyymmdd"
+ "T",
+ enc_STRING(Val#'TimeNotation'.time, State, 8, 8) % "hhmmssss"
+ ].
+
+%% BUGBUG: Does not verify that string must contain at least one char
+%% BUGBUG: This violation of the is required in order to comply with
+%% BUGBUG: the dd/ce ds parameter that may possibly be empty.
+enc_Value({'Value',Val}, State) ->
+ enc_Value(Val, State);
+enc_Value(String, _State) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_, 0, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {false, _, _} ->
+ [?DQUOTE, String, ?DQUOTE];
+ {true, _, _} ->
+ [String]
+ end.
+
+quoted_string_count([?DoubleQuoteToken | T], 0 = Count, _IsSafe, _MaybeQuoted) ->
+ %% Already a quoted string. Make sure it ends
+ quoted_string_count(T, Count + 1, true, true);
+quoted_string_count([?DoubleQuoteToken], Count, IsSafe, true = MaybeQuoted) ->
+ %% An explicitly quoted string
+ {IsSafe, Count, MaybeQuoted};
+quoted_string_count([H | T], Count, IsSafe, MaybeQuoted) ->
+ case ?classify_char(H) of
+ safe_char_upper -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ safe_char -> quoted_string_count(T, Count + 1, IsSafe, MaybeQuoted);
+ rest_char -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ white_space -> quoted_string_count(T, Count + 1, false, MaybeQuoted);
+ _ -> error({illegal_char, H})
+ end;
+quoted_string_count([], _Count, _IsSafe, true = _MaybeQuoted) ->
+ error({illegal_char, ?DoubleQuoteToken});
+quoted_string_count([], Count, IsSafe, MaybeQuoted) ->
+ {IsSafe, Count, MaybeQuoted}.
+
+enc_DigitString(String, _State) when is_list(String) ->
+ [?DQUOTE, String, ?DQUOTE].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Encode an octet string, escape } by \ if necessary
+enc_OCTET_STRING(List, State, Min, Max) ->
+ do_enc_OCTET_STRING(List, State, Min, Max, 0).
+
+do_enc_OCTET_STRING([H | T], State, Min, Max, Count) ->
+ case H of
+ $} ->
+ [$\\, H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)];
+ _ ->
+ [H | do_enc_OCTET_STRING(T, State, Min, Max, Count + 1)]
+ end;
+do_enc_OCTET_STRING([], _State, Min, Max, Count) ->
+ verify_count(Count, Min, Max),
+ [].
+
+enc_QUOTED_STRING(String, _State) when is_list(String) ->
+ case quoted_string_count(String, 0, true, false) of
+ {_IsSafe, Count, false = _QuotedString} ->
+ verify_count(Count, 1, infinity),
+ [?DQUOTE, String, ?DQUOTE];
+ {_IsSafe, Count, true = _QuotedString} ->
+ verify_count(Count, 3, infinity), % quotes not included in the count
+ [String]
+ end.
+
+%% The internal format of hex digits is a list of octets
+%% Min and Max means #hexDigits
+%% Leading zeros are prepended in order to fulfill Min
+enc_HEXDIG(Octets, State, Min, Max) when is_list(Octets) ->
+ do_enc_HEXDIG(Octets, State, Min, Max, 0, []).
+
+do_enc_HEXDIG([Octet | Rest], State, Min, Max, Count, Acc)
+ when (Octet >= 0) and (Octet =< 255) ->
+ Hex = hex(Octet), % OTP-4921
+ if
+ Octet =< 15 ->
+ Acc2 = [[$0|Hex]|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, ["0" | Acc2]);
+ true ->
+ Acc2 = [Hex|Acc], % OTP-4921
+ do_enc_HEXDIG(Rest, State, Min, Max, Count + 2, Acc2)
+ end;
+do_enc_HEXDIG([], State, Min, Max, Count, Acc)
+ when is_integer(Min) and (Count < Min) ->
+ do_enc_HEXDIG([0], State, Min, Max, Count, Acc);
+do_enc_HEXDIG([], _State, Min, Max, Count, Acc) -> %% OTP-4710
+ verify_count(Count, Min, Max),
+ lists:reverse(Acc).
+
+enc_DIGIT(Val, State, Min, Max) ->
+ enc_integer(Val, State, Min, Max).
+
+enc_STRING(String, _State, Min, Max) when is_list(String) ->
+ verify_count(length(String), Min, Max),
+ String.
+
+enc_UINT16(Val, State) ->
+ enc_integer(Val, State, 0, 65535).
+
+enc_UINT32(Val, State) ->
+ enc_integer(Val, State, 0, 4294967295).
+
+enc_integer(Val, _State, Min, Max) ->
+ verify_count(Val, Min, Max),
+ integer_to_list(Val).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Encodes a list of elements with separator tokens between
+%% the elements. Optional asn1_NOVALUE values are ignored.
+
+enc_list(List, State) ->
+ enc_list(List, State, fun(_S) -> ?COMMA_INDENT(_S) end, false).
+
+enc_list([], _State, _SepEncoder, _NeedsSep) ->
+ [];
+enc_list([{Elems, ElemEncoder} | Tail], State, SepEncoder, NeedsSep) ->
+ case do_enc_list(Elems, State, ElemEncoder, SepEncoder, NeedsSep) of
+ [] ->
+ enc_list(Tail, State, SepEncoder, NeedsSep);
+ List ->
+ [List,
+ enc_list(Tail, State, SepEncoder, true)]
+ end;
+enc_list(A, B, C, D) ->
+ error({invalid_list, A, B, C, D}).
+
+do_enc_list(asn1_NOVALUE, _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([], _State, _ElemEncoder, _SepEncoder, _NeedsSep) ->
+ [];
+do_enc_list([asn1_NOVALUE | T], State, ElemEncoder, SepEncoder, NeedsSep) ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+do_enc_list([H | T], State, ElemEncoder, SepEncoder, NeedsSep)
+ when is_function(ElemEncoder) and is_function(SepEncoder) ->
+ case ElemEncoder(H, State) of
+ [] ->
+ do_enc_list(T, State, ElemEncoder, SepEncoder, NeedsSep);
+ List when NeedsSep == true ->
+ [SepEncoder(State),
+ List, do_enc_list(T, State, ElemEncoder, SepEncoder, true)];
+ List when NeedsSep == false ->
+ [List,
+ do_enc_list(T, State, ElemEncoder, SepEncoder, true)]
+ end.
+
+%% Add brackets if list is non-empty
+enc_opt_brackets([], _State) ->
+ [];
+enc_opt_brackets(List, _State) when is_list(List) ->
+ [?LBRKT_INDENT(_State), List, ?RBRKT_INDENT(_State)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Int -> list of hex chars
+hex(Int) ->
+ hexi(get_lo_bits(Int, 4), []).
+
+hexi({0, Lo}, Ack) ->
+ [hex4(Lo) | Ack];
+hexi({Hi, Lo} , Ack) ->
+ hexi(get_lo_bits(Hi, 4), [hex4(Lo) | Ack]).
+
+hex4(Int) when Int < 10 ->
+ Int + $0;
+hex4(Int) ->
+ ($A - 10) + Int.
+
+get_lo_bits(Int, Size) ->
+ Lo = Int band ones_mask(Size),
+ Hi = Int bsr Size,
+ {Hi, Lo}.
+
+ones_mask(Ones) ->
+ (1 bsl Ones) - 1.
+
+%% Verify that Count is within the range of Min and Max
+verify_count(Count, Min, Max) ->
+ if
+ is_integer(Count) ->
+ if
+ is_integer(Min) andalso (Count >= Min) ->
+ if
+ is_integer(Max) andalso (Count =< Max) ->
+ Count;
+ Max =:= infinity ->
+ Count;
+ true ->
+ error({count_too_large, Count, Max})
+ end;
+ true ->
+ error({count_too_small, Count, Min})
+ end;
+ true ->
+ error({count_not_an_integer, Count})
+ end.
+
+
+%% -------------------------------------------------------------------
+
+error(Reason) ->
+ erlang:error(Reason).
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("~p:" ++ F ++"~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
+
diff --git a/lib/megaco/src/text/megaco_text_mini_decoder.erl b/lib/megaco/src/text/megaco_text_mini_decoder.erl
new file mode 100644
index 0000000000..6e1bf9295a
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_mini_decoder.erl
@@ -0,0 +1,88 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%%% Purpose: Encode PRETTY Megaco/H.248 text messages from internal form
+%%----------------------------------------------------------------------
+
+-module(megaco_text_mini_decoder).
+
+-export([decode_message/2]).
+
+-include("megaco_text_tokens.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Convert a binary into a mini 'MegacoMessage' record
+%% Return {ok, MegacoMessageRecord} | {error, Reason}
+%%----------------------------------------------------------------------
+
+decode_message(_, Bin) when is_binary(Bin) ->
+ case megaco_text_scanner:scan(Bin) of
+ {ok, Tokens, _Vsn, _LastLine} ->
+ decode_message(Tokens);
+
+ {error, Reason, Line} ->
+ parse_error(Reason, Line, [])
+ end;
+decode_message(_EC, _BadBin) ->
+ {error, bad_binary}.
+
+
+decode_message(Tokens0) ->
+ Tokens = strip(Tokens0, []),
+ case (catch megaco_text_mini_parser:parse(Tokens)) of
+ {ok, MegacoMessage} ->
+ {ok, MegacoMessage};
+ {error, Reason} ->
+ parse_error(Reason, Tokens);
+
+ %% OTP-4007
+ {'EXIT', Reason} ->
+ parse_error(Reason, Tokens)
+ end.
+
+strip([], Tokens) ->
+ lists:reverse(Tokens);
+strip([{'TransToken', _Line, _Text}|_], Acc) ->
+ strip_finish(Acc);
+strip([{'ReplyToken', _Line, _Text}|_], Acc) ->
+ strip_finish(Acc);
+strip([{'PendingToken', _Line, _Text}|_], Acc) ->
+ strip_finish(Acc);
+strip([{'ResponseAckToken', _Line, _Text}|_], Acc) ->
+ strip_finish(Acc);
+strip([{'ErrorToken', _Line, _Text}|_], Acc) ->
+ strip_finish(Acc);
+strip([H|T], Acc) ->
+ strip(T, [H|Acc]).
+
+strip_finish(RevTokens) ->
+ lists:reverse([{endOfMessage, 1, endOfMessage}|RevTokens]).
+
+
+parse_error(Reason, Tokens) ->
+ {error, [{reason, Reason}, {token, Tokens}]}.
+
+parse_error(Reason, Line, Tokens) ->
+ {error, [{reason, Reason, Line}, {token, Tokens}]}.
+
+
diff --git a/lib/megaco/src/text/megaco_text_mini_parser.hrl b/lib/megaco/src/text/megaco_text_mini_parser.hrl
new file mode 100644
index 0000000000..bb6ee43247
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_mini_parser.hrl
@@ -0,0 +1,1246 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-include("megaco_text_tokens.hrl").
+
+-define(d(F,A), io:format("DBG:"++F++"~n",A)).
+
+make_safe_token({_TokenTag, Line, Text}) ->
+ {safeToken, Line, Text}.
+
+% ensure_value({safeToken, _Line, Text}) ->
+% ensure_value(Text);
+% ensure_value({'QuotedChars', _Line, Text}) ->
+% ensure_value(Text);
+% ensure_value(Text) when list(Text) ->
+% Text. %% BUGBUG: ensure length
+
+% %% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+% ensure_NAME({_TokenTag, _Line, Text}) ->
+% Text. %% BUGBUG: ensure length and chars
+
+% ensure_requestID({safeToken, _Line, "*"}) ->
+% ?megaco_all_request_id;
+% ensure_requestID(RequestId) ->
+% ensure_uint32(RequestId).
+
+% ensure_streamID(StreamId) ->
+% ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% ContextID = (UINT32 / "*" / "-" / "$")
+% ensure_contextID({_TokenTag, _Line, Text}) ->
+% case Text of
+% "*" -> ?megaco_all_context_id;
+% "-" -> ?megaco_null_context_id;
+% "\$" -> ?megaco_choose_context_id;
+% Int -> ensure_uint32(Int)
+% end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr({TokenTag, Line, Addr}) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when (length(Hex4) =< 4) andalso (length(Hex4) > 0) ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+ensure_domainName({_TokenTag, _Line, Name}, Port) ->
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+% ensure_extensionParameter({_TokenTag, Line, Text}) ->
+% case Text of
+% [X, S | _Chars] ->
+% if
+% X /= $X, X /= $x,
+% S /= $+, S /= $- ->
+% return_error(Line, {bad_extension_parameter, Text});
+% true ->
+% {extension_parameter, Text}
+% end;
+% _ ->
+% return_error(Line, {bad_extension_parameter, Text})
+% end.
+
+ensure_message(MegacopToken, MID) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Version} =
+ ensure_profile(MegacopToken),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version, mId = MID};
+ [$!] ->
+ #'Message'{version = Version, mId = MID}
+ end.
+
+
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+% case Text of
+% "v32b" -> v32bis;
+% "v22b" -> v22bis;
+% "v18" -> v18;
+% "v22" -> v22;
+% "v32" -> v32;
+% "v34" -> v34;
+% "v90" -> v90;
+% "v91" -> v91;
+% "synchisdn" -> synchISDN;
+% "sn" -> synchISDN;
+% [$x | _] -> ensure_extensionParameter(Token)
+% end.
+
+%% An mtp address is five octets long
+ensure_mtpAddress({_TokenTag, _Line, Addr}) ->
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+% ensure_muxType({_TokenTag, _Line, Text} = Token) ->
+% case Text of
+% "h221" -> h221;
+% "h223" -> h223;
+% "h226" -> h226;
+% "v76" -> v76;
+% "nx64k" -> nx64k; % v2
+% [$x | _] -> ensure_extensionParameter(Token)
+% end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+% ensure_packagesItem({TokenTag, Line, Text}) ->
+% case string:tokens(Text, [$-]) of
+% [Name, Version] ->
+% #'PackagesItem'{packageName = ensure_NAME({TokenTag, Line, Name}),
+% packageVersion = ensure_uint({TokenTag, Line, Version}, 0, 99)};
+% _ ->
+% return_error(Line, {bad_PackagesItem, Text})
+% end.
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+% ensure_pkgdName({TokenTag, Line, Text}) ->
+% case string:tokens(Text, [$/]) of
+% [Name, Item] ->
+% ensure_name_or_star({TokenTag, Line, Name}),
+% ensure_name_or_star({TokenTag, Line, Item}),
+% Text;
+% _ ->
+% return_error(Line, {bad_pkgdName, Text})
+% end.
+
+% ensure_name_or_star({_, _, Name}) when Name == "*" ->
+% Name;
+% ensure_name_or_star(Name) ->
+% ensure_NAME(Name).
+
+
+
+%% v2 - start
+
+% merge_indAudMediaDescriptor({termStateDescr, Val}) ->
+% #'IndAudMediaDescriptor'{termStateDescr = Val};
+% merge_indAudMediaDescriptor({streamParm, Val}) ->
+% #'IndAudMediaDescriptor'{streams = {oneStream, Val}};
+% merge_indAudMediaDescriptor({streamDescr, Val}) ->
+% #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}.
+
+% merge_indAudLocalControlDescriptor(Parms) ->
+% do_merge_indAudLocalControlDescriptor(Parms,
+% #'IndAudLocalControlDescriptor'{}).
+
+% do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
+% case Parm of
+% modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+% PropParms = [#'IndAudPropertyParm'{name = Val}],
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+% {pkgdName, Val} when list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
+% PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
+% PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
+% Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
+% do_merge_indAudLocalControlDescriptor(Parms, Desc2)
+% end;
+% do_merge_indAudLocalControlDescriptor([], Desc) ->
+% case Desc#'IndAudLocalControlDescriptor'.propertyParms of
+% [_ | _] = PropParms -> % List has more then one element
+% PropParms2= lists:reverse(PropParms),
+% Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+% _ ->
+% Desc
+% end.
+
+% ensure_indAudLocalParm(Token) ->
+% case Token of
+% {safeToken, _Line, "mode"} -> modeToken;
+% {safeToken, _Line, "mo"} -> modeToken;
+% {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
+% {safeToken, _Line, "rg"} -> reservedGroupToken;
+% {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
+% {safeToken, _Line, "rv"} -> reservedValueToken;
+% PkgdName -> {pkgdName,
+% ensure_pkgdName(PkgdName)}
+% end.
+
+% merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
+% PropParm = #'IndAudPropertyParm'{name = Val},
+% #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+% merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+% #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+% merge_indAudTerminationStateDescriptor(bufferToken) ->
+% #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+% merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+% IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+% do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+% do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+% IAEBD;
+% do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+% IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+% do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+% IAEBD) ->
+% %% BUGBUG BUGBUG BUGBUG
+% %% This is an ugly hack to allow the eventParamName which only
+% %% exists in the text encoding...
+% IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+% ensure_indAudSignalListParm(SIG) when record(SIG, 'Signal') ->
+% ensure_indAudSignal(SIG).
+
+% ensure_indAudSignal(#'Signal'{signalName = SignalName,
+% streamID = asn1_NOVALUE,
+% sigType = asn1_NOVALUE,
+% duration = asn1_NOVALUE,
+% notifyCompletion = asn1_NOVALUE,
+% keepActive = asn1_NOVALUE,
+% sigParList = []}) ->
+% #'IndAudSignal'{signalName = SignalName}.
+
+
+% ensure_IADMD({_TokenTag, _Line,
+% #'DigitMapDescriptor'{digitMapName = Name,
+% digitMapValue = asn1_NOVALUE}}) ->
+% #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+% merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
+% packageVersion = V}) ->
+% #'IndAudPackagesDescriptor'{packageName = N,
+% packageVersion = V}.
+
+
+% ensure_indAudTerminationStateParm(Token) ->
+% case Token of
+% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+% {safeToken, _Line, "si"} -> serviceStatesToken;
+% {safeToken, _Line, "buffer"} -> bufferToken;
+% {safeToken, _Line, "bf"} -> bufferToken;
+% PkgdName -> {pkgdName,
+% ensure_pkgdName(PkgdName)}
+% end.
+
+
+% %% Types modified by v2:
+
+% merge_auditDescriptor([]) ->
+% #'AuditDescriptor'{};
+% merge_auditDescriptor(Tokens) when list(Tokens) ->
+% case lists:keysearch(terminationAudit, 1, Tokens) of
+% {value, {terminationAudit, TA}} ->
+% case lists:keydelete(terminationAudit, 1, Tokens) of
+% [] ->
+% #'AuditDescriptor'{auditPropertyToken = TA};
+% AuditTokens ->
+% #'AuditDescriptor'{auditToken = AuditTokens,
+% auditPropertyToken = TA}
+% end;
+% false ->
+% #'AuditDescriptor'{auditToken = Tokens}
+% end;
+% merge_auditDescriptor(_) ->
+% #'AuditDescriptor'{}.
+
+
+% %% v2 - end
+
+
+
+% merge_ServiceChangeParm(Parms) ->
+% Required = [serviceChangeReason, serviceChangeMethod],
+% merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+% merge_ServiceChangeParm([], SCP, []) ->
+% SCP;
+
+% merge_ServiceChangeParm([], _SCP, Required) ->
+% exit({missing_required_serviceChangeParm, Required});
+
+% merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
+% SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+% merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+% MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+% exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+% merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
+% SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+% merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+% exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+% merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% %% REQUIRED (i.e. no default value)
+% merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+% when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+% Req = lists:delete(serviceChangeReason, Req0),
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% %% REQUIRED (i.e. no default value)
+% merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+% when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+% Req = lists:delete(serviceChangeMethod, Req0),
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+% SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+% merge_ServiceChangeParm(Parms, SCP0, Req);
+
+% merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+% when SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE ->
+% SCI = #'AuditDescriptor'{auditToken = [Val]},
+% SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+% merge_ServiceChangeParm(Parms, SCP, Req);
+
+% merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+% Val2 =
+% case Tag of
+% address ->
+% SCP#'ServiceChangeParm'.serviceChangeAddress;
+% mgc_id ->
+% SCP#'ServiceChangeParm'.serviceChangeMgcId;
+% profile ->
+% SCP#'ServiceChangeParm'.serviceChangeProfile;
+% version ->
+% SCP#'ServiceChangeParm'.serviceChangeVersion;
+% reason ->
+% SCP#'ServiceChangeParm'.serviceChangeReason;
+% delay ->
+% SCP#'ServiceChangeParm'.serviceChangeDelay;
+% method ->
+% SCP#'ServiceChangeParm'.serviceChangeMethod;
+% time_stamp ->
+% SCP#'ServiceChangeParm'.timeStamp;
+% audit_item ->
+% SCP#'ServiceChangeParm'.serviceChangeInfo
+% end,
+% exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
+
+
+% merge_ServiceChangeResParm(Parms) ->
+% merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+% merge_ServiceChangeResParm([], SCRP) ->
+% SCRP;
+% merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
+% SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+% merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+% MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+% exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+% merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
+% SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+% merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+% Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+% exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+% merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+% when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+% SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+% merge_ServiceChangeResParm(Parms, SCRP);
+
+% merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+% Val2 =
+% case Tag of
+% address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+% mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+% profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+% version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+% time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+% end,
+% exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+% ensure_serviceChangeMethod({safeToken, _Line, "fl"}) ->
+% failover;
+% ensure_serviceChangeMethod({safeToken, _Line, "failover"}) ->
+% failover;
+% ensure_serviceChangeMethod({safeToken, _Line, "fo"}) ->
+% forced;
+% ensure_serviceChangeMethod({safeToken, _Line, "forced"}) ->
+% forced;
+% ensure_serviceChangeMethod({safeToken, _Line, "gr"}) ->
+% graceful;
+% ensure_serviceChangeMethod({safeToken, _Line, "graceful"}) ->
+% graceful;
+% ensure_serviceChangeMethod({safeToken, _Line, "rs"}) ->
+% restart;
+% ensure_serviceChangeMethod({safeToken, _Line, "restart"}) ->
+% restart;
+% ensure_serviceChangeMethod({safeToken, _Line, "dc"}) ->
+% disconnected;
+% ensure_serviceChangeMethod({safeToken, _Line, "disconnected"}) ->
+% disconnected;
+% ensure_serviceChangeMethod({safeToken, _Line, "ho"}) ->
+% handOff;
+% ensure_serviceChangeMethod({safeToken, _Line, "handoff"}) ->
+% handOff;
+% ensure_serviceChangeMethod({safeToken, Line, Text}) ->
+% return_error(Line, {bad_serviceChangeMethod, Text}).
+
+
+ensure_profile({_TokenTag, Line, Text}) ->
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+% merge_signalRequest(SignalName, PropertyParms) ->
+% Sig = #'Signal'{signalName = SignalName},
+% SPL = [],
+% do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+% do_merge_signalRequest(Sig, [H | T], SPL) ->
+% case H of
+% {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL);
+% {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+% {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+% {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+% do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+% keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+% do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+% {other, Name, PP} ->
+% SP = #'SigParameter'{sigParameterName = Name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_signalRequest(Sig, T, [SP | SPL]);
+% _ ->
+% return_error(0, {bad_sigParm, H})
+% end;
+% do_merge_signalRequest(Sig, [], SPL) ->
+% Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+% %% eventStream = StreamToken EQUAL StreamID
+% %% eventOther = eventParameterName parmValue
+% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("st", Value) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other("stream", Value) ->
+% {stream, ensure_uint16(Value)};
+% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+% EP = #'EventParameter'{eventParameterName = Name,
+% value = Value},
+% {other, EP}.
+
+% ensure_eventDM({_TokenTag, Line, DMD})
+% when record(DMD, 'DigitMapDescriptor') ->
+% Name = DMD#'DigitMapDescriptor'.digitMapName,
+% Val = DMD#'DigitMapDescriptor'.digitMapValue,
+% if
+% Name == asn1_NOVALUE, Val /= asn1_NOVALUE ->
+% {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+% DMV = #'DigitMapValue'{startTimer = Start,
+% shortTimer = Short,
+% longTimer = Long,
+% digitMapBody = Body,
+% durationTimer = Duration},
+% {eventDM, {digitMapValue, DMV}};
+% Name /= asn1_NOVALUE, Val == asn1_NOVALUE ->
+% {eventDM, {digitMapName, Name}};
+% true ->
+% return_error(Line, {bad_eventDM, DMD})
+% end.
+
+% ensure_DMD({_TokenTag, _Line, DMD})
+% when record(DMD, 'DigitMapDescriptor') ->
+% Val2 =
+% case DMD#'DigitMapDescriptor'.digitMapValue of
+% %% Note that the values of the digitMapBody and durationTimers
+% %% are swapped by the scanner (this is done because of a
+% %% problem in the flex scanner).
+% #'DigitMapValue'{durationTimer = Body,
+% digitMapBody = Duration} = DMV ->
+% %% Convert to version 1 DigitMapValue
+% DMV#'DigitMapValue'{digitMapBody = Body,
+% durationTimer = Duration};
+% Other ->
+% Other
+% end,
+% DMD#'DigitMapDescriptor'{digitMapValue = Val2}.
+
+
+% merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+% do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+% do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+% do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+% do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+% do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+% #'ObservedEvent'{eventName = EventName,
+% timeNotation = TimeStamp,
+% streamID = StreamID,
+% eventParList = lists:reverse(EPL)}.
+
+% merge_eventSpec(OE) when record(OE, 'ObservedEvent'),
+% OE#'ObservedEvent'.timeNotation == asn1_NOVALUE ->
+% #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+% streamID = OE#'ObservedEvent'.streamID,
+% eventParList = OE#'ObservedEvent'.eventParList};
+% merge_eventSpec(OE) ->
+% return_error(0, {bad_event_spec, OE}).
+
+% merge_eventParameters(Params) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% RA = #'RequestedActions'{},
+% HasA = no,
+% do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+% do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+% case H of
+% keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{keepActive = true},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+% secondEvent = SED},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
+% RA2 = RA#'RequestedActions'{eventDM = DM},
+% do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+% do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+% {other, PP} when record(PP, 'PropertyParm') ->
+% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+% {other, EP} when record(EP, 'EventParameter') ->
+% do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+% _ ->
+% return_error(0, {bad_eventParameter, H})
+% end;
+% do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+% #'RequestedEvent'{streamID = StreamId,
+% eventAction = RA,
+% evParList = lists:reverse(EPL)};
+% do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+% #'RequestedEvent'{streamID = StreamId,
+% eventAction = asn1_NOVALUE,
+% evParList = lists:reverse(EPL)}.
+
+% merge_secondEventParameters(Params) ->
+% StreamId = asn1_NOVALUE,
+% EPL = [],
+% SRA = #'SecondRequestedActions'{},
+% HasA = no,
+% do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+% do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+% case H of
+% keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
+% SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+% do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+% {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+% do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+% {other, PP} when record(PP, 'PropertyParm') ->
+% EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+% value = PP#'PropertyParm'.value,
+% extraInfo = PP#'PropertyParm'.extraInfo},
+% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+% {other, EP} when record(EP, 'EventParameter') ->
+% do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+% _ ->
+% return_error(0, {bad_secondEventParameter, H})
+% end;
+% do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+% #'SecondRequestedEvent'{streamID = StreamId,
+% eventAction = SRA,
+% evParList = lists:reverse(EPL)};
+% do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+% #'SecondRequestedEvent'{streamID = StreamId,
+% eventAction = asn1_NOVALUE,
+% evParList = lists:reverse(EPL)}.
+
+% %% terminationID = "ROOT" / pathName / "$" / "*"
+% %% Total length of pathName must not exceed 64 chars.
+% %% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+% %% ["@" pathDomainName ]
+% %% ABNF allows two or more consecutive "." although it is meaningless
+% %% in a path domain name.
+% %% pathDomainName = (ALPHA / DIGIT / "*" )
+% %% *63(ALPHA / DIGIT / "-" / "*" / ".")
+% ensure_terminationID({safeToken, _Line, LowerText}) ->
+% %% terminationID = "ROOT" / pathName / "$" / "*"
+% decode_term_id(LowerText, false, [], []).
+
+% decode_term_id([H | T], Wild, Id, Component) ->
+% case H of
+% $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+% $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+% $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+% _ -> decode_term_id(T, Wild, Id, [H | Component])
+% end;
+% decode_term_id([], Wild, Id, Component) ->
+% Id2 = [lists:reverse(Component) | Id],
+% #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+ensure_pathName({_TokenTag, _Line, Text}) ->
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+% ensure_timeStamp({'TimeStampToken', Line, Text}) ->
+% case string:tokens(Text, [$T, $t]) of
+% [Date, Time] ->
+% #'TimeNotation'{date = Date, time = Time};
+% _ ->
+% return_error(Line, {bad_timeStamp, Text})
+% end.
+
+% ensure_transactionID(TransId) ->
+% ensure_uint32(TransId).
+
+% %% transactionAck = transactionID / (transactionID "-" transactionID)
+% ensure_transactionAck({safeToken, _Line, Text}) ->
+% case string:tokens(Text, [$-]) of
+% [Id] ->
+% #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+% [Id, Id2] ->
+% #'TransactionAck'{firstAck = ensure_transactionID(Id),
+% lastAck = ensure_transactionID(Id2)}
+% end.
+
+% merge_action_requests(CtxId, Items) ->
+% CtxReq = #'ContextRequest'{},
+% CtxAuditReq = asn1_NOVALUE,
+% CmdReq = [],
+% TopReq = [],
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
+
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
+% case H of
+% _ when record(H, 'CommandRequest') ->
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
+
+% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+% TopReq, T);
+% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+% do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+% TopReq, T);
+% {topology, Desc} ->
+% TopReq2 = Desc ++ TopReq, %% OTP-4088
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq,
+% TopReq2, T);
+
+% {contextAudit, CAs} ->
+% CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs),
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq,
+% TopReq, T)
+
+% end;
+% do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) ->
+% #'ActionRequest'{contextId = CtxId,
+% contextRequest = strip_contextRequest(CtxReq, TopReq),
+% contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq),
+% commandRequests = lists:reverse(CmdReq)}.
+
+
+% merge_context_attr_audit_request(asn1_NOVALUE, CAs) ->
+% merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs);
+% merge_context_attr_audit_request(CAAR, [H|T]) ->
+% CAAR2 =
+% case H of
+% priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{priority = 'NULL'};
+
+% priorityAudit ->
+% Prio = CAAR#'ContextAttrAuditRequest'.priority,
+% exit({only_once, priorityAudit, Prio});
+
+% emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'};
+
+% emergencyAudit ->
+% Em = CAAR#'ContextAttrAuditRequest'.emergency,
+% exit({only_once, emergencyAudit, Em});
+
+% topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+% CAAR#'ContextAttrAuditRequest'{topology = 'NULL'};
+
+% topologyAudit ->
+% Top = CAAR#'ContextAttrAuditRequest'.topology,
+% exit({only_once, topologyAudit, Top})
+
+% end,
+% merge_context_attr_audit_request(CAAR2, T);
+% merge_context_attr_audit_request(CAAR, []) ->
+% CAAR.
+
+% %% OTP-5085:
+% %% In order to solve a problem in the parser, the error descriptor
+% %% has been put last in the non-empty commandReplyList, if it is not
+% %% asn1_NOVALUE
+% merge_action_reply(ReplyList) ->
+% CtxReq = #'ContextRequest'{},
+% TopReq = [],
+% CmdList = [],
+% case lists:reverse(ReplyList) of
+% [ED|RL2] when record(ED, 'ErrorDescriptor') ->
+% AR = do_merge_action_reply(lists:reverse(RL2),
+% CtxReq, TopReq, CmdList),
+% AR#'ActionReply'{errorDescriptor = ED};
+% _ ->
+% do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList)
+% end.
+
+% do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
+% case H of
+% {command, Cmd} ->
+% do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
+% {context, Ctx} ->
+% case Ctx of
+% {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+% {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+% CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+% do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+% {topology, Desc} ->
+% TopReq2 = Desc ++ TopReq, %% OTP-4088
+% do_merge_action_reply(T, CtxReq, TopReq2, CmdList)
+% end
+% end;
+% do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
+% #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
+% commandReply = lists:reverse(CmdList)}.
+
+% strip_contextRequest(R, TopReq)
+% when R#'ContextRequest'.priority == asn1_NOVALUE,
+% R#'ContextRequest'.emergency == asn1_NOVALUE,
+% TopReq == [] ->
+% asn1_NOVALUE;
+% strip_contextRequest(R, []) ->
+% R#'ContextRequest'{topologyReq = asn1_NOVALUE};
+% strip_contextRequest(R, TopReq) ->
+% R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
+
+
+% strip_contextAttrAuditRequest(R)
+% when R#'ContextAttrAuditRequest'.priority == asn1_NOVALUE,
+% R#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE,
+% R#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+% asn1_NOVALUE;
+% strip_contextAttrAuditRequest(R) ->
+% R.
+
+% make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+% Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+% case Text of
+% [$w, $- | _] ->
+% Req#'CommandRequest'{wildcardReturn = 'NULL'};
+% [$o, $-, $w, $- | _] ->
+% Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+% [$o, $- | _] ->
+% Req#'CommandRequest'{optional = 'NULL'};
+% _ ->
+% Req
+% end.
+
+% merge_terminationAudit(AuditReturnParameters) ->
+% lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+% do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+% case H of
+% {auditReturnItem, AuditItem} ->
+% do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+% AuditReturnParameter ->
+% do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+% end;
+% do_merge_terminationAudit([], AuditReturnParameters, []) ->
+% AuditReturnParameters;
+% do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+% AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+% AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+% [AuditReturnParameter | AuditReturnParameters].
+
+% merge_mediaDescriptor(MediaParms) ->
+% do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+% do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+% case H of
+% {streamParm, Parm} when Multi == [] ->
+% do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+% {streamDescriptor, Desc} when One == [] ->
+% do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+% {termState, TS2} when TS == asn1_NOVALUE ->
+% do_merge_mediaDescriptor(T, TS2, One, Multi);
+% _ ->
+% return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+% end;
+% do_merge_mediaDescriptor([], TS, One, Multi) ->
+% if
+% One == [], Multi == [] ->
+% #'MediaDescriptor'{streams = asn1_NOVALUE,
+% termStateDescr = TS};
+% One /= [], Multi == [] ->
+% #'MediaDescriptor'{streams = {oneStream, merge_streamParms(One)},
+% termStateDescr = TS};
+% One == [], Multi /= [] ->
+% #'MediaDescriptor'{streams = {multiStream, lists:reverse(Multi)},
+% termStateDescr = TS}
+% end.
+
+% merge_streamParms(TaggedStreamParms) ->
+% SP = #'StreamParms'{},
+% do_merge_streamParms(TaggedStreamParms, SP).
+
+% do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+% case Tag of
+% local when SP#'StreamParms'.localDescriptor == asn1_NOVALUE ->
+% do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+% remote when SP#'StreamParms'.remoteDescriptor == asn1_NOVALUE ->
+% do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+% control ->
+% LCD =
+% case SP#'StreamParms'.localControlDescriptor of
+% asn1_NOVALUE ->
+% #'LocalControlDescriptor'{propertyParms = []};
+% PrevLCD ->
+% PrevLCD
+% end,
+% LCD2 = do_merge_control_streamParms(D, LCD),
+% do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+% _ ->
+% return_error(0, {do_merge_streamParms, [All, SP]})
+% end;
+% do_merge_streamParms([], SP) when record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
+% LCD = SP#'StreamParms'.localControlDescriptor,
+% PP = LCD#'LocalControlDescriptor'.propertyParms,
+% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+% SP#'StreamParms'{localControlDescriptor = LCD2};
+% do_merge_streamParms([], SP) ->
+% SP.
+
+
+% do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+% case SubTag of
+% group when LCD#'LocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+% do_merge_control_streamParms(T, LCD2);
+% value when LCD#'LocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+% do_merge_control_streamParms(T, LCD2);
+% mode when LCD#'LocalControlDescriptor'.streamMode == asn1_NOVALUE ->
+% LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+% do_merge_control_streamParms(T, LCD2);
+% prop ->
+% PP = LCD#'LocalControlDescriptor'.propertyParms,
+% LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+% do_merge_control_streamParms(T, LCD2);
+% _ ->
+% return_error(0, {do_merge_control_streamParms, [All, LCD]})
+% end;
+% do_merge_control_streamParms([], LCD) ->
+% LCD.
+
+% merge_terminationStateDescriptor(Parms) ->
+% TSD = #'TerminationStateDescriptor'{propertyParms = []},
+% do_merge_terminationStateDescriptor(Parms, TSD).
+
+% do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+% case Tag of
+% serviceState when TSD#'TerminationStateDescriptor'.serviceState == asn1_NOVALUE ->
+% TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+% do_merge_terminationStateDescriptor(T, TSD2);
+% eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl == asn1_NOVALUE->
+% TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+% do_merge_terminationStateDescriptor(T, TSD2);
+% propertyParm ->
+% PP = TSD#'TerminationStateDescriptor'.propertyParms,
+% TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+% do_merge_terminationStateDescriptor(T, TSD2)
+% end;
+% do_merge_terminationStateDescriptor([], TSD) ->
+% PP = TSD#'TerminationStateDescriptor'.propertyParms,
+% TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+% ensure_prop_groups({_TokenTag, _Line, Text}) ->
+% Group = [],
+% Groups = [],
+% parse_prop_name(Text, Group, Groups).
+
+% parse_prop_name([Char | Rest] = All, Group, Groups) ->
+% case ?classify_char(Char) of
+% white_space ->
+% parse_prop_name(Rest, Group, Groups);
+% end_of_line ->
+% parse_prop_name(Rest, Group, Groups);
+% _ ->
+% Name = [],
+% do_parse_prop_name(All, Name, Group, Groups)
+% end;
+% parse_prop_name([] = All, Group, Groups) ->
+% Name = [],
+% do_parse_prop_name(All, Name, Group, Groups).
+
+% do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
+% case ?classify_char(Char) of
+% safe_char ->
+% do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+% rest_char when Char == $=, Name /= [] ->
+% %% Now we have a complete name
+% if
+% Name == "v", Group /= [] ->
+% %% v= is a property group delimiter,
+% %% lets create yet another property group.
+% Groups2 = [lists:reverse(Group) | Groups],
+% Group2 = [],
+% parse_prop_value(Rest, Name, Group2, Groups2);
+% true ->
+% %% Use current property group
+% parse_prop_value(Rest, Name, Group, Groups)
+% end;
+% _ ->
+% return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+% end;
+% do_parse_prop_name([], [], [], Groups) ->
+% lists:reverse(Groups);
+% do_parse_prop_name([], [], Group, Groups) ->
+% Group2 = lists:reverse(Group),
+% lists:reverse([Group2 | Groups]);
+% do_parse_prop_name([], Name, Group, Groups) when Name /= [] ->
+% %% Assume end of line
+% Value = [],
+% PP = make_prop_parm(Name, Value),
+% Group2 = lists:reverse([PP | Group]),
+% lists:reverse([Group2 | Groups]).
+
+% parse_prop_value(Chars, Name, Group, Groups) ->
+% Value = [],
+% do_parse_prop_value(Chars, Name, Value, Group, Groups).
+
+% do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
+% case ?classify_char(Char) of
+% end_of_line ->
+% %% Now we have a complete "name=value" pair
+% PP = make_prop_parm(Name, Value),
+% parse_prop_name(Rest, [PP | Group], Groups);
+% _ ->
+% do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
+% end;
+% do_parse_prop_value([], Name, Value, Group, Groups) ->
+% %% Assume end of line
+% PP = make_prop_parm(Name, Value),
+% Group2 = lists:reverse([PP | Group]),
+% lists:reverse([Group2 | Groups]).
+
+% make_prop_parm(Name, Value) ->
+% #'PropertyParm'{name = lists:reverse(Name),
+% value = [lists:reverse(Value)]}.
+
+ensure_uint({_TokenTag, Line, Val}, Min, Max) when is_integer(Val) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end;
+ensure_uint({TokenTag, Line, Text}, Min, Max) ->
+ case catch list_to_integer(Text) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint({TokenTag, Line, Val}, Min, Max)
+ end;
+ensure_uint(Val, Min, Max) ->
+ ensure_uint({uint, 0, Val}, Min, Max).
+
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+% ensure_uint32(Int) ->
+% ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when $0 =< Char, Char =< $9 ->
+ Char - $0;
+hchar_to_int(Char) when $A =< Char, Char =< $F ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when $a =< Char, Char =< $f ->
+ Char - $a + 10. % OTP-4710
+
+% value_of({_TokenTag, _Line, Text}) ->
+% Text.
+
+
+% d(F) ->
+% d(F, []).
+
+% d(F, A) ->
+% d(get(dbg), F, A).
+
+% d(true, F, A) ->
+% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
+% d(_, _, _) ->
+% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_mini_parser.yrl b/lib/megaco/src/text/megaco_text_mini_parser.yrl
new file mode 100644
index 0000000000..50e31b9eb4
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_mini_parser.yrl
@@ -0,0 +1,398 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for mini text decoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%----------------------------------------------------------------------
+
+Expect 1.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ authenticationHeader
+ daddr
+ deviceName
+ domainAddress
+ domainName
+ mId
+ megacoMessage
+ message
+ mtpAddress
+ optSep
+ pathName
+ portNumber
+ safeToken
+ safeToken2
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ %% 'AddToken'
+ %% 'AndAUDITselectToken'
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ %% 'BothToken'
+ %% 'BothwayToken'
+ 'BriefToken'
+ %% 'BufferToken'
+ 'COLON'
+ %% 'ContextAttrToken'
+ 'ContextAuditToken'
+ %% 'ContextListToken'
+ 'CtxToken'
+ 'DelayToken'
+ %% 'DigitMapToken'
+ %% 'DigitMapDescriptorToken'
+ 'DirectionToken'
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ %% 'EmergencyToken'
+ %% 'EmergencyOffToken'
+ %% 'EmergencyValueToken'
+ 'ErrorToken'
+ %% 'EventBufferToken'
+ %% 'EventsToken'
+ %% 'ExternalToken'
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ %% 'IEPSToken'
+ 'ImmAckRequiredToken'
+ 'InSvcToken'
+ 'InactiveToken'
+ %% 'InternalToken'
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ %% 'IntsigDelayToken'
+ %% 'IsolateToken'
+ %% 'IterationToken'
+ 'KeepActiveToken'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ %% 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ %% 'MediaToken'
+ %% 'MessageSegmentToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ %% 'ModeToken'
+ %% 'ModemToken'
+ %% 'ModifyToken'
+ %% 'MoveToken'
+ 'MtpAddressToken'
+ %% 'MuxToken'
+ %% 'NeverNotifyToken'
+ 'NotifyCompletionToken'
+ %% 'NotifyImmediateToken'
+ %% 'NotifyRegulatedToken'
+ 'NotifyToken'
+ 'Nx64Token'
+ %% 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ %% 'OnewayToken'
+ %% 'OnewayExternalToken'
+ %% 'OnewayBothToken'
+ %% 'OrAUDITselectToken'
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ %% 'PackagesToken'
+ 'PendingToken'
+ %% 'PriorityToken'
+ 'ProfileToken'
+ %% 'QuotedChars'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ %% 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'RequestIDToken'
+ %% 'ReservedGroupToken'
+ %% 'ReservedValueToken'
+ %% 'ResetEventsDescriptorToken'
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ %% 'ServiceChangeIncompleteToken'
+ %% 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ %% 'SignalsToken'
+ %% 'StatsToken'
+ 'StreamToken'
+ %% 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ %% 'TimeStampToken'
+ %% 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId : ensure_message('$1', '$2') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+%% safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+%% safeToken2 -> 'BothToken' : '$1' . % v3
+%% safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+%% safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% safeToken2 -> 'ContextListToken' : '$1' . % v3
+%% safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+%% safeToken2 -> 'EmergencyToken' : '$1' .
+%% safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% safeToken2 -> 'EventBufferToken' : '$1' .
+%% safeToken2 -> 'EventsToken' : '$1' .
+%% safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+%% safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+%% safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+%% safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+%% safeToken2 -> 'ModeToken' : '$1' .
+%% safeToken2 -> 'ModifyToken' : '$1' .
+%% safeToken2 -> 'ModemToken' : '$1' .
+%% safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64Token' : '$1' .
+%% safeToken2 -> 'ObservedEventsToken' : '$1' .
+%% safeToken2 -> 'OnewayToken' : '$1' .
+%% safeToken2 -> 'OnewayExternalToken' : '$1' .
+%% safeToken2 -> 'OnewayBothToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+%% safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+safeToken2 -> 'RequestIDToken' : '$1' .
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'SafeChars' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+%% safeToken2 -> 'ReservedGroupToken' : '$1' .
+%% safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+%% safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+%% safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' .
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+%% safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+%% safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_mini_parser.hrl").
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3a.hrl b/lib/megaco/src/text/megaco_text_parser_prev3a.hrl
new file mode 100644
index 0000000000..7faf46afc8
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3a.hrl
@@ -0,0 +1,1670 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. % We really should ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+%% case string:tokens(Addr, [$.]) of
+%% [T1, T2, T3, T4] ->
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and issue the
+ %% the error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when length(Hex4) =< 4, length(Hex4) > 0 ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ X /= $X, X /= $x,
+ S /= $+, S /= $- ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% and since this functon is only used when creating
+%% a ModemDescriptor, iit is removed.
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+%% case Text of
+%% "v32b" -> v32bis;
+%% "v22b" -> v22bis;
+%% "v18" -> v18;
+%% "v22" -> v22;
+%% "v32" -> v32;
+%% "v34" -> v34;
+%% "v90" -> v90;
+%% "v91" -> v91;
+%% "synchisdn" -> synchISDN;
+%% "sn" -> synchISDN;
+%% [$x | _] -> ensure_extensionParameter(Token)
+%% end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ "nx64k" -> nx64k; % v2
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_packagesItem,1}]}).
+-endif.
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (length or content) there is really no point in
+ %% "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+
+%% v2 - start
+
+merge_indAudMediaDescriptor({termStateDescr, Val}) ->
+ #'IndAudMediaDescriptor'{termStateDescr = Val};
+merge_indAudMediaDescriptor({streamParm, Val}) ->
+ #'IndAudMediaDescriptor'{streams = {oneStream, Val}};
+merge_indAudMediaDescriptor({streamDescr, Val}) ->
+ #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline, [{merge_indAudLocalControlDescriptor,1}]}).
+-endif.
+merge_indAudLocalControlDescriptor(Parms) ->
+ do_merge_indAudLocalControlDescriptor(Parms,
+ #'IndAudLocalControlDescriptor'{}).
+
+do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
+ case Parm of
+ modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE ->
+ PropParms = [#'IndAudPropertyParm'{name = Val}],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
+ PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
+ PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2)
+ end;
+do_merge_indAudLocalControlDescriptor([], Desc) ->
+ case Desc#'IndAudLocalControlDescriptor'.propertyParms of
+ [_ | _] = PropParms -> % List has more then one element
+ PropParms2= lists:reverse(PropParms),
+ Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+ _ ->
+ Desc
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudLocalParm,1}]}).
+-endif.
+ensure_indAudLocalParm(Token) ->
+ case Token of
+ {safeToken, _Line, "mode"} -> modeToken;
+ {safeToken, _Line, "mo"} -> modeToken;
+ {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
+ {safeToken, _Line, "rg"} -> reservedGroupToken;
+ {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
+ {safeToken, _Line, "rv"} -> reservedValueToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
+ PropParm = #'IndAudPropertyParm'{name = Val},
+ #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+ #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+merge_indAudTerminationStateDescriptor(bufferToken) ->
+ #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}).
+-endif.
+merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+ IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+ do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+ IAEBD;
+do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+ IAEBD) ->
+ %% BUGBUG BUGBUG BUGBUG
+ %% This is an ugly hack to allow the eventParamName which only
+ %% exists in the text encoding...
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') ->
+ ensure_indAudSignal(SIG).
+
+ensure_indAudSignal(#'Signal'{signalName = SignalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = []}) ->
+ #'IndAudSignal'{signalName = SignalName}.
+
+
+ensure_IADMD({_TokenTag, _Line,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE}}) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudTerminationStateParm,1}]}).
+-endif.
+ensure_indAudTerminationStateParm(Token) ->
+ case Token of
+ {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+ {safeToken, _Line, "si"} -> serviceStatesToken;
+ {safeToken, _Line, "buffer"} -> bufferToken;
+ {safeToken, _Line, "bf"} -> bufferToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+
+%% Types modified by v2:
+
+merge_auditDescriptor([]) ->
+ #'AuditDescriptor'{};
+merge_auditDescriptor(Tokens) when is_list(Tokens) ->
+ case lists:keysearch(terminationAudit, 1, Tokens) of
+ {value, {terminationAudit, TA}} ->
+ case lists:keydelete(terminationAudit, 1, Tokens) of
+ [] ->
+ #'AuditDescriptor'{auditPropertyToken = TA};
+ AuditTokens ->
+ #'AuditDescriptor'{auditToken = AuditTokens,
+ auditPropertyToken = TA}
+ end;
+ false ->
+ #'AuditDescriptor'{auditToken = Tokens}
+ end;
+merge_auditDescriptor(_) ->
+ #'AuditDescriptor'{}.
+
+
+%% v2 - end
+
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_atom(Val) ->
+ SCI = #'AuditDescriptor'{auditToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_tuple(Val) ->
+ SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_atom(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditToken,
+ SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_tuple(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditPropertyToken,
+ SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp;
+ audit_item ->
+ SCP#'ServiceChangeParm'.serviceChangeInfo
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
+merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
+ Parm2 =
+ case Parm of
+ incomplete ->
+ SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
+ end,
+ exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+ensure_profile({_TokenTag, Line, Text}) ->
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
+ {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Duration},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ durationTimer = [],
+ digitMapBody = asn1_NOVALUE} ->
+ asn1_NOVALUE;
+ #'DigitMapValue'{durationTimer = Body,
+ digitMapBody = Duration} = DMV ->
+ %% Convert to version 1 DigitMapValue
+ DMV#'DigitMapValue'{digitMapBody = Body,
+ durationTimer = Duration};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+ case H of
+ keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {stream, NewStreamId} when StreamId =:= asn1_NOVALUE ->
+ do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ ensure_transactionAck2(Text, []).
+
+ensure_transactionAck2([], Acc) ->
+ Id = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ensure_transactionAck2([$- | Id2], Acc) ->
+ Id1 = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id1),
+ lastAck = ensure_transactionID(Id2)};
+ensure_transactionAck2([H|T], Acc) ->
+ ensure_transactionAck2(T, [H|Acc]).
+
+
+merge_context_request(CR, []) ->
+ CR;
+merge_context_request(CR, [H|T]) ->
+ case H of
+ {priority, Int} when CR#'ContextRequest'.priority == asn1_NOVALUE ->
+ merge_context_request(CR#'ContextRequest'{priority = Int}, T);
+
+ {emergency, Bool} when CR#'ContextRequest'.emergency == asn1_NOVALUE ->
+ merge_context_request(CR#'ContextRequest'{emergency = Bool}, T);
+
+ {topology, Desc} when CR#'ContextRequest'.topologyReq == asn1_NOVALUE ->
+ merge_context_request(CR#'ContextRequest'{topologyReq = Desc}, T);
+
+ {iepsCallind, Ind} when CR#'ContextRequest'.iepsCallind == asn1_NOVALUE ->
+ merge_context_request(CR#'ContextRequest'{iepsCallind = Ind}, T);
+
+ {prop, Prop} when CR#'ContextRequest'.contextProp == asn1_NOVALUE ->
+ merge_context_request(CR#'ContextRequest'{contextProp = [Prop]}, T);
+ {Tag, Val} ->
+ Val2 =
+ case Tag of
+ priority -> CR#'ContextRequest'.priority;
+ emergency -> CR#'ContextRequest'.emergency;
+ topology -> CR#'ContextRequest'.topologyReq;
+ iepsCallind -> CR#'ContextRequest'.iepsCallind;
+ prop -> CR#'ContextRequest'.contextProp
+ end,
+ exit({at_most_once_contextProperty, {Tag, Val, Val2}})
+ end.
+
+
+merge_context_attr_audit_request(CAAR, []) ->
+ CAAR;
+merge_context_attr_audit_request(CAAR, [H|T]) ->
+ case H of
+ priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ iepsCallind when CAAR#'ContextAttrAuditRequest'.iepsCallind == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{iepsCallind = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
+ CPA = [#'IndAudPropertyParm'{name = Name}],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} ->
+ CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
+ CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
+ merge_context_attr_audit_request(CAAR2, T)
+
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_request,2}]}).
+-endif.
+merge_action_request(CtxId, Items) ->
+ do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
+
+do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ case H of
+ {commandRequest, CmdReq} ->
+ do_merge_action_request(T, [CmdReq|CmdReqs],
+ CtxReq, CtxAuditReq, CtxId);
+
+ {contextProps, ContextReq} when CtxReq == asn1_NOVALUE ->
+ do_merge_action_request(T, CmdReqs,
+ ContextReq, CtxAuditReq, CtxId);
+
+ {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
+ do_merge_action_request(T, CmdReqs,
+ CtxReq, ContextAuditReq, CtxId)
+ end;
+do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ #'ActionRequest'{contextId = CtxId,
+ contextRequest = strip_ContextRequest(CtxReq),
+ contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReqs)}.
+
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(Items) ->
+ do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
+
+do_merge_action_reply([], Err, Ctx, Cmds) ->
+ #'ActionReply'{errorDescriptor = Err,
+ contextReply = strip_ContextRequest(Ctx),
+ commandReply = lists:reverse(Cmds)};
+do_merge_action_reply([H|T], Err0, Ctx0, Cmds) ->
+ case H of
+ {error, Err1} when Err0 == asn1_NOVALUE ->
+ do_merge_action_reply(T, Err1, Ctx0, Cmds);
+ {command, Cmd} ->
+ do_merge_action_reply(T, Err0, Ctx0, [Cmd | Cmds]);
+ {context, Ctx1} when Ctx0 == asn1_NOVALUE ->
+ do_merge_action_reply(T, Err0, Ctx1, Cmds)
+ end.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextProp = []}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+strip_ContextRequest(R) ->
+ R.
+
+strip_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(R) ->
+ R.
+
+merge_AmmRequest_descriptors([], Acc) ->
+ lists:reverse(Acc);
+merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, Acc);
+merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor,
+ 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ parse_prop_name(Text, Group).
+
+parse_prop_name([Char | Rest] = All, Group) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group)
+ end;
+parse_prop_name([] = All, Group) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group).
+
+do_parse_prop_name([Char | Rest], Name, Group)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ NewGroup = [],
+ [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)];
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], []) ->
+ [];
+do_parse_prop_name([], [], Group) ->
+ [lists:reverse(Group)];
+do_parse_prop_name([], Name, Group) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,3}]}).
+-endif.
+parse_prop_value(Chars, Name, Group) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group]);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group)
+ end;
+do_parse_prop_value([], Name, Value, Group) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ Groups.
+
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+
+%% -------------------------------------------------------------------
+
+% d(F) ->
+% d(F,[]).
+% d(F, A) ->
+% d(get(dbg), F, A).
+
+% d(true, F, A) ->
+% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);
+% d(_, _, _) ->
+% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3a.yrl b/lib/megaco/src/text/megaco_text_parser_prev3a.yrl
new file mode 100644
index 0000000000..b8c39a5f33
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3a.yrl
@@ -0,0 +1,1591 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%
+%% NOTE 1 - This syntax specification does not enforce all restrictions
+%% on element inclusions and values. Some additional
+%% restrictions are stated in comments and other restrictions
+%% appear in the text of this Recommendation. These additional
+%% restrictions are part of the protocol even though not
+%% enforced by this Recommendation.
+%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be
+%% the AddToken or a NAME depending on the context in which it
+%% occurs.
+%%
+%% Everything in the ABNF and text encoding is case insensitive. This
+%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+%% per RFC 2327.
+%%
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 118.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestBody
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ authenticationHeader
+ commandReplyList
+ commandReplys %% v3
+ commandRequest
+ contextAttrDescriptor %% v3
+ contextAttrDescProp %% v3
+ contextAttrDescProps %% v3
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextID
+ contextProperties %% v3
+ contextProperty
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ direction %% v3
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlState
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStream
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+
+ %% v2 - start
+ indAudauditReturnParameter
+ indAuddigitMapDescriptor
+ indAudeventBufferDescriptor
+ indAudeventSpec
+ indAudeventSpecParameter
+ %% indAudeventSpecParameterList
+ indAudeventsDescriptor
+ indAudlocalControlDescriptor
+ indAudlocalParm
+ indAudlocalParmList
+ indAudmediaDescriptor
+ indAudmediaParm
+ %% indAudmediaParmList
+ indAudpackagesDescriptor
+ indAudrequestedEvent
+ indAudsignalsDescriptor
+ indAudsignalList
+ %% indAudsignalListParm
+ indAudsignalParm
+ %% indAudsignalRequest
+ indAudstreamDescriptor
+ indAudstreamParm
+ indAudstatisticsDescriptor
+ indAudterminationAudit
+ indAudterminationAuditList
+ indAudterminationStateDescriptor
+ indAudterminationStateParm
+ %% indAudterminationStateParmList
+ optIndAudeventSpecParameter
+ optIndAudsignalParm
+ %% v2 - end
+
+ indAudcontextAttrDescriptor %% v3
+
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor % Deprecated as of Corr 1
+ modemType % Deprecated as of Corr 1
+ modemTypeList % Deprecated as of Corr 1
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ % observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceState
+ serviceStates
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ terminationA
+ terminationAudit
+ terminationB
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyTriple
+ topologyTripleList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothToken' %% v3
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ 'ContextAttrToken' %% v3
+ 'ContextAuditToken'
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DirectionToken' %% v3
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'EmergencyOffToken'
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'ExternalToken' %% v3
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'IEPSToken' %% v3
+ 'ImmAckRequiredToken'
+ 'InSvcToken'
+ 'InactiveToken'
+ 'InternalToken' %% v3
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'IsolateToken'
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NotifyCompletionToken'
+ 'NotifyToken'
+ 'Nx64kToken' %% v2
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'RequestIDToken' %% v3
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceChangeIncompleteToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ 'AndAUDITSelectToken' %% OTP-7534: v3-fix
+ 'ContextListToken' %% OTP-7534: v3-fix
+ 'EmergencyValueToken' %% OTP-7534: v3-fix
+ 'IntsigDelayToken' %% OTP-7534: v3-fix
+ 'IterationToken' %% OTP-7534: v3-fix
+ 'MessageSegmentToken' %% OTP-7534: v3-fix
+ 'NeverNotifyToken' %% OTP-7534: v3-fix
+ 'NotifyImmediateToken' %% OTP-7534: v3-fix
+ 'NotifyRegulatedToken' %% OTP-7534: v3-fix
+ 'OnewayBothToken' %% OTP-7534: v3-fix
+ 'OnewayExternalToken' %% OTP-7534: v3-fix
+ 'OrAUDITselectToken' %% OTP-7534: v3-fix
+ 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix
+ 'SegmentationCompleteToken' %% OTP-7534: v3-fix
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT'
+ : #'TransactionPending'{transactionId = ensure_transactionID('$3') } .
+
+transactionRequest -> 'TransToken'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestBody 'RBRKT'
+ : merge_action_request('$3', '$5') .
+
+actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] .
+
+actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems
+ : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+actionRequestItem -> contextProperties : {contextProps, '$1'} .
+actionRequestItem -> contextAudit : {contextAudit, '$1'} .
+actionRequestItem -> commandRequest : {commandRequest, '$1'} .
+
+contextProperties -> contextAttrDescriptor :
+ merge_context_request(#'ContextRequest'{}, '$1') .
+
+contextAttrDescriptor -> 'ContextAttrToken'
+ 'LBRKT' contextAttrDescProp
+ contextAttrDescProps 'RBRKT'
+ : ['$3' | '$4'] .
+
+contextAttrDescProp -> contextProperty : '$1' .
+
+contextAttrDescProps -> 'COMMA' contextAttrDescProp contextAttrDescProps
+ : ['$2' | '$3'] .
+contextAttrDescProps -> '$empty' : [] .
+
+%% at-most-once
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+contextProperty -> 'EmergencyOffToken' : {emergency, false}.
+contextProperty -> 'IEPSToken' : {iepsCallind, true} . % BMK BMK
+contextProperty -> propertyParm : {prop, '$1'} .
+
+contextAudit -> 'ContextAuditToken' 'LBRKT' indAudcontextAttrDescriptor 'RBRKT'
+ : merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, '$3') .
+
+indAudcontextAttrDescriptor -> 'ContextAttrToken'
+ 'LBRKT' contextAuditProperty
+ contextAuditProperties 'RBRKT'
+ : ['$3' | '$4'] .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties
+ : ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once .
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+contextAuditProperty -> 'IEPSToken' : iepsCallind .
+contextAuditProperty -> pkgdName : {prop, '$1'} .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID
+ 'LBRKT'
+ optImmAckRequired transactionReplyBody
+ 'RBRKT'
+ : #'TransactionReply'{transactionId = '$3',
+ immAckRequired = '$5',
+ transactionResult = '$6'} .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor : {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReplys commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ [{error, '$2'}] .
+commandReplyList -> 'COMMA' commandReplys commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+commandReplys -> serviceChangeReply : {command, '$1'} .
+commandReplys -> auditReply : {command, '$1'} .
+commandReplys -> ammsReply : {command, '$1'} .
+commandReplys -> notifyReply : {command, '$1'} .
+commandReplys -> contextProperties : {context, '$1'} .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody :
+ Descs = merge_AmmRequest_descriptors('$4', []),
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = ['$3'],
+ descriptors = Descs}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, deprecated}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody
+ : {'$1', #'AmmsReply'{terminationID = ['$3'],
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL' terminationID
+ optAuditDescriptor
+ : make_commandRequest({subtractReq, '$1'},
+ #'SubtractRequest'{terminationID = ['$3'],
+ auditDescriptor = '$4'}) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+auditRequest -> 'AuditCapToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther
+ : {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther
+ : {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} .
+
+auditOther -> terminationID :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = []}} .
+auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = '$3'}} .
+
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor.
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} .
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' :
+ merge_auditDescriptor('$3') .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken.
+auditItem -> 'EventBufferToken' : eventBufferToken.
+auditItem -> 'EventsToken' : eventsToken .
+auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2
+%%
+%% IGv11 - end
+
+
+%% v2 - start
+%%
+indAudterminationAudit -> indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$1' | '$2'] .
+
+indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$2' | '$3'] .
+indAudterminationAuditList -> '$empty' : [] .
+
+indAudauditReturnParameter -> indAudmediaDescriptor
+ : {indAudMediaDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventsDescriptor
+ : {indAudEventsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudsignalsDescriptor
+ : {indAudSignalsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAuddigitMapDescriptor
+ : {indAudDigitMapDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventBufferDescriptor
+ : {indAudEventBufferDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudstatisticsDescriptor
+ : {indAudStatisticsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudpackagesDescriptor
+ : {indAudPackagesDescriptor, '$1'} .
+
+
+indAudmediaDescriptor -> 'MediaToken' 'LBRKT'
+ indAudmediaParm 'RBRKT'
+ : merge_indAudMediaDescriptor('$3') .
+
+%% at-most-once per item
+%% and either streamParm or streamDescriptor but not both
+%% <rambling>
+%% This is solved in another way in text than in binary :(
+%% Instead of having a list of indAudmediaParm we put this
+%% stuff in the indAudterminationAuditList with several
+%% indAudmediaDescriptor's.
+%% </rambling>
+%%
+
+indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} .
+indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} .
+indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} .
+
+%% at-most-once
+indAudstreamParm -> indAudlocalControlDescriptor
+ : #'IndAudStreamParms'{localControlDescriptor = '$1'} .
+indAudstreamParm -> indAudstatisticsDescriptor
+ : #'IndAudStreamParms'{statisticsDescriptor = '$1'} .
+
+indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' indAudstreamParm 'RBRKT'
+ : #'IndAudStreamDescriptor'{streamID = '$3',
+ streamParms = '$5'} .
+
+
+indAudlocalControlDescriptor -> 'LocalControlToken'
+ 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' :
+ merge_indAudLocalControlDescriptor(['$3'| '$4']) .
+
+indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2'| '$3'] .
+indAudlocalParmList -> '$empty' : [] .
+
+%% at-most-once per item
+%%
+indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') .
+
+indAudterminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' indAudterminationStateParm 'RBRKT'
+ :
+ merge_indAudTerminationStateDescriptor('$3') .
+
+%% at-most-once per item
+%%
+
+indAudterminationStateParm -> safeToken :
+ ensure_indAudTerminationStateParm('$1') .
+
+indAudeventBufferDescriptor -> 'EventBufferToken'
+ 'LBRKT' indAudeventSpec 'RBRKT' : '$3' .
+
+indAudeventSpec -> pkgdName optIndAudeventSpecParameter
+ : merge_indAudEventBufferDescriptor('$1','$2') .
+
+optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT'
+ : '$2' .
+optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE .
+
+
+indAudeventSpecParameter -> eventStream : {streamID, '$1'} .
+indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} .
+
+indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' indAudrequestedEvent 'RBRKT'
+ : #'IndAudEventsDescriptor'{requestID = '$3',
+ pkgdName = '$5'} .
+
+indAudrequestedEvent -> pkgdName : '$1' .
+
+
+indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' .
+
+
+optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE .
+optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' .
+
+indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} .
+indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} .
+
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm 'RBRKT' :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3'),
+ signalList =
+ ensure_indAudSignalListParm('$5')} .
+
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_IADMD('$1') .
+
+indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' :
+ #'IndAudStatisticsDescriptor'{statName = '$3'} .
+
+indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT'
+ : merge_indAudPackagesDescriptor('$3') .
+
+eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' .
+
+
+%%
+%% v2 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' terminationID
+ 'LBRKT' notifyRequestBody 'RBRKT'
+ : make_commandRequest({notifyReq, '$1'},
+ setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) .
+
+notifyRequestBody -> observedEventsDescriptor
+ : #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor
+ : #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody
+ : {notifyReply,
+ #'NotifyReply'{terminationID = ['$3'],
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID
+ 'LBRKT' serviceChangeDescriptor 'RBRKT'
+ : make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = ['$3'],
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody
+ : {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = ['$3'],
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT'
+ : {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT'
+ : {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT'
+ : #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+%% '-' is used for NULL context
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT'
+ : ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat
+ : ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-onc .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs} } .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+streamParm -> statisticsDescriptor : {statistics, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm
+ terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue :
+ setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue :
+ '$2' .
+
+parmValue -> 'NEQUAL' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT'
+ : #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value :
+ #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT'
+ : ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' .
+
+serviceState -> 'TestToken' : test .
+serviceState -> 'OutOfSvcToken' : outOfSvc .
+serviceState -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' .
+
+eventBufferControlState -> 'OffToken' : off .
+eventBufferControlState -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList :
+ #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT'
+ : {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT'
+ : {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody
+ : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT'
+ : merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' :
+ ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' : [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther /
+%% notifyCompletion / KeepActiveToken /
+%% direction / sigRequestID
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason)
+%% RBRKT)
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken /
+%% InterruptByNewSignalsDescrToken /
+%% OtherReasonToken )
+%% sigDirection = DirectionToken EQUAL direction
+%% sigRequestID = RequestIDToken EQUAL RequestID
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID :
+ {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType :
+ {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken :
+ {duration, ensure_uint16('$3')} .
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT' :
+ {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+sigParameter -> 'DirectionToken' 'EQUAL' direction : {direction, '$3'} .
+sigParameter -> 'RequestIDToken' 'EQUAL' requestID : {requestId, '$3'} .
+sigParameter -> safeToken parmValue :
+ {other, ensure_NAME('$1'), '$2'}.
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+direction -> 'ExternalToken' : external .
+direction -> 'InternalToken' : internal .
+direction -> 'BothToken' : both .
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms :
+ ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+
+observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody :
+ merge_observed_event('$6', '$5', '$1') .
+observedEvent -> optSep pkgdName observedEventBody :
+ merge_observed_event('$3', '$2', asn1_NOVALUE) .
+
+observedEventBody -> 'LBRKT' observedEventParameter
+ observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+%% Deprecated as of Corr 1
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms .
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms.
+modemTypeList -> 'COMMA' modemType modemTypeList.
+modemTypeList -> '$empty'.
+modemType -> safeToken.
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' :
+ ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] .
+propertyParms -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_DMD('$1') .
+
+%% each parameter at-most-once, except auditItem
+%% at most one of either serviceChangeAddress or serviceChangeMgcId but
+%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp, '$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3
+serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken :
+ ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber :
+ {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'} .
+servChgReplyParm -> timeStamp : {time_stamp,'$1'} .
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem
+ packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter
+ statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple
+ topologyTripleList 'RBRKT' : ['$3' | '$4'] .
+
+terminationA -> terminationID : '$1' .
+
+terminationB -> terminationID : '$1' .
+
+topologyTriple -> terminationA 'COMMA'
+ terminationB 'COMMA'
+ topologyDirection :
+ #'TopologyRequest'{terminationFrom = '$1',
+ terminationTo = '$3',
+ topologyDirection = '$5'} .
+
+topologyTripleList -> '$empty' : [] .
+topologyTripleList -> 'COMMA' topologyTriple topologyTripleList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : bothway .
+topologyDirection -> 'IsolateToken' : isolate .
+topologyDirection -> 'OnewayToken' : oneway .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' : ensure_value('$1') .
+value -> safeToken : ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+%% BMK BMK safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothToken' : '$1' . % v3
+safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% v2-safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+%% v3-
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% v2-safeToken2 -> 'EventBufferToken' : '$1' .
+%% v2-safeToken2 -> 'EventsToken' : '$1' .
+%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% v2-safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+safeToken2 -> 'ModeToken' : '$1' .
+%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' .
+%% v2-safeToken2 -> 'ModemToken' : '$1' .
+%% BMK BMK safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% v2-safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64kToken' : '$1' .
+%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' .
+safeToken2 -> 'OnewayToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% v2-safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+%% v3-
+safeToken2 -> 'RequestIDToken' : '$1' . % v3
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+safeToken2 -> 'ReservedGroupToken' : '$1' .
+safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% v2-safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% v2-safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+%% <OTP-7534>
+safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3
+safeToken2 -> 'ContextListToken' : '$1' . % v3
+safeToken2 -> 'EmergencyValueToken' : '$1' . % v3
+safeToken2 -> 'IntsigDelayToken' : '$1' . % v3
+safeToken2 -> 'IterationToken' : '$1' . % v3
+safeToken2 -> 'MessageSegmentToken' : '$1' . % v3
+safeToken2 -> 'NeverNotifyToken' : '$1' . % v3
+safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3
+safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3
+safeToken2 -> 'OnewayBothToken' : '$1' . % v3
+safeToken2 -> 'OnewayExternalToken' : '$1' . % v3
+safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3
+safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3
+safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3
+%% </OTP-7534>
+
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_prev3a.hrl").
+
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3b.hrl b/lib/megaco/src/text/megaco_text_parser_prev3b.hrl
new file mode 100644
index 0000000000..ba10dfb943
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3b.hrl
@@ -0,0 +1,1717 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+%% case string:tokens(Addr, [$.]) of
+%% [T1, T2, T3, T4] ->
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and issue the
+ %% the error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when length(Hex4) =< 4, length(Hex4) > 0 ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ X /= $X, X /= $x,
+ S /= $+, S /= $- ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% and since this functon is only used when creating
+%% a ModemDescriptor, iit is removed.
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+%% case Text of
+%% "v32b" -> v32bis;
+%% "v22b" -> v22bis;
+%% "v18" -> v18;
+%% "v22" -> v22;
+%% "v32" -> v32;
+%% "v34" -> v34;
+%% "v90" -> v90;
+%% "v91" -> v91;
+%% "synchisdn" -> synchISDN;
+%% "sn" -> synchISDN;
+%% [$x | _] -> ensure_extensionParameter(Token)
+%% end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ "nx64k" -> nx64k; % v2
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_packagesItem,1}]}).
+-endif.
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (length or content) there is really no point in
+ %% "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+
+%% v2 - start
+
+merge_indAudMediaDescriptor_streams(asn1_NOVALUE, []) ->
+ asn1_NOVALUE;
+merge_indAudMediaDescriptor_streams(Stream, [])
+ when is_record(Stream, 'IndAudStreamParms') ->
+ {oneStream, Stream};
+merge_indAudMediaDescriptor_streams(asn1_NOVALUE, MStreams) ->
+ {multiStream, lists:reverse(MStreams)};
+merge_indAudMediaDescriptor_streams(Stream, MStreams) ->
+ return_error(0,
+ {invalid_indAudMediaDescriptor_streams, {Stream, MStreams}}).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudMediaDescriptor,1}]}).
+-endif.
+merge_indAudMediaDescriptor(Vals) ->
+ merge_indAudMediaDescriptor(Vals, asn1_NOVALUE, asn1_NOVALUE, []).
+
+merge_indAudMediaDescriptor([], TSD, OneStream, MultiStreams) ->
+ Streams = merge_indAudMediaDescriptor_streams(OneStream, MultiStreams),
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+
+merge_indAudMediaDescriptor([{termStateDescr, H}|T], asn1_NOVALUE, OS, MS) ->
+ merge_indAudMediaDescriptor(T, H, OS, MS);
+merge_indAudMediaDescriptor([{streamDescr, Val}|T], TSD, asn1_NOVALUE, MS) ->
+ merge_indAudMediaDescriptor(T, TSD, asn1_NOVALUE, [Val|MS]);
+merge_indAudMediaDescriptor([{streamParm, Val}|T], TSD, asn1_NOVALUE, []) ->
+ merge_indAudMediaDescriptor(T, TSD, Val, []);
+merge_indAudMediaDescriptor(Vals, TSD, OneStream, MultiStream) ->
+ return_error(0, {invalid_indAudMediaDescriptor,
+ {Vals, TSD, OneStream, MultiStream}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}).
+-endif.
+merge_indAudLocalControlDescriptor(Parms) ->
+ do_merge_indAudLocalControlDescriptor(Parms,
+ #'IndAudLocalControlDescriptor'{}).
+
+do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
+ case Parm of
+ modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE ->
+ PropParms = [#'IndAudPropertyParm'{name = Val}],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
+ PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
+ PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2)
+ end;
+do_merge_indAudLocalControlDescriptor([], Desc) ->
+ case Desc#'IndAudLocalControlDescriptor'.propertyParms of
+ [_ | _] = PropParms -> % List has more then one element
+ PropParms2= lists:reverse(PropParms),
+ Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+ _ ->
+ Desc
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudLocalParm,1}]}).
+-endif.
+ensure_indAudLocalParm(Token) ->
+ case Token of
+ {safeToken, _Line, "mode"} -> modeToken;
+ {safeToken, _Line, "mo"} -> modeToken;
+ {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
+ {safeToken, _Line, "rg"} -> reservedGroupToken;
+ {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
+ {safeToken, _Line, "rv"} -> reservedValueToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
+ PropParm = #'IndAudPropertyParm'{name = Val},
+ #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+ #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+merge_indAudTerminationStateDescriptor(bufferToken) ->
+ #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}).
+-endif.
+merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+ IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+ do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+ IAEBD;
+do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+ IAEBD) ->
+ %% BUGBUG BUGBUG BUGBUG
+ %% This is an ugly hack to allow the eventParamName which only
+ %% exists in the text encoding...
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') ->
+ ensure_indAudSignal(SIG).
+
+ensure_indAudSignal(#'Signal'{signalName = SignalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = []}) ->
+ #'IndAudSignal'{signalName = SignalName}.
+
+
+ensure_IADMD({_TokenTag, _Line,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE}}) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudTerminationStateParm,1}]}).
+-endif.
+ensure_indAudTerminationStateParm(Token) ->
+ case Token of
+ {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+ {safeToken, _Line, "si"} -> serviceStatesToken;
+ {safeToken, _Line, "buffer"} -> bufferToken;
+ {safeToken, _Line, "bf"} -> bufferToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+
+%% Types modified by v2:
+
+merge_auditDescriptor([]) ->
+ #'AuditDescriptor'{};
+merge_auditDescriptor(Tokens) when is_list(Tokens) ->
+ case lists:keysearch(terminationAudit, 1, Tokens) of
+ {value, {terminationAudit, TA}} ->
+ case lists:keydelete(terminationAudit, 1, Tokens) of
+ [] ->
+ #'AuditDescriptor'{auditPropertyToken = TA};
+ AuditTokens ->
+ #'AuditDescriptor'{auditToken = AuditTokens,
+ auditPropertyToken = TA}
+ end;
+ false ->
+ #'AuditDescriptor'{auditToken = Tokens}
+ end;
+merge_auditDescriptor(_) ->
+ #'AuditDescriptor'{}.
+
+
+%% v2 - end
+
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_atom(Val) ->
+ SCI = #'AuditDescriptor'{auditToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_tuple(Val) ->
+ SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_atom(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditToken,
+ SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_tuple(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditPropertyToken,
+ SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp;
+ audit_item ->
+ SCP#'ServiceChangeParm'.serviceChangeInfo
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
+merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
+ Parm2 =
+ case Parm of
+ incomplete ->
+ SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
+ end,
+ exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_profile,1}]}).
+-endif.
+ensure_profile(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
+ {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Duration},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ durationTimer = [],
+ digitMapBody = asn1_NOVALUE} ->
+ asn1_NOVALUE;
+ #'DigitMapValue'{durationTimer = Body,
+ digitMapBody = Duration} = DMV ->
+ %% Convert to version 1 DigitMapValue
+ DMV#'DigitMapValue'{digitMapBody = Body,
+ durationTimer = Duration};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {stream, NewStreamId} when StreamId =:= asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+ case H of
+ keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {stream, NewStreamId} when StreamId =:= asn1_NOVALUE ->
+ do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ ensure_transactionAck2(Text, []).
+
+ensure_transactionAck2([], Acc) ->
+ Id = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ensure_transactionAck2([$- | Id2], Acc) ->
+ Id1 = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id1),
+ lastAck = ensure_transactionID(Id2)};
+ensure_transactionAck2([H|T], Acc) ->
+ ensure_transactionAck2(T, [H|Acc]).
+
+
+merge_context_request(asn1_NOVALUE, Prop) ->
+ merge_context_request(#'ContextRequest'{}, Prop);
+
+merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR,
+ {priority, Int}) ->
+ CR#'ContextRequest'{priority = Int};
+
+merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR,
+ {emergency, Bool}) ->
+ CR#'ContextRequest'{emergency = Bool};
+
+merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR,
+ {topology, Desc}) ->
+ CR#'ContextRequest'{topologyReq = Desc};
+
+merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR,
+ {iepsCallind, Ind}) ->
+ CR#'ContextRequest'{iepscallind = Ind};
+
+merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
+ {contextProp, Props}) ->
+ CR#'ContextRequest'{contextProp = Props};
+
+%% The parser handles this, but we drop it in this version
+%% merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR,
+%% {contextList, _IDs}) ->
+%% CR#'ContextRequest'{contextList = IDs};
+merge_context_request(CR, {contextList, _IDs}) ->
+ CR;
+
+merge_context_request(CR, {Tag, Val}) ->
+ Val2 =
+ case Tag of
+ priority -> CR#'ContextRequest'.priority;
+ emergency -> CR#'ContextRequest'.emergency;
+ topology -> CR#'ContextRequest'.topologyReq;
+ iepsCallind -> CR#'ContextRequest'.iepscallind;
+ contextProp -> CR#'ContextRequest'.contextProp%% ;
+ %% contextList -> CR#'ContextRequest'.contextList
+ end,
+ exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
+
+
+merge_context_attr_audit_request(CAAR, []) ->
+ CAAR;
+merge_context_attr_audit_request(CAAR, [H|T]) ->
+ case H of
+ priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
+ CPA = [#'IndAudPropertyParm'{name = Name}],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} ->
+ CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
+ CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
+ merge_context_attr_audit_request(CAAR2, T)
+
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_request,2}]}).
+-endif.
+merge_action_request(CtxId, Items) ->
+ do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
+
+do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ case H of
+ {commandRequest, CmdReq} ->
+ do_merge_action_request(T, [CmdReq|CmdReqs],
+ CtxReq, CtxAuditReq, CtxId);
+
+ {contextProp, ContextProp} ->
+ do_merge_action_request(T, CmdReqs,
+ merge_context_request(CtxReq, ContextProp),
+ CtxAuditReq, CtxId);
+
+ {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
+ do_merge_action_request(T, CmdReqs,
+ CtxReq, ContextAuditReq, CtxId)
+ end;
+do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ #'ActionRequest'{contextId = CtxId,
+ contextRequest = strip_ContextRequest(CtxReq),
+ contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReqs)}.
+
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(Items) ->
+ do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
+
+do_merge_action_reply([], Err, Ctx, Cmds) ->
+ #'ActionReply'{errorDescriptor = Err,
+ contextReply = strip_ContextRequest(Ctx),
+ commandReply = lists:reverse(Cmds)};
+do_merge_action_reply([H|T], Err0, CR, Cmds) ->
+ case H of
+ {error, Err1} when Err0 == asn1_NOVALUE ->
+ do_merge_action_reply(T, Err1, CR, Cmds);
+ {command, Cmd} ->
+ do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
+ {context, CtxProp} ->
+ do_merge_action_reply(T, Err0,
+ merge_context_request(CR, CtxProp), Cmds)
+ end.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = []}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+strip_ContextRequest(R) ->
+ R.
+
+strip_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(R) ->
+ R.
+
+merge_AmmRequest_descriptors([], Acc) ->
+ lists:reverse(Acc);
+merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, Acc);
+merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor,
+ 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ parse_prop_name(Text, Group).
+
+parse_prop_name([Char | Rest] = All, Group) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group)
+ end;
+parse_prop_name([] = All, Group) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group).
+
+do_parse_prop_name([Char | Rest], Name, Group)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ NewGroup = [],
+ [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)];
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], []) ->
+ [];
+do_parse_prop_name([], [], Group) ->
+ [lists:reverse(Group)];
+do_parse_prop_name([], Name, Group) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,3}]}).
+-endif.
+parse_prop_value(Chars, Name, Group) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group]);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group)
+ end;
+do_parse_prop_value([], Name, Value, Group) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ Groups.
+
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% %% d(true, F, A).
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3b.yrl b/lib/megaco/src/text/megaco_text_parser_prev3b.yrl
new file mode 100644
index 0000000000..d660fb787a
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3b.yrl
@@ -0,0 +1,1601 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%
+%% NOTE 1 - This syntax specification does not enforce all restrictions
+%% on element inclusions and values. Some additional
+%% restrictions are stated in comments and other restrictions
+%% appear in the text of this Recommendation. These additional
+%% restrictions are part of the protocol even though not
+%% enforced by this Recommendation.
+%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be
+%% the AddToken or a NAME depending on the context in which it
+%% occurs.
+%%
+%% Everything in the ABNF and text encoding is case insensitive. This
+%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+%% per RFC 2327.
+%%
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 117.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestBody
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ authenticationHeader
+ commandReplyList
+ commandReplys %% v3
+ commandRequest
+ contextAttrDescriptor %% v3
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextID
+ contextIdList %% v3
+ contextIDs %% v3
+%% contextProperties %% v3
+ contextProperty
+%% contextPropertyList
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ direction %% v3
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlState
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStream
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+
+ iepsValue
+
+ %% v2 - start
+ indAudauditReturnParameter
+ indAuddigitMapDescriptor
+ indAudeventBufferDescriptor
+ indAudeventSpec
+ indAudeventSpecParameter
+ %% indAudeventSpecParameterList
+ indAudeventsDescriptor
+ indAudlocalControlDescriptor
+ indAudlocalParm
+ indAudlocalParmList
+ indAudmediaDescriptor
+ indAudmediaParm
+ indAudmediaParms %% v3
+ %% indAudmediaParmList
+ indAudpackagesDescriptor
+ indAudrequestedEvent
+ indAudsignalsDescriptor
+ indAudsignalList
+ %% indAudsignalListParm
+ indAudsignalParm
+ %% indAudsignalRequest
+ indAudstreamDescriptor
+ indAudstreamParm
+ indAudstatisticsDescriptor
+ indAudterminationAudit
+ indAudterminationAuditList
+ indAudterminationStateDescriptor
+ indAudterminationStateParm
+ %% indAudterminationStateParmList
+ optIndAudeventSpecParameter
+ optIndAudsignalParm
+ %% v2 - end
+
+ indAudcontextAttrDescriptor %% v3
+
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor % Deprecated as of Corr 1
+ modemType % Deprecated as of Corr 1
+ modemTypeList % Deprecated as of Corr 1
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ % observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ propertyParmList
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceState
+ serviceStates
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ terminationA
+ terminationAudit
+ terminationB
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyTriple
+ topologyTripleList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothToken' %% v3
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ 'ContextAttrToken' %% v3
+ 'ContextAuditToken'
+ 'ContextListToken' %% v3
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DirectionToken' %% v3
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'EmergencyOffToken'
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'ExternalToken' %% v3
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'IEPSToken' %% v3
+ 'ImmAckRequiredToken'
+ 'InSvcToken'
+ 'InactiveToken'
+ 'InternalToken' %% v3
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'IsolateToken'
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NotifyCompletionToken'
+ 'NotifyToken'
+ 'Nx64Token' %% v2
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'RequestIDToken' %% v3
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceChangeIncompleteToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ 'AndAUDITSelectToken' %% OTP-7534: v3-fix
+ 'EmergencyValueToken' %% OTP-7534: v3-fix
+ 'IntsigDelayToken' %% OTP-7534: v3-fix
+ 'IterationToken' %% OTP-7534: v3-fix
+ 'MessageSegmentToken' %% OTP-7534: v3-fix
+ 'NeverNotifyToken' %% OTP-7534: v3-fix
+ 'NotifyImmediateToken' %% OTP-7534: v3-fix
+ 'NotifyRegulatedToken' %% OTP-7534: v3-fix
+ 'OnewayBothToken' %% OTP-7534: v3-fix
+ 'OnewayExternalToken' %% OTP-7534: v3-fix
+ 'OrAUDITselectToken' %% OTP-7534: v3-fix
+ 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix
+ 'SegmentationCompleteToken' %% OTP-7534: v3-fix
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT'
+ : #'TransactionPending'{transactionId = ensure_transactionID('$3') } .
+
+transactionRequest -> 'TransToken'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestBody 'RBRKT'
+ : merge_action_request('$3', '$5') .
+
+actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] .
+
+actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems
+ : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+%% actionRequestItem -> contextProperties : '$1' .
+actionRequestItem -> contextProperty : {contextProp, '$1'} .
+actionRequestItem -> contextAudit : {contextAudit, '$1'} .
+actionRequestItem -> commandRequest : {commandRequest, '$1'} .
+
+%% contextProperties -> contextProperty contextPropertyList :
+%% merge_context_request(#'ContextRequest'{}, ['$1' | '$2']) .
+
+%% contextPropertyList -> 'COMMA' contextProperty contextPropertyList : ['$2' | '$3' ] .
+%% contextPropertyList -> '$empty' : [] .
+
+%% at-most-once
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+contextProperty -> 'EmergencyOffToken' : {emergency, false}.
+contextProperty -> iepsValue : {iepsCallind, '$1'} .
+contextProperty -> contextAttrDescriptor : '$1' .
+
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' :
+ {contextProp, '$3'}.
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' :
+ {contextList, '$3'}.
+
+contextIdList -> 'ContextListToken' 'EQUAL'
+ 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] .
+
+contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] .
+contextIDs -> '$empty' : [] .
+
+contextAudit -> 'ContextAuditToken' 'LBRKT' indAudcontextAttrDescriptor 'RBRKT'
+ : merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, '$3') .
+
+indAudcontextAttrDescriptor -> 'ContextAttrToken'
+ 'LBRKT' contextAuditProperty
+ contextAuditProperties 'RBRKT'
+ : ['$3' | '$4'] .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties
+ : ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once .
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+contextAuditProperty -> 'IEPSToken' : iepsCallind .
+contextAuditProperty -> pkgdName : {prop, '$1'} .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID
+ 'LBRKT'
+ optImmAckRequired transactionReplyBody
+ 'RBRKT'
+ : #'TransactionReply'{transactionId = '$3',
+ immAckRequired = '$5',
+ transactionResult = '$6'} .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor : {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReplys commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ [{error, '$2'}] .
+commandReplyList -> 'COMMA' commandReplys commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+commandReplys -> serviceChangeReply : {command, '$1'} .
+commandReplys -> auditReply : {command, '$1'} .
+commandReplys -> ammsReply : {command, '$1'} .
+commandReplys -> notifyReply : {command, '$1'} .
+commandReplys -> contextProperty : {context, '$1'} .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody :
+ Descs = merge_AmmRequest_descriptors('$4', []),
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = ['$3'],
+ descriptors = Descs}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, deprecated}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody
+ : {'$1', #'AmmsReply'{terminationID = ['$3'],
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL' terminationID
+ optAuditDescriptor
+ : make_commandRequest({subtractReq, '$1'},
+ #'SubtractRequest'{terminationID = ['$3'],
+ auditDescriptor = '$4'}) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+auditRequest -> 'AuditCapToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther
+ : {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther
+ : {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList :
+ {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' :
+ {error, '$2'} .
+
+auditOther -> terminationID :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = []}} .
+auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = '$3'}} .
+
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor.
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} .
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' :
+ merge_auditDescriptor('$3') .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken.
+auditItem -> 'EventBufferToken' : eventBufferToken.
+auditItem -> 'EventsToken' : eventsToken .
+auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2
+%%
+%% IGv11 - end
+
+
+%% v2 - start
+%%
+indAudterminationAudit -> indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$1' | '$2'] .
+
+indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$2' | '$3'] .
+indAudterminationAuditList -> '$empty' : [] .
+
+indAudauditReturnParameter -> indAudmediaDescriptor
+ : {indAudMediaDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventsDescriptor
+ : {indAudEventsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudsignalsDescriptor
+ : {indAudSignalsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAuddigitMapDescriptor
+ : {indAudDigitMapDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventBufferDescriptor
+ : {indAudEventBufferDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudstatisticsDescriptor
+ : {indAudStatisticsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudpackagesDescriptor
+ : {indAudPackagesDescriptor, '$1'} .
+
+
+indAudmediaDescriptor -> 'MediaToken' 'LBRKT'
+ indAudmediaParm indAudmediaParms 'RBRKT'
+ : merge_indAudMediaDescriptor(['$3'|'$4']) .
+
+%% at-most-once per item
+%% and either streamParm or streamDescriptor but not both
+%%
+
+indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} .
+indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} .
+indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} .
+
+indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] .
+indAudmediaParms -> '$empty' : [] .
+
+%% at-most-once
+indAudstreamParm -> indAudlocalControlDescriptor
+ : #'IndAudStreamParms'{localControlDescriptor = '$1'} .
+indAudstreamParm -> indAudstatisticsDescriptor
+ : #'IndAudStreamParms'{statisticsDescriptor = '$1'} .
+
+indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' indAudstreamParm 'RBRKT'
+ : #'IndAudStreamDescriptor'{streamID = '$3',
+ streamParms = '$5'} .
+
+
+indAudlocalControlDescriptor -> 'LocalControlToken'
+ 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' :
+ merge_indAudLocalControlDescriptor(['$3' | '$4']) .
+
+indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2' | '$3'] .
+indAudlocalParmList -> '$empty' : [] .
+
+%% at-most-once per item
+%%
+indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') .
+
+indAudterminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' indAudterminationStateParm 'RBRKT'
+ :
+ merge_indAudTerminationStateDescriptor('$3') .
+
+%% at-most-once per item
+%%
+
+indAudterminationStateParm -> safeToken :
+ ensure_indAudTerminationStateParm('$1') .
+
+indAudeventBufferDescriptor -> 'EventBufferToken'
+ 'LBRKT' indAudeventSpec 'RBRKT' : '$3' .
+
+indAudeventSpec -> pkgdName optIndAudeventSpecParameter
+ : merge_indAudEventBufferDescriptor('$1','$2') .
+
+optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT'
+ : '$2' .
+optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE .
+
+
+indAudeventSpecParameter -> eventStream : {streamID, '$1'} .
+indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} .
+
+indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' indAudrequestedEvent 'RBRKT'
+ : #'IndAudEventsDescriptor'{requestID = '$3',
+ pkgdName = '$5'} .
+
+indAudrequestedEvent -> pkgdName : '$1' .
+
+
+indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' .
+
+
+optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE .
+optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' .
+
+indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} .
+indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} .
+
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm 'RBRKT' :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3'),
+ signalList =
+ ensure_indAudSignalListParm('$5')} .
+
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_IADMD('$1') .
+
+indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' :
+ #'IndAudStatisticsDescriptor'{statName = '$3'} .
+
+indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT'
+ : merge_indAudPackagesDescriptor('$3') .
+
+eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' .
+
+
+%%
+%% v2 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' terminationID
+ 'LBRKT' notifyRequestBody 'RBRKT'
+ : make_commandRequest({notifyReq, '$1'},
+ setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) .
+
+notifyRequestBody -> observedEventsDescriptor
+ : #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor
+ : #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody
+ : {notifyReply,
+ #'NotifyReply'{terminationID = ['$3'],
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID
+ 'LBRKT' serviceChangeDescriptor 'RBRKT'
+ : make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = ['$3'],
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody
+ : {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = ['$3'],
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT'
+ : {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT'
+ : {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT'
+ : #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+%% '-' is used for NULL context
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT'
+ : ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat
+ : ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-onc .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+streamParm -> statisticsDescriptor : {statistics, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm
+ terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue :
+ setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue :
+ '$2' .
+
+parmValue -> 'NEQUAL' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT'
+ : #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value :
+ #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT'
+ : ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' .
+
+serviceState -> 'TestToken' : test .
+serviceState -> 'OutOfSvcToken' : outOfSvc .
+serviceState -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' .
+
+eventBufferControlState -> 'OffToken' : off .
+eventBufferControlState -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList :
+ #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT'
+ : {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT'
+ : {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody
+ : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT'
+ : merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' :
+ ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' : [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther /
+%% notifyCompletion / KeepActiveToken /
+%% direction / sigRequestID
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason)
+%% RBRKT)
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken /
+%% InterruptByNewSignalsDescrToken /
+%% OtherReasonToken )
+%% sigDirection = DirectionToken EQUAL direction
+%% sigRequestID = RequestIDToken EQUAL RequestID
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID :
+ {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType :
+ {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken :
+ {duration, ensure_uint16('$3')} .
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT' :
+ {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+sigParameter -> 'DirectionToken' 'EQUAL' direction : {direction, '$3'} .
+sigParameter -> 'RequestIDToken' 'EQUAL' requestID : {requestId, '$3'} .
+sigParameter -> safeToken parmValue :
+ {other, ensure_NAME('$1'), '$2'}.
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+direction -> 'ExternalToken' : external .
+direction -> 'InternalToken' : internal .
+direction -> 'BothToken' : both .
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms :
+ ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+
+observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody :
+ merge_observed_event('$6', '$5', '$1') .
+observedEvent -> optSep pkgdName observedEventBody :
+ merge_observed_event('$3', '$2', asn1_NOVALUE) .
+
+observedEventBody -> 'LBRKT' observedEventParameter
+ observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+%% Deprecated as of Corr 1
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms .
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms.
+modemTypeList -> 'COMMA' modemType modemTypeList.
+modemTypeList -> '$empty'.
+modemType -> safeToken.
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' :
+ ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] .
+propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] .
+propertyParmList -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_DMD('$1') .
+
+%% each parameter at-most-once, except auditItem
+%% at most one of either serviceChangeAddress or serviceChangeMgcId but
+%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp, '$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3
+serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken :
+ ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber :
+ {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'} .
+servChgReplyParm -> timeStamp : {time_stamp,'$1'} .
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem
+ packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter
+ statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple
+ topologyTripleList 'RBRKT' : ['$3' | '$4'] .
+
+terminationA -> terminationID : '$1' .
+
+terminationB -> terminationID : '$1' .
+
+topologyTriple -> terminationA 'COMMA'
+ terminationB 'COMMA'
+ topologyDirection :
+ #'TopologyRequest'{terminationFrom = '$1',
+ terminationTo = '$3',
+ topologyDirection = '$5'} .
+
+topologyTripleList -> '$empty' : [] .
+topologyTripleList -> 'COMMA' topologyTriple topologyTripleList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : bothway .
+topologyDirection -> 'IsolateToken' : isolate .
+topologyDirection -> 'OnewayToken' : oneway .
+
+iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' : ensure_value('$1') .
+value -> safeToken : ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+%% BMK BMK safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothToken' : '$1' . % v3
+safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3
+%% v2-safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+%% v3-
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% v2-safeToken2 -> 'EventBufferToken' : '$1' .
+%% v2-safeToken2 -> 'EventsToken' : '$1' .
+%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% v2-safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+safeToken2 -> 'ModeToken' : '$1' .
+%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' .
+%% v2-safeToken2 -> 'ModemToken' : '$1' .
+%% BMK BMK safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% v2-safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64Token' : '$1' .
+%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' .
+safeToken2 -> 'OnewayToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% v2-safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+%% v3-
+safeToken2 -> 'RequestIDToken' : '$1' . % v3
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+safeToken2 -> 'ReservedGroupToken' : '$1' .
+safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% v2-safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% v2-safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+%% BMK safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+%% BMK safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+%% <OTP-7534>
+safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3
+safeToken2 -> 'EmergencyValueToken' : '$1' . % v3
+safeToken2 -> 'IntsigDelayToken' : '$1' . % v3
+safeToken2 -> 'IterationToken' : '$1' . % v3
+safeToken2 -> 'MessageSegmentToken' : '$1' . % v3
+safeToken2 -> 'NeverNotifyToken' : '$1' . % v3
+safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3
+safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3
+safeToken2 -> 'OnewayBothToken' : '$1' . % v3
+safeToken2 -> 'OnewayExternalToken' : '$1' . % v3
+safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3
+safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3
+safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3
+%% </OTP-7534>
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_prev3b.hrl").
+
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3c.hrl b/lib/megaco/src/text/megaco_text_parser_prev3c.hrl
new file mode 100644
index 0000000000..ab099e5a24
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3c.hrl
@@ -0,0 +1,1980 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include("megaco_text_tokens.hrl").
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and issue the
+ %% the error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when length(Hex4) =< 4, length(Hex4) > 0 ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ X /= $X, X /= $x,
+ S /= $+, S /= $- ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% and since this functon is only used when creating
+%% a ModemDescriptor, iit is removed.
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+%% case Text of
+%% "v32b" -> v32bis;
+%% "v22b" -> v22bis;
+%% "v18" -> v18;
+%% "v22" -> v22;
+%% "v32" -> v32;
+%% "v34" -> v34;
+%% "v90" -> v90;
+%% "v91" -> v91;
+%% "synchisdn" -> synchISDN;
+%% "sn" -> synchISDN;
+%% [$x | _] -> ensure_extensionParameter(Token)
+%% end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ "nx64k" -> nx64k; % v2
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_packagesItem,1}]}).
+-endif.
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (length or content) there is really no point in
+ %% "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+
+
+%% v2 - start
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudMediaDescriptor,1}]}).
+-endif.
+merge_indAudMediaDescriptor(Vals) ->
+ merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}).
+
+merge_indAudMediaDescriptor(
+ [], #'IndAudMediaDescriptor'{streams = Streams1} = D) ->
+ Streams2 =
+ case Streams1 of
+ {multiStream, Descs} ->
+ {multiStream, lists:reverse(Descs)};
+ _ ->
+ Streams1
+ end,
+ D#'IndAudMediaDescriptor'{streams = Streams2};
+merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.termStateDescr == asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{termStateDescr = Val},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.streams == asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamDescr, Val}|Vals],
+ #'IndAudMediaDescriptor'{streams = Streams1} = D1) ->
+ Streams2 =
+ case Streams1 of
+ {multiStream, Descs} ->
+ {multiStream, [Val|Descs]};
+ _ ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
+ Val, Streams1})
+ end,
+ D2 = D1#'IndAudMediaDescriptor'{streams = Streams2},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{Tag, Val}|_], D) ->
+ case Tag of
+ termStateDescr ->
+ return_error(0, {bad_IndAudMediaDescriptor_termStateDescr,
+ Val, D#'IndAudMediaDescriptor'.termStateDescr});
+ streamParm ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamParm,
+ Val, D#'IndAudMediaDescriptor'.streams});
+ streamDescr ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
+ Val, D#'IndAudMediaDescriptor'.streams});
+ _ ->
+ return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}).
+-endif.
+merge_indAudLocalControlDescriptor(Parms) ->
+ merge_indAudLocalControlDescriptor(Parms,
+ #'IndAudLocalControlDescriptor'{},
+ asn1_NOVALUE).
+
+merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
+ D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) ->
+ merge_indAudLocalControlDescriptor(Parms, D, PP);
+
+merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
+ D2 =
+ case Val of
+ {equal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamModeSel = Val2};
+ {inequal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}
+ end,
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamModeSel == asn1_NOVALUE) ->
+ D2 =
+ case Val of
+ {equal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ streamModeSel = Val2};
+ {inequal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ streamModeSel = Val2}
+ end,
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+%% This is really wierd in the standard, so at this point this is the
+%% best I can do... BUGBUG BUGBUG BUGBUG
+%%
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) ->
+ PP = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D, PP);
+
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]},
+ PP2 = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP2);
+
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]},
+ PP2 = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP2);
+
+%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with
+%% just the prop (the mandatory name part is missing), so for now I
+%% assume that it this has been used, then the name part
+%% (pkgdName) must precide it?
+merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
+ when (PP =/= asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE) ->
+ PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]},
+ merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
+
+merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
+ when (PP =/= asn1_NOVALUE) andalso
+ is_list(D#'IndAudLocalControlDescriptor'.propertyParms) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]},
+ merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
+
+merge_indAudLocalControlDescriptor([H | _T], _D, _PP) ->
+ return_error(0, {bad_indAudLocalControlDescriptor_parm, H});
+
+merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE)
+ when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+ D;
+merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PropParms2 = lists:reverse(PPs),
+ D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+merge_indAudLocalControlDescriptor([], D, PP)
+ when D#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+ D#'IndAudLocalControlDescriptor'{propertyParms = [PP]};
+merge_indAudLocalControlDescriptor([], D, PP) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PPs2 = lists:reverse([PP|PPs]),
+ D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}.
+
+
+merge_indAudTerminationStateDescriptor({name, Val}) ->
+ PropParm = #'IndAudPropertyParm'{name = Val},
+ #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+%% BUGBUG BUGBUG BUGBUG
+merge_indAudTerminationStateDescriptor({prop, Val}) ->
+ exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val});
+merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+ #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) ->
+ #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
+merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) ->
+ #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
+merge_indAudTerminationStateDescriptor(bufferToken) ->
+ #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}).
+-endif.
+merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+ IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+ do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+ IAEBD;
+do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+ IAEBD) ->
+ %% BUGBUG BUGBUG BUGBUG
+ %% This is an ugly hack to allow the eventParamName which only
+ %% exists in the text encoding...
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudSignalListParm,1}]}).
+-endif.
+ensure_indAudSignalListParm(SIG) ->
+ if
+ is_record(SIG, 'Signal') ->
+ ensure_indAudSignal(SIG);
+ true ->
+ return_error(0, {bad_Signal, SIG})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudSignal,1}]}).
+-endif.
+ensure_indAudSignal(Sig) ->
+ #'Signal'{signalName = SignalName,
+ streamID = SID,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+ requestID = RID} = Sig,
+ #'IndAudSignal'{signalName = SignalName,
+ streamID = SID,
+ signalRequestID = RID}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_IADMD,1}]}).
+-endif.
+ensure_IADMD(Token) ->
+ {_TokenTag, _Line, DMD} = Token,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE} = DMD,
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudPackagesDescriptor,1}]}).
+-endif.
+merge_indAudPackagesDescriptor(Pkgs) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = V} = Pkgs,
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+
+%% ensure_indAudTerminationStateParm(Token) ->
+%% case Token of
+%% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+%% {safeToken, _Line, "si"} -> serviceStatesToken;
+%% {safeToken, _Line, "buffer"} -> bufferToken;
+%% {safeToken, _Line, "bf"} -> bufferToken;
+%% PkgdName -> {pkgdName,
+%% ensure_pkgdName(PkgdName)}
+%% end.
+
+
+%% Types modified by v2:
+
+merge_auditDescriptor([]) ->
+ #'AuditDescriptor'{};
+merge_auditDescriptor(Tokens) when is_list(Tokens) ->
+ case lists:keysearch(terminationAudit, 1, Tokens) of
+ {value, {terminationAudit, TA}} ->
+ case lists:keydelete(terminationAudit, 1, Tokens) of
+ [] ->
+ #'AuditDescriptor'{auditPropertyToken = TA};
+ AuditTokens ->
+ #'AuditDescriptor'{auditToken = AuditTokens,
+ auditPropertyToken = TA}
+ end;
+ false ->
+ #'AuditDescriptor'{auditToken = Tokens}
+ end;
+merge_auditDescriptor(_) ->
+ #'AuditDescriptor'{}.
+
+
+%% v2 - end
+
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE,
+ SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE,
+ SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_atom(Val) ->
+ SCI = #'AuditDescriptor'{auditToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo == asn1_NOVALUE) andalso
+ is_tuple(Val) ->
+ SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_atom(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditToken,
+ SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_tuple(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditPropertyToken,
+ SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp;
+ audit_item ->
+ SCP#'ServiceChangeParm'.serviceChangeInfo
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
+merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
+ Parm2 =
+ case Parm of
+ incomplete ->
+ SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
+ end,
+ exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_topologyDescriptor,1}]}).
+-endif.
+merge_topologyDescriptor(Components) ->
+ merge_topologyDescriptor(Components, #'TopologyRequest'{}, []).
+
+merge_topologyDescriptor([], TR, TRs) ->
+ lists:reverse([ensure_TopologyRequest(TR)|TRs]);
+merge_topologyDescriptor(
+ [{tid, From}|Comps],
+ #'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{terminationFrom = From},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(
+ [{tid, To}|Comps],
+ #'TopologyRequest'{terminationTo = undefined} = TR1,
+ TRs) ->
+ TR2 = TR1#'TopologyRequest'{terminationTo = To},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) ->
+ TR2 = #'TopologyRequest'{terminationFrom = From},
+ merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]);
+merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirection = Dir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{streamID = SID},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(
+ [{direction_ext, EDir}|Comps],
+ #'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirection = oneway,
+ topologyDirectionExtension = EDir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(Comps, TR, TRs) ->
+ return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}).
+
+
+ensure_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir} = R)
+ when (From =/= asn1_NOVALUE) andalso
+ (To =/= asn1_NOVALUE) andalso
+ (Dir =/= asn1_NOVALUE) ->
+ R;
+ensure_TopologyRequest(R) ->
+ return_error(0, {bad_TopologyRequest, R}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_profile,1}]}).
+-endif.
+ensure_profile(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, SID} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ {direction, Dir} when Sig#'Signal'.direction == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
+ {requestId, RID} when Sig#'Signal'.requestID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
+ {intersigDelay, ISD} when Sig#'Signal'.intersigDelay == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+%% io:format("select_stream_or_other -> entry with"
+%% "~n EventParameterName: ~p"
+%% "~n ParmValue: ~p"
+%% "~n", [EventParameterName, ParmValue]),
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Duration},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ durationTimer = [],
+ digitMapBody = asn1_NOVALUE} ->
+ asn1_NOVALUE;
+ #'DigitMapValue'{durationTimer = Body,
+ digitMapBody = Duration} = DMV ->
+ %% Convert to version 1 DigitMapValue
+ DMV#'DigitMapValue'{digitMapBody = Body,
+ durationTimer = Duration};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+make_RegulatedEmbeddedDescriptor({embed, SD, SED}) ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SED,
+ signalsDescriptor = SD}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+%% io:format("merge_eventParameters -> entry"
+%% "~n", []),
+ SID = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, SID, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], SID, EPL, RA, HasA) ->
+%% io:format("do_merge_eventParameters -> entry with"
+%% "~n H: ~p"
+%% "~n SID: ~p"
+%% "~n EPL: ~p"
+%% "~n RA: ~p"
+%% "~n HasA: ~p"
+%% "~n", [H, SID, EPL, RA, HasA]),
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {stream, NewSID} when SID =:= asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewSID, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
+ {notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{notifyBehaviour = NB},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], SID, EPL, RA, yes) ->
+%% io:format("do_merge_eventParameters(yes) -> entry with"
+%% "~n SID: ~p"
+%% "~n EPL: ~p"
+%% "~n RA: ~p"
+%% "~n", [SID, EPL, RA]),
+ #'RequestedEvent'{streamID = SID,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], SID, EPL, _RA, no) ->
+%% io:format("do_merge_eventParameters(no) -> entry with"
+%% "~n SID: ~p"
+%% "~n EPL: ~p"
+%% "~n", [SID, EPL]),
+ #'RequestedEvent'{streamID = SID,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ SID = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) ->
+ case H of
+ keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+
+ resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+
+ {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+
+ {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+
+ {stream, NewSID} when SID =:= asn1_NOVALUE ->
+ do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA);
+
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
+
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
+
+ {notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], SID, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = SID,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], SID, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = SID,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ ensure_transactionAck2(Text, []).
+
+ensure_transactionAck2([], Acc) ->
+ Id = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ensure_transactionAck2([$- | Id2], Acc) ->
+ Id1 = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id1),
+ lastAck = ensure_transactionID(Id2)};
+ensure_transactionAck2([H|T], Acc) ->
+ ensure_transactionAck2(T, [H|Acc]).
+
+
+merge_context_request(asn1_NOVALUE, Prop) ->
+ merge_context_request(#'ContextRequest'{}, Prop);
+
+merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR,
+ {priority, Int}) ->
+ CR#'ContextRequest'{priority = Int};
+
+merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR,
+ {emergency, Bool}) ->
+ CR#'ContextRequest'{emergency = Bool};
+
+merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR,
+ {topology, Desc}) ->
+ CR#'ContextRequest'{topologyReq = Desc};
+
+merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR,
+ {iepsCallind, Ind}) ->
+ CR#'ContextRequest'{iepscallind = Ind};
+
+merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
+ {contextProp, Props}) ->
+ CR#'ContextRequest'{contextProp = Props};
+
+merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR,
+ {contextList, IDs}) ->
+ CR#'ContextRequest'{contextList = IDs};
+
+merge_context_request(CR, {Tag, Val}) ->
+ Val2 =
+ case Tag of
+ priority -> CR#'ContextRequest'.priority;
+ emergency -> CR#'ContextRequest'.emergency;
+ topology -> CR#'ContextRequest'.topologyReq;
+ iepsCallind -> CR#'ContextRequest'.iepscallind;
+ contextProp -> CR#'ContextRequest'.contextProp;
+ contextList -> CR#'ContextRequest'.contextList
+ end,
+ exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
+
+
+merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) ->
+
+ CAAR;
+merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) ->
+
+ CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)};
+merge_context_attr_audit_request(CAAR, [H|T]) ->
+ case H of
+ priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud == asn1_NOVALUE ->
+ CPA = [#'IndAudPropertyParm'{name = Name}],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} ->
+ CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
+ CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic == asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ %% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
+ %%
+ %% For some strange reason, contextAttrDescriptor was added
+ %% to contextAuditSelector. But there is no place for this
+ %% info in the ContextAttrAuditRequest. Since contextAttrDescriptor
+ %% can also be found in contextProperty (which correspond to
+ %% ContextRequest), the question is if this info should go there
+ %% or if we shall just drop it. For now we drop it.
+ %%
+ {contextProp, _PPs} ->
+ merge_context_attr_audit_request(CAAR, T);
+
+ {contextList, _IDs} ->
+ merge_context_attr_audit_request(CAAR, T);
+
+ _ ->
+ exit({unexpected_contextAttrAudit_item, H})
+
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_request,2}]}).
+-endif.
+merge_action_request(CtxId, Items) ->
+ do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
+
+do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ case H of
+ {commandRequest, CmdReq} ->
+ do_merge_action_request(T, [CmdReq|CmdReqs],
+ CtxReq, CtxAuditReq, CtxId);
+
+ {contextProp, ContextProp} ->
+ do_merge_action_request(T, CmdReqs,
+ merge_context_request(CtxReq, ContextProp),
+ CtxAuditReq, CtxId);
+
+ {contextAudit, ContextAuditReq} when CtxAuditReq == asn1_NOVALUE ->
+ do_merge_action_request(T, CmdReqs,
+ CtxReq, ContextAuditReq, CtxId)
+ end;
+do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ #'ActionRequest'{contextId = CtxId,
+ contextRequest = strip_ContextRequest(CtxReq),
+ contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReqs)}.
+
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(Items) ->
+ do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
+
+do_merge_action_reply([], Err, Ctx, Cmds) ->
+ #'ActionReply'{errorDescriptor = Err,
+ contextReply = strip_ContextRequest(Ctx),
+ commandReply = lists:reverse(Cmds)};
+do_merge_action_reply([H|T], Err0, CR, Cmds) ->
+ case H of
+ {error, Err1} when Err0 == asn1_NOVALUE ->
+ do_merge_action_reply(T, Err1, CR, Cmds);
+ {command, Cmd} ->
+ do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
+ {context, CtxProp} ->
+ do_merge_action_reply(T, Err0,
+ merge_context_request(CR, CtxProp), Cmds)
+ end.
+
+merge_auditOther([TID], TAR) ->
+ {auditResult,
+ #'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}};
+merge_auditOther(TIDs, TAR) ->
+ {auditResultTermList,
+ #'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TAR}}.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+ contextList = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = [],
+ contextList = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+%% strip_ContextRequest(asn1_NOVALUE) ->
+%% asn1_NOVALUE;
+strip_ContextRequest(R) ->
+ R.
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = [],
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(R) ->
+ R.
+
+merge_AmmRequest_descriptors([], Acc) ->
+ lists:reverse(Acc);
+merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, Acc);
+merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
+
+make_auditRequest([TID], AD) ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD};
+make_auditRequest([TID|_] = TIDList, AD) ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = TIDList}.
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor,
+ 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ parse_prop_name(Text, Group).
+
+parse_prop_name([Char | Rest] = All, Group) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group)
+ end;
+parse_prop_name([] = All, Group) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group).
+
+do_parse_prop_name([Char | Rest], Name, Group)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ NewGroup = [],
+ [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)];
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], []) ->
+ [];
+do_parse_prop_name([], [], Group) ->
+ [lists:reverse(Group)];
+do_parse_prop_name([], Name, Group) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,3}]}).
+-endif.
+parse_prop_value(Chars, Name, Group) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group]);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group)
+ end;
+do_parse_prop_value([], Name, Value, Group) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ Groups.
+
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max == infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% %% d(true, F, A).
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_prev3c.yrl b/lib/megaco/src/text/megaco_text_parser_prev3c.yrl
new file mode 100644
index 0000000000..9b7984deab
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_prev3c.yrl
@@ -0,0 +1,1673 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%
+%% NOTE 1 - This syntax specification does not enforce all restrictions
+%% on element inclusions and values. Some additional
+%% restrictions are stated in comments and other restrictions
+%% appear in the text of this Recommendation. These additional
+%% restrictions are part of the protocol even though not
+%% enforced by this Recommendation.
+%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be
+%% the AddToken or a NAME depending on the context in which it
+%% occurs.
+%%
+%% Everything in the ABNF and text encoding is case insensitive. This
+%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+%% per RFC 2327.
+%%
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 93.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestBody
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ auditSelectLogic %% v3
+ authenticationHeader
+ commandReplyList
+ commandReplys %% v3
+ commandRequest
+ contextAttrDescriptor %% v3
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextAuditSelector %% v3
+ contextID
+ contextIdList %% v3
+ contextIDs %% v3
+%% contextProperties %% v3
+ contextProperty
+%% contextPropertyList
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ direction %% v3
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ emergencyValue %% v3
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlValue %% v3
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStream
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+
+ iaServiceStates %% v3
+ iepsValue
+
+ %% v2 - start
+ indAudauditReturnParameter
+ indAuddigitMapDescriptor
+ indAudeventBufferDescriptor
+ indAudeventSpec
+ indAudeventSpecParameter
+ %% indAudeventSpecParameterList
+ indAudeventsDescriptor
+ indAudlocalControlDescriptor
+ indAudlocalParm
+ indAudlocalParmList
+ indAudmediaDescriptor
+ indAudmediaParm
+ indAudmediaParms %% v3
+ %% indAudmediaParmList
+ indAudpackagesDescriptor
+ indAudrequestedEvent
+ indAudsignalsDescriptor
+ indAudsignalList
+ %% indAudsignalListParm
+ indAudsignalParm
+ %% indAudsignalRequest
+ indAudstreamDescriptor
+ indAudstreamParm
+ indAudstatisticsDescriptor
+ indAudterminationAudit
+ indAudterminationAuditList
+ indAudterminationStateDescriptor
+ indAudterminationStateParm
+ %% indAudterminationStateParmList
+ optIndAudeventSpecParameter
+ optIndAudsignalParm
+ %% v2 - end
+
+ indAudcontextAttrDescriptor %% v3
+
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor % Deprecated as of Corr 1
+ modemType % Deprecated as of Corr 1
+ modemTypeList % Deprecated as of Corr 1
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyBehaviour %% v3
+ notifyRegulated %% v3
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ % observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ propertyParmList
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceStates
+ serviceStatesValue %% v3
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ termIDList %% v3
+ terminationAudit
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyDescComp
+ topologyDescCompList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AndAUDITselectToken' %% v3
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothToken' %% v3
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ 'ContextAttrToken' %% v3
+ 'ContextAuditToken'
+ 'ContextListToken' %% v3
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DirectionToken' %% v3
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'EmergencyOffToken'
+ 'EmergencyValueToken' %% v3
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'ExternalToken' %% v3
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'IEPSToken' %% v3
+ 'ImmAckRequiredToken'
+ 'INEQUAL' %% v3
+ 'InSvcToken'
+ 'InactiveToken'
+ 'InternalToken' %% v3
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'IntsigDelayToken' %% v3
+ 'IsolateToken'
+ 'IterationToken' %% v3
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NeverNotifyToken' %% v3
+ 'NotifyCompletionToken'
+ 'NotifyImmediateToken' %% v3
+ 'NotifyRegulatedToken' %% v3
+ 'NotifyToken'
+ 'Nx64Token' %% v2
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OnewayExternalToken' %% v3
+ 'OnewayBothToken' %% v3
+ 'OrAUDITselectToken' %% v3
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'RequestIDToken' %% v3
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResetEventsDescriptorToken' %% v3
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceChangeIncompleteToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ 'MessageSegmentToken' %% OTP-7534: v3-fix
+ 'SegmentationCompleteToken' %% OTP-7534: v3-fix
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody :
+ ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck
+ transactionAckList 'RBRKT' : ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck
+ transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' :
+ #'TransactionPending'{transactionId = ensure_transactionID('$3') } .
+
+transactionRequest -> 'TransToken' 'LBRKT' actionRequest
+ actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL' 'LBRKT' actionRequest
+ actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+%% actionRequest = CtxToken EQUAL ContextID LBRKT ((contextRequest
+%% [COMMA commandRequestList]) /
+%% commandRequestList) RBRKT
+%% contextRequest = ((contextProperties [COMMA contextAudit]) /
+%% contextAudit)
+%% contextProperties = contextProperty *(COMMA contextProperty)
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestBody 'RBRKT' :
+ merge_action_request('$3', '$5') .
+
+actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] .
+
+actionRequestItems -> 'COMMA' actionRequestItem
+ actionRequestItems : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+actionRequestItem -> contextProperty : {contextProp, '$1'} .
+actionRequestItem -> contextAudit : {contextAudit, '$1'} .
+actionRequestItem -> commandRequest : {commandRequest, '$1'} .
+
+
+%% at-most-once (presumebly in contextProperties)
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+contextProperty -> 'EmergencyOffToken' : {emergency, false}.
+contextProperty -> iepsValue : {iepsCallind, '$1'} .
+contextProperty -> contextAttrDescriptor : '$1' .
+
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' :
+ {contextProp, '$3'}.
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' :
+ {contextList, '$3'}.
+
+contextIdList -> 'ContextListToken' 'EQUAL'
+ 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] .
+
+contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] .
+contextIDs -> '$empty' : [] .
+
+contextAudit -> 'ContextAuditToken' 'LBRKT'
+ indAudcontextAttrDescriptor 'RBRKT' :
+ merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, '$3') .
+contextAudit -> 'ContextAuditToken' 'LBRKT'
+ contextAuditProperty contextAuditProperties 'RBRKT' :
+ merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, ['$3' | '$4']) .
+
+indAudcontextAttrDescriptor -> 'ContextAttrToken'
+ 'LBRKT' contextAuditProperty
+ contextAuditProperties 'RBRKT'
+ : ['$3' | '$4'] .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties
+ : ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once except contextAuditSelector.
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+contextAuditProperty -> 'IEPSToken' : iepsCallind .
+contextAuditProperty -> pkgdName : {prop, '$1'} .
+contextAuditProperty -> contextAuditSelector : '$1' .
+
+%% at-most-once
+contextAuditSelector -> priority : {select_prio, '$1'} .
+contextAuditSelector -> emergencyValue : {select_emergency, '$1'} .
+contextAuditSelector -> iepsValue : {select_ieps, '$1'} .
+contextAuditSelector -> auditSelectLogic : {select_logic, '$1'} .
+contextAuditSelector -> contextAttrDescriptor : '$1' .
+
+auditSelectLogic -> 'AndAUDITselectToken' : {andAUDITSelect, 'NULL'} .
+auditSelectLogic -> 'OrAUDITselectToken' : {orAUDITSelect, 'NULL'} .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID
+ 'LBRKT'
+ optImmAckRequired transactionReplyBody
+ 'RBRKT'
+ : #'TransactionReply'{transactionId = '$3',
+ immAckRequired = '$5',
+ transactionResult = '$6'} .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor : {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+actionReply -> 'CtxToken' 'EQUAL' contextID :
+ #'ActionReply'{contextId = '$3'} .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReplys commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ [{error, '$2'}] .
+commandReplyList -> 'COMMA' commandReplys commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+commandReplys -> serviceChangeReply : {command, '$1'} .
+commandReplys -> auditReply : {command, '$1'} .
+commandReplys -> ammsReply : {command, '$1'} .
+commandReplys -> notifyReply : {command, '$1'} .
+commandReplys -> contextProperty : {context, '$1'} .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' termIDList ammRequestBody :
+ Descs = merge_AmmRequest_descriptors('$4', []),
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = '$3',
+ descriptors = Descs}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, deprecated}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' termIDList ammsReplyBody
+ : {'$1', #'AmmsReply'{terminationID = '$3',
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL' termIDList optAuditDescriptor :
+ SR = #'SubtractRequest'{terminationID = '$3',
+ auditDescriptor = '$4'},
+ make_commandRequest({subtractReq, '$1'}, SR) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL' termIDList optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ make_auditRequest('$3', '$4')) .
+auditRequest -> 'AuditCapToken' 'EQUAL' termIDList optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ make_auditRequest('$3', '$4')) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit :
+ {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit :
+ {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther :
+ {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther :
+ {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList :
+ {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' :
+ {error, '$2'} .
+
+auditOther -> termIDList :
+ merge_auditOther('$1', []) .
+auditOther -> termIDList 'LBRKT' terminationAudit 'RBRKT' :
+ merge_auditOther('$1', '$3') .
+
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor.
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} .
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' :
+ merge_auditDescriptor('$3') .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken.
+auditItem -> 'EventBufferToken' : eventBufferToken.
+auditItem -> 'EventsToken' : eventsToken .
+auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2
+%%
+%% IGv11 - end
+
+
+%% v2 - start
+%%
+indAudterminationAudit -> indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$1' | '$2'] .
+
+indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$2' | '$3'] .
+indAudterminationAuditList -> '$empty' : [] .
+
+indAudauditReturnParameter -> indAudmediaDescriptor
+ : {indAudMediaDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventsDescriptor
+ : {indAudEventsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudsignalsDescriptor
+ : {indAudSignalsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAuddigitMapDescriptor
+ : {indAudDigitMapDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventBufferDescriptor
+ : {indAudEventBufferDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudstatisticsDescriptor
+ : {indAudStatisticsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudpackagesDescriptor
+ : {indAudPackagesDescriptor, '$1'} .
+
+
+indAudmediaDescriptor -> 'MediaToken' 'LBRKT'
+ indAudmediaParm indAudmediaParms 'RBRKT'
+ : merge_indAudMediaDescriptor(['$3'|'$4']) .
+
+%% at-most-once per item
+%% and either streamParm or streamDescriptor but not both
+%%
+
+indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} .
+indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} .
+indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} .
+
+indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] .
+indAudmediaParms -> '$empty' : [] .
+
+%% at-most-once
+indAudstreamParm -> 'RemoteDescriptorToken' :
+ RD = ensure_prop_groups('$1'),
+ #'IndAudStreamParms'{remoteDescriptor = RD} .
+indAudstreamParm -> 'LocalDescriptorToken' :
+ LD = ensure_prop_groups('$1'),
+ #'IndAudStreamParms'{localDescriptor = LD} .
+indAudstreamParm -> indAudlocalControlDescriptor :
+ #'IndAudStreamParms'{localControlDescriptor = '$1'} .
+indAudstreamParm -> indAudstatisticsDescriptor :
+ #'IndAudStreamParms'{statisticsDescriptor = '$1'} .
+
+indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' indAudstreamParm 'RBRKT'
+ : #'IndAudStreamDescriptor'{streamID = '$3',
+ streamParms = '$5'} .
+
+
+indAudlocalControlDescriptor -> 'LocalControlToken'
+ 'LBRKT' indAudlocalParm
+ indAudlocalParmList 'RBRKT' :
+ merge_indAudLocalControlDescriptor(['$3' | '$4']) .
+
+indAudlocalParmList -> 'COMMA' indAudlocalParm
+ indAudlocalParmList : ['$2' | '$3'] .
+indAudlocalParmList -> '$empty' : [] .
+
+%% at-most-once per item
+%%
+%% propertyparm and streamModes are used only to specify audit selection
+%% criteria. AND/OR selection logic is specified at context level.
+%%
+indAudlocalParm -> 'ReservedGroupToken' : reservedGroupToken .
+indAudlocalParm -> 'ReservedValueToken' : reservedValueToken .
+indAudlocalParm -> 'ModeToken' : modeToken .
+indAudlocalParm -> 'ModeToken' 'EQUAL' streamModes : {mode, {equal, '$3'}} .
+indAudlocalParm -> 'ModeToken' 'INEQUAL' streamModes : {mode, {inequal,'$3'}} .
+indAudlocalParm -> propertyParm : {prop, '$1'} .
+indAudlocalParm -> pkgdName : {name, '$1'} .
+
+indAudterminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' indAudterminationStateParm 'RBRKT'
+ :
+ merge_indAudTerminationStateDescriptor('$3') .
+
+%% at-most-once per item
+%%
+
+%% at-most-once per item except for propertyParm
+indAudterminationStateParm -> iaServiceStates : '$1' .
+indAudterminationStateParm -> 'BufferToken' : bufferToken .
+indAudterminationStateParm -> propertyParm : {prop, '$1'} .
+indAudterminationStateParm -> pkgdName : {name, '$1'} .
+
+iaServiceStates -> 'ServiceStatesToken' :
+ serviceStatesToken .
+iaServiceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue :
+ {serviceStates, {equal, '$3'}} .
+iaServiceStates -> 'ServiceStatesToken' 'INEQUAL' serviceStatesValue :
+ {serviceStates, {inequal, '$3'}} .
+
+indAudeventBufferDescriptor -> 'EventBufferToken'
+ 'LBRKT' indAudeventSpec 'RBRKT' : '$3' .
+
+indAudeventSpec -> pkgdName optIndAudeventSpecParameter
+ : merge_indAudEventBufferDescriptor('$1','$2') .
+
+optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT'
+ : '$2' .
+optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE .
+
+
+indAudeventSpecParameter -> eventStream : {streamID, '$1'} .
+indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} .
+
+indAudeventsDescriptor -> 'EventsToken' 'LBRKT' indAudrequestedEvent 'RBRKT' :
+ #'IndAudEventsDescriptor'{pkgdName = '$3'} .
+indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' indAudrequestedEvent 'RBRKT' :
+ #'IndAudEventsDescriptor'{requestID = '$3',
+ pkgdName = '$5'} .
+
+indAudrequestedEvent -> pkgdName : '$1' .
+
+
+indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' .
+
+
+optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE .
+optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' .
+
+indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} .
+indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} .
+
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3')} .
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm 'RBRKT' :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3'),
+ signalList =
+ ensure_indAudSignalListParm('$5')} .
+
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_IADMD('$1') .
+
+indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' :
+ #'IndAudStatisticsDescriptor'{statName = '$3'} .
+
+indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT'
+ : merge_indAudPackagesDescriptor('$3') .
+
+eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' .
+
+
+%%
+%% v2 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' termIDList
+ 'LBRKT' notifyRequestBody 'RBRKT' :
+ NR = setelement(#'NotifyRequest'.terminationID,
+ '$5', '$3'),
+ make_commandRequest({notifyReq, '$1'}, NR) .
+
+notifyRequestBody -> observedEventsDescriptor :
+ #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor :
+ #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' termIDList notifyReplyBody :
+ {notifyReply, #'NotifyReply'{terminationID = '$3',
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' termIDList
+ 'LBRKT' serviceChangeDescriptor 'RBRKT' :
+ make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = '$3',
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' termIDList
+ serviceChangeReplyBody :
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = '$3',
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' :
+ {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' :
+ {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' :
+ {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT'
+ errorText 'RBRKT' :
+ #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+%% '-' is used for NULL context
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+termIDList -> terminationID : ['$1'] .
+termIDList -> LSBRKT terminationID terminationIDListRepeat RSBRKT :
+ ['$2' | '$3'] .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' :
+ ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat :
+ ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-once .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs} } .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+streamParm -> statisticsDescriptor : {statistics, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm
+ terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue :
+ setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue :
+ '$2' .
+
+parmValue -> 'NEQUAL' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT' :
+ #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' :
+ #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' :
+ #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value :
+ #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec
+ eventSpecList 'RBRKT' :
+ ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : '$3'.
+
+serviceStatesValue -> 'TestToken' : test .
+serviceStatesValue -> 'OutOfSvcToken' : outOfSvc .
+serviceStatesValue -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlValue : '$3' .
+
+eventBufferControlValue -> 'OffToken' : off .
+eventBufferControlValue -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList :
+ #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} .
+
+
+notifyRegulated -> 'NotifyRegulatedToken' :
+ #'RegulatedEmbeddedDescriptor'{} .
+notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedWithSig 'RBRKT' :
+ make_RegulatedEmbeddedDescriptor('$3') .
+notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedNoSig 'RBRKT' :
+ make_RegulatedEmbeddedDescriptor('$3') .
+
+notifyBehaviour -> 'NotifyImmediateToken' : {notifyImmediate, 'NULL'} .
+notifyBehaviour -> 'NeverNotifyToken' : {neverNotify, 'NULL'} .
+notifyBehaviour -> notifyRegulated : {notifyRegulated, '$1'} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+eventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}.
+eventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor .
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT'
+ : {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT'
+ : {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody
+ : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT'
+ : merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+secondEventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}.
+secondEventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' :
+ ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' : [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther /
+%% notifyCompletion / KeepActiveToken /
+%% direction / sigRequestID
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason)
+%% RBRKT)
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken /
+%% InterruptByNewSignalsDescrToken /
+%% OtherReasonToken )
+%% sigDirection = DirectionToken EQUAL direction
+%% sigRequestID = RequestIDToken EQUAL RequestID
+%% sigIntsigDelay = IntsigDelayToken EQUAL UINT16
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID :
+ {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType :
+ {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken :
+ {duration, ensure_uint16('$3')} .
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT' :
+ {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+sigParameter -> 'DirectionToken' 'EQUAL' direction :
+ {direction, '$3'} .
+sigParameter -> 'RequestIDToken' 'EQUAL' requestID :
+ {requestId, '$3'} .
+sigParameter -> 'IntsigDelayToken' 'EQUAL' safeToken :
+ {intersigDelay, ensure_uint16('$3')} .
+sigParameter -> safeToken parmValue :
+ {other, ensure_NAME('$1'), '$2'}.
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+direction -> 'ExternalToken' : external .
+direction -> 'InternalToken' : internal .
+direction -> 'BothToken' : both .
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+notificationReason -> 'IterationToken' : iteration .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms :
+ ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+
+observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody :
+ merge_observed_event('$6', '$5', '$1') .
+observedEvent -> optSep pkgdName observedEventBody :
+ merge_observed_event('$3', '$2', asn1_NOVALUE) .
+
+observedEventBody -> 'LBRKT' observedEventParameter
+ observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+%% Deprecated as of Corr 1
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms .
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms.
+modemTypeList -> 'COMMA' modemType modemTypeList.
+modemTypeList -> '$empty'.
+modemType -> safeToken.
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' :
+ ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] .
+propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] .
+propertyParmList -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_DMD('$1') .
+
+%% each parameter at-most-once, except auditItem
+%% at most one of either serviceChangeAddress or serviceChangeMgcId but
+%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp, '$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3
+serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken :
+ ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber :
+ {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'} .
+servChgReplyParm -> timeStamp : {time_stamp,'$1'} .
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem
+ packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter
+ statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+statisticsParameter -> pkgdName 'EQUAL' 'LSBRKT' value valueList 'RSBRKT' :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = ['$4' | '$5']} .
+
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT'
+ topologyDescComp topologyDescCompList 'RBRKT' :
+ merge_topologyDescriptor(['$3' | '$4']) .
+
+topologyDescComp -> terminationID : {tid, '$1'} .
+topologyDescComp -> eventStream : {sid, '$1'} .
+topologyDescComp -> topologyDirection : '$1' .
+
+topologyDescCompList -> '$empty' : [] .
+topologyDescCompList -> 'COMMA' topologyDescComp topologyDescCompList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : {direction, bothway} .
+topologyDirection -> 'IsolateToken' : {direction, isolate} .
+topologyDirection -> 'OnewayToken' : {direction, oneway} .
+topologyDirection -> 'OnewayExternalToken' : {direction_ext, onewayexternal} .
+topologyDirection -> 'OnewayBothToken' : {direction_ext, onewayboth} .
+
+iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' .
+
+emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyToken' : true .
+emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyOffToken' : false .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' : ensure_value('$1') .
+value -> safeToken : ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+%% BMK BMK safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothToken' : '$1' . % v3
+%% v3-safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+%% v3-safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3
+%% v2-safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+%% v3-
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% v2-safeToken2 -> 'EventBufferToken' : '$1' .
+%% v2-safeToken2 -> 'EventsToken' : '$1' .
+%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+%% v3-safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% v2-safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+%% v3-safeToken2 -> 'ModeToken' : '$1' .
+%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' .
+%% v2-safeToken2 -> 'ModemToken' : '$1' .
+%% BMK BMK safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% v2-safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64Token' : '$1' .
+%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayExternalToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayBothToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% v2-safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+%% v3-
+safeToken2 -> 'RequestIDToken' : '$1' . % v3
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+%% v3-safeToken2 -> 'ReservedGroupToken' : '$1' .
+%% v3-safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% v2-safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% v2-safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+%% <OTP-7534>
+safeToken2 -> 'MessageSegmentToken' : '$1' . % v3
+safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3
+%% </OTP-7534>
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_prev3c.hrl").
+
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v1.hrl b/lib/megaco/src/text/megaco_text_parser_v1.hrl
new file mode 100644
index 0000000000..ebc43c0352
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v1.hrl
@@ -0,0 +1,1410 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. % We really should ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and issue the
+ %% error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) == 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) == 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when length(Hex4) =< 4, length(Hex4) > 0 ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ (X =/= $X) andalso (X =/= $x) andalso
+ (S =/= $+) andalso (S =/= $-) ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_modemType,1}]}).
+-endif.
+ensure_modemType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "v32b" -> v32bis;
+ "v22b" -> v22bis;
+ "v18" -> v18;
+ "v22" -> v22;
+ "v32" -> v32;
+ "v34" -> v34;
+ "v90" -> v90;
+ "v91" -> v91;
+ "synchisdn" -> synchISDN;
+ "sn" -> synchISDN;
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (neither length nor content) there is really no
+ %% point in "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)
+ andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE)) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeProfile =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeVersion =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when (SCP0#'ServiceChangeParm'.serviceChangeReason =:= undefined) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeDelay =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when (SCP0#'ServiceChangeParm'.serviceChangeMethod =:= undefined) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.timeStamp =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_profile,1}]}).
+-endif.
+ensure_profile(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+%% Version 2 of the DigitMapValue has an extra item (after extension mark),
+%% durationTimer, which does not exist in version 1. The record was created
+%% as defined in megaco_message_internal.hrl, e.g. as in version 2, so we
+%% have to fix it here.
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ %% Convert to version 1 DigitMapValue
+ {'DigitMapValue', Start, Short, Long, _DurationTimer, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+%% Version 2 of the DigitMapValue has an extra item (after extension mark),
+%% durationTimer, which does not exist in version 1. The record is defined
+%% (in megaco_message_internal.hrl) as in version 2, so we have to fix
+%% it here.
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ {'DigitMapValue', asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, []} ->
+ asn1_NOVALUE;
+ {'DigitMapValue', Start, Short, Long, _DurationTimer, Body} ->
+ %% Convert to version 1 DigitMapValue
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+ case H of
+ keepActive when (SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE) ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {second_embed, SD} when (SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE) ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {eventDM, DM} when (SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE) ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {stream, NewStreamId} when (StreamId =:= asn1_NOVALUE) ->
+ do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ ensure_transactionAck2(Text, []).
+
+ensure_transactionAck2([], Acc) ->
+ Id = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ensure_transactionAck2([$- | Id2], Acc) ->
+ Id1 = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id1),
+ lastAck = ensure_transactionID(Id2)};
+ensure_transactionAck2([H|T], Acc) ->
+ ensure_transactionAck2(T, [H|Acc]).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_requests,2}]}).
+-endif.
+merge_action_requests(ContextId, Items) ->
+ CtxReq = #'ContextRequest'{},
+ CtxAuditReq = #'ContextAttrAuditRequest'{},
+ CmdReq = [],
+ TopReq = [],
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
+
+do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
+ case H of
+ _ when is_record(H, 'CommandRequest') ->
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
+
+ {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+ do_merge_action_requests(ContextId, CtxReq2, CtxAuditReq, CmdReq,
+ TopReq, T);
+ {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+ do_merge_action_requests(ContextId, CtxReq2, CtxAuditReq, CmdReq,
+ TopReq, T);
+ {topology, Desc} ->
+ TopReq2 = Desc ++ TopReq, %% OTP-4088
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq,
+ TopReq2, T);
+
+ priorityAudit when CtxAuditReq#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+ CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{priority = 'NULL'},
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq,
+ TopReq, T);
+ emergencyAudit when CtxAuditReq#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+ CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{emergency = 'NULL'},
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq,
+ TopReq, T);
+ topologyAudit when CtxAuditReq#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+ CtxAuditReq2 = CtxAuditReq#'ContextAttrAuditRequest'{topology = 'NULL'},
+ do_merge_action_requests(ContextId, CtxReq, CtxAuditReq2, CmdReq,
+ TopReq, T)
+ end;
+do_merge_action_requests(ContextId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) ->
+ #'ActionRequest'{contextId = ContextId,
+ contextRequest = strip_contextRequest(CtxReq, TopReq),
+ contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReq)}.
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(ReplyList) ->
+ CtxReq = #'ContextRequest'{},
+ TopReq = [],
+ CmdList = [],
+ do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList).
+
+do_merge_action_reply([ED], CtxReq, TopReq, CmdList)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
+ commandReply = lists:reverse(CmdList),
+ errorDescriptor = ED};
+do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
+ case H of
+ {command, Cmd} ->
+ do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
+ {context, Ctx} ->
+ case Ctx of
+ {priority, Int} when CtxReq#'ContextRequest'.priority =:= asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+ do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+ {emergency, Bool} when CtxReq#'ContextRequest'.emergency =:= asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+ do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+ {topology, Desc} ->
+ TopReq2 = Desc ++ TopReq, %% OTP-4088
+ do_merge_action_reply(T, CtxReq, TopReq2, CmdList)
+ end
+ end;
+do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
+ #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
+ commandReply = lists:reverse(CmdList)}.
+
+strip_contextRequest(R, TopReq)
+ when (R#'ContextRequest'.priority =:= asn1_NOVALUE) andalso
+ (R#'ContextRequest'.emergency =:= asn1_NOVALUE) andalso
+ (TopReq =:= []) ->
+ asn1_NOVALUE;
+strip_contextRequest(R, []) ->
+ R#'ContextRequest'{topologyReq = asn1_NOVALUE};
+strip_contextRequest(R, TopReq) ->
+ R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
+
+
+strip_contextAttrAuditRequest(R)
+ when (R#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE) andalso
+ (R#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE) andalso
+ (R#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE) ->
+ asn1_NOVALUE;
+strip_contextAttrAuditRequest(R) ->
+ R.
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor,
+ 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ parse_prop_name(Text, Group).
+
+parse_prop_name([Char | Rest] = All, Group) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group)
+ end;
+parse_prop_name([] = All, Group) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group).
+
+do_parse_prop_name([Char | Rest], Name, Group)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ NewGroup = [],
+ [lists:reverse(Group) | parse_prop_value(Rest, Name, NewGroup)];
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], []) ->
+ [];
+do_parse_prop_name([], [], Group) ->
+ [lists:reverse(Group)];
+do_parse_prop_name([], Name, Group) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,3}]}).
+-endif.
+parse_prop_value(Chars, Name, Group) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group]);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group)
+ end;
+do_parse_prop_value([], Name, Value, Group) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ [Group2].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ %% do_ensure_prop_groups(Groups).
+ Groups.
+
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+% d(F) ->
+% d(F,[]).
+% d(F, A) ->
+% io:format("~p:" ++ F ++ "~n", [?MODULE | A]).
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v1.yrl b/lib/megaco/src/text/megaco_text_parser_v1.yrl
new file mode 100644
index 0000000000..fd50d90523
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v1.yrl
@@ -0,0 +1,1364 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 609.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ authenticationHeader
+ commandReply
+ commandReplyList
+ commandRequest
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextID
+ contextProperty
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlState
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor
+ modemType
+ modemTypeList
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceState
+ serviceStates
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ terminationA
+ terminationAudit
+ terminationB
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyTriple
+ topologyTripleList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ 'ContextAuditToken'
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'ImmAckRequiredToken'
+ 'InSvcToken'
+ 'InactiveToken'
+ 'IsolateToken'
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NotifyCompletionToken'
+ 'NotifyToken'
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ 'AndAUDITSelectToken' %% OTP-7534: v3-fix
+ 'BothToken' %% OTP-7534: v3-fix
+ 'ContextAttrToken' %% OTP-7534: v3-fix
+ 'ContextListToken' %% OTP-7534: v3-fix
+ 'DirectionToken' %% OTP-7534: v3-fix
+ 'EmergencyOffToken' %% OTP-7534: v3-fix
+ 'EmergencyValueToken' %% OTP-7534: v3-fix
+ 'ExternalToken' %% OTP-7534: v3-fix
+ 'IEPSToken' %% OTP-7534: v3-fix
+ 'IntsigDelayToken' %% OTP-7534: v3-fix
+ 'InternalToken' %% OTP-7534: v3-fix
+ 'IterationToken' %% OTP-7534: v3-fix
+ 'MessageSegmentToken' %% OTP-7534: v3-fix
+ 'NeverNotifyToken' %% OTP-7534: v3-fix
+ 'NotifyImmediateToken' %% OTP-7534: v3-fix
+ 'NotifyRegulatedToken' %% OTP-7534: v3-fix
+ 'Nx64kToken' %% OTP-7534: v2-fix
+ 'OnewayBothToken' %% OTP-7534: v3-fix
+ 'OnewayExternalToken' %% OTP-7534: v3-fix
+ 'OrAUDITselectToken' %% OTP-7534: v3-fix
+ 'RequestIDToken' %% OTP-7534: v3-fix
+ 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix
+ 'SegmentationCompleteToken' %% OTP-7534: v3-fix
+ 'ServiceChangeIncompleteToken' %% OTP-7534: v3-fix
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage :
+ #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL'
+ safeToken 'COLON' safeToken 'COLON' safeToken optSep :
+ ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody :
+ ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck transactionAckList 'RBRKT' :
+ ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' :
+ #'TransactionPending'{transactionId = ensure_transactionID('$3')} .
+
+transactionRequest -> 'TransToken'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList :
+ ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestItem actionRequestItems 'RBRKT' :
+ merge_action_requests('$3', ['$5' | '$6']) .
+
+actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+actionRequestItem -> contextProperty : '$1'.
+actionRequestItem -> contextAudit : '$1' .
+actionRequestItem -> commandRequest : '$1'.
+
+%% at-most-once
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+
+contextAudit -> 'ContextAuditToken'
+ 'LBRKT' contextAuditProperty
+ contextAuditProperties 'RBRKT' :
+ ['$3' | '$4'] .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty
+ contextAuditProperties :
+ ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once .
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID
+ 'LBRKT' optImmAckRequired
+ transactionReplyBody 'RBRKT' :
+ #'TransactionReply'{transactionId = '$3',
+ immAckRequired = '$5',
+ transactionResult = '$6'} .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor :
+ {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList :
+ {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReply commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+commandReply -> serviceChangeReply : {command, '$1'} .
+commandReply -> auditReply : {command, '$1'} .
+commandReply -> ammsReply : {command, '$1'} .
+commandReply -> notifyReply : {command, '$1'} .
+commandReply -> contextProperty : {context, '$1'} .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ ['$2'] .
+commandReplyList -> 'COMMA' commandReply commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody :
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = ['$3'],
+ descriptors = '$4'}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, '$1'}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody :
+ {'$1', #'AmmsReply'{terminationID = ['$3'],
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({subtractReq, '$1'},
+ #'SubtractRequest'{terminationID = ['$3'],
+ auditDescriptor = '$4'}) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+auditRequest -> 'AuditCapToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther
+ : {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther
+ : {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} .
+
+auditOther -> terminationID :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = []}} .
+auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = '$3'}} .
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor : {modemDescriptor, '$1'} .
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} . %% IGv11
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT'
+ : #'AuditDescriptor'{auditToken = '$3'} .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+%%
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken .
+auditItem -> 'EventBufferToken' : eventBufferToken .
+auditItem -> 'EventsToken' : eventsToken .
+%%
+%% IGv11 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' terminationID
+ 'LBRKT' notifyRequestBody 'RBRKT'
+ : make_commandRequest({notifyReq, '$1'},
+ setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) .
+
+notifyRequestBody -> observedEventsDescriptor
+ : #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor
+ : #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody
+ : {notifyReply,
+ #'NotifyReply'{terminationID = ['$3'],
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID
+ 'LBRKT' serviceChangeDescriptor 'RBRKT'
+ : make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = ['$3'],
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody
+ : {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = ['$3'],
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT'
+ : {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT'
+ : {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT'
+ : #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT'
+ : ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat
+ : ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-onc .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs} } .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue : '$2' .
+
+parmValue -> 'NEQUAL' value
+ : #'PropertyParm'{value = ['$2'], extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value
+ : #'PropertyParm'{value = ['$2'], extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value
+ : #'PropertyParm'{value = ['$2'], extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT'
+ : #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value : #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT'
+ : ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' .
+
+serviceState -> 'TestToken' : test .
+serviceState -> 'OutOfSvcToken' : outOfSvc .
+serviceState -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' .
+
+eventBufferControlState -> 'OffToken' : off .
+eventBufferControlState -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList
+ : #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' :
+ #'RequestedEvent'{evParList = []} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' :
+ [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT' :
+ {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' :
+ {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT' :
+ {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent
+ secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents :
+ ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody :
+ setelement(#'SecondRequestedEvent'.pkgdName,
+ '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter
+ secondEventParameters 'RBRKT' :
+ merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' :
+ #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters :
+ ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT' :
+ {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken :
+ ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' : ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' :
+ [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther
+%% / notifyCompletion / KeepActiveToken
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason) RBRKT
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken
+%% / InterruptByNewSignalsDescrToken
+%% / OtherReasonToken )
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID : {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken : {duration, ensure_uint16('$3')} .
+sigParameter -> safeToken parmValue : {other, ensure_NAME('$1'), '$2'}.
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT'
+ : {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms : ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+observedEvent -> observedEventTimeStamp optSep pkgdName observedEventBody :
+ merge_observed_event('$4', '$3', '$1') .
+observedEvent -> pkgdName observedEventBody :
+ merge_observed_event('$2', '$1', asn1_NOVALUE) .
+
+observedEventTimeStamp -> timeStamp optSep 'COLON' : '$1' .
+observedEventTimeStamp -> '$empty' : asn1_NOVALUE .
+
+observedEventBody -> 'LBRKT' observedEventParameter observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms :
+ #'ModemDescriptor'{mtl = ['$3'],
+ mpl = '$4'} .
+
+%% at-most-once of each modem type exept for extensionParameter
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms :
+ #'ModemDescriptor'{mtl = ['$3' | '$4'],
+ mpl = '$6'} .
+
+modemTypeList -> 'COMMA' modemType modemTypeList : ['$2' | '$3'] .
+modemTypeList -> '$empty' : [] .
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' : ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] .
+propertyParms -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+modemType -> safeToken : ensure_modemType('$1').
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' : ensure_DMD('$1') .
+
+%% ; at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp,'$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber : {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'}.
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'}.
+servChgReplyParm -> timeStamp : {time_stamp,'$1'}.
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple
+ topologyTripleList 'RBRKT' : ['$3' | '$4'] .
+
+terminationA -> terminationID : '$1' .
+
+terminationB -> terminationID : '$1' .
+
+topologyTriple -> terminationA 'COMMA' terminationB 'COMMA'
+ topologyDirection :
+ #'TopologyRequest'{terminationFrom = '$1',
+ terminationTo = '$3',
+ topologyDirection = '$5'} .
+
+topologyTripleList -> '$empty' : [] .
+topologyTripleList -> 'COMMA' topologyTriple topologyTripleList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : bothway .
+topologyDirection -> 'IsolateToken' : isolate .
+topologyDirection -> 'OnewayToken' : oneway .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' : ensure_value('$1') .
+value -> safeToken : ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+safeToken2 -> 'ContextAuditToken' : '$1' .
+safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+safeToken2 -> 'EmergencyToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+safeToken2 -> 'EventBufferToken' : '$1' .
+safeToken2 -> 'EventsToken' : '$1' .
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+safeToken2 -> 'ModeToken' : '$1' .
+safeToken2 -> 'ModifyToken' : '$1' .
+safeToken2 -> 'ModemToken' : '$1' .
+safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'ObservedEventsToken' : '$1' .
+safeToken2 -> 'OnewayToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+safeToken2 -> 'ReservedGroupToken' : '$1' .
+safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+%% <OTP-7534>
+safeToken2 -> 'AndAUDITSelectToken' : '$1' . % v3
+safeToken2 -> 'BothToken' : '$1' . % v3
+safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextListToken' : '$1' . % v3
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'EmergencyOffToken' : '$1' . % v3
+safeToken2 -> 'EmergencyValueToken' : '$1' . % v3
+safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'IntsigDelayToken' : '$1' . % v3
+safeToken2 -> 'IterationToken' : '$1' . % v3
+safeToken2 -> 'MessageSegmentToken' : '$1' . % v3
+safeToken2 -> 'NeverNotifyToken' : '$1' . % v3
+safeToken2 -> 'NotifyImmediateToken' : '$1' . % v3
+safeToken2 -> 'NotifyRegulatedToken' : '$1' . % v3
+safeToken2 -> 'Nx64kToken' : '$1' . % v2
+safeToken2 -> 'OnewayBothToken' : '$1' . % v3
+safeToken2 -> 'OnewayExternalToken' : '$1' . % v3
+safeToken2 -> 'OrAUDITselectToken' : '$1' . % v3
+safeToken2 -> 'RequestIDToken' : '$1' . % v3
+safeToken2 -> 'ResetEventsDescriptorToken' : '$1' . % v3
+safeToken2 -> 'SegmentationCompleteToken' : '$1' . % v3
+safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3
+%% </OTP-7534>
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_v1.hrl").
+
+%%i(F) ->
+%% i(F, []).
+
+%%i(F, A) ->
+%% i(get(dbg), F, A).
+
+%%i(true, F, A) ->
+%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]);
+%%i(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v2.hrl b/lib/megaco/src/text/megaco_text_parser_v2.hrl
new file mode 100644
index 0000000000..e968db398d
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v2.hrl
@@ -0,0 +1,1643 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-define(encoder_version_pre_prev3c,true).
+-include("megaco_text_tokens.hrl").
+
+-define(d(F,A), io:format("DBG:"++F++"~n",A)).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% The values 0x0, 0xFFFFFFFE and 0xFFFFFFFF are reserved.
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and issue the
+ %% the error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when (length(A) =:= 16) ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when (length(A) =:= 16) ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when (length(A) =:= 16) ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when length(Hex4) =< 4, length(Hex4) > 0 ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ (X =/= $X) andalso (X =/= $x) andalso
+ (S =/= $+) andalso (S =/= $-) ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% and since this functon is only used when creating
+%% a ModemDescriptor, iit is removed.
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+%% case Text of
+%% "v32b" -> v32bis;
+%% "v22b" -> v22bis;
+%% "v18" -> v18;
+%% "v22" -> v22;
+%% "v32" -> v32;
+%% "v34" -> v34;
+%% "v90" -> v90;
+%% "v91" -> v91;
+%% "synchisdn" -> synchISDN;
+%% "sn" -> synchISDN;
+%% [$x | _] -> ensure_extensionParameter(Token)
+%% end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ "nx64k" -> nx64k; % v2
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_packagesItem,1}]}).
+-endif.
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (length or content) there is really no point in
+ %% "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+
+%% v2 - start
+
+merge_indAudMediaDescriptor({termStateDescr, Val}) ->
+ #'IndAudMediaDescriptor'{termStateDescr = Val};
+merge_indAudMediaDescriptor({streamParm, Val}) ->
+ #'IndAudMediaDescriptor'{streams = {oneStream, Val}};
+merge_indAudMediaDescriptor({streamDescr, Val}) ->
+ #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}).
+-endif.
+merge_indAudLocalControlDescriptor(Parms) ->
+ do_merge_indAudLocalControlDescriptor(Parms,
+ #'IndAudLocalControlDescriptor'{}).
+
+do_merge_indAudLocalControlDescriptor([Parm | Parms], Desc) ->
+ case Parm of
+ modeToken when Desc#'IndAudLocalControlDescriptor'.streamMode == asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedGroupToken when Desc#'IndAudLocalControlDescriptor'.reserveGroup == asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ reservedValueToken when Desc#'IndAudLocalControlDescriptor'.reserveValue == asn1_NOVALUE ->
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when Desc#'IndAudLocalControlDescriptor'.propertyParms == asn1_NOVALUE ->
+ PropParms = [#'IndAudPropertyParm'{name = Val}],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2);
+ {pkgdName, Val} when is_list(Desc#'IndAudLocalControlDescriptor'.propertyParms) ->
+ PropParms = Desc#'IndAudLocalControlDescriptor'.propertyParms,
+ PropParms2 = [#'IndAudPropertyParm'{name = Val} | PropParms],
+ Desc2 = Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2},
+ do_merge_indAudLocalControlDescriptor(Parms, Desc2)
+ end;
+do_merge_indAudLocalControlDescriptor([], Desc) ->
+ case Desc#'IndAudLocalControlDescriptor'.propertyParms of
+ [_ | _] = PropParms -> % List has more then one element
+ PropParms2= lists:reverse(PropParms),
+ Desc#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+ _ ->
+ Desc
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudLocalParm,1}]}).
+-endif.
+ensure_indAudLocalParm(Token) ->
+ case Token of
+ {safeToken, _Line, "mode"} -> modeToken;
+ {safeToken, _Line, "mo"} -> modeToken;
+ {safeToken, _Line, "reservedgroup"} -> reservedGroupToken;
+ {safeToken, _Line, "rg"} -> reservedGroupToken;
+ {safeToken, _Line, "reservedvalue"} -> reservedValueToken;
+ {safeToken, _Line, "rv"} -> reservedValueToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+merge_indAudTerminationStateDescriptor({pkgdName, Val}) ->
+ PropParm = #'IndAudPropertyParm'{name = Val},
+ #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+ #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+merge_indAudTerminationStateDescriptor(bufferToken) ->
+ #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}).
+-endif.
+merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+ IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+ do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+ IAEBD;
+do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+ IAEBD) ->
+ %% BUGBUG BUGBUG BUGBUG
+ %% This is an ugly hack to allow the eventParamName which only
+ %% exists in the text encoding...
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+ensure_indAudSignalListParm(SIG) when is_record(SIG, 'Signal') ->
+ ensure_indAudSignal(SIG).
+
+ensure_indAudSignal(#'Signal'{signalName = SignalName,
+ streamID = asn1_NOVALUE,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = []}) ->
+ #'IndAudSignal'{signalName = SignalName}.
+
+
+ensure_IADMD({_TokenTag, _Line,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE}}) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+merge_indAudPackagesDescriptor(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudTerminationStateParm,1}]}).
+-endif.
+ensure_indAudTerminationStateParm(Token) ->
+ case Token of
+ {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+ {safeToken, _Line, "si"} -> serviceStatesToken;
+ {safeToken, _Line, "buffer"} -> bufferToken;
+ {safeToken, _Line, "bf"} -> bufferToken;
+ PkgdName -> {pkgdName,
+ ensure_pkgdName(PkgdName)}
+ end.
+
+
+%% Types modified by v2:
+
+merge_auditDescriptor([]) ->
+ #'AuditDescriptor'{};
+merge_auditDescriptor(Tokens) when is_list(Tokens) ->
+ case lists:keysearch(terminationAudit, 1, Tokens) of
+ {value, {terminationAudit, TA}} ->
+ case lists:keydelete(terminationAudit, 1, Tokens) of
+ [] ->
+ #'AuditDescriptor'{auditPropertyToken = TA};
+ AuditTokens ->
+ #'AuditDescriptor'{auditToken = AuditTokens,
+ auditPropertyToken = TA}
+ end;
+ false ->
+ #'AuditDescriptor'{auditToken = Tokens}
+ end;
+merge_auditDescriptor(_) ->
+ #'AuditDescriptor'{}.
+
+
+%% v2 - end
+
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)
+ andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE)) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE)) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeReason == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeDelay == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeMethod == undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.timeStamp == asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+%% OTP-5353.
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE)
+ andalso is_atom(Val)) ->
+ SCI = #'AuditDescriptor'{auditToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when ((SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE)
+ andalso is_tuple(Val)) ->
+ SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor')
+ andalso is_atom(Val)) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditToken,
+ SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor')
+ andalso is_tuple(Val)) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditPropertyToken,
+ SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp;
+ audit_item ->
+ SCP#'ServiceChangeParm'.serviceChangeInfo
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE,
+ SCRP0#'ServiceChangeResParm'.serviceChangeAddress == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId == asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp == asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_profile,1}]}).
+-endif.
+ensure_profile({_TokenTag, Line, Text}) ->
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, StreamId} when Sig#'Signal'.streamID == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = StreamId}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion == asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive == asn1_NOVALUE->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Duration},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ durationTimer = [],
+ digitMapBody = asn1_NOVALUE} ->
+ asn1_NOVALUE;
+ #'DigitMapValue'{durationTimer = Body,
+ digitMapBody = Duration} = DMV ->
+ %% Convert to version 1 DigitMapValue
+ DMV#'DigitMapValue'{digitMapBody = Body,
+ durationTimer = Duration};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation == asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, StreamId, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], StreamId, EPL, RA, HasA) ->
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM == asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, StreamId, EPL, RA2, yes);
+ {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewStreamId, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, StreamId, [EP | EPL], RA, HasA);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], StreamId, EPL, RA, yes) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], StreamId, EPL, _RA, no) ->
+ #'RequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, StreamId, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], StreamId, EPL, SRA, HasA) ->
+ case H of
+ keepActive when SRA#'SecondRequestedActions'.keepActive == asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor == asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM == asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, StreamId, EPL, SRA2, yes);
+ {stream, NewStreamId} when StreamId == asn1_NOVALUE ->
+ do_merge_secondEventParameters(T, NewStreamId, EPL, SRA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, StreamId, [EP | EPL], SRA, HasA);
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], StreamId, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], StreamId, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = StreamId,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ ensure_transactionAck2(Text, []).
+
+ensure_transactionAck2([], Acc) ->
+ Id = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ensure_transactionAck2([$- | Id2], Acc) ->
+ Id1 = lists:reverse(Acc),
+ #'TransactionAck'{firstAck = ensure_transactionID(Id1),
+ lastAck = ensure_transactionID(Id2)};
+ensure_transactionAck2([H|T], Acc) ->
+ ensure_transactionAck2(T, [H|Acc]).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_requests,2}]}).
+-endif.
+merge_action_requests(CtxId, Items) ->
+ CtxReq = #'ContextRequest'{},
+ CtxAuditReq = asn1_NOVALUE,
+ CmdReq = [],
+ TopReq = [],
+ do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, Items).
+
+do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, [H | T]) ->
+ case H of
+ _ when is_record(H, 'CommandRequest') ->
+ do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, [H | CmdReq], TopReq, T);
+
+ {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+ do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+ TopReq, T);
+ {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+ do_merge_action_requests(CtxId, CtxReq2, CtxAuditReq, CmdReq,
+ TopReq, T);
+ {topology, Desc} ->
+ TopReq2 = Desc ++ TopReq, %% OTP-4088
+ do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq,
+ TopReq2, T);
+
+ {contextAudit, CAs} ->
+ CtxAuditReq2 = merge_context_attr_audit_request(CtxAuditReq, CAs),
+ do_merge_action_requests(CtxId, CtxReq, CtxAuditReq2, CmdReq,
+ TopReq, T)
+
+ end;
+do_merge_action_requests(CtxId, CtxReq, CtxAuditReq, CmdReq, TopReq, []) ->
+ #'ActionRequest'{contextId = CtxId,
+ contextRequest = strip_contextRequest(CtxReq, TopReq),
+ contextAttrAuditReq = strip_contextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReq)}.
+
+
+merge_context_attr_audit_request(asn1_NOVALUE, CAs) ->
+ merge_context_attr_audit_request(#'ContextAttrAuditRequest'{}, CAs);
+merge_context_attr_audit_request(CAAR, [H|T]) ->
+ CAAR2 =
+ case H of
+ priorityAudit when CAAR#'ContextAttrAuditRequest'.priority == asn1_NOVALUE ->
+ CAAR#'ContextAttrAuditRequest'{priority = 'NULL'};
+
+ priorityAudit ->
+ Prio = CAAR#'ContextAttrAuditRequest'.priority,
+ exit({only_once, priorityAudit, Prio});
+
+ emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency == asn1_NOVALUE ->
+ CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'};
+
+ emergencyAudit ->
+ Em = CAAR#'ContextAttrAuditRequest'.emergency,
+ exit({only_once, emergencyAudit, Em});
+
+ topologyAudit when CAAR#'ContextAttrAuditRequest'.topology == asn1_NOVALUE ->
+ CAAR#'ContextAttrAuditRequest'{topology = 'NULL'};
+
+ topologyAudit ->
+ Top = CAAR#'ContextAttrAuditRequest'.topology,
+ exit({only_once, topologyAudit, Top})
+
+ end,
+ merge_context_attr_audit_request(CAAR2, T);
+merge_context_attr_audit_request(CAAR, []) ->
+ CAAR.
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(ReplyList) ->
+ CtxReq = #'ContextRequest'{},
+ TopReq = [],
+ CmdList = [],
+ case lists:reverse(ReplyList) of
+ [ED|RL2] when is_record(ED, 'ErrorDescriptor') ->
+ AR = do_merge_action_reply(lists:reverse(RL2),
+ CtxReq, TopReq, CmdList),
+ AR#'ActionReply'{errorDescriptor = ED};
+ _ ->
+ do_merge_action_reply(ReplyList, CtxReq, TopReq, CmdList)
+ end.
+
+do_merge_action_reply([H | T], CtxReq, TopReq, CmdList) ->
+ case H of
+ {command, Cmd} ->
+ do_merge_action_reply(T, CtxReq, TopReq, [Cmd | CmdList]);
+ {context, Ctx} ->
+ case Ctx of
+ {priority, Int} when CtxReq#'ContextRequest'.priority == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{priority = Int},
+ do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+ {emergency, Bool} when CtxReq#'ContextRequest'.emergency == asn1_NOVALUE ->
+ CtxReq2 = CtxReq#'ContextRequest'{emergency = Bool},
+ do_merge_action_reply(T, CtxReq2, TopReq, CmdList);
+ {topology, Desc} ->
+ TopReq2 = Desc ++ TopReq, %% OTP-4088
+ do_merge_action_reply(T, CtxReq, TopReq2, CmdList)
+ end
+ end;
+do_merge_action_reply([], CtxReq, TopReq, CmdList) ->
+ #'ActionReply'{contextReply = strip_contextRequest(CtxReq, TopReq),
+ commandReply = lists:reverse(CmdList)}.
+
+strip_contextRequest(R, TopReq)
+ when ((R#'ContextRequest'.priority =:= asn1_NOVALUE) andalso
+ (R#'ContextRequest'.emergency =:= asn1_NOVALUE) andalso
+ (TopReq =:= [])) ->
+ asn1_NOVALUE;
+strip_contextRequest(R, []) ->
+ R#'ContextRequest'{topologyReq = asn1_NOVALUE};
+strip_contextRequest(R, TopReq) ->
+ R#'ContextRequest'{topologyReq = TopReq}. %% OTP-4088
+
+
+strip_contextAttrAuditRequest(R)
+ when ((R#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE) andalso
+ (R#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE) andalso
+ (R#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE)) ->
+ asn1_NOVALUE;
+strip_contextAttrAuditRequest(R) ->
+ R.
+
+merge_AmmRequest_descriptors([], Acc) ->
+ lists:reverse(Acc);
+merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, Acc);
+merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor,
+ 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ Groups = [],
+ parse_prop_name(Text, Group, Groups).
+
+parse_prop_name([Char | Rest] = All, Group, Groups) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group, Groups);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group, Groups);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group, Groups)
+ end;
+parse_prop_name([] = All, Group, Groups) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group, Groups).
+
+do_parse_prop_name([Char | Rest], Name, Group, Groups)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ Groups2 = [lists:reverse(Group) | Groups],
+ Group2 = [],
+ parse_prop_value(Rest, Name, Group2, Groups2);
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group, Groups)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], [], Groups) ->
+ lists:reverse(Groups);
+do_parse_prop_name([], [], Group, Groups) ->
+ Group2 = lists:reverse(Group),
+ lists:reverse([Group2 | Groups]);
+do_parse_prop_name([], Name, Group, Groups) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,4}]}).
+-endif.
+parse_prop_value(Chars, Name, Group, Groups) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group, Groups).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group], Groups);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
+ end;
+do_parse_prop_value([], Name, Value, Group, Groups) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ Groups.
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{do_ensure_prop_groups,1}]}).
+%% -endif.
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+
+% d(F) ->
+% d(F, []).
+
+% d(F, A) ->
+% d(get(dbg), F, A).
+
+% d(true, F, A) ->
+% io:format("~p:" ++ F ++ "~n", [?MODULE|A]);
+% d(_, _, _) ->
+% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v2.yrl b/lib/megaco/src/text/megaco_text_parser_v2.yrl
new file mode 100644
index 0000000000..8152cc4e9b
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v2.yrl
@@ -0,0 +1,1538 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 135.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ authenticationHeader
+ commandReply
+ commandReplyList
+ commandRequest
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextID
+ contextProperty
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlState
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStream
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+
+ %% v2 - start
+ indAudauditReturnParameter
+ indAuddigitMapDescriptor
+ indAudeventBufferDescriptor
+ indAudeventSpec
+ indAudeventSpecParameter
+ %% indAudeventSpecParameterList
+ indAudeventsDescriptor
+ indAudlocalControlDescriptor
+ indAudlocalParm
+ indAudlocalParmList
+ indAudmediaDescriptor
+ indAudmediaParm
+ %% indAudmediaParmList
+ indAudpackagesDescriptor
+ indAudrequestedEvent
+ indAudsignalsDescriptor
+ indAudsignalList
+ %% indAudsignalListParm
+ indAudsignalParm
+ %% indAudsignalRequest
+ indAudstreamDescriptor
+ indAudstreamParm
+ indAudstatisticsDescriptor
+ indAudterminationAudit
+ indAudterminationAuditList
+ indAudterminationStateDescriptor
+ indAudterminationStateParm
+ %% indAudterminationStateParmList
+ optIndAudeventSpecParameter
+ optIndAudsignalParm
+ %% v2 - end
+
+
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor % Deprecated as of Corr 1
+ modemType % Deprecated as of Corr 1
+ modemTypeList % Deprecated as of Corr 1
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ % observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceState
+ serviceStates
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ terminationA
+ terminationAudit
+ terminationB
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyTriple
+ topologyTripleList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ %% 'ContextAttrToken' % OTP-7138: See OTP-7534 below
+ 'ContextAuditToken'
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'EmergencyOffToken'
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'ImmAckRequiredToken'
+ 'InSvcToken'
+ 'InactiveToken'
+ %% 'IndAudTerminationAuditToken' %% testing fix...
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'IsolateToken'
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NotifyCompletionToken'
+ 'NotifyToken'
+ 'Nx64kToken' %% v2
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ 'AndAUDITSelectToken' %% OTP-7534: v3-fix
+ 'BothToken' %% OTP-7534: v3-fix
+ 'ContextAttrToken' %% OTP-7534: v3-fix
+ 'ContextListToken' %% OTP-7534: v3-fix
+ 'DirectionToken' %% OTP-7534: v3-fix
+ %% 'EmergencyOffToken' %% OTP-7534: v3-fix
+ 'EmergencyValueToken' %% OTP-7534: v3-fix
+ 'ExternalToken' %% OTP-7534: v3-fix
+ 'IEPSToken' %% OTP-7534: v3-fix
+ 'IntsigDelayToken' %% OTP-7534: v3-fix
+ 'InternalToken' %% OTP-7534: v3-fix
+ 'IterationToken' %% OTP-7534: v3-fix
+ 'MessageSegmentToken' %% OTP-7534: v3-fix
+ 'NeverNotifyToken' %% OTP-7534: v3-fix
+ 'NotifyImmediateToken' %% OTP-7534: v3-fix
+ 'NotifyRegulatedToken' %% OTP-7534: v3-fix
+ 'OnewayBothToken' %% OTP-7534: v3-fix
+ 'OnewayExternalToken' %% OTP-7534: v3-fix
+ 'OrAUDITselectToken' %% OTP-7534: v3-fix
+ 'RequestIDToken' %% OTP-7534: v3-fix
+ 'ResetEventsDescriptorToken' %% OTP-7534: v3-fix
+ 'SegmentationCompleteToken' %% OTP-7534: v3-fix
+ 'ServiceChangeIncompleteToken' %% OTP-7534: v3-fix
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody : ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck transactionAckList 'RBRKT' : ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT'
+ : #'TransactionPending'{transactionId = ensure_transactionID('$3') } .
+
+%% OTP-4359: We have the first two rule's in order to be able
+%% to handle chapter 8.1.1 in RFC3525
+transactionRequest -> 'TransToken'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL'
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT'
+ : #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestItem actionRequestItems 'RBRKT'
+ : merge_action_requests('$3', ['$5' | '$6']) .
+
+actionRequestItems -> 'COMMA' actionRequestItem actionRequestItems : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+actionRequestItem -> contextProperty : '$1' .
+actionRequestItem -> contextAudit : '$1' .
+actionRequestItem -> commandRequest : '$1' .
+
+%% at-most-once
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+contextProperty -> 'EmergencyOffToken' : {emergency, false}.
+
+contextAudit -> 'ContextAuditToken'
+ 'LBRKT' contextAuditProperty contextAuditProperties 'RBRKT'
+ : {contextAudit, ['$3' | '$4']} .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties
+ : ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once .
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID
+ 'LBRKT'
+ optImmAckRequired transactionReplyBody
+ 'RBRKT'
+ : #'TransactionReply'{transactionId = '$3',
+ immAckRequired = '$5',
+ transactionResult = '$6'} .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor : {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReply commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+commandReply -> serviceChangeReply : {command, '$1'} .
+commandReply -> auditReply : {command, '$1'} .
+commandReply -> ammsReply : {command, '$1'} .
+commandReply -> notifyReply : {command, '$1'} .
+commandReply -> contextProperty : {context, '$1'} .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ ['$2'] .
+commandReplyList -> 'COMMA' commandReply commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' terminationID ammRequestBody :
+ Descs = merge_AmmRequest_descriptors('$4', []),
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = ['$3'],
+ descriptors = Descs}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, deprecated}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' terminationID ammsReplyBody
+ : {'$1', #'AmmsReply'{terminationID = ['$3'],
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL' terminationID optAuditDescriptor
+ : make_commandRequest({subtractReq, '$1'},
+ #'SubtractRequest'{terminationID = ['$3'],
+ auditDescriptor = '$4'}) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+auditRequest -> 'AuditCapToken' 'EQUAL'
+ terminationID optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ #'AuditRequest'{terminationID = '$3',
+ auditDescriptor = '$4'}) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit
+ : {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther
+ : {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther
+ : {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList : {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' : {contextAuditResult, '$2'} .
+
+auditOther -> terminationID :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = []}} .
+auditOther -> terminationID 'LBRKT' terminationAudit 'RBRKT' :
+ {auditResult,
+ #'AuditResult'{terminationID = '$1',
+ terminationAuditResult = '$3'}} .
+
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor.
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} .
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' :
+ merge_auditDescriptor('$3') .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken.
+auditItem -> 'EventBufferToken' : eventBufferToken.
+auditItem -> 'EventsToken' : eventsToken .
+auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2
+%%
+%% IGv11 - end
+
+
+%% v2 - start
+%%
+indAudterminationAudit -> indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$1' | '$2'] .
+
+% testing fix...
+% indAudterminationAudit -> 'IndAudTerminationAuditToken'
+% indAudauditReturnParameter
+% indAudterminationAuditList
+% : ['$2' | '$3'] .
+
+indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$2' | '$3'] .
+indAudterminationAuditList -> '$empty' : [] .
+
+indAudauditReturnParameter -> indAudmediaDescriptor
+ : {indAudMediaDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventsDescriptor
+ : {indAudEventsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudsignalsDescriptor
+ : {indAudSignalsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAuddigitMapDescriptor
+ : {indAudDigitMapDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventBufferDescriptor
+ : {indAudEventBufferDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudstatisticsDescriptor
+ : {indAudStatisticsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudpackagesDescriptor
+ : {indAudPackagesDescriptor, '$1'} .
+
+
+indAudmediaDescriptor -> 'MediaToken' 'LBRKT'
+ indAudmediaParm 'RBRKT'
+ : merge_indAudMediaDescriptor('$3') .
+
+%% at-most-once per item
+%% and either streamParm or streamDescriptor but not both
+%% <rambling>
+%% This is solved in another way in text than in binary :(
+%% Instead of having a list of indAudmediaParm we put this
+%% stuff in the indAudterminationAuditList with several
+%% indAudmediaDescriptor's.
+%% </rambling>
+%%
+
+indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} .
+indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} .
+indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} .
+
+%% at-most-once
+indAudstreamParm -> indAudlocalControlDescriptor
+ : #'IndAudStreamParms'{localControlDescriptor = '$1'} .
+
+indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' indAudstreamParm 'RBRKT'
+ : #'IndAudStreamDescriptor'{streamID = '$3',
+ streamParms = '$5'} .
+
+
+indAudlocalControlDescriptor -> 'LocalControlToken'
+ 'LBRKT' indAudlocalParm indAudlocalParmList 'RBRKT' :
+ merge_indAudLocalControlDescriptor(['$3'| '$4']) .
+
+indAudlocalParmList -> 'COMMA' indAudlocalParm indAudlocalParmList : ['$2'| '$3'] .
+indAudlocalParmList -> '$empty' : [] .
+
+%% at-most-once per item
+%%
+indAudlocalParm -> safeToken : ensure_indAudLocalParm('$1') .
+
+indAudterminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' indAudterminationStateParm 'RBRKT'
+ :
+ merge_indAudTerminationStateDescriptor('$3') .
+
+%% at-most-once per item
+%%
+
+indAudterminationStateParm -> safeToken :
+ ensure_indAudTerminationStateParm('$1') .
+
+indAudeventBufferDescriptor -> 'EventBufferToken'
+ 'LBRKT' indAudeventSpec 'RBRKT' : '$3' .
+
+indAudeventSpec -> pkgdName optIndAudeventSpecParameter
+ : merge_indAudEventBufferDescriptor('$1','$2') .
+
+optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT'
+ : '$2' .
+optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE .
+
+
+indAudeventSpecParameter -> eventStream : {streamID, '$1'} .
+indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} .
+
+indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' indAudrequestedEvent 'RBRKT'
+ : #'IndAudEventsDescriptor'{requestID = '$3',
+ pkgdName = '$5'} .
+
+indAudrequestedEvent -> pkgdName : '$1' .
+
+
+indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' .
+
+
+optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE .
+optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' .
+
+indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} .
+indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} .
+
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm 'RBRKT' :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3'),
+ signalList =
+ ensure_indAudSignalListParm('$5')} .
+
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_IADMD('$1') .
+
+indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' :
+ #'IndAudStatisticsDescriptor'{statName = '$3'} .
+
+indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT'
+ : merge_indAudPackagesDescriptor('$3') .
+
+eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' .
+
+
+%%
+%% v2 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' terminationID
+ 'LBRKT' notifyRequestBody 'RBRKT'
+ : make_commandRequest({notifyReq, '$1'},
+ setelement(#'NotifyRequest'.terminationID, '$5', ['$3'])) .
+
+notifyRequestBody -> observedEventsDescriptor
+ : #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor
+ : #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' terminationID notifyReplyBody
+ : {notifyReply,
+ #'NotifyReply'{terminationID = ['$3'],
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' terminationID
+ 'LBRKT' serviceChangeDescriptor 'RBRKT'
+ : make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = ['$3'],
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' terminationID serviceChangeReplyBody
+ : {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = ['$3'],
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT'
+ : {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT'
+ : {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' : {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT' errorText 'RBRKT'
+ : #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+%% '-' is used for NULL context
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+%% terminationIDList -> LBRKT terminationID *(COMMA terminationID) RBRKT .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT'
+ : ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat
+ : ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-onc .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue :
+ setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue :
+ '$2' .
+
+parmValue -> 'NEQUAL' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT' :
+ #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT' :
+ #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT' :
+ #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value :
+ #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec eventSpecList 'RBRKT'
+ : ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceState : '$3' .
+
+serviceState -> 'TestToken' : test .
+serviceState -> 'OutOfSvcToken' : outOfSvc .
+serviceState -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlState : '$3' .
+
+eventBufferControlState -> 'OffToken' : off .
+eventBufferControlState -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList :
+ #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT'
+ : {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT'
+ : {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody
+ : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT'
+ : merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' :
+ ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' : [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther
+%% / notifyCompletion / KeepActiveToken
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason) RBRKT
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken
+%% / InterruptByNewSignalsDescrToken
+%% / OtherReasonToken )
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID : {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType : {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken : {duration, ensure_uint16('$3')} .
+sigParameter -> safeToken parmValue : {other, ensure_NAME('$1'), '$2'}.
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT'
+ : {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms :
+ ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+
+observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody :
+ merge_observed_event('$6', '$5', '$1') .
+observedEvent -> optSep pkgdName observedEventBody :
+ merge_observed_event('$3', '$2', asn1_NOVALUE) .
+
+observedEventBody -> 'LBRKT' observedEventParameter
+ observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+%% Deprecated as of Corr 1
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms .
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms.
+modemTypeList -> 'COMMA' modemType modemTypeList.
+modemTypeList -> '$empty'.
+modemType -> safeToken.
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParms 'RBRKT' :
+ ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> 'COMMA' propertyParm propertyParms : ['$2' | '$3'] .
+propertyParms -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_DMD('$1') .
+
+%% each parameter at-most-once, except auditItem
+%% at most one of either serviceChangeAddress or serviceChangeMgcId but
+%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp, '$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken : ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber :
+ {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'} .
+servChgReplyParm -> timeStamp : {time_stamp,'$1'} .
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value
+ : #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT' topologyTriple
+ topologyTripleList 'RBRKT' : ['$3' | '$4'] .
+
+terminationA -> terminationID : '$1' .
+
+terminationB -> terminationID : '$1' .
+
+topologyTriple -> terminationA 'COMMA' terminationB 'COMMA'
+ topologyDirection 'COMMA' eventStream :
+ #'TopologyRequest'{terminationFrom = '$1',
+ terminationTo = '$3',
+ topologyDirection = '$5',
+ streamID = '$7'} .
+topologyTriple -> terminationA 'COMMA' terminationB 'COMMA'
+ topologyDirection :
+ #'TopologyRequest'{terminationFrom = '$1',
+ terminationTo = '$3',
+ topologyDirection = '$5'} .
+
+topologyTripleList -> '$empty' : [] .
+topologyTripleList -> 'COMMA' topologyTriple topologyTripleList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : bothway .
+topologyDirection -> 'IsolateToken' : isolate .
+topologyDirection -> 'OnewayToken' : oneway .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' :
+ ensure_value('$1') .
+value -> safeToken :
+ ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% safeToken2 -> 'ContextAttrToken' : '$1' .
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% v2-safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+safeToken2 -> 'EmergencyToken' : '$1' .
+safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% v2-safeToken2 -> 'EventBufferToken' : '$1' .
+%% v2-safeToken2 -> 'EventsToken' : '$1' .
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% v2-safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+safeToken2 -> 'ModeToken' : '$1' .
+safeToken2 -> 'ModifyToken' : '$1' .
+%% v2-safeToken2 -> 'ModemToken' : '$1' .
+safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% v2-safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64kToken' : '$1' .
+%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' .
+safeToken2 -> 'OnewayToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% v2-safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+safeToken2 -> 'ReservedGroupToken' : '$1' .
+safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% v2-safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% v2-safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+safeToken2 -> 'TimeStampToken' : '$1' .
+safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+%% <OTP-7534>
+safeToken2 -> 'AndAUDITSelectToken' : '$1' .
+safeToken2 -> 'BothToken' : '$1' .
+safeToken2 -> 'ContextAttrToken' : '$1' .
+safeToken2 -> 'ContextListToken' : '$1' .
+safeToken2 -> 'DirectionToken' : '$1' .
+%% safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'EmergencyValueToken' : '$1' .
+safeToken2 -> 'ExternalToken' : '$1' .
+safeToken2 -> 'IEPSToken' : '$1' .
+safeToken2 -> 'InternalToken' : '$1' .
+safeToken2 -> 'IntsigDelayToken' : '$1' .
+safeToken2 -> 'IterationToken' : '$1' .
+safeToken2 -> 'MessageSegmentToken' : '$1' .
+safeToken2 -> 'NeverNotifyToken' : '$1' .
+safeToken2 -> 'NotifyImmediateToken' : '$1' .
+safeToken2 -> 'NotifyRegulatedToken' : '$1' .
+safeToken2 -> 'OnewayBothToken' : '$1' .
+safeToken2 -> 'OnewayExternalToken' : '$1' .
+safeToken2 -> 'OrAUDITselectToken' : '$1' .
+safeToken2 -> 'RequestIDToken' : '$1' .
+safeToken2 -> 'ResetEventsDescriptorToken' : '$1' .
+safeToken2 -> 'SegmentationCompleteToken' : '$1' .
+safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' .
+%% </OTP-7534>
+
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_v2.hrl").
+
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v3.hrl b/lib/megaco/src/text/megaco_text_parser_v3.hrl
new file mode 100644
index 0000000000..9f68fb6127
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v3.hrl
@@ -0,0 +1,2002 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose : Define semantic text parser actions
+%%----------------------------------------------------------------------
+
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include("megaco_text_tokens.hrl").
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_safe_token,1}]}).
+-endif.
+make_safe_token(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ {safeToken, Line, Text}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_value,1}]}).
+-endif.
+ensure_value(Token) ->
+ case Token of
+ {safeToken, _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ {'QuotedChars', _Line, Text} when is_list(Text) ->
+ Text; % We really should ensure length
+ Text when is_list(Text) ->
+ Text % We really should ensure length
+ end.
+
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_NAME,1}]}).
+-endif.
+ensure_NAME(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure length and chars
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_requestID,1}]}).
+-endif.
+ensure_requestID(Token) ->
+ case Token of
+ {safeToken, _Line, "*"} ->
+ ?megaco_all_request_id;
+ _ ->
+ ensure_uint32(Token)
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_streamID,1}]}).
+-endif.
+ensure_streamID(StreamId) ->
+ ensure_uint16(StreamId).
+
+ensure_auth_header(SpiToken, SnToken, AdToken) ->
+ Spi = ensure_hex(SpiToken, 8, 8),
+ Sn = ensure_hex(SnToken, 8, 8),
+ Ad = ensure_hex(AdToken, 24, 64),
+ #'AuthenticationHeader'{secParmIndex = Spi, seqNum = Sn, ad = Ad}.
+
+%% ContextID = (UINT32 / "*" / "-" / "$")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_contextID,1}]}).
+-endif.
+ensure_contextID(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ "*" -> ?megaco_all_context_id;
+ "-" -> ?megaco_null_context_id;
+ "\$" -> ?megaco_choose_context_id;
+ Int ->
+ CID = ensure_uint32(Int),
+ if
+ (CID =/= 0) andalso
+ (CID =/= 16#FFFFFFFE) andalso
+ (CID =/= 16#FFFFFFFF) ->
+ CID;
+ true ->
+ return_error(Line, {bad_ContextID, CID})
+ end
+ end.
+
+ensure_domainAddress([{_T, _L, _A} = Addr0], Port) ->
+ Addr = ensure_ip4addr(Addr0),
+ {ip4Address, #'IP4Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress([colon,colon], Port) ->
+ Addr = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}};
+ensure_domainAddress(Addr0, Port) ->
+ Addr = ensure_ip6addr(Addr0),
+ {ip6Address, #'IP6Address'{address = Addr, portNumber = Port}}.
+
+
+ensure_ip4addr(Token) ->
+ {_TokenTag, Line, Addr} = Token,
+ case split_ip4addr_text(Addr, []) of
+ [T1, T2, T3, T4] ->
+ %% We optimize by sending only the text part (Addr) of
+ %% the token to the function.
+ %% If something is wrong, then we do not get a proper
+ %% position and therefor we catch and sendissue the
+ %% the error again (with the proper line number).
+ case (catch [
+ ensure_uint(T1, 0, 255),
+ ensure_uint(T2, 0, 255),
+ ensure_uint(T3, 0, 255),
+ ensure_uint(T4, 0, 255)
+ ]) of
+ A when is_list(A) ->
+ A;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end;
+ _ ->
+ return_error(Line, {bad_IP4address, Addr})
+ end.
+
+split_ip4addr_text([], Acc) ->
+ [ lists:reverse(Acc) ];
+split_ip4addr_text([$. | Rest], Acc) ->
+ [ lists:reverse(Acc) | split_ip4addr_text(Rest, []) ];
+split_ip4addr_text([H | T], Acc) ->
+ split_ip4addr_text(T, [H | Acc]).
+
+
+ensure_ip6addr([colon,colon|T]) ->
+ [H1|T1] = lists:reverse(T),
+ case do_ensure_ip6addr(T1, true, [ensure_hex4_or_ip4addr(H1)], 1) of
+ {true, A} when length(A) =:= 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ lists:duplicate(16 - length(B), 0) ++ B;
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ensure_ip6addr(L) ->
+ case lists:reverse(L) of
+ [colon, colon| T] ->
+ case do_ensure_ip6addr(T, true, [], 1) of
+ {true, A} when length(A) =:= 16 ->
+ A;
+ {true, B} when length(B) < 16 ->
+ B ++ lists:duplicate(16 - length(B), 0);
+ {true, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, C}}})
+ end;
+ [H|L1] -> % A (last element) could be an ip4 address
+ case do_ensure_ip6addr(L1,false,[ensure_hex4_or_ip4addr(H)],1) of
+ {false, A} when length(A) =:= 16 ->
+ A;
+ %% allow a pad even if the address is full (i.e. 16)
+ {true, B} when length(B) =< 17 ->
+ do_ensure_ip6addr_padding(B, 0);
+ {Pad, C} ->
+ throw({error, {?MODULE, {bad_mid_ip6addr_length, Pad, C}}})
+ end
+
+ end.
+
+
+do_ensure_ip6addr([], Pad, Acc, _) ->
+ {Pad, lists:flatten(Acc)};
+do_ensure_ip6addr([colon,colon|T], false, Acc, Line) ->
+ do_ensure_ip6addr(T, true, [pad|Acc], Line);
+do_ensure_ip6addr([colon,colon|T], true, Acc, Line) ->
+ return_error(Line, {bad_mid_duplicate_padding, T, Acc});
+do_ensure_ip6addr([colon|T], Pad, Acc, Line) ->
+ do_ensure_ip6addr(T, Pad, Acc, Line);
+do_ensure_ip6addr([{_, Line, _} = A|T], Pad, Acc, _) ->
+ do_ensure_ip6addr(T, Pad, [ensure_hex4(A)|Acc], Line).
+
+do_ensure_ip6addr_padding([], _) ->
+ [];
+do_ensure_ip6addr_padding([pad|T], N) ->
+ lists:duplicate(16 - (N + length(T)), 0) ++ T;
+do_ensure_ip6addr_padding([H|T], N) ->
+ [H|do_ensure_ip6addr_padding(T, N+1)].
+
+ensure_hex4_or_ip4addr({TokenTag, Line, Addr} = V) ->
+ case string:tokens(Addr, [$.]) of
+ [T1, T2, T3, T4] ->
+ A1 = ensure_uint({TokenTag, Line, T1}, 0, 255),
+ A2 = ensure_uint({TokenTag, Line, T2}, 0, 255),
+ A3 = ensure_uint({TokenTag, Line, T3}, 0, 255),
+ A4 = ensure_uint({TokenTag, Line, T4}, 0, 255),
+ [A1, A2, A3, A4];
+ _ ->
+ ensure_hex4(V)
+ %% %% BMK BMK BMK
+ %% %% Here we should test for hexseq
+ %% return_error(Line, {bad_IP4address, Addr})
+ end.
+
+ensure_hex4({_TokenTag, Line, Hex4})
+ when (length(Hex4) =< 4) andalso (length(Hex4) > 0) ->
+ case (catch do_ensure_hex4(Hex4)) of
+ IL when is_list(IL) andalso (length(IL) =:= 2) ->
+ IL;
+ Error ->
+ return_error(Line, {bad_hex4, Hex4, Error})
+ end.
+
+do_ensure_hex4([_H1, _H2, _H3, _H4] = H) ->
+ hex_to_int(H, []);
+do_ensure_hex4([H2, H3, H4]) ->
+ hex_to_int([$0, H2, H3, H4], []);
+do_ensure_hex4([H3, H4]) ->
+ hex_to_int([$0, $0, H3, H4], []);
+do_ensure_hex4([H4]) ->
+ hex_to_int([$0, $0, $0, H4], []).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_domainName,2}]}).
+-endif.
+ensure_domainName(Token, Port) ->
+ {_TokenTag, _Line, Name} = Token,
+ %% BUGBUG: we should really validate name
+ {domainName, #'DomainName'{name = Name, portNumber = Port}}.
+
+%% extensionParameter= "X" ("-" / "+") 1*6(ALPHA / DIGIT)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_extensionParameter,1}]}).
+-endif.
+ensure_extensionParameter(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case Text of
+ [X, S | _Chars] ->
+ if
+ (X =/= $X) andalso (X =/= $x) andalso
+ (S =/= $+) andalso (S =/= $-) ->
+ return_error(Line, {bad_extension_parameter, Text});
+ true ->
+ {extension_parameter, Text}
+ end;
+ _ ->
+ return_error(Line, {bad_extension_parameter, Text})
+ end.
+
+ensure_message(MegacopToken, MID, Body) ->
+%% #'ServiceChangeProfile'{profileName = Name,
+%% version = Version} =
+%% ensure_profile(MegacopToken),
+%% case Name of
+%% "megaco" ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body};
+%% [$!] ->
+%% #'Message'{version = Version, mId = MID, messageBody = Body}
+%% end.
+ {_TokenTag, Line, Text} = MegacopToken,
+ case split_Megacop(Text, []) of
+ {Name, Version} ->
+ Version2 = ensure_version(Version),
+ case Name of
+ "megaco" ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body};
+ [$!] ->
+ #'Message'{version = Version2,
+ mId = MID,
+ messageBody = Body}
+ end;
+ _ ->
+ return_error(Line, {bad_name_or_version, Text})
+ end.
+
+split_Megacop([], _) ->
+ error;
+split_Megacop([$/ | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_Megacop([H | T], Acc) ->
+ split_Megacop(T, [H | Acc]).
+
+
+%% Corr1:
+%% As of corr 1 ModemDescriptor has been deprecated.
+%% and since this functon is only used when creating
+%% a ModemDescriptor, iit is removed.
+%% modemType = (V32bisToken / V22bisToken / V18Token /
+%% V22Token / V32Token / V34Token / V90Token /
+%% V91Token / SynchISDNToken / extensionParameter)
+%% ensure_modemType({_TokenTag, _Line, Text} = Token) ->
+%% case Text of
+%% "v32b" -> v32bis;
+%% "v22b" -> v22bis;
+%% "v18" -> v18;
+%% "v22" -> v22;
+%% "v32" -> v32;
+%% "v34" -> v34;
+%% "v90" -> v90;
+%% "v91" -> v91;
+%% "synchisdn" -> synchISDN;
+%% "sn" -> synchISDN;
+%% [$x | _] -> ensure_extensionParameter(Token)
+%% end.
+
+%% An mtp address is five octets long
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_mtpAddress,1}]}).
+-endif.
+ensure_mtpAddress(Token) ->
+ {_TokenTag, _Line, Addr} = Token,
+ %% BUGBUG: validate address
+ {mtpAddress, Addr}.
+
+%% MuxType = ( H221Token / H223Token / H226Token / V76Token / extensionParameter )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_muxType,1}]}).
+-endif.
+ensure_muxType(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ case Text of
+ "h221" -> h221;
+ "h223" -> h223;
+ "h226" -> h226;
+ "v76" -> v76;
+ "nx64k" -> nx64k; % v2
+ [$x | _] -> ensure_extensionParameter(Token)
+ end.
+
+%% packagesItem = NAME "-" UINT16
+%% NAME = ALPHA *63(ALPHA / DIGIT / "_" )
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_packagesItem,1}]}).
+-endif.
+ensure_packagesItem(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case split_packagesItem(Text, []) of
+ {Name, Version} ->
+ %% As we don't ensure length of the names, there is no point
+ %% in doing the ensure_NAME thing...
+ #'PackagesItem'{packageName = Name,
+ packageVersion = ensure_uint(Version, 0, 99)};
+ _ ->
+ return_error(Line, {bad_PackagesItem, Text})
+ end.
+
+split_packagesItem([], _) ->
+ error;
+split_packagesItem([$- | Version], Acc) ->
+ {lists:reverse(Acc), Version};
+split_packagesItem([H|T], Acc) ->
+ split_packagesItem(T, [H|Acc]).
+
+
+%% pkgdName = (PackageName / "*") SLASH (ItemID / "*" )
+%% PackageName = NAME
+%% ItemID = NAME
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pkgdName,1}]}).
+-endif.
+ensure_pkgdName(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case ensure_pkgdName(Text, []) of
+ ok ->
+ %% As we don't really do any checks on the strings
+ %% (length or content) there is really no point in
+ %% "ensuring" the name and item part of the
+ %% package name
+ %% ensure_name_or_star(Name),
+ %% ensure_name_or_star(Item),
+ Text;
+ _ ->
+ return_error(Line, {bad_pkgdName, Text})
+ end.
+
+ensure_pkgdName([], _) ->
+ error;
+ensure_pkgdName([$/ | T], Acc)
+ when ((length(T) > 0) andalso (length(Acc) > 0)) ->
+ ok;
+ensure_pkgdName([H | T], Acc) ->
+ ensure_pkgdName(T, [H | Acc]).
+
+
+%% -compile({inline,[{ensure_name_or_star,1}]}).
+%% ensure_name_or_star(Val) ->
+%% %% case Token of
+%% %% {_, _, Name} when Name =:= "*" ->
+%% %% Name;
+%% %% _ ->
+%% %% ensure_NAME(Token)
+%% %% end.
+%% if
+%% Val =:= "*" ->
+%% Val;
+%% true ->
+%% %% as we don't really validate the text part of the token(s),
+%% %% we can just return the value assuming it to be correct...
+%% Val
+%% end.
+
+
+%% v2 - start
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudMediaDescriptor,1}]}).
+-endif.
+merge_indAudMediaDescriptor(Vals) ->
+ merge_indAudMediaDescriptor(Vals, #'IndAudMediaDescriptor'{}).
+
+merge_indAudMediaDescriptor(
+ [], #'IndAudMediaDescriptor'{streams = Streams1} = D) ->
+ Streams2 =
+ case Streams1 of
+ {multiStream, Descs} ->
+ {multiStream, lists:reverse(Descs)};
+ _ ->
+ Streams1
+ end,
+ D#'IndAudMediaDescriptor'{streams = Streams2};
+merge_indAudMediaDescriptor([{termStateDescr, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.termStateDescr =:= asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{termStateDescr = Val},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamParm, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.streams =:= asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{streams = {oneStream, Val}},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamDescr, Val}|Vals], D)
+ when D#'IndAudMediaDescriptor'.streams =:= asn1_NOVALUE ->
+ D2 = #'IndAudMediaDescriptor'{streams = {multiStream, [Val]}},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{streamDescr, Val}|Vals],
+ #'IndAudMediaDescriptor'{streams = Streams1} = D1) ->
+ Streams2 =
+ case Streams1 of
+ {multiStream, Descs} ->
+ {multiStream, [Val|Descs]};
+ _ ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
+ Val, Streams1})
+ end,
+ D2 = D1#'IndAudMediaDescriptor'{streams = Streams2},
+ merge_indAudMediaDescriptor(Vals, D2);
+merge_indAudMediaDescriptor([{Tag, Val}|_], D) ->
+ case Tag of
+ termStateDescr ->
+ return_error(0, {bad_IndAudMediaDescriptor_termStateDescr,
+ Val, D#'IndAudMediaDescriptor'.termStateDescr});
+ streamParm ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamParm,
+ Val, D#'IndAudMediaDescriptor'.streams});
+ streamDescr ->
+ return_error(0, {bad_IndAudMediaDescriptor_streamDescr,
+ Val, D#'IndAudMediaDescriptor'.streams});
+ _ ->
+ return_error(0, {bad_IndAudMediaDescriptor_tag, Tag, Val})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudLocalControlDescriptor,1}]}).
+-endif.
+merge_indAudLocalControlDescriptor(Parms) ->
+ merge_indAudLocalControlDescriptor(Parms,
+ #'IndAudLocalControlDescriptor'{},
+ asn1_NOVALUE).
+
+merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) ->
+ D2 = D#'IndAudLocalControlDescriptor'{streamMode = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([modeToken | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) ->
+ merge_indAudLocalControlDescriptor(Parms, D, PP);
+
+merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamMode =:= asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) ->
+ D2 =
+ case Val of
+ {equal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamModeSel = Val2};
+ {inequal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamModeSel = Val2}
+ end,
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([{mode, Val} | Parms], D, PP)
+ when (D#'IndAudLocalControlDescriptor'.streamModeSel =:= asn1_NOVALUE) ->
+ D2 =
+ case Val of
+ {equal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ streamModeSel = Val2};
+ {inequal, Val2} ->
+ D#'IndAudLocalControlDescriptor'{streamMode = asn1_NOVALUE,
+ streamModeSel = Val2}
+ end,
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([reservedGroupToken | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{reserveGroup = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+merge_indAudLocalControlDescriptor([reservedValueToken | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{reserveValue = 'NULL'},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP);
+
+%% This is really wierd in the standard, so at this point this is the
+%% best I can do... BUGBUG BUGBUG BUGBUG
+%%
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, asn1_NOVALUE) ->
+ PP = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D, PP);
+
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP)
+ when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE ->
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP]},
+ PP2 = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP2);
+
+merge_indAudLocalControlDescriptor([{name, Val} | Parms], D, PP) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP|PPs]},
+ PP2 = #'IndAudPropertyParm'{name = Val},
+ merge_indAudLocalControlDescriptor(Parms, D2, PP2);
+
+%% BUGBUG BUGBUG I cannot construct a proper IndAudPropertyParm with
+%% just the prop (the mandatory name part is missing), so for now I
+%% assume that it this has been used, then the name part
+%% (pkgdName) must precide it?
+merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
+ when (PP =/= asn1_NOVALUE) andalso
+ (D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE) ->
+ PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2]},
+ merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
+
+merge_indAudLocalControlDescriptor([{prop, Val} | Parms], D, PP)
+ when (PP =/= asn1_NOVALUE) andalso
+ is_list(D#'IndAudLocalControlDescriptor'.propertyParms) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PP2 = PP#'IndAudPropertyParm'{propertyParms = Val},
+ D2 = D#'IndAudLocalControlDescriptor'{propertyParms = [PP2|PPs]},
+ merge_indAudLocalControlDescriptor(Parms, D2, asn1_NOVALUE);
+
+merge_indAudLocalControlDescriptor([H | _T], _D, _PP) ->
+ return_error(0, {bad_indAudLocalControlDescriptor_parm, H});
+
+merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE)
+ when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE ->
+ D;
+merge_indAudLocalControlDescriptor([], D, asn1_NOVALUE) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PropParms2 = lists:reverse(PPs),
+ D#'IndAudLocalControlDescriptor'{propertyParms = PropParms2};
+merge_indAudLocalControlDescriptor([], D, PP)
+ when D#'IndAudLocalControlDescriptor'.propertyParms =:= asn1_NOVALUE ->
+ D#'IndAudLocalControlDescriptor'{propertyParms = [PP]};
+merge_indAudLocalControlDescriptor([], D, PP) ->
+ PPs = D#'IndAudLocalControlDescriptor'.propertyParms,
+ PPs2 = lists:reverse([PP|PPs]),
+ D#'IndAudLocalControlDescriptor'{propertyParms = PPs2}.
+
+
+merge_indAudTerminationStateDescriptor({name, Val}) ->
+ PropParm = #'IndAudPropertyParm'{name = Val},
+ #'IndAudTerminationStateDescriptor'{propertyParms = [PropParm]};
+%% BUGBUG BUGBUG BUGBUG
+merge_indAudTerminationStateDescriptor({prop, Val}) ->
+ exit({incomplete_propertyParm_in_indAudTerminationStateDescriptor, Val});
+merge_indAudTerminationStateDescriptor(serviceStatesToken) ->
+ #'IndAudTerminationStateDescriptor'{serviceState = 'NULL'};
+merge_indAudTerminationStateDescriptor({serviceStates, {equal, Val}}) ->
+ #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
+merge_indAudTerminationStateDescriptor({serviceStates, {inequal, Val}}) ->
+ #'IndAudTerminationStateDescriptor'{serviceStateSel = Val};
+merge_indAudTerminationStateDescriptor(bufferToken) ->
+ #'IndAudTerminationStateDescriptor'{eventBufferControl = 'NULL'}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudEventBufferDescriptor,2}]}).
+-endif.
+merge_indAudEventBufferDescriptor(EventName, SpecParams) ->
+ IAEBD = #'IndAudEventBufferDescriptor'{eventName = EventName},
+ do_merge_indAudEventBufferDescriptor(SpecParams, IAEBD).
+
+do_merge_indAudEventBufferDescriptor(asn1_NOVALUE, IAEBD) ->
+ IAEBD;
+do_merge_indAudEventBufferDescriptor({streamID, StreamID}, IAEBD) ->
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = StreamID};
+do_merge_indAudEventBufferDescriptor({eventParameterName, _Name} = EPN,
+ IAEBD) ->
+ %% BUGBUG BUGBUG BUGBUG
+ %% This is an ugly hack to allow the eventParamName which only
+ %% exists in the text encoding...
+ IAEBD#'IndAudEventBufferDescriptor'{streamID = EPN}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudSignalListParm,1}]}).
+-endif.
+ensure_indAudSignalListParm(SIG) ->
+ if
+ is_record(SIG, 'Signal') ->
+ ensure_indAudSignal(SIG);
+ true ->
+ return_error(0, {bad_Signal, SIG})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_indAudSignal,1}]}).
+-endif.
+ensure_indAudSignal(Sig) ->
+ #'Signal'{signalName = SignalName,
+ streamID = SID,
+ sigType = asn1_NOVALUE,
+ duration = asn1_NOVALUE,
+ notifyCompletion = asn1_NOVALUE,
+ keepActive = asn1_NOVALUE,
+ sigParList = [],
+ requestID = RID} = Sig,
+ #'IndAudSignal'{signalName = SignalName,
+ streamID = SID,
+ signalRequestID = RID}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_IADMD,1}]}).
+-endif.
+ensure_IADMD(Token) ->
+ {_TokenTag, _Line, DMD} = Token,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = asn1_NOVALUE} = DMD,
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_indAudPackagesDescriptor,1}]}).
+-endif.
+merge_indAudPackagesDescriptor(Pkgs) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = V} = Pkgs,
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+
+%% ensure_indAudTerminationStateParm(Token) ->
+%% case Token of
+%% {safeToken, _Line, "servicestates"} -> serviceStatesToken;
+%% {safeToken, _Line, "si"} -> serviceStatesToken;
+%% {safeToken, _Line, "buffer"} -> bufferToken;
+%% {safeToken, _Line, "bf"} -> bufferToken;
+%% PkgdName -> {pkgdName,
+%% ensure_pkgdName(PkgdName)}
+%% end.
+
+
+%% Types modified by v2:
+
+merge_auditDescriptor([]) ->
+ #'AuditDescriptor'{};
+merge_auditDescriptor(Tokens) when is_list(Tokens) ->
+ case lists:keysearch(terminationAudit, 1, Tokens) of
+ {value, {terminationAudit, TA}} ->
+ case lists:keydelete(terminationAudit, 1, Tokens) of
+ [] ->
+ #'AuditDescriptor'{auditPropertyToken = TA};
+ AuditTokens ->
+ #'AuditDescriptor'{auditToken = AuditTokens,
+ auditPropertyToken = TA}
+ end;
+ false ->
+ #'AuditDescriptor'{auditToken = Tokens}
+ end;
+merge_auditDescriptor(_) ->
+ #'AuditDescriptor'{}.
+
+
+%% v2 - end
+
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeParm,1}]}).
+-endif.
+merge_ServiceChangeParm(Parms) ->
+ Required = [serviceChangeReason, serviceChangeMethod],
+ merge_ServiceChangeParm(Parms, #'ServiceChangeParm'{}, Required).
+
+merge_ServiceChangeParm([], SCP, []) ->
+ SCP;
+
+merge_ServiceChangeParm([], _SCP, Required) ->
+ exit({missing_required_serviceChangeParm, Required});
+
+merge_ServiceChangeParm([{address, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{address, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE ->
+ MgcId = SCP0#'ServiceChangeParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, MgcId});
+
+merge_ServiceChangeParm([{mgc_id, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso
+ (SCP0#'ServiceChangeParm'.serviceChangeAddress =:= asn1_NOVALUE) ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{mgc_id, Val}|_Parms], SCP0, _Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeMgcId =:= asn1_NOVALUE ->
+ Addr = SCP0#'ServiceChangeParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_serviceChangeParm, Val, Addr});
+
+merge_ServiceChangeParm([{profile, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeProfile =:= asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{version, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeVersion =:= asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{reason, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeReason =:= undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeReason = Val},
+ Req = lists:delete(serviceChangeReason, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{delay, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeDelay =:= asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeDelay = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+%% REQUIRED (i.e. no default value)
+merge_ServiceChangeParm([{method, Val}|Parms], SCP0, Req0)
+ when SCP0#'ServiceChangeParm'.serviceChangeMethod =:= undefined ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeMethod = Val},
+ Req = lists:delete(serviceChangeMethod, Req0),
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{time_stamp, Val}|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.timeStamp =:= asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{timeStamp = Val},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{extension, _Val}|Parms], SCP0, Req) ->
+ merge_ServiceChangeParm(Parms, SCP0, Req);
+
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) andalso
+ is_atom(Val) ->
+ SCI = #'AuditDescriptor'{auditToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when (SCP0#'ServiceChangeParm'.serviceChangeInfo =:= asn1_NOVALUE) andalso
+ is_tuple(Val) ->
+ SCI = #'AuditDescriptor'{auditPropertyToken = [Val]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_atom(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditToken,
+ SCI = SCI0#'AuditDescriptor'{auditToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+merge_ServiceChangeParm([{audit_item, Val}|Parms], SCP0, Req)
+ when is_record(SCP0#'ServiceChangeParm'.serviceChangeInfo, 'AuditDescriptor') andalso
+ is_tuple(Val) ->
+ SCI0 = SCP0#'ServiceChangeParm'.serviceChangeInfo,
+ L = SCI0#'AuditDescriptor'.auditPropertyToken,
+ SCI = SCI0#'AuditDescriptor'{auditPropertyToken = [Val|L]},
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeInfo = SCI},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([incomplete|Parms], SCP0, Req)
+ when SCP0#'ServiceChangeParm'.serviceChangeIncompleteFlag =:= asn1_NOVALUE ->
+ SCP = SCP0#'ServiceChangeParm'{serviceChangeIncompleteFlag = 'NULL'},
+ merge_ServiceChangeParm(Parms, SCP, Req);
+
+merge_ServiceChangeParm([{Tag, Val}|_Parms], SCP, _Req) ->
+ Val2 =
+ case Tag of
+ address ->
+ SCP#'ServiceChangeParm'.serviceChangeAddress;
+ mgc_id ->
+ SCP#'ServiceChangeParm'.serviceChangeMgcId;
+ profile ->
+ SCP#'ServiceChangeParm'.serviceChangeProfile;
+ version ->
+ SCP#'ServiceChangeParm'.serviceChangeVersion;
+ reason ->
+ SCP#'ServiceChangeParm'.serviceChangeReason;
+ delay ->
+ SCP#'ServiceChangeParm'.serviceChangeDelay;
+ method ->
+ SCP#'ServiceChangeParm'.serviceChangeMethod;
+ time_stamp ->
+ SCP#'ServiceChangeParm'.timeStamp;
+ audit_item ->
+ SCP#'ServiceChangeParm'.serviceChangeInfo
+ end,
+ exit({at_most_once_serviceChangeParm, {Tag, Val, Val2}});
+merge_ServiceChangeParm([Parm|_Parms], SCP, _Req) ->
+ Parm2 =
+ case Parm of
+ incomplete ->
+ SCP#'ServiceChangeParm'.serviceChangeIncompleteFlag
+ end,
+ exit({at_most_once_serviceChangeParm, {Parm, Parm2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_ServiceChangeResParm,1}]}).
+-endif.
+merge_ServiceChangeResParm(Parms) ->
+ merge_ServiceChangeResParm(Parms, #'ServiceChangeResParm'{}).
+
+merge_ServiceChangeResParm([], SCRP) ->
+ SCRP;
+merge_ServiceChangeResParm([{address, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeAddress = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{address, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE ->
+ MgcId = SCRP0#'ServiceChangeResParm'.serviceChangeMgcId,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, MgcId});
+
+merge_ServiceChangeResParm([{mgc_id, Val}|Parms], SCRP0)
+ when (SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE) andalso
+ (SCRP0#'ServiceChangeResParm'.serviceChangeAddress =:= asn1_NOVALUE) ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeMgcId = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+merge_ServiceChangeResParm([{mgc_id, Val}|_Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeMgcId =:= asn1_NOVALUE ->
+ Addr = SCRP0#'ServiceChangeResParm'.serviceChangeAddress,
+ exit({not_both_address_mgcid_servChgReplyParm, Val, Addr});
+
+merge_ServiceChangeResParm([{profile, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeProfile =:= asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeProfile = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{version, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.serviceChangeVersion =:= asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{serviceChangeVersion = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{time_stamp, Val}|Parms], SCRP0)
+ when SCRP0#'ServiceChangeResParm'.timeStamp =:= asn1_NOVALUE ->
+ SCRP = SCRP0#'ServiceChangeResParm'{timeStamp = Val},
+ merge_ServiceChangeResParm(Parms, SCRP);
+
+merge_ServiceChangeResParm([{Tag, Val}|_Parms], SCRP) ->
+ Val2 =
+ case Tag of
+ address -> SCRP#'ServiceChangeResParm'.serviceChangeAddress;
+ mgc_id -> SCRP#'ServiceChangeResParm'.serviceChangeMgcId;
+ profile -> SCRP#'ServiceChangeResParm'.serviceChangeProfile;
+ version -> SCRP#'ServiceChangeResParm'.serviceChangeVersion;
+ time_stamp -> SCRP#'ServiceChangeResParm'.timeStamp
+ end,
+ exit({at_most_once_servChgReplyParm, {Tag, Val, Val2}}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_serviceChangeMethod,1}]}).
+-endif.
+ensure_serviceChangeMethod(Token) ->
+ case Token of
+ {safeToken, _Line, "fl"} ->
+ failover;
+ {safeToken, _Line, "failover"} ->
+ failover;
+ {safeToken, _Line, "fo"} ->
+ forced;
+ {safeToken, _Line, "forced"} ->
+ forced;
+ {safeToken, _Line, "gr"} ->
+ graceful;
+ {safeToken, _Line, "graceful"} ->
+ graceful;
+ {safeToken, _Line, "rs"} ->
+ restart;
+ {safeToken, _Line, "restart"} ->
+ restart;
+ {safeToken, _Line, "dc"} ->
+ disconnected;
+ {safeToken, _Line, "disconnected"} ->
+ disconnected;
+ {safeToken, _Line, "ho"} ->
+ handOff;
+ {safeToken, _Line, "handoff"} ->
+ handOff;
+ {safeToken, Line, Text} ->
+ return_error(Line, {bad_serviceChangeMethod, Text})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_topologyDescriptor,1}]}).
+-endif.
+merge_topologyDescriptor(Components) ->
+ merge_topologyDescriptor(Components, #'TopologyRequest'{}, []).
+
+merge_topologyDescriptor([], TR, TRs) ->
+ lists:reverse([ensure_TopologyRequest(TR)|TRs]);
+merge_topologyDescriptor(
+ [{tid, From}|Comps],
+ #'TopologyRequest'{terminationFrom = undefined} = TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{terminationFrom = From},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(
+ [{tid, To}|Comps],
+ #'TopologyRequest'{terminationTo = undefined} = TR1,
+ TRs) ->
+ TR2 = TR1#'TopologyRequest'{terminationTo = To},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{tid, From}|Comps], TR1, TRs) ->
+ TR2 = #'TopologyRequest'{terminationFrom = From},
+ merge_topologyDescriptor(Comps, TR2, [TR1 | TRs]);
+merge_topologyDescriptor([{direction, Dir}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirection = Dir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{sid, SID}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{streamID = SID},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(
+ [{direction_ext, EDir}|Comps],
+ #'TopologyRequest'{topologyDirection = asn1_NOVALUE} = TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirection = oneway,
+ topologyDirectionExtension = EDir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor([{direction_ext, EDir}|Comps], TR1, TRs) ->
+ TR2 = TR1#'TopologyRequest'{topologyDirectionExtension = EDir},
+ merge_topologyDescriptor(Comps, TR2, TRs);
+merge_topologyDescriptor(Comps, TR, TRs) ->
+ return_error(0, {bad_topologyDescriptor, Comps, TR, TRs}).
+
+
+ensure_TopologyRequest(#'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir} = R)
+ when (From =/= asn1_NOVALUE) andalso
+ (To =/= asn1_NOVALUE) andalso
+ (Dir =/= asn1_NOVALUE) ->
+ R;
+ensure_TopologyRequest(R) ->
+ return_error(0, {bad_TopologyRequest, R}).
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_profile,1}]}).
+-endif.
+ensure_profile(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ case string:tokens(Text, [$/]) of
+ [Name, Version] ->
+ Version2 = ensure_version(Version),
+ #'ServiceChangeProfile'{profileName = Name, version = Version2};
+ _ ->
+ return_error(Line, {bad_profile, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_version,1}]}).
+-endif.
+ensure_version(Version) ->
+ ensure_uint(Version, 0, 99).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_signalRequest,2}]}).
+-endif.
+merge_signalRequest(SignalName, PropertyParms) ->
+ Sig = #'Signal'{signalName = SignalName},
+ SPL = [],
+ do_merge_signalRequest(Sig, PropertyParms, SPL).
+
+do_merge_signalRequest(Sig, [H | T], SPL) ->
+ case H of
+ {stream, SID} when Sig#'Signal'.streamID =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{streamID = SID}, T, SPL);
+ {signal_type, SigType} when Sig#'Signal'.sigType =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{sigType = SigType}, T, SPL);
+ {duration, Duration} when Sig#'Signal'.duration =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{duration = Duration}, T, SPL);
+ {notify_completion, NC} when Sig#'Signal'.notifyCompletion =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{notifyCompletion = NC}, T, SPL);
+ keepActive when Sig#'Signal'.keepActive =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{keepActive = true}, T, SPL);
+ {other, Name, PP} ->
+ SP = #'SigParameter'{sigParameterName = Name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_signalRequest(Sig, T, [SP | SPL]);
+ {direction, Dir} when Sig#'Signal'.direction =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{direction = Dir}, T, SPL);
+ {requestId, RID} when Sig#'Signal'.requestID =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{requestID = RID}, T, SPL);
+ {intersigDelay, ISD} when Sig#'Signal'.intersigDelay =:= asn1_NOVALUE ->
+ do_merge_signalRequest(Sig#'Signal'{intersigDelay = ISD}, T, SPL);
+ _ ->
+ return_error(0, {bad_sigParm, H})
+ end;
+do_merge_signalRequest(Sig, [], SPL) ->
+ Sig#'Signal'{sigParList = lists:reverse(SPL)} .
+
+%% eventStream = StreamToken EQUAL StreamID
+%% eventOther = eventParameterName parmValue
+-ifdef(megaco_parser_inline).
+-compile({inline,[{select_stream_or_other,2}]}).
+-endif.
+select_stream_or_other(EventParameterName, ParmValue) ->
+ if
+ (EventParameterName =:= "st") orelse
+ (EventParameterName =:= "stream") ->
+ case ParmValue of
+ #'PropertyParm'{value = [Value]} ->
+ {stream, ensure_uint16(Value)};
+ _ ->
+ {stream, ensure_uint16(ParmValue)}
+ end;
+ true ->
+ #'PropertyParm'{value = Value} = ParmValue,
+ EP = #'EventParameter'{eventParameterName = EventParameterName,
+ value = Value},
+ {other, EP}
+ end.
+
+%% select_stream_or_other("st", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("st", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", #'PropertyParm'{value = [Value]}) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other("stream", Value) ->
+%% {stream, ensure_uint16(Value)};
+%% select_stream_or_other(Name, #'PropertyParm'{value = Value}) ->
+%% EP = #'EventParameter'{eventParameterName = Name,
+%% value = Value},
+%% {other, EP}.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_eventDM,1}]}).
+-endif.
+ensure_eventDM(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Name = DMD#'DigitMapDescriptor'.digitMapName,
+ Val = DMD#'DigitMapDescriptor'.digitMapValue,
+ if
+ (Name =:= asn1_NOVALUE) andalso (Val =/= asn1_NOVALUE) ->
+ {'DigitMapValue', Start, Short, Long, Duration, Body} = Val,
+ DMV = #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Duration},
+ {eventDM, {digitMapValue, DMV}};
+ (Name =/= asn1_NOVALUE) andalso (Val =:= asn1_NOVALUE) ->
+ {eventDM, {digitMapName, Name}};
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end;
+ true ->
+ return_error(Line, {bad_eventDM, DMD})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_DMD,1}]}).
+-endif.
+ensure_DMD(Token) ->
+ {_TokenTag, Line, DMD} = Token,
+ if
+ is_record(DMD, 'DigitMapDescriptor') ->
+ Val2 =
+ case DMD#'DigitMapDescriptor'.digitMapValue of
+ %% Note that the values of the digitMapBody and
+ %% durationTimers are swapped by the scanner
+ %% (this is done because of a problem in the flex scanner).
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ durationTimer = [],
+ digitMapBody = asn1_NOVALUE} ->
+ asn1_NOVALUE;
+ #'DigitMapValue'{durationTimer = Body,
+ digitMapBody = Duration} = DMV ->
+ %% Convert to version 1 DigitMapValue
+ DMV#'DigitMapValue'{digitMapBody = Body,
+ durationTimer = Duration};
+ Other ->
+ Other
+ end,
+ DMD#'DigitMapDescriptor'{digitMapValue = Val2};
+ true ->
+ return_error(Line, {bad_DigitMapDescriptor, DMD})
+ end.
+
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_observed_event,3}]}).
+-endif.
+merge_observed_event(ObservedEvents, EventName, TimeStamp) ->
+ StreamId = asn1_NOVALUE,
+ EPL = [],
+ do_merge_observed_event(ObservedEvents, EventName, TimeStamp, StreamId, EPL).
+
+do_merge_observed_event([{stream, StreamID} | T], EventName, TimeStamp, asn1_NOVALUE, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, EPL);
+do_merge_observed_event([{other, PP} | T], EventName, TimeStamp, StreamID, EPL) ->
+ do_merge_observed_event(T, EventName, TimeStamp, StreamID, [PP | EPL]);
+do_merge_observed_event([], EventName, TimeStamp, StreamID, EPL) ->
+ #'ObservedEvent'{eventName = EventName,
+ timeNotation = TimeStamp,
+ streamID = StreamID,
+ eventParList = lists:reverse(EPL)}.
+
+merge_eventSpec(OE)
+ when is_record(OE, 'ObservedEvent') andalso
+ (OE#'ObservedEvent'.timeNotation =:= asn1_NOVALUE) ->
+ #'EventSpec'{eventName = OE#'ObservedEvent'.eventName,
+ streamID = OE#'ObservedEvent'.streamID,
+ eventParList = OE#'ObservedEvent'.eventParList};
+merge_eventSpec(OE) ->
+ return_error(0, {bad_event_spec, OE}).
+
+make_RegulatedEmbeddedDescriptor({embed, SD, SED}) ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SED,
+ signalsDescriptor = SD}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_eventParameters,1}]}).
+-endif.
+merge_eventParameters(Params) ->
+ SID = asn1_NOVALUE,
+ EPL = [],
+ RA = #'RequestedActions'{},
+ HasA = no,
+ do_merge_eventParameters(Params, SID, EPL, RA, HasA) .
+
+do_merge_eventParameters([H | T], SID, EPL, RA, HasA) ->
+ case H of
+ keepActive when RA#'RequestedActions'.keepActive =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{keepActive = true},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ resetEventsDescriptor when RA#'RequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{resetEventsDescriptor = 'NULL'},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {embed, SD, SED} when RA#'RequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{signalsDescriptor = SD,
+ secondEvent = SED},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {eventDM, DM} when RA#'RequestedActions'.eventDM =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{eventDM = DM},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ {stream, NewSID} when SID =:= asn1_NOVALUE ->
+ do_merge_eventParameters(T, NewSID, EPL, RA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_eventParameters(T, SID, [EP | EPL], RA, HasA);
+ {notifyBehaviour, NB} when RA#'RequestedActions'.notifyBehaviour =:= asn1_NOVALUE ->
+ RA2 = RA#'RequestedActions'{notifyBehaviour = NB},
+ do_merge_eventParameters(T, SID, EPL, RA2, yes);
+ _ ->
+ return_error(0, {bad_eventParameter, H})
+ end;
+do_merge_eventParameters([], SID, EPL, RA, yes) ->
+ #'RequestedEvent'{streamID = SID,
+ eventAction = RA,
+ evParList = lists:reverse(EPL)};
+do_merge_eventParameters([], SID, EPL, _RA, no) ->
+ #'RequestedEvent'{streamID = SID,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_secondEventParameters,1}]}).
+-endif.
+merge_secondEventParameters(Params) ->
+ SID = asn1_NOVALUE,
+ EPL = [],
+ SRA = #'SecondRequestedActions'{},
+ HasA = no,
+ do_merge_secondEventParameters(Params, SID, EPL, SRA, HasA) .
+
+do_merge_secondEventParameters([H | T], SID, EPL, SRA, HasA) ->
+ case H of
+ keepActive when SRA#'SecondRequestedActions'.keepActive =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{keepActive = true},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+ resetEventsDescriptor when SRA#'SecondRequestedActions'.resetEventsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{resetEventsDescriptor = 'NULL'},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+ {second_embed, SD} when SRA#'SecondRequestedActions'.signalsDescriptor =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{signalsDescriptor = SD},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+ {eventDM, DM} when SRA#'SecondRequestedActions'.eventDM =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{eventDM = DM},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+ {stream, NewSID} when SID =:= asn1_NOVALUE ->
+ do_merge_secondEventParameters(T, NewSID, EPL, SRA, HasA);
+ {other, PP} when is_record(PP, 'PropertyParm') ->
+ EP = #'EventParameter'{eventParameterName = PP#'PropertyParm'.name,
+ value = PP#'PropertyParm'.value,
+ extraInfo = PP#'PropertyParm'.extraInfo},
+ do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
+ {other, EP} when is_record(EP, 'EventParameter') ->
+ do_merge_secondEventParameters(T, SID, [EP | EPL], SRA, HasA);
+ {notifyBehaviour, NB} when SRA#'SecondRequestedActions'.notifyBehaviour =:= asn1_NOVALUE ->
+ SRA2 = SRA#'SecondRequestedActions'{notifyBehaviour = NB},
+ do_merge_secondEventParameters(T, SID, EPL, SRA2, yes);
+ _ ->
+ return_error(0, {bad_secondEventParameter, H})
+ end;
+do_merge_secondEventParameters([], SID, EPL, SRA, yes) ->
+ #'SecondRequestedEvent'{streamID = SID,
+ eventAction = SRA,
+ evParList = lists:reverse(EPL)};
+do_merge_secondEventParameters([], SID, EPL, _SRA, no) ->
+ #'SecondRequestedEvent'{streamID = SID,
+ eventAction = asn1_NOVALUE,
+ evParList = lists:reverse(EPL)}.
+
+%% terminationID = "ROOT" / pathName / "$" / "*"
+%% Total length of pathName must not exceed 64 chars.
+%% pathName = ["*"] NAME *("/" / "*"/ ALPHA / DIGIT /"_" / "$" )
+%% ["@" pathDomainName ]
+%% ABNF allows two or more consecutive "." although it is meaningless
+%% in a path domain name.
+%% pathDomainName = (ALPHA / DIGIT / "*" )
+%% *63(ALPHA / DIGIT / "-" / "*" / ".")
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_terminationID,1}]}).
+-endif.
+ensure_terminationID(Token) ->
+ {safeToken, _Line, LowerText} = Token,
+ %% terminationID = "ROOT" / pathName / "$" / "*"
+ decode_term_id(LowerText, false, [], []).
+
+decode_term_id([H | T], Wild, Id, Component) ->
+ case H of
+ $/ -> decode_term_id(T, Wild, [lists:reverse(Component) | Id], []);
+ $* -> decode_term_id(T, true, Id, [?megaco_all | Component]);
+ $$ -> decode_term_id(T, true, Id, [?megaco_choose | Component]);
+ _ -> decode_term_id(T, Wild, Id, [H | Component])
+ end;
+decode_term_id([], Wild, Id, Component) ->
+ Id2 = [lists:reverse(Component) | Id],
+ #megaco_term_id{contains_wildcards = Wild, id = lists:reverse(Id2)}.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_pathName,1}]}).
+-endif.
+ensure_pathName(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text. %% BUGBUG: ensure values
+
+%% TimeStamp = Date "T" Time ; per ISO 8601:1988
+%% Date = 8(DIGIT) ; Date = yyyymmdd
+%% Time = 8(DIGIT) ; Time = hhmmssss
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_timeStamp,1}]}).
+-endif.
+ensure_timeStamp(Token) ->
+ {'TimeStampToken', Line, Text} = Token,
+ case string:tokens(Text, [$T, $t]) of
+ [Date, Time] ->
+ #'TimeNotation'{date = Date, time = Time};
+ _ ->
+ return_error(Line, {bad_timeStamp, Text})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionID,1}]}).
+-endif.
+ensure_transactionID(TransId) ->
+ ensure_uint32(TransId).
+
+make_transactionID_and_segment_info({TokenTag, Line, Text}) ->
+ case string:tokens(Text, [$/]) of
+ [TidText, SegNoText, SegComplText] ->
+ Tid = ensure_uint32({TokenTag, Line, TidText}),
+ SegNo = ensure_uint16({TokenTag, Line, SegNoText}),
+ ensure_segmentationComplete({TokenTag, Line, SegComplText}),
+ {Tid, SegNo, 'NULL'};
+ [TidText, SegNoText] ->
+ Tid = ensure_uint32({TokenTag, Line, TidText}),
+ SegNo = ensure_uint16({TokenTag, Line, SegNoText}),
+ {Tid, SegNo};
+ [TidText] ->
+ ensure_uint32({TokenTag, Line, TidText})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_segmentationComplete,1}]}).
+-endif.
+ensure_segmentationComplete(Token) ->
+ {_TokenTag, Line, Text} = Token,
+ if
+ (Text =:= "end") orelse (Text =:= "&") ->
+ ok;
+ true ->
+ return_error(Line, {invalid_segmentationCompleteToken, Text})
+ end.
+
+make_TransactionReply({Tid, SegNo, 'NULL'}, IAR, Res) ->
+ #'TransactionReply'{transactionId = Tid,
+ immAckRequired = IAR,
+ transactionResult = Res,
+ segmentNumber = SegNo,
+ segmentationComplete = 'NULL'};
+make_TransactionReply({Tid, SegNo}, IAR, Res) ->
+ #'TransactionReply'{transactionId = Tid,
+ immAckRequired = IAR,
+ transactionResult = Res,
+ segmentNumber = SegNo};
+make_TransactionReply(Tid, IAR, Res) ->
+ #'TransactionReply'{transactionId = Tid,
+ immAckRequired = IAR,
+ transactionResult = Res}.
+
+make_SegmentReply({Tid, SegNo, 'NULL'}) ->
+ #'SegmentReply'{transactionId = Tid,
+ segmentNumber = SegNo,
+ segmentationComplete = 'NULL'};
+make_SegmentReply({Tid, SegNo}) ->
+ #'SegmentReply'{transactionId = Tid,
+ segmentNumber = SegNo}.
+
+
+%% transactionAck = transactionID / (transactionID "-" transactionID)
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_transactionAck,1}]}).
+-endif.
+ensure_transactionAck(Tokens) ->
+ {safeToken, _Line, Text} = Tokens,
+ case string:tokens(Text, [$-]) of
+ [Id] ->
+ #'TransactionAck'{firstAck = ensure_transactionID(Id)};
+ [Id, Id2] ->
+ #'TransactionAck'{firstAck = ensure_transactionID(Id),
+ lastAck = ensure_transactionID(Id2)}
+ end.
+
+merge_context_request(asn1_NOVALUE, Prop) ->
+ merge_context_request(#'ContextRequest'{}, Prop);
+
+merge_context_request(#'ContextRequest'{priority = asn1_NOVALUE} = CR,
+ {priority, Int}) ->
+ CR#'ContextRequest'{priority = Int};
+
+merge_context_request(#'ContextRequest'{emergency = asn1_NOVALUE} = CR,
+ {emergency, Bool}) ->
+ CR#'ContextRequest'{emergency = Bool};
+
+merge_context_request(#'ContextRequest'{topologyReq = asn1_NOVALUE} = CR,
+ {topology, Desc}) ->
+ CR#'ContextRequest'{topologyReq = Desc};
+
+merge_context_request(#'ContextRequest'{iepscallind = asn1_NOVALUE} = CR,
+ {iepsCallind, Ind}) ->
+ CR#'ContextRequest'{iepscallind = Ind};
+
+merge_context_request(#'ContextRequest'{contextProp = asn1_NOVALUE} = CR,
+ {contextProp, Props}) ->
+ CR#'ContextRequest'{contextProp = Props};
+
+merge_context_request(#'ContextRequest'{contextList = asn1_NOVALUE} = CR,
+ {contextList, IDs}) ->
+ CR#'ContextRequest'{contextList = IDs};
+
+merge_context_request(CR, {Tag, Val}) ->
+ Val2 =
+ case Tag of
+ priority -> CR#'ContextRequest'.priority;
+ emergency -> CR#'ContextRequest'.emergency;
+ topology -> CR#'ContextRequest'.topologyReq;
+ iepsCallind -> CR#'ContextRequest'.iepscallind;
+ contextProp -> CR#'ContextRequest'.contextProp;
+ contextList -> CR#'ContextRequest'.contextList
+ end,
+ exit({at_most_once_contextProperty, {Tag, Val, Val2}}).
+
+
+merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{contextPropAud = asn1_NOVALUE} = CAAR, []) ->
+
+ CAAR;
+merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{contextPropAud = CPA} = CAAR, []) ->
+
+ CAAR#'ContextAttrAuditRequest'{contextPropAud = lists:reverse(CPA)};
+merge_context_attr_audit_request(CAAR, [H|T]) ->
+ case H of
+ priorityAudit when CAAR#'ContextAttrAuditRequest'.priority =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{priority = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ emergencyAudit when CAAR#'ContextAttrAuditRequest'.emergency =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{emergency = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ topologyAudit when CAAR#'ContextAttrAuditRequest'.topology =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{topology = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ iepsCallind when CAAR#'ContextAttrAuditRequest'.iepscallind =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{iepscallind = 'NULL'},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} when CAAR#'ContextAttrAuditRequest'.contextPropAud =:= asn1_NOVALUE ->
+ CPA = [#'IndAudPropertyParm'{name = Name}],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {prop, Name} ->
+ CPA = CAAR#'ContextAttrAuditRequest'.contextPropAud,
+ CPA2 = [#'IndAudPropertyParm'{name = Name}|CPA],
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{contextPropAud = CPA2},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_prio, Prio} when CAAR#'ContextAttrAuditRequest'.selectpriority =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectpriority = Prio},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_emergency, EV} when CAAR#'ContextAttrAuditRequest'.selectemergency =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectemergency = EV},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_ieps, IV} when CAAR#'ContextAttrAuditRequest'.selectiepscallind =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectiepscallind = IV},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ {select_logic, SL} when CAAR#'ContextAttrAuditRequest'.selectLogic =:= asn1_NOVALUE ->
+ CAAR2 = CAAR#'ContextAttrAuditRequest'{selectLogic = SL},
+ merge_context_attr_audit_request(CAAR2, T);
+
+ %% BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
+ %%
+ %% For some strange reason, contextAttrDescriptor was added
+ %% to contextAuditSelector. But there is no place for this
+ %% info in the ContextAttrAuditRequest. Since contextAttrDescriptor
+ %% can also be found in contextProperty (which correspond to
+ %% ContextRequest), the question is if this info should go there
+ %% or if we shall just drop it. For now we drop it.
+ %%
+ {contextProp, _PPs} ->
+ merge_context_attr_audit_request(CAAR, T);
+
+ {contextList, _IDs} ->
+ merge_context_attr_audit_request(CAAR, T);
+
+ _ ->
+ exit({unexpected_contextAttrAudit_item, H})
+
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_request,2}]}).
+-endif.
+merge_action_request(CtxId, Items) ->
+ do_merge_action_request(Items, [], asn1_NOVALUE, asn1_NOVALUE, CtxId).
+
+do_merge_action_request([H|T], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ case H of
+ {commandRequest, CmdReq} ->
+ do_merge_action_request(T, [CmdReq|CmdReqs],
+ CtxReq, CtxAuditReq, CtxId);
+
+ {contextProp, ContextProp} ->
+ do_merge_action_request(T, CmdReqs,
+ merge_context_request(CtxReq, ContextProp),
+ CtxAuditReq, CtxId);
+
+ {contextAudit, ContextAuditReq} when CtxAuditReq =:= asn1_NOVALUE ->
+ do_merge_action_request(T, CmdReqs,
+ CtxReq, ContextAuditReq, CtxId)
+ end;
+do_merge_action_request([], CmdReqs, CtxReq, CtxAuditReq, CtxId) ->
+ #'ActionRequest'{contextId = CtxId,
+ contextRequest = strip_ContextRequest(CtxReq),
+ contextAttrAuditReq = strip_ContextAttrAuditRequest(CtxAuditReq),
+ commandRequests = lists:reverse(CmdReqs)}.
+
+
+%% OTP-5085:
+%% In order to solve a problem in the parser, the error descriptor
+%% has been put last in the non-empty commandReplyList, if it is not
+%% asn1_NOVALUE
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_action_reply,1}]}).
+-endif.
+merge_action_reply(Items) ->
+ do_merge_action_reply(Items, asn1_NOVALUE, asn1_NOVALUE, []).
+
+do_merge_action_reply([], Err, Ctx, Cmds) ->
+ #'ActionReply'{errorDescriptor = Err,
+ contextReply = strip_ContextRequest(Ctx),
+ commandReply = lists:reverse(Cmds)};
+do_merge_action_reply([H|T], Err0, CR, Cmds) ->
+ case H of
+ {error, Err1} when Err0 =:= asn1_NOVALUE ->
+ do_merge_action_reply(T, Err1, CR, Cmds);
+ {command, Cmd} ->
+ do_merge_action_reply(T, Err0, CR, [Cmd | Cmds]);
+ {context, CtxProp} ->
+ do_merge_action_reply(T, Err0,
+ merge_context_request(CR, CtxProp), Cmds)
+ end.
+
+merge_auditOther([TID], TAR) ->
+ {auditResult,
+ #'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}};
+merge_auditOther(TIDs, TAR) ->
+ {auditResultTermList,
+ #'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TAR}}.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE,
+ contextList = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = [],
+ contextList = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+%% strip_ContextRequest(asn1_NOVALUE) ->
+%% asn1_NOVALUE;
+strip_ContextRequest(R) ->
+ R.
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE,
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topology = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = [],
+ selectpriority = asn1_NOVALUE,
+ selectemergency = asn1_NOVALUE,
+ selectiepscallind = asn1_NOVALUE,
+ selectLogic = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(R) ->
+ R.
+
+merge_AmmRequest_descriptors([], Acc) ->
+ lists:reverse(Acc);
+merge_AmmRequest_descriptors([{_, deprecated}|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, Acc);
+merge_AmmRequest_descriptors([Desc|Descs], Acc) ->
+ merge_AmmRequest_descriptors(Descs, [Desc|Acc]).
+
+make_auditRequest([TID], AD) ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD};
+make_auditRequest([TID|_] = TIDList, AD) ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = TIDList}.
+
+make_commandRequest({CmdTag, {_TokenTag, _Line, Text}}, Cmd) ->
+ Req = #'CommandRequest'{command = {CmdTag, Cmd}},
+ case Text of
+ [$w, $- | _] ->
+ Req#'CommandRequest'{wildcardReturn = 'NULL'};
+ [$o, $-, $w, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL', wildcardReturn = 'NULL'};
+ [$o, $- | _] ->
+ Req#'CommandRequest'{optional = 'NULL'};
+ _ ->
+ Req
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationAudit,1}]}).
+-endif.
+merge_terminationAudit(AuditReturnParameters) ->
+ lists:reverse(do_merge_terminationAudit(AuditReturnParameters, [], [])).
+
+do_merge_terminationAudit([H| T], ARPs, AuditItems) ->
+ case H of
+ {auditReturnItem, AuditItem} ->
+ do_merge_terminationAudit(T, ARPs, [AuditItem | AuditItems]);
+ AuditReturnParameter ->
+ do_merge_terminationAudit(T, [AuditReturnParameter | ARPs], AuditItems)
+ end;
+do_merge_terminationAudit([], AuditReturnParameters, []) ->
+ AuditReturnParameters;
+do_merge_terminationAudit([], AuditReturnParameters, AuditItems) ->
+ AuditDescriptor = #'AuditDescriptor'{auditToken = AuditItems},
+ AuditReturnParameter = {emptyDescriptors, AuditDescriptor},
+ [AuditReturnParameter | AuditReturnParameters].
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_mediaDescriptor,1}]}).
+-endif.
+merge_mediaDescriptor(MediaParms) ->
+ do_merge_mediaDescriptor(MediaParms, asn1_NOVALUE, [], []).
+
+do_merge_mediaDescriptor([H | T], TS, One, Multi) ->
+ case H of
+ {streamParm, Parm} when Multi =:= [] ->
+ do_merge_mediaDescriptor(T, TS, [Parm | One], Multi);
+ {streamDescriptor, Desc} when One =:= [] ->
+ do_merge_mediaDescriptor(T, TS, One, [Desc | Multi]);
+ {termState, TS2} when TS =:= asn1_NOVALUE ->
+ do_merge_mediaDescriptor(T, TS2, One, Multi);
+ _ ->
+ return_error(0, {bad_merge_mediaDescriptor, [H, TS, One, Multi]})
+ end;
+do_merge_mediaDescriptor([], TS, One, Multi) ->
+ if
+ (One =:= []) ->
+ if (Multi =:= []) ->
+ #'MediaDescriptor'{streams = asn1_NOVALUE,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ Streams = {multiStream, lists:reverse(Multi)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS}
+ end;
+ true -> % (One =/= [])
+ if
+ (Multi =:= []) ->
+ Streams = {oneStream, merge_streamParms(One)},
+ #'MediaDescriptor'{streams = Streams,
+ termStateDescr = TS};
+ true -> % (Multi =/= [])
+ return_error(0,
+ {bad_merge_mediaDescriptor, [TS, One, Multi]})
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_streamParms,1}]}).
+-endif.
+merge_streamParms(TaggedStreamParms) ->
+ SP = #'StreamParms'{},
+ do_merge_streamParms(TaggedStreamParms, SP).
+
+do_merge_streamParms([{Tag, D} | T] = All, SP) ->
+ case Tag of
+ local when SP#'StreamParms'.localDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{localDescriptor = D});
+ remote when SP#'StreamParms'.remoteDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{remoteDescriptor = D});
+ control ->
+ LCD =
+ case SP#'StreamParms'.localControlDescriptor of
+ asn1_NOVALUE ->
+ #'LocalControlDescriptor'{propertyParms = []};
+ PrevLCD ->
+ PrevLCD
+ end,
+ LCD2 = do_merge_control_streamParms(D, LCD),
+ do_merge_streamParms(T, SP#'StreamParms'{localControlDescriptor = LCD2});
+ statistics when SP#'StreamParms'.statisticsDescriptor =:= asn1_NOVALUE ->
+ do_merge_streamParms(T, SP#'StreamParms'{statisticsDescriptor = D});
+ _ ->
+ return_error(0, {do_merge_streamParms, [All, SP]})
+ end;
+do_merge_streamParms([], SP)
+ when is_record(SP#'StreamParms'.localControlDescriptor, 'LocalControlDescriptor') ->
+ LCD = SP#'StreamParms'.localControlDescriptor,
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = lists:reverse(PP)},
+ SP#'StreamParms'{localControlDescriptor = LCD2};
+do_merge_streamParms([], SP) ->
+ SP.
+
+
+do_merge_control_streamParms([{SubTag, SD} | T] = All, LCD) ->
+ case SubTag of
+ group when LCD#'LocalControlDescriptor'.reserveGroup =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveGroup = SD},
+ do_merge_control_streamParms(T, LCD2);
+ value when LCD#'LocalControlDescriptor'.reserveValue =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{reserveValue = SD},
+ do_merge_control_streamParms(T, LCD2);
+ mode when LCD#'LocalControlDescriptor'.streamMode =:= asn1_NOVALUE ->
+ LCD2 = LCD#'LocalControlDescriptor'{streamMode = SD},
+ do_merge_control_streamParms(T, LCD2);
+ prop ->
+ PP = LCD#'LocalControlDescriptor'.propertyParms,
+ LCD2 = LCD#'LocalControlDescriptor'{propertyParms = [SD | PP]},
+ do_merge_control_streamParms(T, LCD2);
+ _ ->
+ return_error(0, {do_merge_control_streamParms, [All, LCD]})
+ end;
+do_merge_control_streamParms([], LCD) ->
+ LCD.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{merge_terminationStateDescriptor,1}]}).
+-endif.
+merge_terminationStateDescriptor(Parms) ->
+ TSD = #'TerminationStateDescriptor'{propertyParms = []},
+ do_merge_terminationStateDescriptor(Parms, TSD).
+
+do_merge_terminationStateDescriptor([{Tag, Val} | T], TSD) ->
+ case Tag of
+ serviceState when TSD#'TerminationStateDescriptor'.serviceState =:= asn1_NOVALUE ->
+ TSD2 = TSD#'TerminationStateDescriptor'{serviceState = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ eventBufferControl when TSD#'TerminationStateDescriptor'.eventBufferControl =:= asn1_NOVALUE->
+ TSD2 = TSD#'TerminationStateDescriptor'{eventBufferControl = Val},
+ do_merge_terminationStateDescriptor(T, TSD2);
+ propertyParm ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD2 = TSD#'TerminationStateDescriptor'{propertyParms = [Val | PP]},
+ do_merge_terminationStateDescriptor(T, TSD2)
+ end;
+do_merge_terminationStateDescriptor([], TSD) ->
+ PP = TSD#'TerminationStateDescriptor'.propertyParms,
+ TSD#'TerminationStateDescriptor'{propertyParms = lists:reverse(PP)}.
+
+-ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Group = [],
+ Groups = [],
+ parse_prop_name(Text, Group, Groups).
+
+parse_prop_name([Char | Rest] = All, Group, Groups) ->
+ if
+ ?white_space(Char) ->
+ parse_prop_name(Rest, Group, Groups);
+ ?end_of_line(Char) ->
+ parse_prop_name(Rest, Group, Groups);
+ true ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group, Groups)
+ end;
+parse_prop_name([] = All, Group, Groups) ->
+ Name = [],
+ do_parse_prop_name(All, Name, Group, Groups).
+
+do_parse_prop_name([Char | Rest], Name, Group, Groups)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ Groups2 = [lists:reverse(Group) | Groups],
+ Group2 = [],
+ parse_prop_value(Rest, Name, Group2, Groups2);
+ true ->
+ %% Use current property group
+ parse_prop_value(Rest, Name, Group, Groups)
+ end;
+do_parse_prop_name([Char | Rest], Name, Group, Groups) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+ safe_char ->
+ do_parse_prop_name(Rest, [Char | Name], Group, Groups);
+ _ ->
+ return_error(0, {bad_prop_name, lists:reverse(Name), Char})
+ end;
+do_parse_prop_name([], [], [], Groups) ->
+ lists:reverse(Groups);
+do_parse_prop_name([], [], Group, Groups) ->
+ Group2 = lists:reverse(Group),
+ lists:reverse([Group2 | Groups]);
+do_parse_prop_name([], Name, Group, Groups) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{parse_prop_value,4}]}).
+-endif.
+parse_prop_value(Chars, Name, Group, Groups) ->
+ Value = [],
+ do_parse_prop_value(Chars, Name, Value, Group, Groups).
+
+do_parse_prop_value([Char | Rest], Name, Value, Group, Groups) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_prop_parm(Name, Value),
+ parse_prop_name(Rest, [PP | Group], Groups);
+ true ->
+ do_parse_prop_value(Rest, Name, [Char | Value], Group, Groups)
+ end;
+do_parse_prop_value([], Name, Value, Group, Groups) ->
+ %% Assume end of line
+ PP = make_prop_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{make_prop_parm,2}]}).
+-endif.
+make_prop_parm(Name, Value) ->
+ #'PropertyParm'{name = lists:reverse(Name),
+ value = [lists:reverse(Value)]}.
+
+-else. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_prop_groups,1}]}).
+-endif.
+ensure_prop_groups(Token) ->
+ {_TokenTag, _Line, Groups} = Token,
+ Groups.
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{do_ensure_prop_groups,1}]}).
+%% -endif.
+%% do_ensure_prop_groups(Groups) when is_list(Groups) ->
+%% [ensure_prop_group(Group) || Group <- Groups];
+%% do_ensure_prop_groups(BadGroups) ->
+%% throw({error, {?MODULE, {bad_property_groups, BadGroups}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_group,1}]}).
+%% -endif.
+%% ensure_prop_group(Group) when is_list(Group) ->
+%% [ensure_prop_parm(PropParm) || PropParm <- Group];
+%% ensure_prop_group(BadGroup) ->
+%% throw({error, {?MODULE, {bad_property_group, BadGroup}}}).
+
+%% -ifdef(megaco_parser_inline).
+%% -compile({inline,[{ensure_prop_parm,1}]}).
+%% -endif.
+%% ensure_prop_parm(#property_parm{name = Name,
+%% value = Value}) ->
+%% #'PropertyParm'{name = Name,
+%% value = Value};
+%% ensure_prop_parm(PP) when is_record(PP, 'PropertyParm') ->
+%% PP;
+%% ensure_prop_parm(BadPropParm) ->
+%% throw({error, {?MODULE, {bad_property_parm, BadPropParm}}}).
+
+-endif. % -ifdef(megaco_nscanner_props).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,3}]}).
+-endif.
+ensure_uint(Token, Min, Max) ->
+ case Token of
+ {_TokenTag, Line, Val} when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line);
+ {_TokenTag, Line, Text} ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(Line, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, Line)
+ end;
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0);
+ Text ->
+ case (catch list_to_integer(Text)) of
+ {'EXIT', _} ->
+ return_error(0, {not_an_integer, Text});
+ Val when is_integer(Val) ->
+ ensure_uint(Val, Min, Max, 0)
+ end
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint,4}]}).
+-endif.
+ensure_uint(Val, Min, Max, Line) ->
+ if
+ is_integer(Min) andalso (Val >= Min) ->
+ if
+ is_integer(Max) andalso (Val =< Max) ->
+ Val;
+ Max =:= infinity ->
+ Val;
+ true ->
+ return_error(Line, {too_large_integer, Val, Max})
+ end;
+ true ->
+ return_error(Line, {too_small_integer, Val, Min})
+ end.
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint16,1}]}).
+-endif.
+ensure_uint16(Int) ->
+ ensure_uint(Int, 0, 65535).
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{ensure_uint32,1}]}).
+-endif.
+ensure_uint32(Int) ->
+ ensure_uint(Int, 0, 4294967295) .
+
+%% OTP-4710
+ensure_hex({_TokenTag, _Line, [$0, $x |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex({_TokenTag, _Line, [$0, $X |Chars]}, Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $x |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []);
+ensure_hex([$0, $X |Chars], Min, Max) ->
+ ensure_uint(length(Chars), Min, Max),
+ hex_to_int(Chars, []).
+
+%% OTP-4710
+hex_to_int([], Acc) ->
+ lists:reverse(Acc);
+hex_to_int([Char1,Char2|Tail], Acc) ->
+ Int1 = hchar_to_int(Char1),
+ Int2 = hchar_to_int(Char2),
+ Val = Int2 bor (Int1 bsl 4),
+ hex_to_int(Tail, [Val| Acc]);
+hex_to_int([Char], Acc) ->
+ Int = hchar_to_int(Char),
+ lists:reverse([Int|Acc]).
+
+hchar_to_int(Char) when ($0 =< Char) andalso (Char =< $9) ->
+ Char - $0;
+hchar_to_int(Char) when ($A =< Char) andalso (Char =< $F) ->
+ Char - $A + 10; % OTP-4710
+hchar_to_int(Char) when ($a =< Char) andalso (Char =< $f) ->
+ Char - $a + 10. % OTP-4710
+
+-ifdef(megaco_parser_inline).
+-compile({inline,[{value_of,1}]}).
+-endif.
+value_of(Token) ->
+ {_TokenTag, _Line, Text} = Token,
+ Text.
+
+
+%% -------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F,[]).
+%% d(F, A) ->
+%% %% d(true, F, A).
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("DBG:~w:" ++ F ++ "~n", [?MODULE | A]);
+%% d(_, _, _) ->
+%% ok.
+
diff --git a/lib/megaco/src/text/megaco_text_parser_v3.yrl b/lib/megaco/src/text/megaco_text_parser_v3.yrl
new file mode 100644
index 0000000000..d400a93c66
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_parser_v3.yrl
@@ -0,0 +1,1680 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: YECC grammar for text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Annex B TEXT ENCODING OF THE PROTOCOL (NORMATIVE)
+%%
+%% B.1 Coding of wildcards
+%%
+%% In a text encoding of the protocol, while TerminationIDs are
+%% arbitrary, by judicious choice of names, the wildcard character, "*"
+%% may be made more useful. When the wildcard character is encountered,
+%% it will "match" all TerminationIDs having the same previous and
+%% following characters (if appropriate). For example, if there were
+%% TerminationIDs of R13/3/1, R13/3/2 and R13/3/3, the TerminationID
+%% R13/3/* would match all of them. There are some circumstances where
+%% ALL Terminations must be referred to. The TerminationID "*" suffices,
+%% and is referred to as ALL. The CHOOSE TerminationID "$" may be used to
+%% signal to the MG that it has to create an ephemeral Termination or
+%% select an idle physical Termination.
+%%
+%% B.2 ABNF specification
+%%
+%% The protocol syntax is presented in ABNF according to RFC2234. The
+%% protocol is not case sensitive. Identifiers are not case sensitive.
+%%
+%% NOTE 1 - This syntax specification does not enforce all restrictions
+%% on element inclusions and values. Some additional
+%% restrictions are stated in comments and other restrictions
+%% appear in the text of this Recommendation. These additional
+%% restrictions are part of the protocol even though not
+%% enforced by this Recommendation.
+%% NOTE 2 - The syntax is context-dependent. For example, "Add" can be
+%% the AddToken or a NAME depending on the context in which it
+%% occurs.
+%%
+%% Everything in the ABNF and text encoding is case insensitive. This
+%% includes TerminationIDs, digitmap Ids etc. SDP is case sensitive as
+%% per RFC 2327.
+%%
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 91.
+
+
+%%----------------------------------------------------------------------
+%% Non-terminals
+%%----------------------------------------------------------------------
+
+Nonterminals
+
+ actionReply
+ actionReplyBody
+ actionReplyList
+ actionRequest
+ actionRequestBody
+ actionRequestItem
+ actionRequestItems
+ actionRequestList
+ alternativeValue
+ ammParameter
+ ammParameters
+ ammRequest
+ ammRequestBody
+ ammToken
+ ammsReply
+ ammsReplyBody
+ ammsToken
+ auditDescriptor
+ auditDescriptorBody
+ auditItem
+ auditItemList
+ auditOther
+ auditReply
+ auditRequest
+ auditReturnItem
+ auditReturnParameter
+ auditReturnParameterList
+ auditSelectLogic %% v3
+ authenticationHeader
+ commandReplyList
+ commandReplys %% v3
+ commandRequest
+ contextAttrDescriptor %% v3
+ contextAudit
+ contextAuditProperties
+ contextAuditProperty
+ contextAuditSelector %% v3
+ contextID
+ contextIdList %% v3
+ contextIDs %% v3
+%% contextProperties %% v3
+ contextProperty
+%% contextPropertyList
+ contextTerminationAudit
+ daddr
+ deviceName
+ digitMapDescriptor
+ direction %% v3
+ domainAddress
+ domainName
+ embedFirst
+ embedNoSig
+ embedSig
+ embedWithSig
+ emergencyValue %% v3
+ errorCode
+ errorDescriptor
+ errorText
+ eventBufferControl
+ eventBufferControlValue %% v3
+ eventBufferDescriptor
+ eventDM
+ eventParameter
+ eventParameterName
+ eventParameters
+ eventSpec
+ eventSpecList
+ eventStream
+ eventStreamOrOther
+ eventsDescriptor
+ extension
+ extensionParameter
+
+ iaServiceStates %% v3
+ iepsValue
+
+ %% v2 - start
+ indAudauditReturnParameter
+ indAuddigitMapDescriptor
+ indAudeventBufferDescriptor
+ indAudeventSpec
+ indAudeventSpecParameter
+ %% indAudeventSpecParameterList
+ indAudeventsDescriptor
+ indAudlocalControlDescriptor
+ indAudlocalParm
+ indAudlocalParmList
+ indAudmediaDescriptor
+ indAudmediaParm
+ indAudmediaParms %% v3
+ %% indAudmediaParmList
+ indAudpackagesDescriptor
+ indAudrequestedEvent
+ indAudsignalsDescriptor
+ indAudsignalList
+ %% indAudsignalListParm
+ indAudsignalParm
+ %% indAudsignalRequest
+ indAudstreamDescriptor
+ indAudstreamParm
+ indAudstatisticsDescriptor
+ indAudterminationAudit
+ indAudterminationAuditList
+ indAudterminationStateDescriptor
+ indAudterminationStateParm
+ %% indAudterminationStateParmList
+ optIndAudeventSpecParameter
+ optIndAudsignalParm
+ %% v2 - end
+
+ indAudcontextAttrDescriptor %% v3
+
+ localControlDescriptor
+ localParm
+ localParmList
+ mId
+ mediaDescriptor
+ mediaParm
+ mediaParmList
+ megacoMessage
+ message
+ messageBody
+ modemDescriptor % Deprecated as of Corr 1
+ modemType % Deprecated as of Corr 1
+ modemTypeList % Deprecated as of Corr 1
+ mtpAddress
+ muxDescriptor
+ muxType
+ notificationReason
+ notificationReasons
+ notifyBehaviour %% v3
+ notifyRegulated %% v3
+ notifyReply
+ notifyReplyBody
+ notifyRequest
+ notifyRequestBody
+ observedEvent
+ observedEventBody
+ observedEventParameter
+ observedEventParameters
+ % observedEventTimeStamp
+ observedEvents
+ observedEventsDescriptor
+ onOrOff
+ optAuditDescriptor
+ optImmAckRequired
+ optPropertyParms
+ optSep
+ packagesDescriptor
+ packagesItem
+ packagesItems
+ %% parmName
+ parmValue
+ pathName
+ pkgdName
+ portNumber
+ priority
+ propertyParm
+ propertyParms
+ propertyParmList
+ requestID
+ requestedEvent
+ requestedEventBody
+ requestedEvents
+ safeToken
+ safeToken2
+ secondEventParameter
+ secondEventParameters
+ secondRequestedEvent
+ secondRequestedEventBody
+ secondRequestedEvents
+ segmentReply %% v3
+ %% segmentNumber %% v3
+ servChgReplyParm
+ servChgReplyParms
+ serviceChangeAddress
+ serviceChangeDelay
+ serviceChangeDescriptor
+ serviceChangeMethod
+ serviceChangeMgcId
+ serviceChangeParm
+ serviceChangeParms
+ serviceChangeProfile
+ serviceChangeReason
+ serviceChangeReply
+ serviceChangeReplyBody
+ serviceChangeReplyDescriptor
+ serviceChangeRequest
+ serviceChangeVersion
+ serviceStates
+ serviceStatesValue %% v3
+ sigParameter
+ sigParameters
+ signalList
+ signalListId
+ signalListParm
+ signalListParms
+ signalName
+ signalParm
+ signalParms
+ signalRequest
+ signalsDescriptor
+ signalType
+ statisticsDescriptor
+ statisticsParameter
+ statisticsParameters
+ streamDescriptor
+ streamID
+ streamModes
+ streamParm
+ streamParmList
+ subtractRequest
+ termIDList %% v3
+ terminationAudit
+ terminationID
+ terminationIDList
+ terminationIDListRepeat
+ terminationStateDescriptor
+ terminationStateParm
+ terminationStateParms
+ timeStamp
+ topologyDescriptor
+ topologyDirection
+ topologyDescComp
+ topologyDescCompList
+ transactionAck
+ transactionAckList
+ transactionID
+ transactionID_and_segment_info
+ transactionItem
+ transactionList
+ transactionPending
+ transactionReply
+ transactionReplyBody
+ transactionRequest
+ transactionResponseAck
+ value
+ valueList
+
+.
+
+%%----------------------------------------------------------------------
+%% Terminals
+%%----------------------------------------------------------------------
+
+Terminals
+
+ 'AddToken'
+ 'AndAUDITselectToken' %% v3
+ 'AuditCapToken'
+ 'AuditToken'
+ 'AuditValueToken'
+ 'AuthToken'
+ 'BothToken' %% v3
+ 'BothwayToken'
+ 'BriefToken'
+ 'BufferToken'
+ 'COLON'
+ 'COMMA'
+ 'ContextAttrToken' %% v3
+ 'ContextAuditToken'
+ 'ContextListToken' %% v3
+ 'CtxToken'
+ 'DelayToken'
+ 'DigitMapToken'
+ 'DigitMapDescriptorToken'
+ 'DirectionToken' %% v3
+ 'DiscardToken'
+ 'DisconnectedToken'
+ 'DurationToken'
+ 'EQUAL'
+ 'EmbedToken'
+ 'EmergencyToken'
+ 'EmergencyOffToken'
+ 'EmergencyValueToken' %% v3
+ 'ErrorToken'
+ 'EventBufferToken'
+ 'EventsToken'
+ 'ExternalToken' %% v3
+ 'FailoverToken'
+ 'ForcedToken'
+ 'GREATER'
+ 'GracefulToken'
+ 'H221Token'
+ 'H223Token'
+ 'H226Token'
+ 'HandOffToken'
+ 'IEPSToken' %% v3
+ 'ImmAckRequiredToken'
+ 'INEQUAL' %% v3
+ 'InSvcToken'
+ 'InactiveToken'
+ 'InternalToken' %% v3
+ 'InterruptByEventToken'
+ 'InterruptByNewSignalsDescrToken'
+ 'IntsigDelayToken' %% v3
+ 'IsolateToken'
+ 'IterationToken' %% v3
+ 'KeepActiveToken'
+ 'LBRKT'
+ 'LESSER'
+ 'LSBRKT'
+ 'LocalControlToken'
+ 'LocalDescriptorToken'
+ 'LockStepToken'
+ 'LoopbackToken'
+ 'MediaToken'
+ %% 'MegacopToken'
+ 'MessageSegmentToken'
+ 'MethodToken'
+ 'MgcIdToken'
+ 'ModeToken'
+ 'ModemToken'
+ 'ModifyToken'
+ 'MoveToken'
+ 'MtpAddressToken'
+ 'MuxToken'
+ 'NEQUAL'
+ 'NeverNotifyToken' %% v3
+ 'NotifyCompletionToken'
+ 'NotifyImmediateToken' %% v3
+ 'NotifyRegulatedToken' %% v3
+ 'NotifyToken'
+ 'Nx64Token' %% v2
+ 'ObservedEventsToken'
+ 'OffToken'
+ 'OnToken'
+ 'OnOffToken'
+ 'OnewayToken'
+ 'OnewayExternalToken' %% v3
+ 'OnewayBothToken' %% v3
+ 'OrAUDITselectToken' %% v3
+ 'OtherReasonToken'
+ 'OutOfSvcToken'
+ 'PackagesToken'
+ 'PendingToken'
+ 'PriorityToken'
+ 'ProfileToken'
+ 'QuotedChars'
+ 'RBRKT'
+ 'RSBRKT'
+ 'ReasonToken'
+ 'RecvonlyToken'
+ 'RemoteDescriptorToken'
+ 'ReplyToken'
+ 'RequestIDToken' %% v3
+ 'ReservedGroupToken'
+ 'ReservedValueToken'
+ 'ResetEventsDescriptorToken' %% v3
+ 'ResponseAckToken'
+ 'RestartToken'
+ 'SEP'
+ 'SafeChars'
+ %% 'SegmentationCompleteToken'
+ 'SendonlyToken'
+ 'SendrecvToken'
+ 'ServiceChangeAddressToken'
+ 'ServiceChangeToken'
+ 'ServiceChangeIncompleteToken'
+ 'ServiceStatesToken'
+ 'ServicesToken'
+ 'SignalListToken'
+ 'SignalTypeToken'
+ 'SignalsToken'
+ %% 'SLASH'
+ 'StatsToken'
+ 'StreamToken'
+ 'SubtractToken'
+ 'SynchISDNToken'
+ 'TerminationStateToken'
+ 'TestToken'
+ 'TimeOutToken'
+ 'TimeStampToken'
+ 'TopologyToken'
+ 'TransToken'
+ 'V18Token'
+ 'V22Token'
+ 'V22bisToken'
+ 'V32Token'
+ 'V32bisToken'
+ 'V34Token'
+ 'V76Token'
+ 'V90Token'
+ 'V91Token'
+ 'VersionToken'
+ endOfMessage
+
+.
+
+%%----------------------------------------------------------------------
+%% Root symbol
+%%----------------------------------------------------------------------
+
+Rootsymbol megacoMessage.
+
+%%----------------------------------------------------------------------
+%% The grammar
+%%----------------------------------------------------------------------
+
+%% megacoMessage = LWSP [authenticationHeader SEP ] message
+%% authenticationHeader = AuthToken EQUAL SecurityParmIndex COLON
+%% SequenceNum COLON AuthData
+%%
+%% SecurityParmIndex = "0x" 8(HEXDIG)
+%% SequenceNum = "0x" 8(HEXDIG)
+%% AuthData = "0x" 24*64(HEXDIG)
+%% message = MegacopToken SLASH version SEP mId SEP messageBody
+%% version = 1*2(DIGIT) .
+
+megacoMessage -> optSep authenticationHeader message endOfMessage
+ : #'MegacoMessage'{authHeader = '$2', mess = '$3'} .
+
+optSep -> 'SEP' : sep .
+optSep -> '$empty' : no_sep .
+
+authenticationHeader -> 'AuthToken' 'EQUAL' safeToken 'COLON'
+ safeToken 'COLON' safeToken optSep
+ : ensure_auth_header('$3', '$5', '$7') .
+authenticationHeader -> '$empty' : asn1_NOVALUE .
+
+message -> safeToken mId messageBody :
+ ensure_message('$1', '$2', '$3') .
+
+messageBody -> errorDescriptor : {messageError, '$1'} .
+messageBody -> transactionList : {transactions, '$1'} .
+
+transactionList -> transactionItem : ['$1'] .
+transactionList -> transactionItem transactionList : ['$1' | '$2'] .
+
+transactionItem -> transactionRequest : {transactionRequest, '$1'} .
+transactionItem -> transactionReply : {transactionReply, '$1'}.
+transactionItem -> transactionPending : {transactionPending, '$1'} .
+transactionItem -> transactionResponseAck : {transactionResponseAck, '$1'} .
+transactionItem -> segmentReply : {segmentReply, '$1'} .
+
+transactionResponseAck -> 'ResponseAckToken'
+ 'LBRKT' transactionAck
+ transactionAckList 'RBRKT' : ['$3' | '$4'] .
+
+transactionAckList -> 'COMMA' transactionAck
+ transactionAckList : ['$2' | '$3'] .
+transactionAckList -> '$empty' : [] .
+
+transactionAck -> safeToken : ensure_transactionAck('$1') .
+
+transactionPending -> 'PendingToken' 'EQUAL' transactionID 'LBRKT' 'RBRKT' :
+ #'TransactionPending'{transactionId = ensure_transactionID('$3') } .
+
+transactionRequest -> 'TransToken' 'LBRKT' actionRequest
+ actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$3' | '$4']} .
+transactionRequest -> 'TransToken' 'EQUAL' 'LBRKT' actionRequest
+ actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = asn1_NOVALUE,
+ actions = ['$4' | '$5']} .
+transactionRequest -> 'TransToken' 'EQUAL' transactionID
+ 'LBRKT' actionRequest actionRequestList 'RBRKT' :
+ #'TransactionRequest'{transactionId = ensure_transactionID('$3'),
+ actions = ['$5' | '$6']} .
+
+actionRequestList -> 'COMMA' actionRequest actionRequestList : ['$2' | '$3'] .
+actionRequestList -> '$empty' : [] .
+
+%% actionRequest = CtxToken EQUAL ContextID LBRKT ((contextRequest
+%% [COMMA commandRequestList]) /
+%% commandRequestList) RBRKT
+%% contextRequest = ((contextProperties [COMMA contextAudit]) /
+%% contextAudit)
+%% contextProperties = contextProperty *(COMMA contextProperty)
+
+actionRequest -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionRequestBody 'RBRKT' :
+ merge_action_request('$3', '$5') .
+
+actionRequestBody -> actionRequestItem actionRequestItems : ['$1' | '$2'] .
+
+actionRequestItems -> 'COMMA' actionRequestItem
+ actionRequestItems : ['$2' | '$3'] .
+actionRequestItems -> '$empty' : [] .
+
+actionRequestItem -> contextProperty : {contextProp, '$1'} .
+actionRequestItem -> contextAudit : {contextAudit, '$1'} .
+actionRequestItem -> commandRequest : {commandRequest, '$1'} .
+
+
+%% at-most-once (presumebly in contextProperties)
+contextProperty -> topologyDescriptor : {topology, '$1'}.
+contextProperty -> priority : {priority, '$1'}.
+contextProperty -> 'EmergencyToken' : {emergency, true}.
+contextProperty -> 'EmergencyOffToken' : {emergency, false}.
+contextProperty -> iepsValue : {iepsCallind, '$1'} .
+contextProperty -> contextAttrDescriptor : '$1' .
+
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' propertyParms 'RBRKT' :
+ {contextProp, '$3'}.
+contextAttrDescriptor -> 'ContextAttrToken' 'LBRKT' contextIdList 'RBRKT' :
+ {contextList, '$3'}.
+
+contextIdList -> 'ContextListToken' 'EQUAL'
+ 'LBRKT' contextID contextIDs 'RBRKT' : ['$4' | '$5'] .
+
+contextIDs -> 'COMMA' contextID contextIDs : ['$2' | '$3'] .
+contextIDs -> '$empty' : [] .
+
+contextAudit -> 'ContextAuditToken' 'LBRKT'
+ indAudcontextAttrDescriptor 'RBRKT' :
+ merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, '$3') .
+contextAudit -> 'ContextAuditToken' 'LBRKT'
+ contextAuditProperty contextAuditProperties 'RBRKT' :
+ merge_context_attr_audit_request(
+ #'ContextAttrAuditRequest'{}, ['$3' | '$4']) .
+
+indAudcontextAttrDescriptor -> 'ContextAttrToken'
+ 'LBRKT' contextAuditProperty
+ contextAuditProperties 'RBRKT'
+ : ['$3' | '$4'] .
+
+contextAuditProperties -> 'COMMA' contextAuditProperty contextAuditProperties
+ : ['$2' | '$3'] .
+contextAuditProperties -> '$empty' : [] .
+
+%% at-most-once except contextAuditSelector.
+contextAuditProperty -> 'TopologyToken' : topologyAudit .
+contextAuditProperty -> 'EmergencyToken' : emergencyAudit .
+contextAuditProperty -> 'PriorityToken' : priorityAudit .
+contextAuditProperty -> 'IEPSToken' : iepsCallind .
+contextAuditProperty -> pkgdName : {prop, '$1'} .
+contextAuditProperty -> contextAuditSelector : '$1' .
+
+%% at-most-once
+contextAuditSelector -> priority : {select_prio, '$1'} .
+contextAuditSelector -> emergencyValue : {select_emergency, '$1'} .
+contextAuditSelector -> iepsValue : {select_ieps, '$1'} .
+contextAuditSelector -> auditSelectLogic : {select_logic, '$1'} .
+contextAuditSelector -> contextAttrDescriptor : '$1' .
+
+auditSelectLogic -> 'AndAUDITselectToken' : {andAUDITSelect, 'NULL'} .
+auditSelectLogic -> 'OrAUDITselectToken' : {orAUDITSelect, 'NULL'} .
+
+commandRequest -> ammRequest : '$1'.
+commandRequest -> subtractRequest : '$1'.
+commandRequest -> auditRequest : '$1'.
+commandRequest -> notifyRequest : '$1'.
+commandRequest -> serviceChangeRequest : '$1'.
+
+transactionReply -> 'ReplyToken' 'EQUAL' transactionID_and_segment_info
+ 'LBRKT'
+ optImmAckRequired transactionReplyBody
+ 'RBRKT' :
+ make_TransactionReply('$3', '$5', '$6') .
+
+segmentReply -> 'MessageSegmentToken' 'EQUAL'
+ transactionID_and_segment_info :
+ make_SegmentReply('$3') .
+
+%% segmentNumber -> safeToken : ensure_uint16('$1') .
+
+optImmAckRequired -> 'ImmAckRequiredToken' 'COMMA' : 'NULL' .
+optImmAckRequired -> '$empty' : asn1_NOVALUE .
+
+transactionReplyBody -> errorDescriptor : {transactionError, '$1'} .
+transactionReplyBody -> actionReply actionReplyList : {actionReplies, ['$1' | '$2']} .
+
+actionReplyList -> 'COMMA' actionReply actionReplyList : ['$2' | '$3'] .
+actionReplyList -> '$empty' : [] .
+
+actionReply -> 'CtxToken' 'EQUAL' contextID
+ 'LBRKT' actionReplyBody 'RBRKT' :
+ setelement(#'ActionReply'.contextId, '$5', '$3') .
+actionReply -> 'CtxToken' 'EQUAL' contextID :
+ #'ActionReply'{contextId = '$3'} .
+
+actionReplyBody -> errorDescriptor :
+ #'ActionReply'{errorDescriptor = '$1'} .
+actionReplyBody -> commandReplys commandReplyList :
+ merge_action_reply(['$1' | '$2']) .
+
+%% OTP-5085
+%% This ugly thing is to fool the parser. The errorDescriptor does not
+%% realy belong here. The merge_action_reply will remove it and put it
+%% in it's right place later.
+commandReplyList -> 'COMMA' errorDescriptor :
+ [{error, '$2'}] .
+commandReplyList -> 'COMMA' commandReplys commandReplyList :
+ ['$2' | '$3'] .
+commandReplyList -> '$empty' : [] .
+
+commandReplys -> serviceChangeReply : {command, '$1'} .
+commandReplys -> auditReply : {command, '$1'} .
+commandReplys -> ammsReply : {command, '$1'} .
+commandReplys -> notifyReply : {command, '$1'} .
+commandReplys -> contextProperty : {context, '$1'} .
+
+%Add Move and Modify have the same request parameter
+ammRequest -> ammToken 'EQUAL' termIDList ammRequestBody :
+ Descs = merge_AmmRequest_descriptors('$4', []),
+ make_commandRequest('$1',
+ #'AmmRequest'{terminationID = '$3',
+ descriptors = Descs}) .
+
+ammToken -> 'AddToken' : {addReq, '$1'} .
+ammToken -> 'MoveToken' : {moveReq, '$1'} .
+ammToken -> 'ModifyToken' : {modReq, '$1'} .
+
+ammRequestBody -> 'LBRKT' ammParameter ammParameters 'RBRKT' : ['$2' | '$3'] .
+ammRequestBody -> '$empty' : [] .
+
+ammParameters -> 'COMMA' ammParameter ammParameters : ['$2' | '$3'] .
+ammParameters -> '$empty' : [] .
+
+%at-most-once
+ammParameter -> mediaDescriptor : {mediaDescriptor, '$1'}.
+ammParameter -> modemDescriptor : {modemDescriptor, deprecated}.
+ammParameter -> muxDescriptor : {muxDescriptor, '$1'}.
+ammParameter -> eventsDescriptor : {eventsDescriptor, '$1'}.
+ammParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'}.
+ammParameter -> signalsDescriptor : {signalsDescriptor, '$1'}.
+ammParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'}.
+ammParameter -> auditDescriptor : {auditDescriptor, '$1'}.
+ammParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'}.
+
+ammsReply -> ammsToken 'EQUAL' termIDList ammsReplyBody
+ : {'$1', #'AmmsReply'{terminationID = '$3',
+ terminationAudit = '$4'}} .
+
+ammsToken -> 'AddToken' : addReply .
+ammsToken -> 'MoveToken' : moveReply .
+ammsToken -> 'ModifyToken' : modReply .
+ammsToken -> 'SubtractToken' : subtractReply .
+
+ammsReplyBody -> 'LBRKT' terminationAudit 'RBRKT' : '$2' .
+ammsReplyBody -> '$empty' : asn1_NOVALUE .
+
+subtractRequest -> 'SubtractToken' 'EQUAL' termIDList optAuditDescriptor :
+ SR = #'SubtractRequest'{terminationID = '$3',
+ auditDescriptor = '$4'},
+ make_commandRequest({subtractReq, '$1'}, SR) .
+
+
+optAuditDescriptor -> 'LBRKT' auditDescriptor 'RBRKT' : '$2'.
+optAuditDescriptor -> '$empty' : asn1_NOVALUE .
+
+auditRequest -> 'AuditValueToken' 'EQUAL' termIDList optAuditDescriptor :
+ make_commandRequest({auditValueRequest, '$1'},
+ make_auditRequest('$3', '$4')) .
+auditRequest -> 'AuditCapToken' 'EQUAL' termIDList optAuditDescriptor :
+ make_commandRequest({auditCapRequest, '$1'},
+ make_auditRequest('$3', '$4')) .
+
+auditReply -> 'AuditValueToken' 'EQUAL' 'CtxToken' contextTerminationAudit :
+ {auditValueReply, '$4'} .
+auditReply -> 'AuditCapToken' 'EQUAL' 'CtxToken' contextTerminationAudit :
+ {auditCapReply, '$4'} .
+auditReply -> 'AuditValueToken' 'EQUAL' auditOther :
+ {auditValueReply, '$3'} .
+auditReply -> 'AuditCapToken' 'EQUAL' auditOther :
+ {auditCapReply, '$3'} .
+
+contextTerminationAudit -> terminationIDList :
+ {contextAuditResult, '$1'} .
+contextTerminationAudit -> 'LBRKT' errorDescriptor 'RBRKT' :
+ {error, '$2'} .
+
+auditOther -> termIDList :
+ merge_auditOther('$1', []) .
+auditOther -> termIDList 'LBRKT' terminationAudit 'RBRKT' :
+ merge_auditOther('$1', '$3') .
+
+
+terminationAudit -> auditReturnParameter auditReturnParameterList :
+ merge_terminationAudit(['$1' |'$2' ]) .
+
+auditReturnParameterList -> 'COMMA' auditReturnParameter auditReturnParameterList : ['$2' | '$3'] .
+auditReturnParameterList -> '$empty' : [] .
+
+auditReturnParameter -> mediaDescriptor : {mediaDescriptor, '$1'} .
+auditReturnParameter -> modemDescriptor.
+auditReturnParameter -> muxDescriptor : {muxDescriptor, '$1'} .
+auditReturnParameter -> eventsDescriptor : {eventsDescriptor, '$1'} .
+auditReturnParameter -> signalsDescriptor : {signalsDescriptor, '$1'} .
+auditReturnParameter -> digitMapDescriptor : {digitMapDescriptor, '$1'} .
+auditReturnParameter -> observedEventsDescriptor : {observedEventsDescriptor, '$1'} .
+auditReturnParameter -> eventBufferDescriptor : {eventBufferDescriptor, '$1'} .
+auditReturnParameter -> statisticsDescriptor : {statisticsDescriptor, '$1'} .
+auditReturnParameter -> packagesDescriptor : {packagesDescriptor, '$1'} .
+auditReturnParameter -> errorDescriptor : {errorDescriptor, '$1'} .
+auditReturnParameter -> auditReturnItem : {auditReturnItem, '$1'} .
+
+auditDescriptor -> 'AuditToken' 'LBRKT' auditDescriptorBody 'RBRKT' :
+ merge_auditDescriptor('$3') .
+
+auditDescriptorBody -> auditItem auditItemList : ['$1' | '$2'].
+auditDescriptorBody -> '$empty' : asn1_NOVALUE .
+
+auditItemList -> 'COMMA' auditItem auditItemList : ['$2' | '$3'] .
+auditItemList -> '$empty' : [] .
+
+%% IGv11 - begin
+%%
+auditReturnItem -> 'MuxToken' : muxToken .
+auditReturnItem -> 'ModemToken' : modemToken .
+auditReturnItem -> 'MediaToken' : mediaToken .
+auditReturnItem -> 'DigitMapToken' : digitMapToken .
+auditReturnItem -> 'StatsToken' : statsToken .
+auditReturnItem -> 'ObservedEventsToken' : observedEventsToken .
+auditReturnItem -> 'PackagesToken' : packagesToken .
+
+%% at-most-once, and DigitMapToken and PackagesToken are not allowed
+%% in AuditCapabilities command
+auditItem -> auditReturnItem : '$1' .
+auditItem -> 'SignalsToken' : signalsToken.
+auditItem -> 'EventBufferToken' : eventBufferToken.
+auditItem -> 'EventsToken' : eventsToken .
+auditItem -> indAudterminationAudit : {terminationAudit, '$1'} . % v2
+%%
+%% IGv11 - end
+
+
+%% v2 - start
+%%
+indAudterminationAudit -> indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$1' | '$2'] .
+
+indAudterminationAuditList -> 'COMMA' indAudauditReturnParameter
+ indAudterminationAuditList
+ : ['$2' | '$3'] .
+indAudterminationAuditList -> '$empty' : [] .
+
+indAudauditReturnParameter -> indAudmediaDescriptor
+ : {indAudMediaDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventsDescriptor
+ : {indAudEventsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudsignalsDescriptor
+ : {indAudSignalsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAuddigitMapDescriptor
+ : {indAudDigitMapDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudeventBufferDescriptor
+ : {indAudEventBufferDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudstatisticsDescriptor
+ : {indAudStatisticsDescriptor, '$1'} .
+indAudauditReturnParameter -> indAudpackagesDescriptor
+ : {indAudPackagesDescriptor, '$1'} .
+
+
+indAudmediaDescriptor -> 'MediaToken' 'LBRKT'
+ indAudmediaParm indAudmediaParms 'RBRKT'
+ : merge_indAudMediaDescriptor(['$3'|'$4']) .
+
+%% at-most-once per item
+%% and either streamParm or streamDescriptor but not both
+%%
+
+indAudmediaParm -> indAudstreamParm : {streamParm, '$1'} .
+indAudmediaParm -> indAudstreamDescriptor : {streamDescr, '$1'} .
+indAudmediaParm -> indAudterminationStateDescriptor : {termStateDescr, '$1'} .
+
+indAudmediaParms -> 'COMMA' indAudmediaParm indAudmediaParms : ['$2' | '$3'] .
+indAudmediaParms -> '$empty' : [] .
+
+%% at-most-once
+indAudstreamParm -> 'RemoteDescriptorToken' :
+ RD = ensure_prop_groups('$1'),
+ #'IndAudStreamParms'{remoteDescriptor = RD} .
+indAudstreamParm -> 'LocalDescriptorToken' :
+ LD = ensure_prop_groups('$1'),
+ #'IndAudStreamParms'{localDescriptor = LD} .
+indAudstreamParm -> indAudlocalControlDescriptor :
+ #'IndAudStreamParms'{localControlDescriptor = '$1'} .
+indAudstreamParm -> indAudstatisticsDescriptor :
+ #'IndAudStreamParms'{statisticsDescriptor = '$1'} .
+
+indAudstreamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' indAudstreamParm 'RBRKT'
+ : #'IndAudStreamDescriptor'{streamID = '$3',
+ streamParms = '$5'} .
+
+
+indAudlocalControlDescriptor -> 'LocalControlToken'
+ 'LBRKT' indAudlocalParm
+ indAudlocalParmList 'RBRKT' :
+ merge_indAudLocalControlDescriptor(['$3' | '$4']) .
+
+indAudlocalParmList -> 'COMMA' indAudlocalParm
+ indAudlocalParmList : ['$2' | '$3'] .
+indAudlocalParmList -> '$empty' : [] .
+
+%% at-most-once per item
+%%
+%% propertyparm and streamModes are used only to specify audit selection
+%% criteria. AND/OR selection logic is specified at context level.
+%%
+indAudlocalParm -> 'ReservedGroupToken' : reservedGroupToken .
+indAudlocalParm -> 'ReservedValueToken' : reservedValueToken .
+indAudlocalParm -> 'ModeToken' : modeToken .
+indAudlocalParm -> 'ModeToken' 'EQUAL' streamModes : {mode, {equal, '$3'}} .
+indAudlocalParm -> 'ModeToken' 'INEQUAL' streamModes : {mode, {inequal,'$3'}} .
+indAudlocalParm -> propertyParm : {prop, '$1'} .
+indAudlocalParm -> pkgdName : {name, '$1'} .
+
+indAudterminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' indAudterminationStateParm 'RBRKT'
+ :
+ merge_indAudTerminationStateDescriptor('$3') .
+
+%% at-most-once per item
+%%
+
+%% at-most-once per item except for propertyParm
+indAudterminationStateParm -> iaServiceStates : '$1' .
+indAudterminationStateParm -> 'BufferToken' : bufferToken .
+indAudterminationStateParm -> propertyParm : {prop, '$1'} .
+indAudterminationStateParm -> pkgdName : {name, '$1'} .
+
+iaServiceStates -> 'ServiceStatesToken' :
+ serviceStatesToken .
+iaServiceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue :
+ {serviceStates, {equal, '$3'}} .
+iaServiceStates -> 'ServiceStatesToken' 'INEQUAL' serviceStatesValue :
+ {serviceStates, {inequal, '$3'}} .
+
+indAudeventBufferDescriptor -> 'EventBufferToken'
+ 'LBRKT' indAudeventSpec 'RBRKT' : '$3' .
+
+indAudeventSpec -> pkgdName optIndAudeventSpecParameter
+ : merge_indAudEventBufferDescriptor('$1','$2') .
+
+optIndAudeventSpecParameter -> 'LBRKT' indAudeventSpecParameter 'RBRKT'
+ : '$2' .
+optIndAudeventSpecParameter -> '$empty' : asn1_NOVALUE .
+
+
+indAudeventSpecParameter -> eventStream : {streamID, '$1'} .
+indAudeventSpecParameter -> eventParameterName : {eventParameterName, '$1'} .
+
+indAudeventsDescriptor -> 'EventsToken' 'LBRKT' indAudrequestedEvent 'RBRKT' :
+ #'IndAudEventsDescriptor'{pkgdName = '$3'} .
+indAudeventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' indAudrequestedEvent 'RBRKT' :
+ #'IndAudEventsDescriptor'{requestID = '$3',
+ pkgdName = '$5'} .
+
+indAudrequestedEvent -> pkgdName : '$1' .
+
+
+indAudsignalsDescriptor -> 'SignalsToken' optIndAudsignalParm : '$2' .
+
+
+optIndAudsignalParm -> 'LBRKT' 'RBRKT' : asn1_NOVALUE .
+optIndAudsignalParm -> 'LBRKT' indAudsignalParm 'RBRKT' : '$2' .
+
+indAudsignalParm -> indAudsignalList : {seqSigList, '$1'} .
+indAudsignalParm -> signalRequest : {signal, ensure_indAudSignal('$1')} .
+
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3')} .
+indAudsignalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm 'RBRKT' :
+ #'IndAudSeqSigList'{id = ensure_uint16('$3'),
+ signalList =
+ ensure_indAudSignalListParm('$5')} .
+
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+indAuddigitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_IADMD('$1') .
+
+indAudstatisticsDescriptor -> 'StatsToken' 'LBRKT' pkgdName 'RBRKT' :
+ #'IndAudStatisticsDescriptor'{statName = '$3'} .
+
+indAudpackagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem 'RBRKT'
+ : merge_indAudPackagesDescriptor('$3') .
+
+eventStream -> 'StreamToken' 'EQUAL' streamID : '$3' .
+
+
+%%
+%% v2 - end
+
+notifyRequest -> 'NotifyToken' 'EQUAL' termIDList
+ 'LBRKT' notifyRequestBody 'RBRKT' :
+ NR = setelement(#'NotifyRequest'.terminationID,
+ '$5', '$3'),
+ make_commandRequest({notifyReq, '$1'}, NR) .
+
+notifyRequestBody -> observedEventsDescriptor :
+ #'NotifyRequest'{observedEventsDescriptor = '$1'}.
+notifyRequestBody -> errorDescriptor :
+ #'NotifyRequest'{errorDescriptor = '$1'}.
+
+notifyReply -> 'NotifyToken' 'EQUAL' termIDList notifyReplyBody :
+ {notifyReply, #'NotifyReply'{terminationID = '$3',
+ errorDescriptor = '$4'}} .
+
+notifyReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' : '$2'.
+notifyReplyBody -> '$empty' : asn1_NOVALUE .
+
+serviceChangeRequest -> 'ServiceChangeToken' 'EQUAL' termIDList
+ 'LBRKT' serviceChangeDescriptor 'RBRKT' :
+ make_commandRequest({serviceChangeReq, '$1'},
+ #'ServiceChangeRequest'{terminationID = '$3',
+ serviceChangeParms = '$5'}) .
+
+serviceChangeReply -> 'ServiceChangeToken' 'EQUAL' termIDList
+ serviceChangeReplyBody :
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = '$3',
+ serviceChangeResult = '$4'}} .
+
+serviceChangeReplyBody -> 'LBRKT' errorDescriptor 'RBRKT' :
+ {errorDescriptor, '$2'} .
+serviceChangeReplyBody -> 'LBRKT' serviceChangeReplyDescriptor 'RBRKT' :
+ {serviceChangeResParms, '$2'} .
+serviceChangeReplyBody -> '$empty' :
+ {serviceChangeResParms, #'ServiceChangeResParm'{}}.
+
+errorDescriptor -> 'ErrorToken' 'EQUAL' errorCode 'LBRKT'
+ errorText 'RBRKT' :
+ #'ErrorDescriptor'{errorCode = '$3',
+ errorText = '$5'} .
+
+errorCode -> safeToken : ensure_uint('$1', 0, 999) .
+
+errorText -> 'QuotedChars' : value_of('$1') .
+errorText -> '$empty' : asn1_NOVALUE .
+
+transactionID -> safeToken : ensure_uint32('$1') .
+transactionID_and_segment_info -> safeToken :
+ make_transactionID_and_segment_info('$1') .
+
+mId -> domainName : '$1' .
+mId -> domainAddress : '$1' .
+mId -> optSep mtpAddress optSep : '$2' .
+mId -> optSep deviceName optSep : '$2' .
+
+domainName -> 'LESSER' safeToken 'GREATER' 'COLON' portNumber optSep
+ : ensure_domainName('$2', '$5') .
+domainName -> 'LESSER' safeToken 'GREATER'
+ : ensure_domainName('$2', asn1_NOVALUE) .
+
+deviceName -> pathName : {deviceName, '$1'} .
+
+%% '-' is used for NULL context
+contextID -> safeToken : ensure_contextID('$1') .
+
+domainAddress -> 'LSBRKT' daddr 'RSBRKT' 'COLON' portNumber optSep
+ : ensure_domainAddress('$2', '$5') .
+domainAddress -> 'LSBRKT' daddr 'RSBRKT'
+ : ensure_domainAddress('$2', asn1_NOVALUE) .
+
+daddr -> '$empty' : [] .
+daddr -> 'COLON' daddr : [colon| '$2'] .
+daddr -> safeToken daddr : ['$1'| '$2'] .
+
+
+portNumber -> safeToken : ensure_uint16('$1') .
+
+mtpAddress -> 'MtpAddressToken' : ensure_mtpAddress('$1') .
+
+termIDList -> terminationID : ['$1'] .
+termIDList -> LSBRKT terminationID terminationIDListRepeat RSBRKT :
+ ['$2' | '$3'] .
+
+terminationIDList -> 'LBRKT' terminationID terminationIDListRepeat 'RBRKT' :
+ ['$2' | '$3'] .
+
+terminationIDListRepeat -> 'COMMA' terminationID terminationIDListRepeat :
+ ['$2'| '$3'] .
+terminationIDListRepeat -> '$empty' : [] .
+
+
+pathName -> safeToken : ensure_pathName('$1') .
+
+terminationID -> safeToken : ensure_terminationID('$1') .
+
+mediaDescriptor -> 'MediaToken' 'LBRKT' mediaParm mediaParmList 'RBRKT'
+ : merge_mediaDescriptor(['$3' | '$4']) .
+
+mediaParmList -> 'COMMA' mediaParm mediaParmList : ['$2' | '$3'] .
+mediaParmList -> '$empty' : [] .
+
+
+%% at-most-once per item
+%% using either streamParms or streamDescriptors but not both
+mediaParm -> streamParm
+ : {streamParm, '$1'} .
+mediaParm -> streamDescriptor
+ : {streamDescriptor, '$1'} .
+mediaParm -> terminationStateDescriptor
+ : {termState, '$1'} .
+
+%% at-most-once .
+%% Specially treated by the scanner.
+streamParm -> 'LocalDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {local, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> 'RemoteDescriptorToken' :
+ PGs = ensure_prop_groups('$1'),
+ {remote, #'LocalRemoteDescriptor'{propGrps = PGs}} .
+streamParm -> localControlDescriptor : {control, '$1'} .
+streamParm -> statisticsDescriptor : {statistics, '$1'} .
+
+streamDescriptor -> 'StreamToken' 'EQUAL' streamID
+ 'LBRKT' streamParm streamParmList 'RBRKT'
+ : #'StreamDescriptor'{streamID = '$3',
+ streamParms = merge_streamParms(['$5' | '$6'])} .
+
+streamParmList -> 'COMMA' streamParm streamParmList : ['$2' | '$3'] .
+streamParmList -> '$empty' : [] .
+
+localControlDescriptor -> 'LocalControlToken' 'LBRKT' localParm localParmList 'RBRKT'
+ : ['$3' | '$4'] .
+
+localParmList -> 'COMMA' localParm localParmList : ['$2' | '$3'] .
+localParmList -> '$empty': [] .
+
+terminationStateDescriptor -> 'TerminationStateToken'
+ 'LBRKT' terminationStateParm
+ terminationStateParms 'RBRKT'
+ : merge_terminationStateDescriptor(['$3' | '$4']) .
+
+terminationStateParms -> 'COMMA' terminationStateParm terminationStateParms : ['$2' | '$3'] .
+terminationStateParms -> '$empty' : [] .
+
+%% at-most-once per item except for propertyParm
+localParm -> 'ReservedGroupToken' 'EQUAL' onOrOff : {group, '$3'} .
+localParm -> 'ReservedValueToken' 'EQUAL' onOrOff : {value, '$3'} .
+localParm -> 'ModeToken' 'EQUAL' streamModes : {mode, '$3'} .
+localParm -> propertyParm : {prop, '$1'} .
+
+onOrOff -> 'OnToken' : true .
+onOrOff -> 'OffToken' : false .
+
+%% at-most-once
+streamModes -> 'SendonlyToken' : sendOnly .
+streamModes -> 'RecvonlyToken' : recvOnly .
+streamModes -> 'SendrecvToken' : sendRecv .
+streamModes -> 'InactiveToken' : inactive .
+streamModes -> 'LoopbackToken' : loopBack .
+
+propertyParm -> pkgdName parmValue :
+ setelement(#'PropertyParm'.name, '$2', '$1') .
+
+parmValue -> 'EQUAL' alternativeValue :
+ '$2' .
+
+parmValue -> 'NEQUAL' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, unequalTo}} .
+parmValue -> 'LESSER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, smallerThan}} .
+parmValue -> 'GREATER' value :
+ #'PropertyParm'{value = ['$2'],
+ extraInfo = {relation, greaterThan}} .
+
+%% OTP-4013
+%% alternativeValue = ( VALUE /
+%% LSBRKT VALUE *(COMMA VALUE) RSBRKT /
+%% LSBRKT VALUE COLON VALUE RSBRKT ) /
+%% LBRKT VALUE *(COMMA VALUE) RBRKT
+alternativeValue -> 'LBRKT' value valueList 'RBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, false}}. % OR
+
+alternativeValue -> 'LSBRKT' value 'COLON' value 'RSBRKT'
+ : #'PropertyParm'{value = ['$2', '$4'],
+ extraInfo = {range, true}}.
+
+alternativeValue -> 'LSBRKT' value valueList 'RSBRKT'
+ : #'PropertyParm'{value = ['$2' | '$3'],
+ extraInfo = {sublist, true}}. % AND
+
+alternativeValue -> value :
+ #'PropertyParm'{value = ['$1']} .
+
+valueList -> 'COMMA' value valueList : ['$2' | '$3'] .
+valueList -> '$empty' : [] .
+
+
+eventBufferDescriptor -> 'EventBufferToken' : [] .
+eventBufferDescriptor -> 'EventBufferToken' 'LBRKT' eventSpec
+ eventSpecList 'RBRKT' :
+ ['$3' | '$4'] .
+
+eventSpecList -> 'COMMA' eventSpec eventSpecList : ['$2' | '$3'] .
+eventSpecList -> '$empty' : [] .
+
+eventSpec -> observedEvent : merge_eventSpec('$1') .
+
+%% at-most-once per item except for propertyParm
+terminationStateParm -> serviceStates : {serviceState, '$1'} .
+terminationStateParm -> eventBufferControl : {eventBufferControl, '$1'} .
+terminationStateParm -> propertyParm : {propertyParm, '$1'} .
+
+serviceStates -> 'ServiceStatesToken' 'EQUAL' serviceStatesValue : '$3'.
+
+serviceStatesValue -> 'TestToken' : test .
+serviceStatesValue -> 'OutOfSvcToken' : outOfSvc .
+serviceStatesValue -> 'InSvcToken' : inSvc .
+
+eventBufferControl -> 'BufferToken' 'EQUAL' eventBufferControlValue : '$3' .
+
+eventBufferControlValue -> 'OffToken' : off .
+eventBufferControlValue -> 'LockStepToken' : lockStep .
+
+muxDescriptor -> 'MuxToken' 'EQUAL' muxType terminationIDList :
+ #'MuxDescriptor'{muxType = '$3',
+ termList = '$4'} .
+
+muxType -> safeToken : ensure_muxType('$1') .
+
+streamID -> safeToken : ensure_streamID('$1') .
+
+pkgdName -> safeToken : ensure_pkgdName('$1') .
+
+eventsDescriptor -> 'EventsToken' :
+ #'EventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+eventsDescriptor -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' requestedEvent requestedEvents 'RBRKT' :
+ #'EventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+requestedEvents -> 'COMMA' requestedEvent requestedEvents : ['$2' | '$3'] .
+requestedEvents -> '$empty' : [] .
+
+requestedEvent -> pkgdName requestedEventBody :
+ setelement(#'RequestedEvent'.pkgdName, '$2', '$1') .
+
+requestedEventBody -> 'LBRKT' eventParameter eventParameters 'RBRKT' :
+ merge_eventParameters(['$2' | '$3']) .
+requestedEventBody -> '$empty' : #'RequestedEvent'{evParList = []} .
+
+
+notifyRegulated -> 'NotifyRegulatedToken' :
+ #'RegulatedEmbeddedDescriptor'{} .
+notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedWithSig 'RBRKT' :
+ make_RegulatedEmbeddedDescriptor('$3') .
+notifyRegulated -> 'NotifyRegulatedToken' 'LBRKT' embedNoSig 'RBRKT' :
+ make_RegulatedEmbeddedDescriptor('$3') .
+
+notifyBehaviour -> 'NotifyImmediateToken' : {notifyImmediate, 'NULL'} .
+notifyBehaviour -> 'NeverNotifyToken' : {neverNotify, 'NULL'} .
+notifyBehaviour -> notifyRegulated : {notifyRegulated, '$1'} .
+
+eventParameters -> 'COMMA' eventParameter eventParameters :
+ ['$2' | '$3'] .
+eventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+eventParameter -> 'KeepActiveToken' : keepActive .
+eventParameter -> embedWithSig : '$1'.
+eventParameter -> embedNoSig : '$1'.
+eventParameter -> eventDM : '$1'.
+eventParameter -> eventStreamOrOther : '$1'.
+eventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}.
+eventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor .
+
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor
+ 'COMMA' embedFirst 'RBRKT'
+ : {embed, '$3', '$5'} .
+embedWithSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {embed, '$3', asn1_NOVALUE} .
+
+embedNoSig -> 'EmbedToken' 'LBRKT' embedFirst 'RBRKT'
+ : {embed, asn1_NOVALUE, '$3'} .
+
+embedFirst -> 'EventsToken' :
+ #'SecondEventsDescriptor'{requestID = asn1_NOVALUE,
+ eventList = []} .
+embedFirst -> 'EventsToken' 'EQUAL' requestID
+ 'LBRKT' secondRequestedEvent secondRequestedEvents 'RBRKT' :
+ #'SecondEventsDescriptor'{requestID = '$3',
+ eventList = ['$5' | '$6']} .
+
+secondRequestedEvents -> 'COMMA' secondRequestedEvent secondRequestedEvents : ['$2' | '$3'] .
+secondRequestedEvents -> '$empty' : [] .
+
+%% at-most-once of each
+secondRequestedEvent -> pkgdName secondRequestedEventBody
+ : setelement(#'SecondRequestedEvent'.pkgdName, '$2', '$1') .
+
+secondRequestedEventBody -> 'LBRKT' secondEventParameter secondEventParameters 'RBRKT'
+ : merge_secondEventParameters(['$2' | '$3']) .
+secondRequestedEventBody -> '$empty' : #'SecondRequestedEvent'{evParList = []} .
+
+secondEventParameters -> 'COMMA' secondEventParameter secondEventParameters : ['$2' | '$3'] .
+secondEventParameters -> '$empty' : [] .
+
+%% at-most-once each of embedOrKeepActive , eventDM or eventStream
+secondEventParameter -> 'KeepActiveToken' : keepActive .
+secondEventParameter -> embedSig : '$1' .
+secondEventParameter -> eventDM : '$1' .
+secondEventParameter -> eventStreamOrOther : '$1' .
+secondEventParameter -> notifyBehaviour : {notifyBehaviour, '$1'}.
+secondEventParameter -> 'ResetEventsDescriptorToken' : resetEventsDescriptor .
+
+embedSig -> 'EmbedToken' 'LBRKT' signalsDescriptor 'RBRKT'
+ : {second_embed, '$3'} .
+
+eventStreamOrOther -> eventParameterName parmValue :
+ select_stream_or_other('$1', '$2') .
+
+eventParameterName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+eventDM -> 'DigitMapDescriptorToken' :
+ ensure_eventDM('$1') .
+
+%% H248S-IG (IGv11)
+signalsDescriptor -> 'SignalsToken' 'LBRKT' signalParm signalParms 'RBRKT' :
+ ['$3' | '$4'] .
+signalsDescriptor -> 'SignalsToken' : [] .
+
+signalParms -> 'COMMA' signalParm signalParms : [ '$2' | '$3'] .
+signalParms -> '$empty' : [] .
+
+signalParm -> signalList : {seqSigList, '$1'} .
+signalParm -> signalRequest : {signal, '$1'} .
+
+signalRequest -> signalName 'LBRKT' sigParameter sigParameters 'RBRKT'
+ : merge_signalRequest('$1', ['$3' | '$4']).
+signalRequest -> signalName : merge_signalRequest('$1', []).
+
+sigParameters -> 'COMMA' sigParameter sigParameters : ['$2' | '$3'] .
+sigParameters -> '$empty' : [] .
+
+%% sigParameter = sigStream / sigSignalType / sigDuration / sigOther /
+%% notifyCompletion / KeepActiveToken /
+%% direction / sigRequestID
+%% sigStream = StreamToken EQUAL StreamID
+%% sigOther = sigParameterName parmValue
+%% sigParameterName = NAME
+%% sigSignalType = SignalTypeToken EQUAL signalType
+%% signalType = (OnOffToken / TimeOutToken / BriefToken)
+%% sigDuration = DurationToken EQUAL UINT16
+%% notifyCompletion = NotifyCompletionToken EQUAL (LBRKT
+%% notificationReason *(COMMA notificationReason)
+%% RBRKT)
+%%
+%% notificationReason = ( TimeOutToken / InterruptByEventToken /
+%% InterruptByNewSignalsDescrToken /
+%% OtherReasonToken )
+%% sigDirection = DirectionToken EQUAL direction
+%% sigRequestID = RequestIDToken EQUAL RequestID
+%% sigIntsigDelay = IntsigDelayToken EQUAL UINT16
+
+sigParameter -> 'StreamToken' 'EQUAL' streamID :
+ {stream, '$3'}.
+sigParameter -> 'SignalTypeToken' 'EQUAL' signalType :
+ {signal_type, '$3'} .
+sigParameter -> 'DurationToken' 'EQUAL' safeToken :
+ {duration, ensure_uint16('$3')} .
+sigParameter -> 'NotifyCompletionToken' 'EQUAL'
+ 'LBRKT' notificationReason notificationReasons 'RBRKT' :
+ {notify_completion, ['$4' | '$5']} .
+sigParameter -> 'KeepActiveToken' : keepActive .
+sigParameter -> 'DirectionToken' 'EQUAL' direction :
+ {direction, '$3'} .
+sigParameter -> 'RequestIDToken' 'EQUAL' requestID :
+ {requestId, '$3'} .
+sigParameter -> 'IntsigDelayToken' 'EQUAL' safeToken :
+ {intersigDelay, ensure_uint16('$3')} .
+sigParameter -> safeToken parmValue :
+ {other, ensure_NAME('$1'), '$2'}.
+
+signalType -> 'OnOffToken' : onOff.
+signalType -> 'TimeOutToken' : timeOut.
+signalType -> 'BriefToken' : brief.
+
+direction -> 'ExternalToken' : external .
+direction -> 'InternalToken' : internal .
+direction -> 'BothToken' : both .
+
+notificationReasons -> 'COMMA' notificationReason notificationReasons : ['$2' | '$3'] .
+notificationReasons -> '$empty' : [] .
+
+notificationReason -> 'TimeOutToken' : onTimeOut .
+notificationReason -> 'InterruptByEventToken' : onInterruptByEvent .
+notificationReason -> 'InterruptByNewSignalsDescrToken' : onInterruptByNewSignalDescr .
+notificationReason -> 'OtherReasonToken' : otherReason .
+notificationReason -> 'IterationToken' : iteration .
+
+signalList -> 'SignalListToken' 'EQUAL' signalListId
+ 'LBRKT' signalListParm signalListParms 'RBRKT'
+ : #'SeqSigList'{id = ensure_uint16('$3'),
+ signalList = ['$5' | '$6']} .
+
+signalListParms -> 'COMMA' signalListParm signalListParms :
+ ['$2' | '$3'] .
+signalListParms -> '$empty' : [] .
+
+signalListId -> safeToken : ensure_uint16('$1') .
+
+%% exactly once signalType,
+%% at most once duration and every signal parameter
+signalListParm -> signalRequest : '$1'.
+
+signalName -> pkgdName : '$1'.
+
+observedEventsDescriptor -> 'ObservedEventsToken' 'EQUAL' requestID
+ 'LBRKT' observedEvent observedEvents 'RBRKT'
+ : #'ObservedEventsDescriptor'{requestId = '$3',
+ observedEventLst = ['$5' | '$6']} .
+
+observedEvents -> 'COMMA' observedEvent observedEvents : ['$2' | '$3'] .
+observedEvents -> '$empty' : [] .
+
+%%time per event, because it might be buffered
+
+observedEvent -> timeStamp optSep 'COLON' optSep pkgdName observedEventBody :
+ merge_observed_event('$6', '$5', '$1') .
+observedEvent -> optSep pkgdName observedEventBody :
+ merge_observed_event('$3', '$2', asn1_NOVALUE) .
+
+observedEventBody -> 'LBRKT' observedEventParameter
+ observedEventParameters 'RBRKT'
+ : ['$2' | '$3'] .
+observedEventBody -> '$empty' : [] .
+
+observedEventParameters -> 'COMMA' observedEventParameter observedEventParameters : ['$2' | '$3'] .
+observedEventParameters -> '$empty' : [] .
+
+%%at-most-once eventStream, every eventParameterName at most once
+observedEventParameter -> eventStreamOrOther : '$1' .
+
+requestID -> safeToken : ensure_requestID('$1') .
+
+%% Deprecated as of Corr 1
+modemDescriptor -> 'ModemToken' 'EQUAL' modemType optPropertyParms .
+modemDescriptor -> 'ModemToken' 'LSBRKT' modemType modemTypeList 'RSBRKT'
+ optPropertyParms.
+modemTypeList -> 'COMMA' modemType modemTypeList.
+modemTypeList -> '$empty'.
+modemType -> safeToken.
+
+optPropertyParms -> 'LBRKT' propertyParm propertyParmList 'RBRKT' :
+ ['$2' | '$3'] .
+optPropertyParms -> '$empty' : [] .
+
+propertyParms -> propertyParm propertyParmList : ['$1' | '$2'] .
+propertyParmList -> 'COMMA' propertyParm propertyParmList : ['$2' | '$3'] .
+propertyParmList -> '$empty' : [] .
+
+% parmName -> safeToken : ensure_NAME('$1') .
+
+%% The DigitMapDescriptorToken is specially treated by the scanner
+digitMapDescriptor -> 'DigitMapDescriptorToken' :
+ ensure_DMD('$1') .
+
+%% each parameter at-most-once, except auditItem
+%% at most one of either serviceChangeAddress or serviceChangeMgcId but
+%% not both. serviceChangeMethod and serviceChangeReason are REQUIRED
+serviceChangeDescriptor -> 'ServicesToken'
+ 'LBRKT' serviceChangeParm
+ serviceChangeParms 'RBRKT' :
+ merge_ServiceChangeParm(['$3' | '$4']) .
+
+serviceChangeParms -> 'COMMA' serviceChangeParm serviceChangeParms :
+ ['$2' | '$3'] .
+serviceChangeParms -> '$empty' : [] .
+
+serviceChangeParm -> serviceChangeMethod : {method, '$1'} .
+serviceChangeParm -> serviceChangeReason : {reason, '$1'} .
+serviceChangeParm -> serviceChangeDelay : {delay, '$1'} .
+serviceChangeParm -> serviceChangeAddress : {address, '$1'} .
+serviceChangeParm -> serviceChangeProfile : {profile, '$1'} .
+serviceChangeParm -> extension : {extension, '$1'} .
+serviceChangeParm -> timeStamp : {time_stamp, '$1'} .
+serviceChangeParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+serviceChangeParm -> serviceChangeVersion : {version, '$1'} .
+serviceChangeParm -> 'ServiceChangeIncompleteToken' : incomplete . % v3
+serviceChangeParm -> auditItem : {audit_item, '$1'} . % v2
+
+serviceChangeMethod -> 'MethodToken' 'EQUAL' safeToken :
+ ensure_serviceChangeMethod('$3') .
+
+serviceChangeReason -> 'ReasonToken' 'EQUAL' value : ['$3'] .
+
+serviceChangeDelay -> 'DelayToken' 'EQUAL' safeToken : ensure_uint32('$3').
+
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' mId : '$3' .
+serviceChangeAddress -> 'ServiceChangeAddressToken' 'EQUAL' portNumber :
+ {portNumber, '$3'} .
+
+serviceChangeMgcId -> 'MgcIdToken' 'EQUAL' mId : '$3' .
+
+serviceChangeProfile -> 'ProfileToken' 'EQUAL' safeToken : ensure_profile('$3').
+
+serviceChangeVersion -> 'VersionToken' 'EQUAL' safeToken : ensure_version('$3') .
+
+extension -> extensionParameter parmValue
+ : setelement(#'PropertyParm'.name, '$2', '$1') .
+
+%% at most once. Version is REQUIRED on first ServiceChange response
+%% at most of either serviceChangeAddress or serviceChangeMgcId but not both
+serviceChangeReplyDescriptor -> 'ServicesToken'
+ 'LBRKT' servChgReplyParm
+ servChgReplyParms 'RBRKT' :
+ merge_ServiceChangeResParm(['$3' | '$4']) .
+
+servChgReplyParms -> 'COMMA' servChgReplyParm servChgReplyParms :
+ ['$2' | '$3'] .
+servChgReplyParms -> '$empty' : [] .
+
+servChgReplyParm -> serviceChangeAddress : {address, '$1'} .
+servChgReplyParm -> serviceChangeMgcId : {mgc_id, '$1'} .
+servChgReplyParm -> serviceChangeProfile : {profile, '$1'} .
+servChgReplyParm -> serviceChangeVersion : {version, '$1'} .
+servChgReplyParm -> timeStamp : {time_stamp,'$1'} .
+
+packagesDescriptor -> 'PackagesToken' 'LBRKT' packagesItem
+ packagesItems 'RBRKT'
+ : ['$3' | '$4'] .
+
+packagesItems -> 'COMMA' packagesItem packagesItems : ['$2' | '$3'] .
+packagesItems -> '$empty' : [] .
+
+packagesItem -> safeToken : ensure_packagesItem('$1') .
+
+timeStamp -> TimeStampToken : ensure_timeStamp('$1') .
+
+statisticsDescriptor -> 'StatsToken'
+ 'LBRKT' statisticsParameter
+ statisticsParameters 'RBRKT'
+ : ['$3' | '$4'] .
+
+statisticsParameters -> 'COMMA' statisticsParameter statisticsParameters : ['$2' | '$3'] .
+statisticsParameters -> '$empty' : [] .
+
+%%at-most-once per item
+statisticsParameter -> pkgdName :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = asn1_NOVALUE} .
+statisticsParameter -> pkgdName 'EQUAL' value :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = ['$3']} .
+statisticsParameter -> pkgdName 'EQUAL' 'LSBRKT' value valueList 'RSBRKT' :
+ #'StatisticsParameter'{statName = '$1',
+ statValue = ['$4' | '$5']} .
+
+
+topologyDescriptor -> 'TopologyToken' 'LBRKT'
+ topologyDescComp topologyDescCompList 'RBRKT' :
+ merge_topologyDescriptor(['$3' | '$4']) .
+
+topologyDescComp -> terminationID : {tid, '$1'} .
+topologyDescComp -> eventStream : {sid, '$1'} .
+topologyDescComp -> topologyDirection : '$1' .
+
+topologyDescCompList -> '$empty' : [] .
+topologyDescCompList -> 'COMMA' topologyDescComp topologyDescCompList :
+ ['$2' | '$3'] .
+
+topologyDirection -> 'BothwayToken' : {direction, bothway} .
+topologyDirection -> 'IsolateToken' : {direction, isolate} .
+topologyDirection -> 'OnewayToken' : {direction, oneway} .
+topologyDirection -> 'OnewayExternalToken' : {direction_ext, onewayexternal} .
+topologyDirection -> 'OnewayBothToken' : {direction_ext, onewayboth} .
+
+iepsValue -> 'IEPSToken' 'EQUAL' onOrOff : '$3' .
+
+emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyToken' : true .
+emergencyValue -> 'EmergencyValueToken' 'EQUAL' 'EmergencyOffToken' : false .
+
+priority -> 'PriorityToken' 'EQUAL' safeToken : ensure_uint16('$3') .
+
+extensionParameter -> safeToken : ensure_extensionParameter('$1') .
+
+value -> 'QuotedChars' : ensure_value('$1') .
+value -> safeToken : ensure_value('$1').
+
+safeToken -> safeToken2 : make_safe_token('$1') .
+
+safeToken2 -> 'SafeChars' : '$1' .
+%% BMK BMK safeToken2 -> 'AddToken' : '$1' .
+safeToken2 -> 'AuditToken' : '$1' .
+safeToken2 -> 'AuditCapToken' : '$1' .
+safeToken2 -> 'AuditValueToken' : '$1' .
+safeToken2 -> 'AuthToken' : '$1' .
+safeToken2 -> 'BothToken' : '$1' . % v3
+%% v3-safeToken2 -> 'BothwayToken' : '$1' .
+safeToken2 -> 'BriefToken' : '$1' .
+%% v3-safeToken2 -> 'BufferToken' : '$1' .
+safeToken2 -> 'CtxToken' : '$1' .
+%% v3-safeToken2 -> 'ContextAttrToken' : '$1' . % v3
+safeToken2 -> 'ContextAuditToken' : '$1' .
+%% v3-safeToken2 -> 'ContextListToken' : '$1' . % v3
+%% v2-safeToken2 -> 'DigitMapToken' : '$1' .
+%% safeToken2 -> 'DigitMapDescriptorToken' : '$1' .
+%% v3-
+safeToken2 -> 'DirectionToken' : '$1' . % v3
+safeToken2 -> 'DiscardToken' : '$1' .
+safeToken2 -> 'DisconnectedToken' : '$1' .
+safeToken2 -> 'DelayToken' : '$1' .
+safeToken2 -> 'DurationToken' : '$1' .
+safeToken2 -> 'EmbedToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyToken' : '$1' .
+%% BMK BMK safeToken2 -> 'EmergencyOffToken' : '$1' .
+safeToken2 -> 'ErrorToken' : '$1' .
+%% v2-safeToken2 -> 'EventBufferToken' : '$1' .
+%% v2-safeToken2 -> 'EventsToken' : '$1' .
+%% v3-safeToken2 -> 'ExternalToken' : '$1' . % v3
+safeToken2 -> 'FailoverToken' : '$1' .
+safeToken2 -> 'ForcedToken' : '$1' .
+safeToken2 -> 'GracefulToken' : '$1' .
+safeToken2 -> 'H221Token' : '$1' .
+safeToken2 -> 'H223Token' : '$1' .
+safeToken2 -> 'H226Token' : '$1' .
+safeToken2 -> 'HandOffToken' : '$1' .
+%% v3-safeToken2 -> 'IEPSToken' : '$1' . % v3
+safeToken2 -> 'ImmAckRequiredToken' : '$1' .
+safeToken2 -> 'InactiveToken' : '$1' .
+%% v3-safeToken2 -> 'InternalToken' : '$1' . % v3
+safeToken2 -> 'InterruptByEventToken' : '$1' .
+safeToken2 -> 'InterruptByNewSignalsDescrToken' : '$1' .
+%% v3-safeToken2 -> 'IsolateToken' : '$1' .
+safeToken2 -> 'InSvcToken' : '$1' .
+safeToken2 -> 'KeepActiveToken' : '$1' .
+%% safeToken2 -> 'LocalToken' : '$1' .
+%% safeToken2 -> 'LocalDescriptorToken' : '$1' .
+safeToken2 -> 'LocalControlToken' : '$1' .
+safeToken2 -> 'LoopbackToken' : '$1' .
+safeToken2 -> 'LockStepToken' : '$1' .
+%% v2-safeToken2 -> 'MediaToken' : '$1' .
+%% safeToken2 -> 'MegacopToken' : '$1' .
+safeToken2 -> 'MethodToken' : '$1' .
+safeToken2 -> 'MgcIdToken' : '$1' .
+%% v3-safeToken2 -> 'ModeToken' : '$1' .
+%% BMK BMK safeToken2 -> 'ModifyToken' : '$1' .
+%% v2-safeToken2 -> 'ModemToken' : '$1' .
+%% BMK BMK safeToken2 -> 'MoveToken' : '$1' .
+%% safeToken2 -> 'MtpToken' : '$1' .
+%% safeToken2 -> 'MtpAddressToken' : '$1' .
+%% v2-safeToken2 -> 'MuxToken' : '$1' .
+safeToken2 -> 'NotifyToken' : '$1' .
+safeToken2 -> 'NotifyCompletionToken' : '$1' .
+safeToken2 -> 'Nx64Token' : '$1' .
+%% v2-safeToken2 -> 'ObservedEventsToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayExternalToken' : '$1' .
+%% v3-safeToken2 -> 'OnewayBothToken' : '$1' .
+safeToken2 -> 'OffToken' : '$1' .
+safeToken2 -> 'OnToken' : '$1' .
+safeToken2 -> 'OnOffToken' : '$1' .
+safeToken2 -> 'OutOfSvcToken' : '$1' .
+safeToken2 -> 'OtherReasonToken' : '$1' .
+%% v2-safeToken2 -> 'PackagesToken' : '$1' .
+safeToken2 -> 'PendingToken' : '$1' .
+%% BMK BMK safeToken2 -> 'PriorityToken' : '$1' .
+safeToken2 -> 'ProfileToken' : '$1' .
+safeToken2 -> 'ReasonToken' : '$1' .
+safeToken2 -> 'RecvonlyToken' : '$1' .
+safeToken2 -> 'ReplyToken' : '$1' .
+%% v3-
+safeToken2 -> 'RequestIDToken' : '$1' . % v3
+safeToken2 -> 'ResponseAckToken' : '$1' .
+safeToken2 -> 'RestartToken' : '$1' .
+%% safeToken2 -> 'RemoteToken' : '$1' .
+%% safeToken2 -> 'RemoteDescriptorToken' : '$1' .
+%% v3-safeToken2 -> 'ReservedGroupToken' : '$1' .
+%% v3-safeToken2 -> 'ReservedValueToken' : '$1' .
+safeToken2 -> 'SendonlyToken' : '$1' .
+safeToken2 -> 'SendrecvToken' : '$1' .
+safeToken2 -> 'ServicesToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceStatesToken' : '$1' .
+safeToken2 -> 'ServiceChangeToken' : '$1' .
+%% v3-safeToken2 -> 'ServiceChangeIncompleteToken' : '$1' . % v3
+safeToken2 -> 'ServiceChangeAddressToken' : '$1' .
+safeToken2 -> 'SignalListToken' : '$1' .
+%% v2-safeToken2 -> 'SignalsToken' : '$1' .
+safeToken2 -> 'SignalTypeToken' : '$1' .
+%% v2-safeToken2 -> 'StatsToken' : '$1' .
+safeToken2 -> 'StreamToken' : '$1' .
+%% BMK BMK safeToken2 -> 'SubtractToken' : '$1' .
+safeToken2 -> 'SynchISDNToken' : '$1' .
+safeToken2 -> 'TerminationStateToken' : '$1' .
+safeToken2 -> 'TestToken' : '$1' .
+safeToken2 -> 'TimeOutToken' : '$1' .
+%% BMK BMK safeToken2 -> 'TopologyToken' : '$1' .
+safeToken2 -> 'TransToken' : '$1' .
+safeToken2 -> 'V18Token' : '$1' .
+safeToken2 -> 'V22Token' : '$1' .
+safeToken2 -> 'V22bisToken' : '$1' .
+safeToken2 -> 'V32Token' : '$1' .
+safeToken2 -> 'V32bisToken' : '$1' .
+safeToken2 -> 'V34Token' : '$1' .
+safeToken2 -> 'V76Token' : '$1' .
+safeToken2 -> 'V90Token' : '$1' .
+safeToken2 -> 'V91Token' : '$1' .
+safeToken2 -> 'VersionToken' : '$1' .
+
+Erlang code.
+
+%% The following directive is needed for (significantly) faster compilation
+%% of the generated .erl file by the HiPE compiler. Please do not remove.
+-compile([{hipe,[{regalloc,linear_scan}]}]).
+
+-include("megaco_text_parser_v3.hrl").
+
+
diff --git a/lib/megaco/src/text/megaco_text_scanner.erl b/lib/megaco/src/text/megaco_text_scanner.erl
new file mode 100644
index 0000000000..8559941e5f
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_scanner.erl
@@ -0,0 +1,869 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose : Scanner for text encoded Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module('megaco_text_scanner').
+
+-export([scan/1, skip_sep_chars/2]).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+-include("megaco_text_tokens.hrl").
+
+-define(LOWER1(Char),
+ if
+ (Char >= $A) andalso (Char =< $Z) ->
+ Char - ($A - $a);
+ true ->
+ Char
+ end).
+
+%% This is used when we _know_ it to be upper case
+-define(LOWER2(Char), Char - ($A - $a)).
+
+scan(Bin) when is_binary(Bin) ->
+ Chars = erlang:binary_to_list(Bin),
+ tokens1(Chars, 1, []);
+scan(Chars) when is_list(Chars) ->
+ tokens1(Chars, 1, []).
+
+%% As long as we dont know the version, we will loop in this function
+tokens1(Chars, Line, Acc) ->
+ case any_chars(Chars, Line, 1) of
+ {token, Token, [], LatestLine} ->
+ %% We got to the end without actually getting a version token.
+ Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc],
+ {error, no_version_found, lists:reverse(Tokens), Line};
+
+ %% -- Version token for version 1 --
+ {token, {'SafeChars',_,"!/1"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 1, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/1"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 1, [Token | Acc]);
+
+
+ %% -- Version token for version 2 --
+ {token, {'SafeChars',_,"!/2"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 2, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/2"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 2, [Token | Acc]);
+
+
+ %% -- Version token for version 3 --
+ {token, {'SafeChars',_,"!/3"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 3, [Token | Acc]);
+
+ {token, {'SafeChars',_,"megaco/3"} = Token, Rest, LatestLine} ->
+ tokens2(Rest, LatestLine, 3, [Token | Acc]);
+
+
+ %% -- Version token for version X --
+ {token, {'SafeChars',_,[$!,$/| Vstr]} = Token, Rest, LatestLine} ->
+ case guess_version(Vstr) of
+ {ok, V} ->
+ tokens2(Rest, LatestLine, V, [Token | Acc]);
+ {error, Reason} ->
+ {error, Reason, LatestLine}
+ end;
+
+ {token, {'SafeChars',_,[$m,$e,$g,$a,$c,$o,$/|Vstr]} = Token, Rest, LatestLine} ->
+ case guess_version(Vstr) of
+ {ok, V} ->
+ tokens2(Rest, LatestLine, V, [Token | Acc]);
+ {error, Reason} ->
+ {error, Reason, LatestLine}
+ end;
+
+ %% -- Other tokens --
+ {token, Token, Rest, LatestLine} ->
+ tokens1(Rest, LatestLine, [Token | Acc]);
+
+ {bad_token, Token, _Rest, _LatestLine} ->
+ {error, {bad_token, [Token, Acc]}, Line}
+ end.
+
+tokens2(Chars, Line0, Version, Tokens0) ->
+ case tokens3(Chars, Line0, Tokens0, Version) of
+ {ok, Tokens, Line} ->
+ {ok, Tokens, Version, Line};
+ Error ->
+ Error
+ end.
+
+tokens3(Chars, Line, Acc, Version) ->
+ %% d("tokens2 -> entry with"
+ %% "~n Chars: ~s"
+ %% "~n Line: ~p", [Chars, Line]),
+ case any_chars(Chars, Line, Version) of
+ {token, Token, [], LatestLine} ->
+ %% d("tokens2 -> Token: ~n~p", [Token]),
+ Tokens = [{endOfMessage, LatestLine, endOfMessage}, Token | Acc],
+ {ok, lists:reverse(Tokens), Line};
+
+ {token, Token, Rest, LatestLine} ->
+ %% d("tokens2 -> Token: ~n~p", [Token]),
+ tokens3(Rest, LatestLine, [Token | Acc], Version);
+
+ {bad_token, Token, _Rest, _LatestLine} ->
+ {error, {bad_token, [Token, Acc]}, Line}
+ end.
+
+
+guess_version([C]) when (48 =< C) and (C =< 57) ->
+ {ok, C-48};
+guess_version(Str) when is_list(Str) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) ->
+ {ok, I};
+ _ ->
+ {error, {invalid_version, Str}}
+ end.
+
+
+%% Returns {token, Token, Rest, LatestLine}
+%% Returns {bad_token, Token, Rest, LatestLine}
+any_chars([Char | Rest], Line, Version) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ safe_chars(Rest, [Char], [?LOWER2(Char)], Line, Version);
+ safe_char ->
+ safe_chars(Rest, [Char], [Char], Line, Version);
+ rest_char ->
+ case Char of
+ ?SemiColonToken ->
+ comment_chars(Rest, Line);
+ _ ->
+ rest_chars(Rest, [Char], Line)
+ end;
+ double_quote ->
+ quoted_chars(Rest, [], Line);
+ white_space ->
+ sep_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line);
+ bad_char ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'AnyChars', Line, Char}, Rest, Line}
+ end;
+any_chars([] = All, Line, _Version) ->
+ {token, {'SEP', Line, end_of_input}, All, Line}.
+
+comment_chars([Char | Rest], Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ comment_chars(Rest, Line);
+ safe_char ->
+ comment_chars(Rest, Line);
+ rest_char ->
+ comment_chars(Rest, Line);
+ white_space ->
+ comment_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line);
+ _ when Char =:= 22 ->
+ comment_chars(Rest, Line);
+ _ ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'CommentChars', Line, Char}, Rest, Line}
+ end;
+comment_chars([] = All, Line) ->
+ {token, {'SEP', Line}, All, Line}.
+
+sep_chars([Char | Rest] = All, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ {token, {'SEP', Line}, All, Line};
+ safe_char ->
+ {token, {'SEP', Line}, All, Line};
+ rest_char when Char =:= ?SemiColonToken ->
+ comment_chars(Rest, Line);
+ rest_char ->
+ rest_chars(Rest, [Char], Line);
+ white_space ->
+ sep_chars(Rest, Line);
+ end_of_line ->
+ sep_chars(Rest, Line + 1);
+ _ ->
+ %% {bad_token, {'SEP', Line, Char}, Rest, Line}
+ {bad_token, {'SepChars', Line, Char}, Rest, Line}
+ end;
+sep_chars([] = All, Line) ->
+ {token, {'SEP', Line}, All, Line}.
+
+rest_chars(Rest, [?ColonToken], Line) ->
+ {token, {'COLON', Line}, Rest, Line};
+rest_chars(Rest, [AccChar], Line) ->
+ TokenTag =
+ case AccChar of
+ ?EqualToken -> 'EQUAL';
+ ?NequalToken -> 'NEQUAL';
+ ?LesserToken -> 'LESSER';
+ ?GreaterToken -> 'GREATER';
+ ?LbrktToken -> 'LBRKT';
+ ?RbrktToken -> 'RBRKT';
+ ?LsbrktToken -> 'LSBRKT';
+ ?RsbrktToken -> 'RSBRKT';
+ ?LparToken -> 'LPAR';
+ ?RparToken -> 'RPAR';
+ ?VbarToken -> 'VBAR';
+ ?CommaToken -> 'COMMA'
+ end,
+ {Rest2, Line2} = skip_sep_chars(Rest, Line),
+ {token, {TokenTag, Line}, Rest2, Line2}.
+
+skip_sep_chars([Char | Rest] = All, Line) ->
+ case ?classify_char2(Char) of
+ rest_char when Char =:= ?SemiColonToken ->
+ skip_comment_chars(Rest, Line);
+ white_space ->
+ skip_sep_chars(Rest, Line);
+ end_of_line ->
+ skip_sep_chars(Rest, Line + 1);
+ _ ->
+ {All, Line}
+ end;
+skip_sep_chars([] = All, Line) ->
+ {All, Line}.
+
+skip_comment_chars([Char | Rest] = All, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ skip_comment_chars(Rest, Line);
+ safe_char ->
+ skip_comment_chars(Rest, Line);
+ rest_char ->
+ skip_comment_chars(Rest, Line);
+ double_quote ->
+ skip_comment_chars(Rest, Line);
+ white_space ->
+ skip_comment_chars(Rest, Line);
+ end_of_line ->
+ skip_sep_chars(Rest, Line + 1);
+ _ ->
+ {All, Line}
+ end;
+skip_comment_chars([] = All, Line) ->
+ {All, Line}.
+
+quoted_chars([Char | Rest], Acc, Line) ->
+ case ?classify_char(Char) of
+ safe_char_upper ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ safe_char ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ rest_char ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ white_space ->
+ quoted_chars(Rest, [Char | Acc], Line);
+ double_quote ->
+ {token, {'QuotedChars', Line, lists:reverse(Acc)}, Rest, Line};
+ _ ->
+ {bad_token, {'QuotedChars', Line, Char}, Rest, Line}
+ end;
+quoted_chars([] = All, _Acc, Line) ->
+ {bad_token, {'QuotedChars', Line, end_of_input}, All, Line}.
+
+safe_chars([Char | Rest] = All, Acc, LowerAcc, Line, Version) ->
+ %% d("safe_chars -> entry with"
+ %% "~n Char: ~p"
+ %% "~n LowerAcc: ~p", [Char, LowerAcc]),
+ case ?classify_char3(Char) of
+ safe_char_upper ->
+ safe_chars(Rest, [Char | Acc],
+ [?LOWER2(Char) | LowerAcc], Line, Version);
+ safe_char ->
+ safe_chars(Rest, [Char | Acc], [Char | LowerAcc], Line, Version);
+ _ ->
+ LowerSafeChars = lists:reverse(LowerAcc),
+ TokenTag = select_token(LowerSafeChars, Version),
+ SafeChars = lists:reverse(Acc),
+ case TokenTag of
+ 'MtpToken' ->
+ %% 'MtpToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, LowerSafeChars, Line, TokenTag);
+ 'LocalToken' ->
+ %% 'LocalToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, SafeChars, Line, TokenTag);
+ 'RemoteToken' ->
+ %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT'
+ special_chars(All, SafeChars, Line, TokenTag);
+ 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ %% 'DigitMapToken' 'EQUAL' Name
+ %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' Value 'RBRKT'
+ %% 'DigitMapToken' 'EQUAL' 'LBRKT' Value 'RBRKT'
+ %% 'DigitMapToken' 'LBRKT' Value 'RBRKT'
+ special_chars(All, LowerSafeChars, Line, TokenTag);
+ _ ->
+ {token, {TokenTag, Line, LowerSafeChars}, All, Line}
+ end
+ end;
+safe_chars([] = All, _Acc, LowerAcc, Line, Version) ->
+ LowerSafeChars = lists:reverse(LowerAcc),
+ TokenTag = select_token(LowerSafeChars, Version),
+ %%SafeChars = lists:reverse(Acc),
+ {token, {TokenTag, Line, LowerSafeChars}, All, Line}.
+
+collect_safe_chars([Char | Rest] = All, LowerAcc) ->
+ case ?classify_char3(Char) of
+ safe_char_upper ->
+ collect_safe_chars(Rest, [?LOWER2(Char) | LowerAcc]);
+ safe_char ->
+ collect_safe_chars(Rest, [Char | LowerAcc]);
+ _ ->
+ {All, lists:reverse(LowerAcc)}
+ end;
+collect_safe_chars([] = Rest, LowerAcc) ->
+ {Rest, lists:reverse(LowerAcc)}.
+
+special_chars(All, SafeChars, Line, TokenTag) ->
+ {Rest, Line2} = skip_sep_chars(All, Line),
+ case Rest of
+ [?LbrktToken | Rest2] ->
+ {token, {'OctetString', _, OctetString}, Rest4, Line4} =
+ octet_string(Rest2, Line2),
+ case Rest4 of
+ [?RbrktToken | Rest6] ->
+ Token =
+ case TokenTag of
+ 'MtpToken' ->
+ %% 'MtpToken' 'LBRKT' OctetString 'RBRKT'
+ {'MtpAddressToken', Line, OctetString};
+ 'LocalToken' ->
+ %% 'LocalToken' 'LBRKT' OctetString 'RBRKT'
+ PGs = property_groups(OctetString),
+ {'LocalDescriptorToken', Line, PGs};
+ 'RemoteToken' ->
+ %% 'RemoteToken' 'LBRKT' OctetString 'RBRKT'
+ PGs = property_groups(OctetString),
+ {'RemoteDescriptorToken', Line, PGs};
+ 'DigitMapToken' ->
+ %% 'DigitMapToken' 'LBRKT' OctetString 'RBRKT'
+ DMV = digit_map_value(OctetString),
+ DMD = #'DigitMapDescriptor'{digitMapValue = DMV},
+ {'DigitMapDescriptorToken', Line, DMD}
+ end,
+ {token, Token, Rest6, Line4};
+ _ when TokenTag =:= 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line};
+ _ ->
+ {token, {'SafeChars', Line, SafeChars}, All, Line}
+ end;
+ [?EqualToken | Rest2] when TokenTag =:= 'DigitMapToken' ->
+ {Rest3, Line3} = skip_sep_chars(Rest2, Line2),
+ {Rest4, DigitMapName} = collect_safe_chars(Rest3, []),
+ {Rest6, Line6, DMD} =
+ if
+ DigitMapName =:= [] ->
+ {Rest3, Line3, #'DigitMapDescriptor'{}};
+ true ->
+ {Rest5, Line5} = skip_sep_chars(Rest4, Line3),
+ {Rest5, Line5, #'DigitMapDescriptor'{digitMapName = DigitMapName}}
+ end,
+ case Rest6 of
+ [?LbrktToken | Rest7] ->
+ {token, {'OctetString', _, OctetString}, Rest8, Line8} =
+ octet_string(Rest7, Line6),
+ case Rest8 of
+ [?RbrktToken | Rest10] ->
+ %% 'DigitMapToken' 'EQUAL' 'LBRKT' OctetString 'RBRKT'
+ %% 'DigitMapToken' 'EQUAL' Name 'LBRKT' OctetString 'RBRKT'
+ {Rest11, Line11} = skip_sep_chars(Rest10, Line8),
+ DMV = digit_map_value(OctetString),
+ DMD2 = DMD#'DigitMapDescriptor'{digitMapValue = DMV},
+ {token, {'DigitMapDescriptorToken', Line, DMD2}, Rest11, Line11};
+ _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE ->
+ %% 'DigitMapToken' 'EQUAL' Name
+ {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line}
+ end;
+ _ when DMD#'DigitMapDescriptor'.digitMapName /= asn1_NOVALUE ->
+ %% 'DigitMapToken' 'EQUAL' Name
+ {token, {'DigitMapDescriptorToken', Line, DMD}, Rest4, Line3};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line}
+ end;
+ _ when TokenTag =:= 'DigitMapToken' ->
+ %% 'DigitMapToken'
+ {token, {'DigitMapToken', Line, SafeChars}, All, Line};
+ _ ->
+ %% 'DigitMapToken'
+ {token, {'SafeChars', Line, SafeChars}, All, Line}
+ end.
+
+octet_string(Chars, Line) ->
+ {Chars2, Line2} = skip_sep_chars(Chars, Line),
+ Acc = [],
+ {Rest, RevChars, RestLine} = octet_string(Chars2, Acc, Line2),
+ {RevChars2, _} = skip_sep_chars(RevChars, RestLine),
+ OctetString = lists:reverse(RevChars2),
+ {token, {'OctetString', Line, OctetString}, Rest, RestLine}.
+
+
+octet_string([Char | Rest] = All, Acc, Line) ->
+ if
+ (Char =:= ?CrToken) ->
+ octet_string(Rest, [Char | Acc], Line + 1);
+ (Char =:= ?LfToken) ->
+ octet_string(Rest, [Char | Acc], Line + 1);
+ (Char >= 8#1) andalso (Char =< 8#174) ->
+ octet_string(Rest, [Char | Acc], Line);
+ (Char >= 8#176) andalso (Char =< 8#377) ->
+ octet_string(Rest, [Char | Acc], Line);
+ (Char =:= ?BackslashToken) ->
+ case Rest of
+ [?RbrktToken | _Rest2] ->
+ %% OTP-4357
+ octet_string(Rest,
+ [?RbrktToken, ?BackslashToken | Acc], Line);
+ _ ->
+ octet_string(Rest, [Char | Acc], Line)
+ end;
+ true ->
+ {All, Acc, Line}
+ end;
+octet_string([] = All, Acc, Line) ->
+ {All, Acc, Line}.
+
+
+%% digitMapValue = ["T" COLON Timer COMMA]
+%% ["S" COLON Timer COMMA]
+%% ["L" COLON Timer COMMA]
+%% ["Z" COLON Timer COMMA] digitMap
+digit_map_value(Chars) ->
+ digit_map_value(Chars, #'DigitMapValue'{}).
+
+%% NOTE: The swap of the digitMapBody and the durationTimer is
+%% intentional. The reason is a problem with the flex scanner.
+%% Hopefully this is temporary...
+%% The values are swapped back later by the parser...
+digit_map_value([Char, ?ColonToken | Rest] = All, DMV) ->
+ case ?LOWER1(Char) of
+ $t -> digit_map_timer(All, Rest, #'DigitMapValue'.startTimer, DMV);
+ $s -> digit_map_timer(All, Rest, #'DigitMapValue'.shortTimer, DMV);
+ $l -> digit_map_timer(All, Rest, #'DigitMapValue'.longTimer, DMV);
+% $z -> digit_map_timer(All, Rest, #'DigitMapValue'.durationTimer, DMV);
+% _ -> DMV#'DigitMapValue'{digitMapBody = All}
+ $z -> digit_map_timer(All, Rest, #'DigitMapValue'.digitMapBody, DMV);
+ _ -> DMV#'DigitMapValue'{durationTimer = All}
+ end;
+digit_map_value(Chars, DMV) ->
+ DMV#'DigitMapValue'{durationTimer = Chars}.
+
+digit_map_timer(All, Chars, TimerPos, DMV) ->
+ {Rest, Digits} = collect_safe_chars(Chars, []),
+ {Rest2, _} = skip_sep_chars(Rest, 0),
+ case {Rest2, catch list_to_integer(Digits)} of
+ {[?CommaToken | Rest3], Int} when is_integer(Int) andalso
+ (Int >= 0) andalso
+ (element(TimerPos, DMV) =:= asn1_NOVALUE) ->
+ {Rest4, _} = skip_sep_chars(Rest3, 0),
+ DMV2 = setelement(TimerPos, DMV, Int),
+ digit_map_value(Rest4, DMV2);
+ _ ->
+ DMV#'DigitMapValue'{digitMapBody = All}
+ end.
+
+%% ============================================================================
+%% <prev-parser-stuff>
+%%
+%% This stuff was originally in the parser(s), but was,
+%% for performance reasons, moved to the scanner(s). This
+%% scanner does not make it faster, but the flex scanner
+%% does, which is why the move was made.
+%%
+
+property_groups(OctetString) ->
+ Group = [],
+ Groups = [],
+ property_name(OctetString, Group, Groups).
+
+property_name([Char | Rest] = All, Group, Groups) ->
+ if
+ ?white_space(Char) ->
+ property_name(Rest, Group, Groups);
+ ?end_of_line(Char) ->
+ property_name(Rest, Group, Groups);
+ true ->
+ Name = [],
+ do_property_name(All, Name, Group, Groups)
+ end;
+property_name([] = All, Group, Groups) ->
+ Name = [],
+ do_property_name(All, Name, Group, Groups).
+
+do_property_name([Char | Rest], Name, Group, Groups)
+ when (Char =:= $=) andalso (Name =/= []) ->
+ %% Now we have a complete name
+ if
+ (Name =:= "v") andalso (Group =/= []) ->
+ %% v= is a property group delimiter,
+ %% lets create yet another property group.
+ Groups2 = [lists:reverse(Group) | Groups],
+ Group2 = [],
+ property_value(Rest, Name, Group2, Groups2);
+ true ->
+ %% Use current property group
+ property_value(Rest, Name, Group, Groups)
+ end;
+do_property_name([Char | Rest], Name, Group, Groups) ->
+ case ?classify_char4(Char) of
+ safe_char_upper ->
+ do_property_name(Rest, [Char | Name], Group, Groups);
+ safe_char ->
+ do_property_name(Rest, [Char | Name], Group, Groups);
+ _ ->
+ throw({error, {bad_prop_name, lists:reverse(Name), Char}})
+ end;
+do_property_name([], [], [], Groups) ->
+ lists:reverse(Groups);
+do_property_name([], [], Group, Groups) ->
+ Group2 = lists:reverse(Group),
+ lists:reverse([Group2 | Groups]);
+do_property_name([], Name, Group, Groups) when Name =/= [] ->
+ %% Assume end of line
+ Value = [],
+ PP = make_property_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_scanner_inline).
+-compile({inline,[{property_value,4}]}).
+-endif.
+property_value(Chars, Name, Group, Groups) ->
+ Value = [],
+ do_property_value(Chars, Name, Value, Group, Groups).
+
+do_property_value([Char | Rest], Name, Value, Group, Groups) ->
+ if
+ ?end_of_line(Char) ->
+ %% Now we have a complete "name=value" pair
+ PP = make_property_parm(Name, Value),
+ property_name(Rest, [PP | Group], Groups);
+ true ->
+ do_property_value(Rest, Name, [Char | Value], Group, Groups)
+ end;
+do_property_value([], Name, Value, Group, Groups) ->
+ %% Assume end of line
+ PP = make_property_parm(Name, Value),
+ Group2 = lists:reverse([PP | Group]),
+ lists:reverse([Group2 | Groups]).
+
+-ifdef(megaco_scanner_inline).
+-compile({inline,[{make_property_parm,2}]}).
+-endif.
+make_property_parm(Name, Value) ->
+ %% Record name, name field, value field, extraInfo field
+ {'PropertyParm',
+ lists:reverse(Name),
+ [lists:reverse(Value)],
+ asn1_NOVALUE}.
+
+
+%% </prev-parser-stuff>
+%% ===========================================================================
+
+select_token([$o, $- | LowerText], Version) ->
+ select_token(LowerText, Version);
+select_token([$w, $- | LowerText], Version) ->
+ select_token(LowerText, Version);
+select_token(LowerText, Version) ->
+ case LowerText of
+ "add" -> 'AddToken';
+ "a" -> 'AddToken';
+ "andlgc" when (Version >= 3) -> 'AndAUDITSelectToken'; % v3
+ "audit" -> 'AuditToken';
+ "at" -> 'AuditToken';
+ "auditcapability" -> 'AuditCapToken';
+ "ac" -> 'AuditCapToken';
+ "auditvalue" -> 'AuditValueToken';
+ "av" -> 'AuditValueToken';
+ "authentication" -> 'AuthToken';
+ "au" -> 'AuthToken';
+ "both" when (Version >= 3) -> 'BothToken'; % v3
+ "b" when (Version >= 3) -> 'BothToken'; % v3
+ "bothway" -> 'BothwayToken';
+ "bw" -> 'BothwayToken';
+ "brief" -> 'BriefToken';
+ "br" -> 'BriefToken';
+ "buffer" -> 'BufferToken';
+ "bf" -> 'BufferToken';
+ "context" -> 'CtxToken';
+ "c" -> 'CtxToken';
+ "contextattr" when (Version >= 3) -> 'ContextAttrToken'; % v3
+ "ct" when (Version >= 3) -> 'ContextAttrToken'; % v3
+ "contextlist" when (Version >= 3) -> 'ContextListToken'; % v3
+ "clt" when (Version >= 3) -> 'ContextListToken'; % v3
+ "contextaudit" -> 'ContextAuditToken';
+ "ca" -> 'ContextAuditToken';
+ "digitmap" -> 'DigitMapToken';
+ "dm" -> 'DigitMapToken';
+ "spadirection" when (Version >= 3) -> 'DirectionToken'; % v3
+ "direction" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b)
+ "spadi" when (Version >= 3) -> 'DirectionToken'; % v3
+ "di" when (Version >= 3) -> 'DirectionToken'; % v3 (pre-v3a/v3b)
+ "discard" -> 'DiscardToken';
+ "ds" -> 'DiscardToken';
+ "disconnected" -> 'DisconnectedToken';
+ "dc" -> 'DisconnectedToken';
+ "delay" -> 'DelayToken';
+ "dl" -> 'DelayToken';
+ "delete" -> 'DeleteToken';
+ "de" -> 'DeleteToken';
+ "duration" -> 'DurationToken';
+ "dr" -> 'DurationToken';
+ "embed" -> 'EmbedToken';
+ "em" -> 'EmbedToken';
+ "emergency" -> 'EmergencyToken';
+ "eg" -> 'EmergencyToken';
+ "emergencyofftoken" -> 'EmergencyOffToken';
+ "emergencyoff" when (Version >= 3) -> 'EmergencyOffToken'; % v3 (as of prev3c)
+ "ego" -> 'EmergencyOffToken';
+ "emergencyvalue" when (Version >= 3) -> 'EmergencyValueToken'; % v3
+ "egv" when (Version >= 3) -> 'EmergencyValueToken'; % v3
+ "error" -> 'ErrorToken';
+ "er" -> 'ErrorToken';
+ "eventbuffer" -> 'EventBufferToken';
+ "eb" -> 'EventBufferToken';
+ "events" -> 'EventsToken';
+ "e" -> 'EventsToken';
+ "external" when (Version >= 3) -> 'ExternalToken'; % v3
+ "ex" when (Version >= 3) -> 'ExternalToken'; % v3
+ "failover" -> 'FailoverToken';
+ "fl" -> 'FailoverToken';
+ "forced" -> 'ForcedToken';
+ "fo" -> 'ForcedToken';
+ "graceful" -> 'GracefulToken';
+ "gr" -> 'GracefulToken';
+ "h221" -> 'H221Token';
+ "h223" -> 'H223Token';
+ "h226" -> 'H226Token';
+ "handoff" -> 'HandOffToken';
+ "ho" -> 'HandOffToken';
+ "iepscall" when (Version >= 3) -> 'IEPSToken'; % v3
+ "ieps" when (Version >= 3) -> 'IEPSToken'; % v3
+ "inactive" -> 'InactiveToken';
+ "in" -> 'InactiveToken';
+ "internal" when (Version >= 3) -> 'InternalToken'; % v3
+ "it" when (Version >= 3) -> 'InternalToken'; % v3
+ "immackrequired" -> 'ImmAckRequiredToken';
+ "ia" -> 'ImmAckRequiredToken';
+ "inservice" -> 'InSvcToken';
+ "intersignal" when (Version >= 3) -> 'IntsigDelayToken'; % v3
+ "spais" when (Version >= 3) -> 'IntsigDelayToken'; % v3
+ "intbyevent" -> 'InterruptByEventToken';
+ "ibe" -> 'InterruptByEventToken';
+ "intbysigdescr" -> 'InterruptByNewSignalsDescrToken';
+ "ibs" -> 'InterruptByNewSignalsDescrToken';
+ "iv" -> 'InSvcToken';
+ "isolate" -> 'IsolateToken';
+ "is" -> 'IsolateToken';
+ "iterationtoken" when (Version >= 3) -> 'IterationToken'; % v3
+ "ir" when (Version >= 3) -> 'IterationToken'; % v3
+ "keepactive" -> 'KeepActiveToken';
+ "ka" -> 'KeepActiveToken';
+ "local" -> 'LocalToken';
+ "l" -> 'LocalToken';
+ "localcontrol" -> 'LocalControlToken';
+ "lockstep" -> 'LockStepToken';
+ "sp" -> 'LockStepToken';
+ "o" -> 'LocalControlToken';
+ "loopback" -> 'LoopbackToken';
+ "lb" -> 'LoopbackToken';
+ "media" -> 'MediaToken';
+ "m" -> 'MediaToken';
+ %% "megaco" -> 'MegacopToken';
+ %% "!" -> 'megacoptoken';
+ "segment" when (Version >= 3) -> 'MessageSegmentToken'; % v3
+ "sm" when (Version >= 3) -> 'MessageSegmentToken'; % v3
+ "method" -> 'MethodToken';
+ "mt" -> 'MethodToken';
+ "mtp" -> 'MtpToken';
+ "mgcidtotry" -> 'MgcIdToken';
+ "mg" -> 'MgcIdToken';
+ "mode" -> 'ModeToken';
+ "mo" -> 'ModeToken';
+ "modify" -> 'ModifyToken';
+ "mf" -> 'ModifyToken';
+ "modem" -> 'ModemToken';
+ "md" -> 'ModemToken';
+ "move" -> 'MoveToken';
+ "mv" -> 'MoveToken';
+ "mux" -> 'MuxToken';
+ "mx" -> 'MuxToken';
+ "nevernotify" when (Version >= 3) -> 'NeverNotifyToken'; % v3
+ "nbnn" when (Version >= 3) -> 'NeverNotifyToken'; % v3
+ "notify" -> 'NotifyToken';
+ "n" -> 'NotifyToken';
+ "notifycompletion" -> 'NotifyCompletionToken';
+ "nc" -> 'NotifyCompletionToken';
+ "immediatenotify" when (Version >= 3) -> 'NotifyImmediateToken'; % v3
+ "nbin" when (Version >= 3) -> 'NotifyImmediateToken'; % v3
+ "regulatednotify" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3
+ "nbrn" when (Version >= 3) -> 'NotifyRegulatedToken'; % v3
+ "nx64kservice" when (Version >= 2) -> 'Nx64kToken'; % v2
+ "n64" when (Version >= 2) -> 'Nx64kToken'; % v2
+ "observedevents" -> 'ObservedEventsToken';
+ "oe" -> 'ObservedEventsToken';
+ "oneway" -> 'OnewayToken';
+ "ow" -> 'OnewayToken';
+ "onewayboth" when (Version >= 3) -> 'OnewayBothToken'; % v3
+ "owb" when (Version >= 3) -> 'OnewayBothToken'; % v3
+ "onewayexternal" when (Version >= 3) -> 'OnewayExternalToken'; % v3
+ "owe" when (Version >= 3) -> 'OnewayExternalToken'; % v3
+ "off" -> 'OffToken';
+ "on" -> 'OnToken';
+ "onoff" -> 'OnOffToken';
+ "oo" -> 'OnOffToken';
+ "orlgc" when (Version >= 3) -> 'OrAUDITselectToken'; % v3
+ "otherreason" -> 'OtherReasonToken';
+ "or" -> 'OtherReasonToken';
+ "outofservice" -> 'OutOfSvcToken';
+ "os" -> 'OutOfSvcToken';
+ "packages" -> 'PackagesToken';
+ "pg" -> 'PackagesToken';
+ "pending" -> 'PendingToken';
+ "pn" -> 'PendingToken';
+ "priority" -> 'PriorityToken';
+ "pr" -> 'PriorityToken';
+ "profile" -> 'ProfileToken';
+ "pf" -> 'ProfileToken';
+ "reason" -> 'ReasonToken';
+ "re" -> 'ReasonToken';
+ "receiveonly" -> 'RecvonlyToken';
+ "requestid" when (Version >= 3) -> 'RequestIDToken'; % v3
+ "rq" when (Version >= 3) -> 'RequestIDToken'; % v3
+ "rc" -> 'RecvonlyToken';
+ "reply" -> 'ReplyToken';
+ "p" -> 'ReplyToken';
+ "reseteventsdescriptor" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3
+ "rse" when (Version >= 3) -> 'ResetEventsDescriptorToken'; % v3
+ "transactionresponseack"-> 'ResponseAckToken';
+ "k" -> 'ResponseAckToken';
+ "restart" -> 'RestartToken';
+ "rs" -> 'RestartToken';
+ "remote" -> 'RemoteToken';
+ "r" -> 'RemoteToken';
+ "sparequestid" -> 'RequestIDToken';
+ "sparq" -> 'RequestIDToken';
+ "reservedgroup" -> 'ReservedGroupToken';
+ "rg" -> 'ReservedGroupToken';
+ "reservedvalue" -> 'ReservedValueToken';
+ "rv" -> 'ReservedValueToken';
+ "end" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3
+ "&" when (Version >= 3) -> 'SegmentationCompleteToken'; % v3
+ "sendonly" -> 'SendonlyToken';
+ "so" -> 'SendonlyToken';
+ "sendreceive" -> 'SendrecvToken';
+ "sr" -> 'SendrecvToken';
+ "services" -> 'ServicesToken';
+ "sv" -> 'ServicesToken';
+ "servicestates" -> 'ServiceStatesToken';
+ "si" -> 'ServiceStatesToken';
+ "servicechange" -> 'ServiceChangeToken';
+ "sc" -> 'ServiceChangeToken';
+ "servicechangeaddress" -> 'ServiceChangeAddressToken';
+ "ad" -> 'ServiceChangeAddressToken';
+ "servicechangeinc" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3
+ "sic" when (Version >= 3) -> 'ServiceChangeIncompleteToken'; % v3
+ "signallist" -> 'SignalListToken';
+ "sl" -> 'SignalListToken';
+ "signals" -> 'SignalsToken';
+ "sg" -> 'SignalsToken';
+ "signaltype" -> 'SignalTypeToken';
+ "sy" -> 'SignalTypeToken';
+ "statistics" -> 'StatsToken';
+ "sa" -> 'StatsToken';
+ "stream" -> 'StreamToken';
+ "st" -> 'StreamToken';
+ "subtract" -> 'SubtractToken';
+ "s" -> 'SubtractToken';
+ "synchisdn" -> 'SynchISDNToken';
+ "sn" -> 'SynchISDNToken';
+ "terminationstate" -> 'TerminationStateToken';
+ "ts" -> 'TerminationStateToken';
+ "test" -> 'TestToken';
+ "te" -> 'TestToken';
+ "timeout" -> 'TimeOutToken';
+ "to" -> 'TimeOutToken';
+ "topology" -> 'TopologyToken';
+ "tp" -> 'TopologyToken';
+ "transaction" -> 'TransToken';
+ "t" -> 'TransToken';
+ "v18" -> 'V18Token';
+ "v22" -> 'V22Token';
+ "v22b" -> 'V22bisToken';
+ "v32" -> 'V32Token';
+ "v32b" -> 'V32bisToken';
+ "v34" -> 'V34Token';
+ "v76" -> 'V76Token';
+ "v90" -> 'V90Token';
+ "v91" -> 'V91Token';
+ "version" -> 'VersionToken';
+ "v" -> 'VersionToken';
+ [_,_,_,_,_,_,_,_,$t,_,_,_,_,_,_,_,_] -> % Could be a time-stamp
+ [D1,D2,D3,D4,D5,D6,D7,D8,_,T1,T2,T3,T4,T5,T6,T7,T8] = LowerText,
+ select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8,
+ T1,T2,T3,T4,T5,T6,T7,T8);
+ _ -> 'SafeChars'
+ end.
+
+select_TimeStampToken(D1,D2,D3,D4,D5,D6,D7,D8,
+ T1,T2,T3,T4,T5,T6,T7,T8)
+ when ($0 =< D1) andalso (D1 =< $9) andalso
+ ($0 =< D2) andalso (D2 =< $9) andalso
+ ($0 =< D3) andalso (D3 =< $9) andalso
+ ($0 =< D4) andalso (D4 =< $9) andalso
+ ($0 =< D5) andalso (D5 =< $9) andalso
+ ($0 =< D6) andalso (D6 =< $9) andalso
+ ($0 =< D7) andalso (D7 =< $9) andalso
+ ($0 =< D8) andalso (D8 =< $9) andalso
+ ($0 =< T1) andalso (T1 =< $9) andalso
+ ($0 =< T2) andalso (T2 =< $9) andalso
+ ($0 =< T3) andalso (T3 =< $9) andalso
+ ($0 =< T4) andalso (T4 =< $9) andalso
+ ($0 =< T5) andalso (T5 =< $9) andalso
+ ($0 =< T6) andalso (T6 =< $9) andalso
+ ($0 =< T7) andalso (T7 =< $9) andalso
+ ($0 =< T8) andalso (T8 =< $9) ->
+ 'TimeStampToken';
+select_TimeStampToken(_D1,_D2,_D3,_D4,_D5,_D6,_D7,_D8,
+ _T1,_T2,_T3,_T4,_T5,_T6,_T7,_T8) ->
+ 'SafeChars'.
+
+
+%% d(F) ->
+%% d(F, []).
+
+%% d(F, A) ->
+%% d(get(dbg), F, A).
+
+%% d(true, F, A) ->
+%% io:format("DBG:~p:" ++ F ++ "~n", [?MODULE|A]);
+%% d(_, _, _) ->
+%% ok.
diff --git a/lib/megaco/src/text/megaco_text_tokens.hrl b/lib/megaco/src/text/megaco_text_tokens.hrl
new file mode 100644
index 0000000000..14f59c3f06
--- /dev/null
+++ b/lib/megaco/src/text/megaco_text_tokens.hrl
@@ -0,0 +1,475 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define of tokens used in text encoding of Megaco/H.248
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Adding a new token requires changes in the following files:
+%%
+%% megaco_text_tokens.hrl
+%% megaco_text_gen.hrl
+%% megaco_compact_text_encoder.erl
+%% megaco_pretty_text_encoder.erl
+%% megaco_text_scanner.erl
+%% megaco_text_parser.yrl (safeToken rule, make_safe_token/1, actual rule)
+%%
+%% Plus regeneration the ASN.1 related files including
+%% manual patches
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Special records
+%%----------------------------------------------------------------------
+
+-record(property_parm,
+ {
+ name,
+ value,
+ extraInfo = asn1_NOVALUE
+ }).
+
+
+
+%%----------------------------------------------------------------------
+%% Special characters
+%%----------------------------------------------------------------------
+
+-define(EqualToken, 16#3d).
+-define(ColonToken, 16#3a).
+-define(LbrktToken, 16#7b).
+-define(RbrktToken, 16#7d).
+-define(LsbrktToken, $[).
+-define(RsbrktToken, $]).
+-define(CommaToken, 16#2c).
+-define(DotToken, 16#2e).
+-define(SlashToken, 16#2f).
+-define(DoubleQuoteToken, 16#22).
+-define(SpToken, 16#20).
+-define(HtabToken, 16#09).
+-define(CrToken, 16#0d).
+-define(LfToken, 16#0a).
+
+-define(SemiColonToken, $;).
+-define(NequalToken, $#).
+-define(GreaterToken, $>).
+-define(LesserToken, $<).
+-define(BackslashToken, $\\).
+-define(LparToken, $().
+-define(RparToken, $)).
+-define(VbarToken, $|).
+
+%%----------------------------------------------------------------------
+%% Pretty version of tokens
+%%----------------------------------------------------------------------
+
+-define(PrettyAddToken , "Add" ).
+-define(PrettyAndAUDITSelectToken , "ANSLgc" ).
+-define(PrettyAuditToken , "Audit" ).
+-define(PrettyAuditCapToken , "AuditCapability" ).
+-define(PrettyAuditValueToken , "AuditValue" ).
+-define(PrettyAuthToken , "Authentication" ).
+-define(PrettyBothToken , "Both" ). % v3
+-define(PrettyBothwayToken , "Bothway" ).
+-define(PrettyBriefToken , "Brief" ).
+-define(PrettyBufferToken , "Buffer" ).
+-define(PrettyCtxToken , "Context" ).
+-define(PrettyContextAuditToken , "ContextAudit" ).
+-define(PrettyContextAttrToken , "ContextAttr" ). % v3
+-define(PrettyContextListToken , "ContextList" ). % v3
+-define(PrettyDigitMapToken , "DigitMap" ).
+-ifdef(encoder_version_pre_prev3c).
+-define(PrettyDirectionToken , "Direction" ). % v3
+-else.
+-define(PrettyDirectionToken , "SPADirection" ). % v3
+-endif.
+-define(PrettyDiscardToken , "Discard" ).
+-define(PrettyDisconnectedToken , "Disconnected" ).
+-define(PrettyDelayToken , "Delay" ).
+-define(PrettyDurationToken , "Duration" ).
+-define(PrettyEmbedToken , "Embed" ).
+-define(PrettyEmergencyToken , "Emergency" ).
+-ifdef(encoder_version_pre_prev3c).
+-define(PrettyEmergencyOffToken , "EmergencyOffToken" ). % v2
+-else.
+-define(PrettyEmergencyOffToken , "EmergencyOff" ). % v3
+-endif.
+-define(PrettyEmergencyValueToken , "EmergencyValue" ). % v3
+-define(PrettyErrorToken , "Error" ).
+-define(PrettyEventBufferToken , "EventBuffer" ).
+-define(PrettyEventsToken , "Events" ).
+-define(PrettyExternalToken , "External" ). % v3
+-define(PrettyFailoverToken , "Failover" ).
+-define(PrettyForcedToken , "Forced" ).
+-define(PrettyGracefulToken , "Graceful" ).
+-define(PrettyH221Token , "H221" ).
+-define(PrettyH223Token , "H223" ).
+-define(PrettyH226Token , "H226" ).
+-define(PrettyHandOffToken , "HandOff" ).
+-define(PrettyIEPSToken , "IEPSCall" ). % v3
+-define(PrettyImmAckRequiredToken , "ImmAckRequired" ).
+-define(PrettyInactiveToken , "Inactive" ).
+-define(PrettyInternalToken , "Internal" ). % v3
+-define(PrettyIntsigDelayToken , "Intersignal" ). % v3
+-define(PrettyInterruptByEventToken , "IntByEvent" ).
+-define(PrettyInterruptByNewSignalsDescrToken, "IntBySigDescr" ).
+-define(PrettyIsolateToken , "Isolate" ).
+-define(PrettyInSvcToken , "InService" ).
+-define(PrettyIterationToken , "Iteration" ). % v3
+-define(PrettyKeepActiveToken , "KeepActive" ).
+-define(PrettyLocalToken , "Local" ).
+-define(PrettyLocalControlToken , "LocalControl" ).
+-define(PrettyLockStepToken , "LockStep" ).
+-define(PrettyLoopbackToken , "Loopback" ).
+-define(PrettyMediaToken , "Media" ).
+-define(PrettyMegacopToken , "MEGACO" ).
+-define(PrettyMessageSegmentToken , "Segment" ). % v3
+-define(PrettyMethodToken , "Method" ).
+-define(PrettyMgcIdToken , "MgcIdToTry" ).
+-define(PrettyModeToken , "Mode" ).
+-define(PrettyModifyToken , "Modify" ).
+-define(PrettyModemToken , "Modem" ).
+-define(PrettyMoveToken , "Move" ).
+-define(PrettyMtpToken , "MTP" ).
+-define(PrettyMuxToken , "Mux" ).
+-define(PrettyNeverNotifyToken , "NeverNotify" ). % v3
+-define(PrettyNotifyToken , "Notify" ).
+-define(PrettyNotifyCompletionToken , "NotifyCompletion" ).
+-define(PrettyNotifyImmediateToken , "ImmediateNotify" ). % v3
+-define(PrettyNotifyRegulatedToken , "RegulatedNotify" ). % v3
+-define(PrettyNx64kToken , "Nx64Kservice" ).
+-define(PrettyObservedEventsToken , "ObservedEvents" ).
+-define(PrettyOffToken , "OFF" ).
+-define(PrettyOnewayToken , "Oneway" ).
+-define(PrettyOnewayBothToken , "OnewayBoth" ). % v3
+-define(PrettyOnewayExternalToken , "OnewayExternal" ). % v3
+-define(PrettyOnOffToken , "OnOff" ).
+-define(PrettyOrAUDITselectToken , "ORLgc" ). % v3
+-define(PrettyOnToken , "ON" ).
+-define(PrettyOtherReasonToken , "OtherReason" ).
+-define(PrettyOutOfSvcToken , "OutOfService" ).
+-define(PrettyPackagesToken , "Packages" ).
+-define(PrettyPendingToken , "Pending" ).
+-define(PrettyPriorityToken , "Priority" ).
+-define(PrettyProfileToken , "Profile" ).
+-define(PrettyReasonToken , "Reason" ).
+-define(PrettyRecvonlyToken , "ReceiveOnly" ).
+-define(PrettyReplyToken , "Reply" ).
+-define(PrettyResetEventsDescriptorToken , "ResetEventsDescriptor" ). % v3
+-define(PrettyRestartToken , "Restart" ).
+-define(PrettyRemoteToken , "Remote" ).
+-ifdef(encoder_version_pre_prev3c).
+-define(PrettyRequestIDToken , "RequestID" ). % v3
+-else.
+-define(PrettyRequestIDToken , "SPARequestID" ). % v3
+-endif.
+-define(PrettyReservedGroupToken , "ReservedGroup" ).
+-define(PrettyReservedValueToken , "ReservedValue" ).
+-define(PrettySegmentationCompleteToken , "END" ). % v3
+-define(PrettySendonlyToken , "SendOnly" ).
+-define(PrettySendrecvToken , "SendReceive" ).
+-define(PrettyServicesToken , "Services" ).
+-define(PrettyServiceStatesToken , "ServiceStates" ).
+-define(PrettyServiceChangeToken , "ServiceChange" ).
+-define(PrettyServiceChangeAddressToken , "ServiceChangeAddress" ).
+-define(PrettyServiceChangeIncompleteToken , "ServiceChangeInc" ). % v3
+-define(PrettySignalListToken , "SignalList" ).
+-define(PrettySignalsToken , "Signals" ).
+-define(PrettySignalTypeToken , "SignalType" ).
+-define(PrettyStatsToken , "Statistics" ).
+-define(PrettyStreamToken , "Stream" ).
+-define(PrettySubtractToken , "Subtract" ).
+-define(PrettySynchISDNToken , "SynchISDN" ).
+-define(PrettyTerminationStateToken , "TerminationState" ).
+-define(PrettyTestToken , "Test" ).
+-define(PrettyTimeOutToken , "TimeOut" ).
+-define(PrettyTopologyToken , "Topology" ).
+-define(PrettyTransToken , "Transaction" ).
+-define(PrettyResponseAckToken , "TransactionResponseAck").
+-define(PrettyV18Token , "V18" ).
+-define(PrettyV22Token , "V22" ).
+-define(PrettyV22bisToken , "V22b" ).
+-define(PrettyV32Token , "V32" ).
+-define(PrettyV32bisToken , "V32b" ).
+-define(PrettyV34Token , "V34" ).
+-define(PrettyV76Token , "V76" ).
+-define(PrettyV90Token , "V90" ).
+-define(PrettyV91Token , "V91" ).
+-define(PrettyVersionToken , "Version" ).
+
+%%----------------------------------------------------------------------
+%% Compact version of tokens
+%%----------------------------------------------------------------------
+
+-define(CompactAddToken , "A" ).
+-define(CompactAndAUDITSelectToken , "ANSLgc" ).
+-define(CompactAuditToken , "AT" ).
+-define(CompactAuditCapToken , "AC" ).
+-define(CompactAuditValueToken , "AV" ).
+-define(CompactAuthToken , "AU" ).
+-define(CompactBothToken , "B" ). % v3
+-define(CompactBothwayToken , "BW" ).
+-define(CompactBriefToken , "BR" ).
+-define(CompactBufferToken , "BF" ).
+-define(CompactCtxToken , "C" ).
+-define(CompactContextAuditToken , "CA" ).
+-define(CompactContextAttrToken , "CT" ). % v3
+-define(CompactContextListToken , "CLT" ). % v3
+-define(CompactDigitMapToken , "DM" ).
+-ifdef(encoder_version_pre_prev3c).
+-define(CompactDirectionToken , "DI" ). % v3
+-else.
+-define(CompactDirectionToken , "SPADI" ). % v3
+-endif.
+-define(CompactDiscardToken , "DS" ).
+-define(CompactDisconnectedToken , "DC" ).
+-define(CompactDelayToken , "DL" ).
+-define(CompactDurationToken , "DR" ).
+-define(CompactEmbedToken , "EM" ).
+-define(CompactEmergencyToken , "EG" ).
+-define(CompactEmergencyOffToken , "EGO" ).
+-define(CompactEmergencyValueToken , "EGV" ). % v3
+-define(CompactErrorToken , "ER" ).
+-define(CompactEventBufferToken , "EB" ).
+-define(CompactEventsToken , "E" ).
+-define(CompactExternalToken , "EX" ). % v3
+-define(CompactFailoverToken , "FL" ).
+-define(CompactForcedToken , "FO" ).
+-define(CompactGracefulToken , "GR" ).
+-define(CompactH221Token , ?PrettyH221Token ).
+-define(CompactH223Token , ?PrettyH223Token ).
+-define(CompactH226Token , ?PrettyH226Token ).
+-define(CompactHandOffToken , "HO" ).
+-define(CompactIEPSToken , "IEPS" ). % v3
+-define(CompactImmAckRequiredToken , "IA" ).
+-define(CompactInactiveToken , "IN" ).
+-define(CompactInternalToken , "IT" ). % v3
+-define(CompactIntsigDelayToken , "SPAIS" ). % v3
+-define(CompactInterruptByEventToken , "IBE" ).
+-define(CompactInterruptByNewSignalsDescrToken, "IBS" ).
+-define(CompactIsolateToken , "IS" ).
+-define(CompactInSvcToken , "IV" ).
+-define(CompactIterationToken , "IR" ). % v3
+-define(CompactKeepActiveToken , "KA" ).
+-define(CompactLocalToken , "L" ).
+-define(CompactLocalControlToken , "O" ).
+-define(CompactLockStepToken , "SP" ).
+-define(CompactLoopbackToken , "LB" ).
+-define(CompactMediaToken , "M" ).
+-define(CompactMegacopToken , "!" ).
+-define(CompactMessageSegmentToken , "SM" ). % v3
+-define(CompactMethodToken , "MT" ).
+-define(CompactMgcIdToken , "MG" ).
+-define(CompactModeToken , "MO" ).
+-define(CompactModifyToken , "MF" ).
+-define(CompactModemToken , "MD" ).
+-define(CompactMoveToken , "MV" ).
+-define(CompactMtpToken , ?PrettyMtpToken ).
+-define(CompactMuxToken , "MX" ).
+-define(CompactNeverNotifyToken , "NBNN" ). % v3
+-define(CompactNotifyToken , "N" ).
+-define(CompactNotifyCompletionToken , "NC" ).
+-define(CompactNotifyImmediateToken , "NBIN" ). % v3
+-define(CompactNotifyRegulatedToken , "NBRN" ). % v3
+-define(CompactNx64kToken , "N64" ).
+-define(CompactObservedEventsToken , "OE" ).
+-define(CompactOffToken , "OFF" ).
+-define(CompactOnewayToken , "OW" ).
+-define(CompactOnewayBothToken , "OWB" ). % v3
+-define(CompactOnewayExternalToken , "OWE" ). % v3
+-define(CompactOnOffToken , "OO" ).
+-define(CompactOrAUDITselectToken , "ORLgc" ). % v3
+-define(CompactOnToken , "ON" ).
+-define(CompactOtherReasonToken , "OR" ).
+-define(CompactOutOfSvcToken , "OS" ).
+-define(CompactPackagesToken , "PG" ).
+-define(CompactPendingToken , "PN" ).
+-define(CompactPriorityToken , "PR" ).
+-define(CompactProfileToken , "PF" ).
+-define(CompactReasonToken , "RE" ).
+-define(CompactRecvonlyToken , "RC" ).
+-define(CompactReplyToken , "P" ).
+-define(CompactResetEventsDescriptorToken , "RSE" ). % v3
+-define(CompactRestartToken , "RS" ).
+-define(CompactRemoteToken , "R" ).
+-ifdef(encoder_version_pre_prev3c).
+-define(CompactRequestIDToken , "RQ" ). % v3
+-else.
+-define(CompactRequestIDToken , "SPARQ" ). % v3
+-endif.
+-define(CompactReservedGroupToken , "RG" ).
+-define(CompactReservedValueToken , "RV" ).
+-define(CompactSegmentationCompleteToken , "&" ). % v3
+-define(CompactSendonlyToken , "SO" ).
+-define(CompactSendrecvToken , "SR" ).
+-define(CompactServicesToken , "SV" ).
+-define(CompactServiceStatesToken , "SI" ).
+-define(CompactServiceChangeToken , "SC" ).
+-define(CompactServiceChangeAddressToken , "AD" ).
+-define(CompactServiceChangeIncompleteToken , "SIC" ). % v3
+-define(CompactSignalListToken , "SL" ).
+-define(CompactSignalsToken , "SG" ).
+-define(CompactSignalTypeToken , "SY" ).
+-define(CompactStatsToken , "SA" ).
+-define(CompactStreamToken , "ST" ).
+-define(CompactSubtractToken , "S" ).
+-define(CompactSynchISDNToken , "SN" ).
+-define(CompactTerminationStateToken , "TS" ).
+-define(CompactTestToken , "TE" ).
+-define(CompactTimeOutToken , "TO" ).
+-define(CompactTopologyToken , "TP" ).
+-define(CompactTransToken , "T" ).
+-define(CompactResponseAckToken , "K" ).
+-define(CompactV18Token , ?PrettyV18Token ).
+-define(CompactV22Token , ?PrettyV22Token ).
+-define(CompactV22bisToken , ?PrettyV22bisToken ).
+-define(CompactV32Token , ?PrettyV32Token ).
+-define(CompactV32bisToken , ?PrettyV32bisToken ).
+-define(CompactV34Token , ?PrettyV34Token ).
+-define(CompactV76Token , ?PrettyV76Token ).
+-define(CompactV90Token , ?PrettyV90Token ).
+-define(CompactV91Token , ?PrettyV91Token ).
+-define(CompactVersionToken , "V" ).
+
+-define(white_space(Char), ((Char) =:= ?SpToken) orelse ((Char) =:= ?HtabToken)).
+-define(end_of_line(Char), ((Char) =:= ?LfToken) orelse ((Char) =:= ?CrToken)).
+
+-define(classify_char(Char),
+ (case Char of
+ $+ -> safe_char;
+ $- -> safe_char;
+ $& -> safe_char;
+ $! -> safe_char;
+ $_ -> safe_char;
+ $/ -> safe_char;
+ $' -> safe_char;
+ $? -> safe_char;
+ $@ -> safe_char;
+ $^ -> safe_char;
+ $` -> safe_char;
+ $~ -> safe_char;
+ $* -> safe_char;
+ $$ -> safe_char;
+ ?BackslashToken -> safe_char;
+ ?LparToken -> safe_char;
+ ?RparToken -> safe_char;
+ $% -> safe_char;
+ ?VbarToken -> safe_char;
+ $. -> safe_char;
+ ?SemiColonToken -> rest_char;
+ ?LsbrktToken -> rest_char;
+ ?RsbrktToken -> rest_char;
+ ?LbrktToken -> rest_char;
+ ?RbrktToken -> rest_char;
+ ?ColonToken -> rest_char;
+ ?CommaToken -> rest_char;
+ ?NequalToken -> rest_char;
+ ?LesserToken -> rest_char;
+ ?GreaterToken -> rest_char;
+ ?EqualToken -> rest_char;
+ ?DoubleQuoteToken -> double_quote;
+ ?SpToken -> white_space;
+ ?HtabToken -> white_space;
+ ?LfToken -> end_of_line;
+ ?CrToken -> end_of_line;
+ _ when (Char >= $0) andalso (Char =< $9) -> safe_char;
+ _ when (Char >= $a) andalso (Char =< $z) -> safe_char;
+ _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper;
+ _ -> bad_char
+ end)).
+
+-define(classify_char2(Char),
+ (case Char of
+ ?SemiColonToken -> rest_char;
+ ?LsbrktToken -> rest_char;
+ ?RsbrktToken -> rest_char;
+ ?LbrktToken -> rest_char;
+ ?RbrktToken -> rest_char;
+ ?ColonToken -> rest_char;
+ ?CommaToken -> rest_char;
+ ?NequalToken -> rest_char;
+ ?LesserToken -> rest_char;
+ ?GreaterToken -> rest_char;
+ ?EqualToken -> rest_char;
+ ?SpToken -> white_space;
+ ?HtabToken -> white_space;
+ ?LfToken -> end_of_line;
+ ?CrToken -> end_of_line;
+ _ -> no_skip_char
+ end)).
+
+-define(classify_char3(Char),
+ (case Char of
+ $+ -> safe_char;
+ $- -> safe_char;
+ $& -> safe_char;
+ $! -> safe_char;
+ $_ -> safe_char;
+ $/ -> safe_char;
+ $' -> safe_char;
+ $? -> safe_char;
+ $@ -> safe_char;
+ $^ -> safe_char;
+ $` -> safe_char;
+ $~ -> safe_char;
+ $* -> safe_char;
+ $$ -> safe_char;
+ ?BackslashToken -> safe_char;
+ ?LparToken -> safe_char;
+ ?RparToken -> safe_char;
+ $% -> safe_char;
+ ?VbarToken -> safe_char;
+ $. -> safe_char;
+ _ when (Char >= $0) andalso (Char =< $9) -> safe_char;
+ _ when (Char >= $a) andalso (Char =< $z) -> safe_char;
+ _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper;
+ _ -> non_safe_char
+ end)).
+
+%% Only safe_char and safe_char_upper
+-define(classify_char4(Char),
+ (case Char of
+ $+ -> safe_char;
+ $- -> safe_char;
+ $& -> safe_char;
+ $! -> safe_char;
+ $_ -> safe_char;
+ $/ -> safe_char;
+ $' -> safe_char;
+ $? -> safe_char;
+ $@ -> safe_char;
+ $^ -> safe_char;
+ $` -> safe_char;
+ $~ -> safe_char;
+ $* -> safe_char;
+ $$ -> safe_char;
+ ?BackslashToken -> safe_char;
+ ?LparToken -> safe_char;
+ ?RparToken -> safe_char;
+ $% -> safe_char;
+ ?VbarToken -> safe_char;
+ $. -> safe_char;
+ _ when (Char >= $0) andalso (Char =< $9) -> safe_char;
+ _ when (Char >= $a) andalso (Char =< $z) -> safe_char;
+ _ when (Char >= $A) andalso (Char =< $Z) -> safe_char_upper;
+ _ -> not_safe_char
+ end)).
+
diff --git a/lib/megaco/src/text/modules.mk b/lib/megaco/src/text/modules.mk
new file mode 100644
index 0000000000..c493c978a8
--- /dev/null
+++ b/lib/megaco/src/text/modules.mk
@@ -0,0 +1,65 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco_compact_text_encoder \
+ megaco_compact_text_encoder_v1 \
+ megaco_compact_text_encoder_v2 \
+ megaco_compact_text_encoder_v3 \
+ megaco_compact_text_encoder_prev3a \
+ megaco_compact_text_encoder_prev3b \
+ megaco_compact_text_encoder_prev3c \
+ megaco_pretty_text_encoder \
+ megaco_pretty_text_encoder_v1 \
+ megaco_pretty_text_encoder_v2 \
+ megaco_pretty_text_encoder_v3 \
+ megaco_pretty_text_encoder_prev3a \
+ megaco_pretty_text_encoder_prev3b \
+ megaco_pretty_text_encoder_prev3c \
+ megaco_text_mini_decoder \
+ megaco_text_scanner
+
+
+INTERNAL_HRL_FILES = \
+ megaco_text_gen_v1.hrl \
+ megaco_text_gen_v2.hrl \
+ megaco_text_gen_v3.hrl \
+ megaco_text_gen_prev3a.hrl \
+ megaco_text_gen_prev3b.hrl \
+ megaco_text_gen_prev3c.hrl \
+ megaco_text_parser_v1.hrl \
+ megaco_text_parser_v2.hrl \
+ megaco_text_parser_v3.hrl \
+ megaco_text_parser_prev3a.hrl \
+ megaco_text_parser_prev3b.hrl \
+ megaco_text_parser_prev3c.hrl \
+ megaco_text_mini_parser.hrl \
+ megaco_text_tokens.hrl
+
+
+INTERNAL_YRL_FILES = \
+ megaco_text_parser_v1.yrl \
+ megaco_text_parser_v2.yrl \
+ megaco_text_parser_v3.yrl \
+ megaco_text_parser_prev3a.yrl \
+ megaco_text_parser_prev3b.yrl \
+ megaco_text_parser_prev3c.yrl \
+ megaco_text_mini_parser.yrl
+
+
diff --git a/lib/megaco/src/udp/Makefile b/lib/megaco/src/udp/Makefile
new file mode 100644
index 0000000000..64b6478c2c
--- /dev/null
+++ b/lib/megaco/src/udp/Makefile
@@ -0,0 +1,117 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2000-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+MEGACO_INCLUDEDIR = ../../include
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = \
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+include ../app/megaco.mk
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -I../../include
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/udp
+ $(INSTALL_DATA) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/udp
+
+
+release_docs_spec:
+
+
+# ----------------------------------------------------
+# Include dependencies
+# ----------------------------------------------------
+
+$(EBIN)/megaco_udp.$(EMULATOR): megaco_udp.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_server.$(EMULATOR): megaco_udp_server.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_sup.$(EMULATOR): megaco_udp_sup.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
+$(EBIN)/megaco_udp_test.$(EMULATOR): megaco_udp_test.erl \
+ megaco_udp.hrl $(MEGACO_INCLUDEDIR)/megaco.hrl
+
diff --git a/lib/megaco/src/udp/megaco_udp.erl b/lib/megaco/src/udp/megaco_udp.erl
new file mode 100644
index 0000000000..c75b703949
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp.erl
@@ -0,0 +1,324 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Interface to the UDP transport module for Megaco/H.248
+%%-----------------------------------------------------------------
+-module(megaco_udp).
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+
+-record(send_handle, {socket, addr, port}).
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_transport/0, stop_transport/1,
+ open/2,
+ socket/1,
+ create_send_handle/3,
+ send_message/2,
+ close/1,
+ block/1,
+ unblock/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%% Statistics exports
+-export([get_stats/0, get_stats/1, get_stats/2,
+ reset_stats/0, reset_stats/1]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: get_stats/0, get_stats/1, get_stats/2
+%% Description: Retreive statistics (counters) for TCP
+%%-----------------------------------------------------------------
+get_stats() ->
+ megaco_stats:get_stats(megaco_udp_stats).
+
+get_stats(SH) when is_record(SH, send_handle) ->
+ megaco_stats:get_stats(megaco_udp_stats, SH).
+
+get_stats(SH, Counter)
+ when is_record(SH, send_handle) andalso is_atom(Counter) ->
+ megaco_stats:get_stats(megaco_udp_stats, SH, Counter).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset_stats/0, reaet_stats/1
+%% Description: Reset statistics (counters) for TCP
+%%-----------------------------------------------------------------
+reset_stats() ->
+ megaco_stats:reset_stats(megaco_udp_stats).
+
+reset_stats(SH) when is_record(SH, send_handle) ->
+ megaco_stats:reset_stats(megaco_udp_stats, SH).
+
+
+
+%%-----------------------------------------------------------------
+%% Func: start_transport
+%% Description: Starts the UDP transport service
+%%-----------------------------------------------------------------
+start_transport() ->
+ (catch megaco_stats:init(megaco_udp_stats)),
+ megaco_udp_sup:start_link().
+
+
+%%-----------------------------------------------------------------
+%% Func: stop_transport
+%% Description: Stop the UDP transport service
+%%-----------------------------------------------------------------
+stop_transport(Pid) ->
+ (catch unlink(Pid)),
+ stop_transport(Pid, shutdown).
+
+stop_transport(Pid, Reason) ->
+ exit(Pid, Reason).
+
+
+%%-----------------------------------------------------------------
+%% Func: open
+%% Description: Function is used when opening an UDP socket
+%%-----------------------------------------------------------------
+open(SupPid, Options) ->
+ Mand = [port, receive_handle],
+ case parse_options(Options, #megaco_udp{}, Mand) of
+ {ok, UdpRec} ->
+
+ %%------------------------------------------------------
+ %% Setup the socket
+ IpOpts = [binary, {reuseaddr, true}, {active, once} |
+ UdpRec#megaco_udp.options],
+
+ case (catch gen_udp:open(UdpRec#megaco_udp.port, IpOpts)) of
+ {ok, Socket} ->
+ ?udp_debug(UdpRec, "udp open", []),
+ NewUdpRec = UdpRec#megaco_udp{socket = Socket},
+ case start_udp_server(SupPid, NewUdpRec) of
+ {ok, ControlPid} ->
+ gen_udp:controlling_process(Socket, ControlPid),
+ {ok, Socket, ControlPid};
+ {error, Reason} ->
+ Error = {error, {could_not_start_udp_server, Reason}},
+ ?udp_debug({socket, Socket}, "udp close", []),
+ gen_udp:close(Socket),
+ Error
+
+ end;
+ {'EXIT', Reason} ->
+ Error = {error, {could_not_open_udp_port, Reason}},
+ ?udp_debug(UdpRec, "udp open exited", [Error]),
+ Error;
+ {error, Reason} ->
+ Error = {error, {could_not_open_udp_port, Reason}},
+ ?udp_debug(UdpRec, "udp open failed", [Error]),
+ Error
+ end;
+ {error, Reason} = Error ->
+ ?udp_debug(#megaco_udp{}, "udp open failed",
+ [Error, {options, Options}]),
+ {error, Reason}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: socket
+%% Description: Returns the inet socket
+%%-----------------------------------------------------------------
+socket(SH) when is_record(SH, send_handle) ->
+ SH#send_handle.socket;
+socket(Socket) ->
+ Socket.
+
+
+upgrade_receive_handle(Pid, NewHandle)
+ when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) ->
+ megaco_udp_server:upgrade_receive_handle(Pid, NewHandle).
+
+
+%%-----------------------------------------------------------------
+%% Func: create_send_handle
+%% Description: Function is used for creating the handle used when
+%% sending data on the UDP socket
+%%-----------------------------------------------------------------
+create_send_handle(Socket, {_, _, _, _} = Addr, Port) ->
+ do_create_send_handle(Socket, Addr, Port);
+create_send_handle(Socket, Addr0, Port) ->
+ {ok, Addr} = inet:getaddr(Addr0, inet),
+ do_create_send_handle(Socket, Addr, Port).
+
+do_create_send_handle(Socket, Addr, Port) ->
+ %% If neccessary create snmp counter's
+ SH = #send_handle{socket = Socket, addr = Addr, port = Port},
+ maybe_create_snmp_counters(SH),
+ SH.
+
+
+maybe_create_snmp_counters(SH) ->
+ Counters = [medGwyGatewayNumInMessages,
+ medGwyGatewayNumInOctets,
+ medGwyGatewayNumOutMessages,
+ medGwyGatewayNumOutOctets,
+ medGwyGatewayNumErrors],
+ %% Only need to check one of them, since either all of them exist
+ %% or none of them exist:
+ Key = {SH, medGwyGatewayNumInMessages},
+ case (catch ets:lookup(megaco_udp_stats, Key)) of
+ [] ->
+ create_snmp_counters(SH, Counters);
+ [_] ->
+ ok;
+ _ ->
+ ok
+ end.
+
+create_snmp_counters(_SH, []) ->
+ ok;
+create_snmp_counters(SH, [Counter|Counters]) ->
+ Key = {SH, Counter},
+ ets:insert(megaco_udp_stats, {Key, 0}),
+ create_snmp_counters(SH, Counters).
+
+
+%%-----------------------------------------------------------------
+%% Func: send_message
+%% Description: Function is used for sending data on the UDP socket
+%%-----------------------------------------------------------------
+send_message(SH, Data) when is_record(SH, send_handle) ->
+ #send_handle{socket = Socket, addr = Addr, port = Port} = SH,
+ Res = gen_udp:send(Socket, Addr, Port, Data),
+ case Res of
+ ok ->
+ incNumOutMessages(SH),
+ incNumOutOctets(SH, size(Data));
+ _ ->
+ ok
+ end,
+ Res;
+send_message(SH, _Data) ->
+ {error, {bad_send_handle, SH}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: block
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+block(SH) when is_record(SH, send_handle) ->
+ block(SH#send_handle.socket);
+block(Socket) ->
+ ?udp_debug({socket, Socket}, "udp block", []),
+ inet:setopts(Socket, [{active, false}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: unblock
+%% Description: Function is used for blocking incomming messages
+%% on the TCP socket
+%%-----------------------------------------------------------------
+unblock(SH) when is_record(SH, send_handle) ->
+ unblock(SH#send_handle.socket);
+unblock(Socket) ->
+ ?udp_debug({socket, Socket}, "udp unblock", []),
+ inet:setopts(Socket, [{active, once}]).
+
+
+%%-----------------------------------------------------------------
+%% Func: close
+%% Description: Function is used for closing the UDP socket
+%%-----------------------------------------------------------------
+close(#send_handle{socket = Socket}) ->
+ close(Socket);
+close(Socket) ->
+ ?udp_debug({socket, Socket}, "udp close", []),
+ case erlang:port_info(Socket, connected) of
+ {connected, ControlPid} ->
+ megaco_udp_server:stop(ControlPid);
+ undefined ->
+ {error, already_closed}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_udp_server/1
+%% Description: Function is used for starting up a connection
+%% process
+%%-----------------------------------------------------------------
+start_udp_server(SupPid, UdpRec) ->
+ megaco_udp_sup:start_child(SupPid, UdpRec).
+
+
+%%-----------------------------------------------------------------
+%% Func: parse_options
+%% Description: Function that parses the options sent to the UDP
+%% module.
+%%-----------------------------------------------------------------
+parse_options([{Tag, Val} | T], UdpRec, Mand) ->
+ Mand2 = Mand -- [Tag],
+ case Tag of
+ port ->
+ parse_options(T, UdpRec#megaco_udp{port = Val}, Mand2);
+ udp_options when is_list(Val) ->
+ parse_options(T, UdpRec#megaco_udp{options = Val}, Mand2);
+ receive_handle ->
+ parse_options(T, UdpRec#megaco_udp{receive_handle = Val}, Mand2);
+ module when is_atom(Val) ->
+ parse_options(T, UdpRec#megaco_udp{module = Val}, Mand2);
+ serialize when (Val =:= true) orelse (Val =:= false) ->
+ parse_options(T, UdpRec#megaco_udp{serialize = Val}, Mand2);
+ Bad ->
+ {error, {bad_option, Bad}}
+ end;
+parse_options([], UdpRec, []) ->
+ {ok, UdpRec};
+parse_options([], _UdpRec, Mand) ->
+ {error, {missing_options, Mand}};
+parse_options(BadList, _UdpRec, _Mand) ->
+ {error, {bad_option_list, BadList}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumOutMessages(SH) ->
+ incCounter({SH, medGwyGatewayNumOutMessages}, 1).
+
+incNumOutOctets(SH, NumOctets) ->
+ incCounter({SH, medGwyGatewayNumOutOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_udp_stats, Key, Inc).
+
+% incNumErrors(SH) ->
+% incCounter({SH, medGwyGatewayNumErrors}, 1).
diff --git a/lib/megaco/src/udp/megaco_udp.hrl b/lib/megaco/src/udp/megaco_udp.hrl
new file mode 100644
index 0000000000..d0b9ec1916
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp.hrl
@@ -0,0 +1,64 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Define the protocol options for Megaco/H.248 IP connections
+%%-----------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% IP options
+%%----------------------------------------------------------------------
+-record(megaco_udp,
+ {port,
+ options = [],
+ socket,
+ receive_handle,
+ module = megaco,
+ serialize = false % false: Spawn a new process for each message
+ }).
+
+
+-define(GC_MSG_LIMIT,1000).
+-define(HEAP_SIZE(S),5000 + 2*(S)).
+
+
+%%----------------------------------------------------------------------
+%% Event Trace
+%%----------------------------------------------------------------------
+
+-define(udp_report(Level, UdpRec, From, To, Label, Contents),
+ megaco:report_event(Level, From, To, Label,
+ [{line, ?MODULE, ?LINE}, UdpRec | Contents])).
+
+-define(udp_debug(UdpRec, Label, Contents),
+ ?udp_report_debug(UdpRec,
+ megaco_udp,
+ megaco_udp,
+ Label,
+ Contents)).
+
+-define(udp_report_important(C, From, To, Label, Contents),
+ ?udp_report(20, C, From, To, Label, Contents)).
+-define(udp_report_verbose(C, From, To, Label, Contents),
+ ?udp_report(40, C, From, To, Label, Contents)).
+-define(udp_report_debug(C, From, To, Label, Contents),
+ ?udp_report(60, C, From, To, Label, Contents)).
+-define(udp_report_trace(C, From, To, Label, Contents),
+ ?udp_report(80, C, From, To, Label, Contents)).
diff --git a/lib/megaco/src/udp/megaco_udp_server.erl b/lib/megaco/src/udp/megaco_udp_server.erl
new file mode 100644
index 0000000000..f126043141
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp_server.erl
@@ -0,0 +1,234 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%%
+%% Description:
+%% This file handles the H.248 UDP connections.
+%%
+%%-----------------------------------------------------------------
+-module(megaco_udp_server).
+
+-behaviour(gen_server).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/1,
+ stop/1,
+
+ upgrade_receive_handle/2
+ ]).
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ code_change/3,
+ terminate/2,
+
+ handle_received_message/5
+ ]).
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Description: Starts the process that keeps track of an UDP
+%% socket.
+%%-----------------------------------------------------------------
+start_link(Arg) ->
+ gen_server:start_link(?MODULE, Arg, []).
+
+%%-----------------------------------------------------------------
+%% Func: stop/1
+%% Description: Stops the process that keeps track of an UDP
+%% socket.
+%%-----------------------------------------------------------------
+stop(Pid) ->
+ call(Pid, stop).
+
+
+upgrade_receive_handle(Pid, NewHandle) ->
+ call(Pid, {upgrade_receive_handle, NewHandle}).
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the generic server
+%%-----------------------------------------------------------------
+init(Arg) ->
+ ?udp_debug(Arg, "udp server starting", [self()]),
+ {ok, Arg}.
+
+%%-----------------------------------------------------------------
+%% Func: terminate/2
+%% Description: Termination function for the generic server
+%%-----------------------------------------------------------------
+terminate(Reason, State) ->
+ ?udp_debug(State, "udp server terminating", [self(), Reason]),
+ ok.
+
+%%-----------------------------------------------------------------
+%% Func: handle_call/3
+%% Description: Handling call messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_call(stop, _From, UdpRec) ->
+ Reply = do_stop(UdpRec),
+ {stop, shutdown, Reply, UdpRec};
+handle_call({upgrade_receive_handle, NewHandle}, _From, UdpRec) ->
+ {reply, ok, UdpRec#megaco_udp{receive_handle = NewHandle}};
+handle_call(Req, From, UdpRec) ->
+ warning_msg("received unexpected request from ~p: "
+ "~n~p", [From, Req]),
+ {reply, {error, {invalid_request, Req}}, UdpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_cast/2
+%% Description: Handling cast messages (really just stop and garbage)
+%%-----------------------------------------------------------------
+handle_cast(stop, UdpRec) ->
+ do_stop(UdpRec),
+ {stop, shutdown, UdpRec};
+handle_cast(Msg, UdpRec) ->
+ warning_msg("received unexpected message: "
+ "~n~w", [Msg]),
+ {noreply, UdpRec}.
+
+%%-----------------------------------------------------------------
+%% Func: handle_info/2
+%% Description: Handling non call/cast messages. Incomming messages
+%% from the socket and exit codes.
+%%-----------------------------------------------------------------
+handle_info({udp, _UdpId, Ip, Port, Msg},
+ #megaco_udp{serialize = false} = UdpRec) ->
+ #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec,
+ SH = megaco_udp:create_send_handle(Socket, Ip, Port),
+ MsgSize = size(Msg),
+ incNumInMessages(SH),
+ incNumInOctets(SH, MsgSize),
+ case MsgSize of
+ Sz when Sz < ?GC_MSG_LIMIT ->
+ apply(Mod, receive_message, [RH, self(), SH, Msg]);
+ Sz ->
+ receive_message(Mod, RH, SH, Sz, Msg)
+ end,
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, UdpRec};
+handle_info({udp, _UdpId, Ip, Port, Msg},
+ #megaco_udp{serialize = true} = UdpRec) ->
+ #megaco_udp{socket = Socket, module = Mod, receive_handle = RH} = UdpRec,
+ SH = megaco_udp:create_send_handle(Socket, Ip, Port),
+ MsgSize = size(Msg),
+ incNumInMessages(SH),
+ incNumInOctets(SH, MsgSize),
+ process_received_message(Mod, RH, SH, Msg),
+ inet:setopts(Socket, [{active, once}]),
+ {noreply, UdpRec};
+handle_info(Info, UdpRec) ->
+ warning_msg("received unexpected info: "
+ "~n~w", [Info]),
+ {noreply, UdpRec}.
+
+
+process_received_message(Mod, RH, SH, Msg) ->
+ case (catch Mod:process_received_message(RH, self(), SH, Msg)) of
+ ok ->
+ ok;
+ Error ->
+ error_msg("failed processing received message: "
+ "~n~p", [Error]),
+ ok
+ end.
+
+
+receive_message(Mod, RH, SendHandle, Length, Msg) ->
+ Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}],
+ spawn_opt(?MODULE, handle_received_message,
+ [Mod, RH, self(), SendHandle, Msg], Opts).
+
+
+handle_received_message(Mod, RH, Parent, SH, Msg) ->
+ Mod:process_received_message(RH, Parent, SH, Msg),
+ unlink(Parent),
+ exit(normal).
+
+
+
+%%-----------------------------------------------------------------
+%% Func: code_change/3
+%% Descrition: Handles code change messages during upgrade.
+%%-----------------------------------------------------------------
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+do_stop(#megaco_udp{socket = Socket}) ->
+ gen_udp:close(Socket).
+
+
+%%-----------------------------------------------------------------
+%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1
+%% Description: SNMP counter increment functions
+%%
+%%-----------------------------------------------------------------
+incNumInMessages(SH) ->
+ incCounter({SH, medGwyGatewayNumInMessages}, 1).
+
+incNumInOctets(SH, NumOctets) ->
+ incCounter({SH, medGwyGatewayNumInOctets}, NumOctets).
+
+incCounter(Key, Inc) ->
+ ets:update_counter(megaco_udp_stats, Key, Inc).
+
+% incNumErrors(SH) ->
+% incCounter({SH, medGwyGatewayNumErrors}, 1).
+
+
+%% info_msg(F, A) ->
+%% ?megaco_info("UDP server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?megaco_warning("UDP server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?megaco_error("UDP server: " ++ F, A).
+
+
+call(Pid, Req) ->
+ gen_server:call(Pid, Req, infinity).
diff --git a/lib/megaco/src/udp/megaco_udp_sup.erl b/lib/megaco/src/udp/megaco_udp_sup.erl
new file mode 100644
index 0000000000..6a381c22d8
--- /dev/null
+++ b/lib/megaco/src/udp/megaco_udp_sup.erl
@@ -0,0 +1,112 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%-----------------------------------------------------------------
+%% Purpose: Supervisor for all active UDP port servers
+%%-----------------------------------------------------------------
+-module(megaco_udp_sup).
+
+-behaviour(supervisor).
+
+%%-----------------------------------------------------------------
+%% Include files
+%%-----------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+
+%%-----------------------------------------------------------------
+%% External exports
+%%-----------------------------------------------------------------
+-export([
+ start_link/0,
+ start_child/2
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% Internal exports
+%%-----------------------------------------------------------------
+-export([
+ init/1,
+ terminate/2,
+ start_server/1
+ ]).
+
+
+%%-----------------------------------------------------------------
+%% External interface functions
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: start_link
+%% Description: Starts the UDP port server supervisor
+%%-----------------------------------------------------------------
+start_link() ->
+ supervisor:start_link(?MODULE, [[]]).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_child
+%% Description: Starts the UDP port server supervisor
+%%-----------------------------------------------------------------
+start_child(SupPid, UdpRec) ->
+ supervisor:start_child(SupPid, [UdpRec]).
+
+
+%%-----------------------------------------------------------------
+%% Internal interface functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: start_server/1
+%% Description: Function which the supervisor calls to start a child
+%%-----------------------------------------------------------------
+start_server(Args) ->
+ megaco_udp_server:start_link(Args).
+
+
+%%-----------------------------------------------------------------
+%% Server functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: init/1
+%% Description: Init funcion for the supervisor
+%%-----------------------------------------------------------------
+init(_) ->
+ SupFlags = {simple_one_for_one, 500, 100},
+ ChildSpec = [
+ {megaco_udp_server,
+ {?MODULE, start_server, []},
+ permanent,
+ 10000,
+ worker,
+ []}
+ ],
+ {ok, {SupFlags, ChildSpec}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate/1
+%% Description: Termination function for the supervisor
+%%-----------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
diff --git a/lib/megaco/src/udp/modules.mk b/lib/megaco/src/udp/modules.mk
new file mode 100644
index 0000000000..47126f6207
--- /dev/null
+++ b/lib/megaco/src/udp/modules.mk
@@ -0,0 +1,30 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MODULES = \
+ megaco_udp \
+ megaco_udp_sup \
+ megaco_udp_server
+
+
+INTERNAL_HRL_FILES = \
+ megaco_udp.hrl
+
+
+
diff --git a/lib/megaco/subdirs.mk b/lib/megaco/subdirs.mk
new file mode 100644
index 0000000000..8c20c3e815
--- /dev/null
+++ b/lib/megaco/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+SUB_DIRS = src examples/simple examples/meas
+
diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile
new file mode 100644
index 0000000000..a6f50f87c4
--- /dev/null
+++ b/lib/megaco/test/Makefile
@@ -0,0 +1,611 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(MEGACO_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/megaco_test
+
+ifeq ($(findstring win32,$(TARGET)),win32)
+
+MAKEFILE_SRC = Makefile.win32.src
+
+else
+
+MAKEFILE_SRC = Makefile.src
+
+endif
+
+ifeq ($(TT_DIR),)
+TT_DIR = /tmp
+endif
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+HRL_FILES = megaco_test_lib.hrl
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
+
+COVER_SPEC_FILE = megaco.cover
+
+APP_CASES = app appup
+
+CODEC_CASES = codec1 codec2 codec3a codec3b codec3c
+
+MISC_CASES = tid sdp dm conf udp tcp ex timer flex
+
+OP_CASES = mess mib mreq pending trans actions load
+
+ALL_CASES = $(APP_CASES) $(CODEC_CASES) $(MISC_CASES) $(OP_CASES)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+include ../src/app/megaco.mk
+
+ifeq ($(USE_MEGACO_TEST_CODE),true)
+ERL_COMPILE_FLAGS += -DMEGACO_TEST_CODE=mona_lisa_spelar_doom
+endif
+
+ifeq ($(USE_MEGACO_HIPE),true)
+ERL_COMPILE_FLAGS += +native -Dmegaco_hipe_special=true
+endif
+
+ERL_COMPILE_FLAGS += \
+ $(MEGACO_ERL_COMPILE_FLAGS) \
+ -pa $(ERL_TOP)/lib/test_server/ebin \
+ -I$(ERL_TOP)/lib/test_server/include
+
+ERL_PATH = -pa ../../megaco/examples/simple \
+ -pa ../../megaco/ebin \
+ -pa ../../et/ebin
+
+ifndef SUITE
+SUITE = megaco_SUITE
+endif
+
+ESTOP = -s init stop
+
+ifeq ($(DONT_STOP),true)
+MAYBE_ESTOP =
+else
+MAYBE_ESTOP = $(ESTOP)
+endif
+
+ETVIEW = -s et_viewer
+ifeq ($(USE_ET_VIEWER),true)
+MAYBE_ETVIEW =
+else
+MAYBE_ETVIEW = $(ETVIEW)
+endif
+
+ifeq ($(MERL),)
+MERL = erl
+endif
+
+ARGS += -noshell
+
+ifeq ($(DISABLE_TC_TIMEOUT),true)
+ARGS += -megaco_test_timeout
+endif
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+tests debug opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+info:
+ @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
+ @echo "ERL = $(ERL)"
+ @echo "MERL = $(MERL)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Special Targets
+# ----------------------------------------------------
+
+aall: make
+ @echo "make sure epmd is new"
+ @epmd -kill > /dev/null
+ @echo "Running all app sub-suites separatelly"
+ @for i in $(APP_CASES); do \
+ echo "SUITE: $$i"; \
+ clearmake -V $$i > $$i.log; \
+ done
+ echo "done"
+
+call: make
+ @echo "make sure epmd is new"
+ @epmd -kill > /dev/null
+ @echo "Running all codec sub-suites separatelly"
+ @for i in $(CODEC_CASES); do \
+ echo "SUITE: $$i"; \
+ clearmake -V $$i > $$i.log; \
+ done
+
+mall: make
+ @echo "make sure epmd is new"
+ @epmd -kill > /dev/null
+ @echo "Running all misc sub-suites separatelly"
+ @for i in $(MISC_CASES); do \
+ echo "SUITE: $$i"; \
+ clearmake -V $$i > $$i.log; \
+ done
+
+oall: make
+ @echo "make sure epmd is new"
+ @epmd -kill > /dev/null
+ @echo "Running all operation sub-suites separatelly"
+ @for i in $(OP_CASES); do \
+ echo "SUITE: $$i"; \
+ clearmake -V $$i > $$i.log; \
+ done
+
+all: make
+ @echo "make sure epmd is new"
+ @epmd -kill > /dev/null
+ @echo "Running all sub-suites separatelly"
+ @for i in $(ALL_CASES); do \
+ echo "SUITE: $$i"; \
+ clearmake -V $$i > $$i.log; \
+ done
+
+make: targets
+
+targets: $(TARGET_FILES)
+
+test: make
+ $(MERL) $(ARGS) -sname megaco_test $(ERL_PATH) \
+ -s megaco_test_lib t $(SUITE) \
+ $(MAYBE_ESTOP)
+
+utest: make
+ $(MERL) $(ARGS) -sname megaco_utest $(ERL_PATH) \
+ $(MAYBE_ETVIEW) \
+ -s megaco_test_lib t $(SUITE) \
+ $(ESTOP)
+
+ftest: make
+ $(MERL) $(ARGS) -sname megaco_ftest $(ERL_PATH) \
+ -s megaco_filter \
+ -s megaco_test_lib t $(SUITE) \
+ $(ESTOP)
+
+decode_compact_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_compact $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_decode_compact_text_messages \
+ $(ESTOP)
+
+decode_compact_flex_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_compact_flex $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_decode_compact_flex_text_messages \
+ $(ESTOP)
+
+decode_compact_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_compact $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_decode_compact_text_messages \
+ $(ESTOP)
+
+decode_compact_flex_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_compact_flex $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_decode_compact_flex_text_messages \
+ $(ESTOP)
+
+decode_pretty_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_pretty $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_decode_pretty_text_messages \
+ $(ESTOP)
+
+decode_pretty_flex_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_pretty_flex $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_decode_pretty_flex_text_messages \
+ $(ESTOP)
+
+decode_pretty_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_pretty $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_decode_pretty_text_messages \
+ $(ESTOP)
+
+decode_pretty_flex_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_decode_pretty_flex $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_decode_pretty_flex_text_messages \
+ $(ESTOP)
+
+encode_compact_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_encode_compact $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_encode_compact_text_messages \
+ $(ESTOP)
+
+encode_compact_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_encode_compact $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_encode_compact_text_messages \
+ $(ESTOP)
+
+encode_pretty_prof1: make
+ $(MERL) $(ARGS) -sname megaco_profile_encode_pretty $(ERL_PATH) \
+ -s megaco_codec_v1_test profile_encode_pretty_text_messages \
+ $(ESTOP)
+
+encode_pretty_prof2: make
+ $(MERL) $(ARGS) -sname megaco_profile_encode_pretty $(ERL_PATH) \
+ -s megaco_codec_v2_test profile_encode_pretty_text_messages \
+ $(ESTOP)
+
+
+##########################
+
+tickets: make
+ $(MERL) $(ARGS) -sname megaco_tickets $(ERL_PATH) \
+ -s megaco_test_lib tickets $(SUITE) \
+ $(ESTOP)
+
+app: make
+ $(MERL) $(ARGS) -sname megaco_app $(ERL_PATH) \
+ -s megaco_test_lib t megaco_app_test \
+ $(ESTOP)
+
+appup: make
+ $(MERL) $(ARGS) -sname megaco_appup $(ERL_PATH) \
+ -s megaco_test_lib t megaco_appup_test \
+ $(ESTOP)
+
+conf: make
+ $(MERL) $(ARGS) -sname megaco_config $(ERL_PATH) \
+ -s megaco_test_lib t megaco_config_test \
+ $(ESTOP)
+
+
+##########################
+
+codec: make
+ $(MERL) $(ARGS) -sname megaco_codec $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_test \
+ $(MAYBE_ESTOP)
+
+codec1: make
+ $(MERL) $(ARGS) -sname megaco_codec1 $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_v1_test \
+ $(MAYBE_ESTOP)
+
+codec1_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec1_tickets $(ERL_PATH) \
+ -s megaco_codec_v1_test tickets \
+ $(ESTOP)
+
+codec2: make
+ $(MERL) $(ARGS) -sname megaco_codec2 $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_v2_test \
+ $(MAYBE_ESTOP)
+
+codec2_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec2_tickets $(ERL_PATH) \
+ -s megaco_codec_v2_test tickets \
+ $(ESTOP)
+
+codec3a: make
+ $(MERL) $(ARGS) -sname megaco_codec3a $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_prev3a_test \
+ $(MAYBE_ESTOP)
+
+codec3a_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec3a_tickets $(ERL_PATH) \
+ -s megaco_codec_prev3a_test tickets \
+ $(ESTOP)
+
+codec3b: make
+ $(MERL) $(ARGS) -sname megaco_codec3b $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_prev3b_test \
+ $(MAYBE_ESTOP)
+
+codec3b_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec3b_tickets $(ERL_PATH) \
+ -s megaco_codec_prev3b_test tickets \
+ $(ESTOP)
+
+codec3c: make
+ $(MERL) $(ARGS) -sname megaco_codec3c $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_prev3c_test \
+ $(MAYBE_ESTOP)
+
+codec3c_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec3c_tickets $(ERL_PATH) \
+ -s megaco_codec_prev3c_test tickets \
+ $(ESTOP)
+
+codec3: make
+ $(MERL) $(ARGS) -sname megaco_codec3 $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_v3_test \
+ $(MAYBE_ESTOP)
+
+codec3_tickets: make
+ $(MERL) $(ARGS) -sname megaco_codec3_tickets $(ERL_PATH) \
+ -s megaco_codec_v3_test tickets \
+ $(ESTOP)
+
+codecm: make
+ $(MERL) $(ARGS) -sname megaco_codec1 $(ERL_PATH) \
+ -s megaco_test_lib t megaco_codec_mini_test \
+ $(MAYBE_ESTOP)
+
+
+##########################
+
+time1: make
+ $(MERL) $(ARGS) -sname megaco_time1 $(ERL_PATH) \
+ -run megaco_codec_v1_test tt $(TT_DIR) \
+ $(ESTOP)
+
+time2: make
+ $(MERL) $(ARGS) -sname megaco_time2 $(ERL_PATH) \
+ -run megaco_codec_v2_test tt $(TT_DIR) \
+ $(ESTOP)
+
+timeo1: make
+ $(MERL) $(ARGS) -sname megaco_timeo1 $(ERL_PATH) \
+ -run megaco_codec_v1_test tt_official $(TT_DIR) \
+ $(ESTOP)
+
+timeo2: make
+ $(MERL) $(ARGS) -sname megaco_timeo2 $(ERL_PATH) \
+ -run megaco_codec_v2_test tt_official $(TT_DIR) \
+ $(ESTOP)
+
+timeo3: make
+ $(MERL) $(ARGS) -sname megaco_timeo3 $(ERL_PATH) \
+ -run megaco_codec_v3_test tt_official $(TT_DIR) \
+ $(ESTOP)
+
+timet1: make
+ $(MERL) $(ARGS) -sname megaco_timet1 $(ERL_PATH) \
+ -run megaco_codec_v1_test tt_texts $(TT_DIR) \
+ $(ESTOP)
+
+timet2: make
+ $(MERL) $(ARGS) -sname megaco_timet2 $(ERL_PATH) \
+ -run megaco_codec_v2_test tt_texts $(TT_DIR) \
+ $(ESTOP)
+
+timet3: make
+ $(MERL) $(ARGS) -sname megaco_timet3 $(ERL_PATH) \
+ -run megaco_codec_v3_test tt_texts $(TT_DIR) \
+ $(ESTOP)
+
+timeb1: make
+ $(MERL) $(ARGS) -sname megaco_timeb1 $(ERL_PATH) \
+ -run megaco_codec_v1_test tt_bins $(TT_DIR) \
+ $(ESTOP)
+
+timeb2: make
+ $(MERL) $(ARGS) -sname megaco_timeb2 $(ERL_PATH) \
+ -run megaco_codec_v2_test tt_bins $(TT_DIR) \
+ $(ESTOP)
+
+timeb3: make
+ $(MERL) $(ARGS) -sname megaco_timeb3 $(ERL_PATH) \
+ -run megaco_codec_v3_test tt_bins $(TT_DIR) \
+ $(ESTOP)
+
+
+##########################
+
+flex: make
+ $(MERL) $(ARGS) -sname megaco_flex $(ERL_PATH) \
+ -s megaco_test_lib t megaco_flex_test \
+ $(ESTOP)
+
+dm: make
+ $(MERL) $(ARGS) -sname megaco_dm $(ERL_PATH) \
+ -s megaco_test_lib t megaco_digit_map_test \
+ $(ESTOP)
+
+tid: make
+ $(MERL) $(ARGS) -sname megaco_tid $(ERL_PATH) \
+ -s megaco_test_lib t megaco_binary_term_id_test \
+ $(ESTOP)
+
+sdp: make
+ $(MERL) $(ARGS) -sname megaco_sdp $(ERL_PATH) \
+ -s megaco_test_lib t megaco_sdp_test \
+ $(MAYBE_ESTOP)
+
+actions: make
+ $(MERL) $(ARGS) -sname megaco_actions $(ERL_PATH) \
+ -s megaco_test_lib t megaco_actions_test \
+ $(MAYBE_ESTOP)
+
+mess: make
+ $(MERL) $(ARGS) -sname megaco_mess $(ERL_PATH) \
+ $(MAYBE_ETVIEW) \
+ -s megaco_test_lib t megaco_mess_test \
+ $(ESTOP)
+
+trans: make
+ $(MERL) $(ARGS) -sname megaco_trans $(ERL_PATH) \
+ -s megaco_test_lib t megaco_trans_test \
+ $(MAYBE_ESTOP)
+
+mib: make
+ $(MERL) $(ARGS) -sname megaco_mib $(ERL_PATH) \
+ -s megaco_test_lib t megaco_mib_test \
+ $(MAYBE_ESTOP)
+
+mreq: make
+ $(MERL) $(ARGS) -sname megaco_mreq $(ERL_PATH) \
+ -s megaco_test_lib t megaco_mreq_test \
+ $(MAYBE_ESTOP)
+
+pending: make
+ $(MERL) $(ARGS) -sname megaco_pending $(ERL_PATH) \
+ -s megaco_test_lib t megaco_pending_limit_test \
+ $(MAYBE_ESTOP)
+
+pl: make
+ $(MERL) $(ARGS) -sname megaco_pl $(ERL_PATH) \
+ -s megaco_test_lib t megaco_pending_limit_test \
+ $(MAYBE_ESTOP)
+
+udp: make
+ $(MERL) $(ARGS) -sname megaco_pl $(ERL_PATH) \
+ -s megaco_test_lib t megaco_udp_test \
+ $(MAYBE_ESTOP)
+
+tcp: make
+ $(MERL) $(ARGS) -sname megaco_pl $(ERL_PATH) \
+ -s megaco_test_lib t megaco_tcp_test \
+ $(MAYBE_ESTOP)
+
+load: make
+ $(MERL) $(ARGS) -sname megaco_load $(ERL_PATH) \
+ -s megaco_test_lib t megaco_load_test \
+ $(MAYBE_ESTOP)
+
+ex: make
+ $(MERL) $(ARGS) -sname megaco_ex $(ERL_PATH) \
+ -s megaco_test_lib t megaco_examples_test \
+ $(MAYBE_ESTOP)
+
+segment: make
+ $(MERL) $(ARGS) -sname megaco_segment $(ERL_PATH) \
+ -s megaco_test_lib t megaco_segment_test \
+ $(ESTOP)
+
+timer: make
+ $(MERL) $(ARGS) -sname megaco_timer $(ERL_PATH) \
+ -s megaco_test_lib t megaco_timer_test \
+ $(ESTOP)
+
+
+###################
+
+gnuplot_gif: make
+ $(MERL) $(ARGS) -sname megaco_gnuplot_gif $(ERL_PATH) \
+ -s megaco_call_flow_test gnuplot_gif \
+ $(ESTOP)
+
+display_v1: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_v1 $(ERL_PATH) \
+ -s megaco_codec_v1_test display_text_messages \
+ $(ESTOP)
+
+generate_v1: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs_v1 $(ERL_PATH) \
+ -s megaco_codec_v1_test generate_text_messages \
+ $(ESTOP)
+
+display_v2: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_v2 $(ERL_PATH) \
+ -s megaco_codec_v2_test display_text_messages \
+ $(ESTOP)
+
+generate_v2: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs_v2 $(ERL_PATH) \
+ -s megaco_codec_v2_test generate_text_messages \
+ $(ESTOP)
+
+display_prev3a: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_prev3a $(ERL_PATH) \
+ -s megaco_codec_prev3a_test display_text_messages \
+ $(ESTOP)
+
+display_prev3b: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_prev3b $(ERL_PATH) \
+ -s megaco_codec_prev3b_test display_text_messages \
+ $(ESTOP)
+
+generate_prev3b: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs_prev3b $(ERL_PATH) \
+ -s megaco_codec_prev3b_test generate_text_messages \
+ $(ESTOP)
+
+display_prev3c: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_prev3c $(ERL_PATH) \
+ -s megaco_codec_prev3c_test display_text_messages \
+ $(ESTOP)
+
+generate_prev3c: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs_prev3c $(ERL_PATH) \
+ -s megaco_codec_prev3c_test generate_text_messages \
+ $(ESTOP)
+
+display_v3: make
+ $(MERL) $(ARGS) -sname megaco_display_text_msgs_v3 $(ERL_PATH) \
+ -s megaco_codec_v3_test display_text_messages \
+ $(ESTOP)
+
+generate_v3: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs_v3 $(ERL_PATH) \
+ -s megaco_codec_v3_test generate_text_messages \
+ $(ESTOP)
+
+generate: make
+ $(MERL) $(ARGS) -sname megaco_generate_text_msgs $(ERL_PATH) \
+ -s megaco_codec_v1_test generate_text_messages \
+ -s megaco_codec_v2_test generate_text_messages \
+ -s megaco_codec_v3_test generate_text_messages \
+ $(ESTOP)
+
+node:
+ $(MERL) -sname megaco $(ERL_PATH)
+
+
+# ----------------------------------------------------
+# Release Targets
+# ----------------------------------------------------
+
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec:
+
+release_docs_spec:
+
+release_tests_spec: tests
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) \
+ $(HRL_FILES) $(ERL_FILES) \
+ $(RELSYSDIR)
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)
+ chmod -f -R u+w $(RELSYSDIR)
+
diff --git a/lib/megaco/test/megaco.cover b/lib/megaco/test/megaco.cover
new file mode 100644
index 0000000000..e7764017d4
--- /dev/null
+++ b/lib/megaco/test/megaco.cover
@@ -0,0 +1,70 @@
+%% -*- erlang -*-
+{exclude,
+ [megaco_encoder,
+ megaco_edist_compress,
+ megaco_filter,
+ megaco_transport,
+ megaco_erl_dist_encoder,
+ megaco_erl_dist_encoder_mc,
+ megaco_compact_text_encoder,
+ megaco_compact_text_encoder_v1,
+ megaco_compact_text_encoder_v2,
+ megaco_compact_text_encoder_prev3a,
+ megaco_compact_text_encoder_prev3b,
+ megaco_compact_text_encoder_prev3c,
+ megaco_compact_text_encoder_v3,
+ megaco_pretty_text_encoder,
+ megaco_pretty_text_encoder_v1,
+ megaco_pretty_text_encoder_v2,
+ megaco_pretty_text_encoder_prev3a,
+ megaco_pretty_text_encoder_prev3b,
+ megaco_pretty_text_encoder_prev3c,
+ megaco_pretty_text_encoder_v3,
+ megaco_text_mini_decoder,
+ megaco_text_mini_parser,
+ megaco_text_parser_v1,
+ megaco_text_parser_v2,
+ megaco_text_parser_prev3a,
+ megaco_text_parser_prev3b,
+ megaco_text_parser_prev3c,
+ megaco_text_parser_v3,
+ megaco_ber_bin_drv_media_gateway_control_v1,
+ megaco_ber_bin_drv_media_gateway_control_v2,
+ megaco_ber_bin_drv_media_gateway_control_prev3a,
+ megaco_ber_bin_drv_media_gateway_control_prev3b,
+ megaco_ber_bin_drv_media_gateway_control_prev3c,
+ megaco_ber_bin_drv_media_gateway_control_v3,
+ megaco_ber_bin_media_gateway_control_v1,
+ megaco_ber_bin_media_gateway_control_v2,
+ megaco_ber_bin_media_gateway_control_prev3a,
+ megaco_ber_bin_media_gateway_control_prev3b,
+ megaco_ber_bin_media_gateway_control_prev3c,
+ megaco_ber_bin_media_gateway_control_v3,
+ megaco_ber_media_gateway_control_v1,
+ megaco_ber_media_gateway_control_v2,
+ megaco_ber_media_gateway_control_prev3a,
+ megaco_ber_media_gateway_control_prev3b,
+ megaco_ber_media_gateway_control_prev3c,
+ megaco_ber_media_gateway_control_v3,
+ megaco_per_bin_drv_media_gateway_control_v1,
+ megaco_per_bin_drv_media_gateway_control_v2,
+ megaco_per_bin_drv_media_gateway_control_prev3a,
+ megaco_per_bin_drv_media_gateway_control_prev3b,
+ megaco_per_bin_drv_media_gateway_control_prev3c,
+ megaco_per_bin_drv_media_gateway_control_v3,
+ megaco_per_bin_media_gateway_control_v1,
+ megaco_per_bin_media_gateway_control_v2,
+ megaco_per_bin_media_gateway_control_prev3a,
+ megaco_per_bin_media_gateway_control_prev3b,
+ megaco_per_bin_media_gateway_control_prev3c,
+ megaco_per_bin_media_gateway_control_v3,
+ megaco_per_media_gateway_control_v1,
+ megaco_per_media_gateway_control_v2,
+ megaco_per_media_gateway_control_prev3a,
+ megaco_per_media_gateway_control_prev3b,
+ megaco_per_media_gateway_control_prev3c,
+ megaco_per_media_gateway_control_v3,
+ megaco_user_default
+ ]
+}.
+
diff --git a/lib/megaco/test/megaco.spec b/lib/megaco/test/megaco.spec
new file mode 100644
index 0000000000..7493bd5df8
--- /dev/null
+++ b/lib/megaco/test/megaco.spec
@@ -0,0 +1,5 @@
+{topcase, {dir, "../megaco_test"}}.
+{require_nodenames, 1}.
+%{skip, {megaco_digit_map_test, all, "Not yet implemented"}}.
+{skip, {megaco_measure_test, all, "Not yet implemented"}}.
+%{skip, {M, F, "Not yet implemented"}}.
diff --git a/lib/megaco/test/megaco.spec.vxworks b/lib/megaco/test/megaco.spec.vxworks
new file mode 100644
index 0000000000..2ac250e443
--- /dev/null
+++ b/lib/megaco/test/megaco.spec.vxworks
@@ -0,0 +1,5 @@
+{topcase, {dir, "../megaco_test"}}.
+{require_nodenames, 1}.
+{skip, {megaco_digit_map_test, all, "Not yet implemented"}}.
+{skip, {megaco_measure_test, all, "Not yet implemented"}}.
+%{skip, {M, F, "Not yet implemented"}}.
diff --git a/lib/megaco/test/megaco_SUITE.erl b/lib/megaco/test/megaco_SUITE.erl
new file mode 100644
index 0000000000..1bb3a570a4
--- /dev/null
+++ b/lib/megaco/test/megaco_SUITE.erl
@@ -0,0 +1,142 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test application config
+%%----------------------------------------------------------------------
+
+-module(megaco_SUITE).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+init() ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:flush().
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ app_test,
+ appup_test,
+ config,
+ flex,
+ udp,
+ tcp,
+ examples,
+ %% call_flow,
+ digit_map,
+ mess,
+ measure,
+ binary_term_id,
+ codec,
+ sdp,
+ mib,
+ trans,
+ actions,
+ load,
+ pending_limit,
+ segmented,
+ timer
+ ].
+
+tickets(suite) ->
+ [
+ mess,
+ codec
+ ].
+
+app_test(suite) ->
+ [{megaco_app_test, all}].
+
+appup_test(suite) ->
+ [{megaco_appup_test, all}].
+
+config(suite) ->
+ [{megaco_config_test, all}].
+
+call_flow(suite) ->
+ [{megaco_call_flow_test, all}].
+
+digit_map(suite) ->
+ [{megaco_digit_map_test, all}].
+
+mess(suite) ->
+ [{megaco_mess_test, all}].
+
+udp(suite) ->
+ [{megaco_udp_test, all}].
+
+tcp(suite) ->
+ [{megaco_tcp_test, all}].
+
+examples(suite) ->
+ [{megaco_examples_test, all}].
+
+measure(suite) ->
+ [{megaco_measure_test, all}].
+
+binary_term_id(suite) ->
+ [{megaco_binary_term_id_test, all}].
+
+codec(suite) ->
+ [{megaco_codec_test, all}].
+
+sdp(suite) ->
+ [{megaco_sdp_test, all}].
+
+mib(suite) ->
+ [{megaco_mib_test, all}].
+
+trans(suite) ->
+ [{megaco_trans_test, all}].
+
+actions(suite) ->
+ [{megaco_actions_test, all}].
+
+load(suite) ->
+ [{megaco_load_test, all}].
+
+pending_limit(suite) ->
+ [{megaco_pending_limit_test, all}].
+
+segmented(suite) ->
+ [{megaco_segment_test, all}].
+
+timer(suite) ->
+ [{megaco_timer_test, all}].
+
+flex(suite) ->
+ [{megaco_flex_test, all}].
+
diff --git a/lib/megaco/test/megaco_actions_test.erl b/lib/megaco/test/megaco_actions_test.erl
new file mode 100644
index 0000000000..d493022ca1
--- /dev/null
+++ b/lib/megaco/test/megaco_actions_test.erl
@@ -0,0 +1,446 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify that it is possible to separatelly encode
+%% the action requests list. Do this with all codec's
+%% that supports partial encode.
+%%----------------------------------------------------------------------
+-module(megaco_actions_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
+
+-define(LOAD_COUNTER_START, 10).
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+-define(MGC_START(Pid, Mid, ET, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)).
+-define(MGC_RESET_STATS(Pid), megaco_test_mgc:reset_stats(Pid)).
+-define(MGC_REQ_DISC(Pid,To), megaco_test_mgc:request_discard(Pid,To)).
+-define(MGC_REQ_PEND(Pid,To), megaco_test_mgc:request_pending(Pid,To)).
+-define(MGC_REQ_HAND(Pid), megaco_test_mgc:request_handle(Pid)).
+
+-define(MG_START(Pid, Mid, Codec, EC, Transp, Verb),
+ megaco_test_mg:start(Pid, Mid, {Codec, EC}, Transp, Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_GET_STATS(Pid), megaco_test_mg:get_stats(Pid)).
+-define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
+-define(MG_NOTIF_AR(Pid), megaco_test_mg:await_notify_reply(Pid)).
+-define(MG_CANCEL(Pid,R), megaco_test_mg:cancel_request(Pid,R)).
+-define(MG_APPLY_LOAD(Pid,CntStart), megaco_test_mg:apply_load(Pid,CntStart)).
+-define(MG_EAR(Pid, Val), megaco_test_mg:encode_ar_first(Pid, Val)).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ pretty_text,
+ flex_pretty_text,
+ compact_text,
+ flex_compact_text,
+ erl_dist,
+ erl_dist_mc,
+ ber_bin,
+ ber_bin_drv,
+ ber_bin_native,
+ ber_bin_drv_native
+ ],
+ Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_text(suite) ->
+ [];
+pretty_text(doc) ->
+ [];
+pretty_text(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("pretty_text -> starting"),
+
+ Codec = pretty_text,
+ Version = 1,
+ EncodingConfig = [],
+ req_and_rep(Config, Codec, Version, EncodingConfig).
+
+
+flex_pretty_text(suite) ->
+ [];
+flex_pretty_text(doc) ->
+ [];
+flex_pretty_text(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+compact_text(suite) ->
+ [];
+compact_text(doc) ->
+ [];
+compact_text(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("compact_text -> starting"),
+
+ Codec = compact_text,
+ Version = 1,
+ EncodingConfig = [],
+ req_and_rep(Config, Codec, Version, EncodingConfig).
+
+
+flex_compact_text(suite) ->
+ [];
+flex_compact_text(doc) ->
+ [];
+flex_compact_text(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+erl_dist(suite) ->
+ [];
+erl_dist(doc) ->
+ [];
+erl_dist(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("erl_dist -> starting"),
+
+ Codec = erl_dist,
+ Version = 1,
+ EncodingConfig = [],
+ req_and_rep(Config, Codec, Version, EncodingConfig).
+
+
+erl_dist_mc(suite) ->
+ [];
+erl_dist_mc(doc) ->
+ [];
+erl_dist_mc(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("erl_dist_mc -> starting"),
+
+ Codec = erl_dist,
+ Version = 1,
+ EncodingConfig = [megaco_compressed],
+ req_and_rep(Config, Codec, Version, EncodingConfig).
+
+
+ber_bin(suite) ->
+ [];
+ber_bin(doc) ->
+ [];
+ber_bin(Config) when is_list(Config) ->
+ ?SKIP(currently_not_supported_by_asn1).
+
+
+ber_bin_drv(suite) ->
+ [];
+ber_bin_drv(doc) ->
+ [];
+ber_bin_drv(Config) when is_list(Config) ->
+ ?SKIP(currently_not_supported_by_asn1).
+
+
+ber_bin_native(suite) ->
+ [];
+ber_bin_native(doc) ->
+ [];
+ber_bin_native(Config) when is_list(Config) ->
+ ?SKIP(currently_not_supported_by_asn1).
+
+
+ber_bin_drv_native(suite) ->
+ [];
+ber_bin_drv_native(doc) ->
+ [];
+ber_bin_drv_native(Config) when is_list(Config) ->
+ ?SKIP(currently_not_supported_by_asn1).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+req_and_rep(Config, Codec, _Version, EC) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("req_and_rep -> starting"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ d("req_and_rep -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node, Mg2Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("req_and_rep -> start the MGC"),
+ ET = [{Codec, EC, tcp}, {Codec, EC, udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("req_and_rep -> start and connect the MGs"),
+ MgConf0 = [{Mg1Node, "mg1", Codec, EC, tcp, ?MG_VERBOSITY},
+ {Mg2Node, "mg2", Codec, EC, udp, ?MG_VERBOSITY}],
+ MgConf = connect_mg(MgConf0, []),
+
+ %% Collect the (initial) MGs statistics
+ Stats1 = get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for the MGs: ~n~p", [Stats1]),
+
+ %% Collect and check the MGC statistics
+ i("req_and_rep -> collect and check the MGC stats"),
+ {ok, MgcStats1} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats1]),
+
+
+ sleep(1000),
+
+
+ %% And apply some load
+ i("req_and_rep -> apply traffic load"),
+ ok = apply_load(MgConf),
+
+ %% Await completion of load part and the collect traffic
+ i("req_and_rep -> await load completion"),
+ ok = await_load_complete(MgConf),
+
+
+ sleep(1000),
+
+
+ i("req_and_rep -> collect the MGs statistics"),
+ Stats2 = get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for MGs: ~n~p", [Stats2]),
+
+ i("req_and_rep -> collect the MGC statistics"),
+ {ok, MgcStats2} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats2]),
+
+
+ sleep(1000),
+
+
+ %% Reset counters
+ i("req_and_rep -> reset the MGs statistics"),
+ reset_mg_stats(MgConf),
+ Stats3 = get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for the MGs: ~n~p", [Stats3]),
+
+ i("req_and_rep -> reset the MGC statistics"),
+ reset_mgc_stats(Mgc),
+ {ok, MgcStats3} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats3]),
+
+
+ sleep(1000),
+
+
+ %% Tell MGs to stop
+ i("req_and_rep -> stop the MGs"),
+ stop_mg(MgConf),
+
+
+ sleep(1000),
+
+
+ %% Collect the statistics
+ i("req_and_rep -> collect the MGC statistics"),
+ {ok, MgcStats4} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats4]),
+ {ok, MgcStats5} = ?MGC_GET_STATS(Mgc, 2),
+ d("req_and_rep -> stats (2) for Mgc: ~n~p~n", [MgcStats5]),
+
+ %% Tell Mgc to stop
+ i("req_and_rep -> stop the MGC"),
+ ?MGC_STOP(Mgc),
+
+ i("req_and_rep -> done", []),
+ ok.
+
+
+connect_mg([], Acc) ->
+ lists:reverse(Acc);
+connect_mg([{Node, Name, Codec, EC, Trans, Verb}|Mg], Acc) ->
+ Pid = connect_mg(Node, Name, Codec, EC, Trans, Verb),
+ connect_mg(Mg, [{Name, Pid}|Acc]).
+
+connect_mg(Node, Name, Codec, EC, Trans, Verb) ->
+ Mid = {deviceName, Name},
+ {ok, Pid} = ?MG_START(Node, Mid, Codec, EC, Trans, Verb),
+
+ {ok, _} = ?MG_EAR(Pid, true),
+
+ %% Ask the MGs to do a service change
+ Res = ?MG_SERV_CHANGE(Pid),
+ d("connect_mg -> (~s) service change result: ~p", [Name,Res]),
+
+ Pid.
+
+
+stop_mg(MGs) ->
+ [?MG_STOP(Pid) || {_Name, Pid} <- MGs].
+
+
+get_mg_stats([], Acc) ->
+ lists:reverse(Acc);
+get_mg_stats([{Name, Pid}|Mgs], Acc) ->
+ {ok, Stats} = ?MG_GET_STATS(Pid),
+ d("get_mg_stats -> stats for ~s: ~n~p~n", [Name, Stats]),
+ get_mg_stats(Mgs, [{Name, Stats}|Acc]).
+
+
+apply_load([]) ->
+ ok;
+apply_load([{_, MG}|MGs]) ->
+ d("apply_load -> apply load to ~p", [MG]),
+ ?MG_APPLY_LOAD(MG,?LOAD_COUNTER_START),
+ apply_load(MGs).
+
+
+reset_mg_stats([]) ->
+ ok;
+reset_mg_stats([{Name, Pid}|MGs]) ->
+ d("reset_mg_stats -> resetting ~s", [Name]),
+ ?MG_RESET_STATS(Pid),
+ reset_mg_stats(MGs).
+
+reset_mgc_stats(Mgc) ->
+ d("reset_mgc_stats -> resetting ~p", [Mgc]),
+ ?MGC_RESET_STATS(Mgc).
+
+
+await_load_complete([]) ->
+ ok;
+await_load_complete(MGs0) ->
+ receive
+ {load_complete, Pid} ->
+ d("received load_complete from ~p", [Pid]),
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ await_load_complete(lists:delete(Pid, MGs1));
+ {'EXIT', Pid, Reason} ->
+ i("exit signal from ~p: ~p", [Pid, Reason]),
+ case lists:keymember(Pid, 2, MGs0) of
+ true ->
+ exit({mg_exit, Pid, Reason});
+ false ->
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ await_load_complete(lists:delete(Pid, MGs1))
+ end;
+ Other ->
+ d("received unexpected message: ~n~p", [Other]),
+ await_load_complete(MGs0)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) ->
+ receive after X -> ok end.
+
+
+error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), "", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), "DBG: ", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, P, F, A) ->
+ print(printable(Severity,Verbosity), P, F, A).
+
+print(true, P, F, A) ->
+ io:format("~s~p:~s: " ++ F ++ "~n", [P, self(), get(sname) | A]);
+print(_, _, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ 10 * random:uniform(50).
+
+apply_load_timer() ->
+ erlang:send_after(random(), self(), apply_load_timeout).
+
diff --git a/lib/megaco/test/megaco_app_test.erl b/lib/megaco/test/megaco_app_test.erl
new file mode 100644
index 0000000000..8e2148c236
--- /dev/null
+++ b/lib/megaco/test/megaco_app_test.erl
@@ -0,0 +1,308 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_app_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(undef_funcs = Case, Config) ->
+ NewConfig = [{tc_timeout, ?MINUTES(10)} | Config],
+ megaco_test_lib:init_per_testcase(Case, NewConfig);
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ fields,
+ modules,
+ exportall,
+ app_depend,
+ undef_funcs
+ ],
+ {req, [], {conf, app_init, Cases, app_fin}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+app_init(suite) -> [];
+app_init(doc) -> [];
+app_init(Config) when is_list(Config) ->
+ case is_app(megaco) of
+ {ok, AppFile} ->
+ io:format("AppFile: ~n~p~n", [AppFile]),
+ case megaco_flex_scanner:is_enabled() of
+ true ->
+ case megaco_flex_scanner:is_reentrant_enabled() of
+ true ->
+ io:format("~nMegaco reentrant flex scanner enabled~n~n", []);
+ false ->
+ io:format("~nMegaco non-reentrant flex scanner enabled~n~n", [])
+ end;
+ false ->
+ io:format("~nMegaco flex scanner disabled~n~n", [])
+ end,
+ megaco:print_version_info(),
+ [{app_file, AppFile}|Config];
+ {error, Reason} ->
+ fail(Reason)
+ end.
+
+is_app(App) ->
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ {ok, AppFile};
+ Error ->
+ {error, {invalid_format, Error}}
+ end.
+
+
+app_fin(suite) -> [];
+app_fin(doc) -> [];
+app_fin(Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+fields(suite) ->
+ [];
+fields(doc) ->
+ [];
+fields(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Fields = [vsn, description, modules, registered, applications],
+ case check_fields(Fields, AppFile, []) of
+ [] ->
+ ok;
+ Missing ->
+ fail({missing_fields, Missing})
+ end.
+
+check_fields([], _AppFile, Missing) ->
+ Missing;
+check_fields([Field|Fields], AppFile, Missing) ->
+ check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
+
+check_field(Name, AppFile, Missing) ->
+ io:format("checking field: ~p~n", [Name]),
+ case lists:keymember(Name, 1, AppFile) of
+ true ->
+ Missing;
+ false ->
+ [Name|Missing]
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+modules(suite) ->
+ [];
+modules(doc) ->
+ [];
+modules(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ EbinList = get_ebin_mods(megaco),
+ case missing_modules(Mods, EbinList, []) of
+ [] ->
+ ok;
+ Missing ->
+ throw({error, {missing_modules, Missing}})
+ end,
+ case extra_modules(Mods, EbinList, []) of
+ [] ->
+ ok;
+ Extra ->
+ throw({error, {extra_modules, Extra}})
+ end,
+ {ok, Mods}.
+
+get_ebin_mods(App) ->
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ {ok, Files0} = file:list_dir(EbinDir),
+ Files1 = [lists:reverse(File) || File <- Files0],
+ [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
+
+
+missing_modules([], _Ebins, Missing) ->
+ Missing;
+missing_modules([Mod|Mods], Ebins, Missing) ->
+ case lists:member(Mod, Ebins) of
+ true ->
+ missing_modules(Mods, Ebins, Missing);
+ false ->
+ io:format("missing module: ~p~n", [Mod]),
+ missing_modules(Mods, Ebins, [Mod|Missing])
+ end.
+
+
+extra_modules(_Mods, [], Extra) ->
+ Extra;
+extra_modules(Mods, [Mod|Ebins], Extra) ->
+ case lists:member(Mod, Mods) of
+ true ->
+ extra_modules(Mods, Ebins, Extra);
+ false ->
+ io:format("supefluous module: ~p~n", [Mod]),
+ extra_modules(Mods, Ebins, [Mod|Extra])
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+exportall(suite) ->
+ [];
+exportall(doc) ->
+ [];
+exportall(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ check_export_all(Mods).
+
+
+check_export_all([]) ->
+ ok;
+check_export_all([Mod|Mods]) ->
+ case (catch apply(Mod, module_info, [compile])) of
+ {'EXIT', {undef, _}} ->
+ check_export_all(Mods);
+ O ->
+ case lists:keysearch(options, 1, O) of
+ false ->
+ check_export_all(Mods);
+ {value, {options, List}} ->
+ case lists:member(export_all, List) of
+ true ->
+ throw({error, {export_all, Mod}});
+ false ->
+ check_export_all(Mods)
+ end
+ end
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+app_depend(suite) ->
+ [];
+app_depend(doc) ->
+ [];
+app_depend(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Apps = key1search(applications, AppFile),
+ check_apps(Apps).
+
+
+check_apps([]) ->
+ ok;
+check_apps([App|Apps]) ->
+ case is_app(App) of
+ {ok, _} ->
+ check_apps(Apps);
+ Error ->
+ throw({error, {missing_app, {App, Error}}})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+undef_funcs(suite) ->
+ [];
+undef_funcs(doc) ->
+ [];
+undef_funcs(Config) when is_list(Config) ->
+ App = megaco,
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ Root = code:root_dir(),
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ XRefTestName = undef_funcs_make_name(App, xref_test_name),
+ {ok, XRef} = xref:start(XRefTestName),
+ ok = xref:set_default(XRef,
+ [{verbose,false},{warnings,false}]),
+ XRefName = undef_funcs_make_name(App, xref_name),
+ {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
+ {ok, App} = xref:replace_application(XRef, App, EbinDir),
+ {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
+ xref:stop(XRef),
+ analyze_undefined_function_calls(Undefs, Mods, []).
+
+analyze_undefined_function_calls([], _, []) ->
+ ok;
+analyze_undefined_function_calls([], _, AppUndefs) ->
+ exit({suite_failed, {undefined_function_calls, AppUndefs}});
+analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
+ AppModules, AppUndefs) ->
+ %% Check that this module is our's
+ case lists:member(Mod,AppModules) of
+ true ->
+ {Calling,Called} = AppUndef,
+ {Mod1,Func1,Ar1} = Calling,
+ {Mod2,Func2,Ar2} = Called,
+ io:format("undefined function call: "
+ "~n ~w:~w/~w calls ~w:~w/~w~n",
+ [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
+ analyze_undefined_function_calls(Undefs, AppModules,
+ [AppUndef|AppUndefs]);
+ false ->
+ io:format("dropping ~p~n", [Mod]),
+ analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
+ end.
+
+%% This function is used simply to avoid cut-and-paste errors later...
+undef_funcs_make_name(App, PostFix) ->
+ list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+fail(Reason) ->
+ exit({suite_failed, Reason}).
+
+key1search(Key, L) ->
+ case lists:keysearch(Key, 1, L) of
+ undefined ->
+ fail({not_found, Key, L});
+ {value, {Key, Value}} ->
+ Value
+ end.
diff --git a/lib/megaco/test/megaco_appup_mg.erl b/lib/megaco/test/megaco_appup_mg.erl
new file mode 100644
index 0000000000..f6060e406b
--- /dev/null
+++ b/lib/megaco/test/megaco_appup_mg.erl
@@ -0,0 +1,198 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Used when performing testing appup tests
+%%
+%% {ok, P} = megaco_appup_mg:start().
+%% megaco_appup_mg:stop(P).
+%% megaco_appup_mg:verbosity(P,silence).
+%% megaco_appup_mg:verbosity(P,debug).
+%% megaco_appup_mg:timeout(P,100).
+%% megaco_appup_mg:aam(P,10).
+%% megaco_appup_mg:aam(P,15).
+%% megaco_appup_mg:aat(P,2000).
+%% megaco_appup_mg:aat(P,10000).
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_appup_mg).
+
+%% API
+-export([start1/0, start2/0, start3/0, start4/0]).
+-export([start/0, start/1, start/2]).
+-export([verbosity/2, timeout/2]).
+-export([aat/2, aam/2]).
+
+%% Internal
+-export([main/4]).
+
+%% Constants:
+-define(TIMEOUT,1000).
+-define(MAXCOUNT,1).
+
+%% Wrapper macros
+-define(START(Mid, Enc, Transp, Conf, Verb),
+ megaco_test_mg:start(node(), Mid, Enc, Transp, Conf, Verb)).
+-define(STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+-define(GRP_REQ(Pid,N), megaco_test_mg:group_requests(Pid,N)).
+-define(VERBOSITY(Pid,V), megaco_test_mg:verbosity(Pid,V)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start1() -> start(text, tcp).
+start2() -> start(text, udp).
+start3() -> start(binary, tcp).
+start4() -> start(binary, udp).
+
+start() ->
+ start(text, tcp).
+
+start(tcp) ->
+ start(text, tcp);
+start(udp) ->
+ start(text, udp).
+
+start(Encoding, Transport) ->
+ proc_lib:start_link(?MODULE, main, [self(), Encoding, Transport, 1]).
+
+stop(Pid) ->
+ Pid ! stop.
+
+verbosity(Pid, V) ->
+ Pid ! {verbosity, V}.
+
+timeout(Pid, T) ->
+ Pid ! {timeout, T}.
+
+aat(Pid, Val) ->
+ uci(Pid, accu_ack_timer, Val).
+
+aam(Pid, Val) ->
+ uci(Pid, accu_ack_maxcount, Val).
+
+uci(Pid, Item, Val) ->
+ Pid ! {update_conn_info, Item, Val}.
+
+
+%% -------------------------------------------------------------------------
+
+%% - start function -
+main(Parent, Encoding, Transport, MaxCount) ->
+ Mg = init(Encoding, Transport, MaxCount),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(Mg, ?TIMEOUT, ?TIMEOUT).
+
+%% - init -
+init(Encoding, Transport, MaxCount) ->
+ verify_encoding(Encoding),
+ verify_transport(Transport),
+
+ Mid = {deviceName, "mg"},
+ Config = [{auto_ack, true} %,
+ %{trans_timer, 2000},
+ %{trans_ack_maxcount, MaxCount}
+ ],
+
+ d("start MG"),
+ {ok, Mg} = ?START(Mid, Encoding, Transport, Config, debug),
+
+ d("service change"),
+ ok = ?SERV_CHANGE(Mg),
+
+ ?GRP_REQ(Mg, MaxCount),
+
+ Mg.
+
+%% - main loop -
+loop(Mg, Timeout, To) when To =< 0 ->
+ ?NOTIF_RAR(Mg),
+ loop(Mg, Timeout, Timeout);
+loop(Mg, Timeout, To) ->
+ Start = t(),
+ receive
+ stop ->
+ d("stop"),
+ megaco_test_mg:stop(Mg),
+ exit(normal);
+
+ {update_conn_info, Item, Val} ->
+ d("update_conn_info -> ~p:~p", [Item, Val]),
+ megaco_test_mg:update_conn_info(Mg, Item, Val),
+ loop(Mg, Timeout, To - (t() - Start));
+
+ {request_group_size, Size} when Size > 1 ->
+ d("request_group_size -> ~p", [Size]),
+ ?GRP_REQ(Mg, Size),
+ loop(Mg, Timeout, To - (t() - Start));
+
+ {verbosity, V} ->
+ d("verbosity: ~p", [V]),
+ ?VERBOSITY(Mg, V),
+ loop(Mg, Timeout, To - (t() - Start));
+
+ {timeout, T} ->
+ d("timeout: ~p", [T]),
+ T1 = T - Timeout,
+ loop(Mg, T, To - (t() - Start) + T1);
+
+ Any ->
+ error("received unknown request: ~n~p", [Any]),
+ loop(Mg, Timeout, To - (t() - Start))
+
+ after To ->
+ ?NOTIF_RAR(Mg),
+ loop(Mg, Timeout, Timeout)
+ end.
+
+
+
+%% -------------------------------------------------------------------------
+
+verify_encoding(text) -> ok;
+verify_encoding(binary) -> ok;
+verify_encoding(Encoding) -> exit({invalid_encoding, Encoding}).
+
+verify_transport(tcp) -> ok;
+verify_transport(udp) -> ok;
+verify_transport(Transport) -> exit({invalid_transport, Transport}).
+
+%% -
+
+sleep(X) -> receive after X -> ok end.
+
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+%% -
+
+error(F, A) ->
+ d("ERROR: " ++ F, A).
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ io:format("~pAMG-" ++ F ++ "~n", [self()|A]).
diff --git a/lib/megaco/test/megaco_appup_mgc.erl b/lib/megaco/test/megaco_appup_mgc.erl
new file mode 100644
index 0000000000..b6e53655f8
--- /dev/null
+++ b/lib/megaco/test/megaco_appup_mgc.erl
@@ -0,0 +1,107 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Used when performing testing appup tests
+%%
+%% {ok, P} = megaco_appup_mgc:start().
+%% megaco_appup_mgc:stop(P).
+%% megaco_appup_mgc:verbosity(P,silence).
+%% megaco_appup_mgc:verbosity(P,debug).
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_appup_mgc).
+
+-export([start/0, start/1, stop/1]).
+-export([verbosity/2]).
+
+-export([main/2]).
+
+-define(START(Mid, ET, Verb),
+ megaco_test_mgc:start(node(), Mid, ET, Verb)).
+-define(STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(REQ_HANDS(Pid), megaco_test_mgc:request_handle_sloppy(Pid)).
+-define(VERBOSITY(Pid,V), megaco_test_mgc:verbosity(Pid,V)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ start(silence).
+start(V) ->
+ proc_lib:start_link(?MODULE, main, [self(), V]).
+
+stop(Pid) ->
+ Pid ! stop.
+
+verbosity(Pid, V) ->
+ Pid ! {verbosity, V}.
+
+
+%% ------------------------------------------------------------------------
+
+main(Parent, V) ->
+ d("starting"),
+ Mgc = init(V),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ d("started"),
+ loop(Mgc).
+
+init(V) ->
+ Mid = {deviceName, "mgc"},
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+
+ d("start MGC"),
+ {ok, Mgc} = ?START(Mid, ET, debug),
+
+ ?VERBOSITY(Mgc, V),
+
+ Mgc.
+
+loop(Mgc) ->
+ d("awaiting request..."),
+ receive
+
+ stop ->
+ d("stopping"),
+ ?STOP(Mgc),
+ exit(normal);
+
+ {verbosity, V} ->
+ d("verbosity: ~p", [V]),
+ ?VERBOSITY(Mgc, V);
+
+ Any ->
+ error("received unknown request: ~n~p", [Any])
+
+ end,
+ loop(Mgc).
+
+%% ------------------------------------------------------------------------
+
+error(F, A) ->
+ io:format("AMGC-ERROR: " ++ F, A).
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ io:format("AMGC: " ++ F ++ "~n", A).
diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl
new file mode 100644
index 0000000000..09732c6a4d
--- /dev/null
+++ b/lib/megaco/test/megaco_appup_test.erl
@@ -0,0 +1,516 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_appup_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+
+-define(APPLICATION, megaco).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ appup
+ ],
+ {req, [], {conf, appup_init, Cases, appup_fin}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+appup_init(suite) -> [];
+appup_init(doc) -> [];
+appup_init(Config) when is_list(Config) ->
+ AppFile = file_name(?APPLICATION, ".app"),
+ AppupFile = file_name(?APPLICATION, ".appup"),
+ [{app_file, AppFile}, {appup_file, AppupFile}|Config].
+
+
+file_name(App, Ext) ->
+ LibDir = code:lib_dir(App),
+ filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]).
+
+
+appup_fin(suite) -> [];
+appup_fin(doc) -> [];
+appup_fin(Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+appup(suite) ->
+ [];
+appup(doc) ->
+ "perform a simple check of the appup file";
+appup(Config) when is_list(Config) ->
+ AppupFile = key1search(appup_file, Config),
+ AppFile = key1search(app_file, Config),
+ Modules = modules(AppFile),
+ check_appup(AppupFile, Modules).
+
+modules(File) ->
+ case file:consult(File) of
+ {ok, [{application,megaco,Info}]} ->
+ case lists:keysearch(modules,1,Info) of
+ {value, {modules, Modules}} ->
+ Modules;
+ false ->
+ fail({bad_appinfo, Info})
+ end;
+ Error ->
+ fail({bad_appfile, Error})
+ end.
+
+
+check_appup(AppupFile, Modules) ->
+ case file:consult(AppupFile) of
+ {ok, [{V, UpFrom, DownTo}]} ->
+ check_appup(V, UpFrom, DownTo, Modules);
+ Else ->
+ fail({bad_appupfile, Else})
+ end.
+
+
+check_appup(V, UpFrom, DownTo, Modules) ->
+ check_version(V),
+ check_depends(up, UpFrom, Modules),
+ check_depends(down, DownTo, Modules),
+ check_module_subset(UpFrom),
+ check_module_subset(DownTo),
+ ok.
+
+
+check_depends(_, [], _) ->
+ ok;
+check_depends(UpDown, [Dep|Deps], Modules) ->
+ check_depend(UpDown, Dep, Modules),
+ check_depends(UpDown, Deps, Modules).
+
+
+check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instruction: ~p"
+ "~n Modules: ~p", [UpDown, Instr, Modules]),
+ ok;
+check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr,
+ Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instruction: ~p"
+ "~n Modules: ~p", [UpDown, Instr, Modules]),
+ ok;
+check_depend(UpDown, {V, Instructions}, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n V: ~p"
+ "~n Modules: ~p", [UpDown, V, Modules]),
+ check_version(V),
+ case check_instructions(UpDown,
+ Instructions, Instructions, [], [], Modules) of
+ {_Good, []} ->
+ ok;
+ {_, Bad} ->
+ fail({bad_instructions, Bad, UpDown})
+ end.
+
+
+check_instructions(_, [], _, Good, Bad, _) ->
+ {lists:reverse(Good), lists:reverse(Bad)};
+check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instr: ~p", [UpDown,Instr]),
+ case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of
+ ok ->
+ check_instructions(UpDown, Instrs, AllInstr,
+ [Instr|Good], Bad, Modules);
+ {error, Reason} ->
+ d("check_instructions(~w) -> bad instruction: "
+ "~n Reason: ~p", [UpDown,Reason]),
+ check_instructions(UpDown, Instrs, AllInstr, Good,
+ [{Instr, Reason}|Bad], Modules)
+ end.
+
+%% A new module is added
+check_instruction(up, {add_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when up-add_module instruction with"
+ "~n Module: ~p", [Module]),
+ check_module(Module, Modules);
+
+%% An old module is re-added
+check_instruction(down, {add_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when down-add_module instruction with"
+ "~n Module: ~p", [Module]),
+ case (catch check_module(Module, Modules)) of
+ {error, {unknown_module, Module, Modules}} ->
+ ok;
+ ok ->
+ error({existing_readded_module, Module})
+ end;
+
+%% Removing a module on upgrade:
+%% - the module has been removed from the app-file.
+%% - check that no module depends on this (removed) module
+check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules)
+ when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
+ d("check_instruction -> entry when up-remove instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p", [Module, Pre, Post]),
+ case (catch check_module(Module, Modules)) of
+ {error, {unknown_module, Module, Modules}} ->
+ check_purge(Pre),
+ check_purge(Post);
+ ok ->
+ error({existing_removed_module, Module})
+ end;
+
+%% Removing a module on downgrade: the module exist
+%% in the app-file.
+check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules)
+ when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
+ d("check_instruction -> entry when down-remove instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p", [Module, Pre, Post]),
+ case (catch check_module(Module, Modules)) of
+ ok ->
+ check_purge(Pre),
+ check_purge(Post),
+ check_no_remove_depends(Module, AllInstr);
+ {error, {unknown_module, Module, Modules}} ->
+ error({nonexisting_removed_module, Module})
+ end;
+
+check_instruction(_, {load_module, Module, Pre, Post, Depend},
+ AllInstr, Modules)
+ when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
+ d("check_instruction -> entry when load_module instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p"
+ "~n Depend: ~p", [Module, Pre, Post, Depend]),
+ check_module(Module, Modules),
+ check_module_depend(Module, Depend, Modules),
+ check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
+ check_purge(Pre),
+ check_purge(Post);
+
+check_instruction(_, {update, Module, Change, Pre, Post, Depend},
+ AllInstr, Modules)
+ when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
+ d("check_instruction -> entry when update instruction with"
+ "~n Module: ~p"
+ "~n Change: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p"
+ "~n Depend: ~p", [Module, Change, Pre, Post, Depend]),
+ check_module(Module, Modules),
+ check_module_depend(Module, Depend, Modules),
+ check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
+ check_change(Change),
+ check_purge(Pre),
+ check_purge(Post);
+
+check_instruction(_, {update, Module, supervisor}, _, Modules)
+ when is_atom(Module) ->
+ check_module(Module, Modules);
+
+check_instruction(_, {apply, {Module, Function, Args}}, _, Modules)
+ when is_atom(Module) andalso is_atom(Function) andalso is_list(Args) ->
+ d("check_instruction -> entry when down-apply instruction with"
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p", [Module, Function, Args]),
+ check_module(Module, Modules),
+ check_apply(Module, Function, Args);
+
+check_instruction(_, {restart_application, ?APPLICATION}, _AllInstr, _Modules) ->
+ ok;
+
+check_instruction(_, Instr, _AllInstr, _Modules) ->
+ d("check_instruction -> entry when unknown instruction with"
+ "~n Instr: ~p", [Instr]),
+ error({error, {unknown_instruction, Instr}}).
+
+
+%% If Module X depends on Module Y, then module Y must have an update
+%% instruction of some sort (otherwise the depend is faulty).
+updated_modules([], Modules) ->
+ d("update_modules -> entry when done with"
+ "~n Modules: ~p", [Modules]),
+ Modules;
+updated_modules([Instr|Instrs], Modules) ->
+ d("update_modules -> entry with"
+ "~n Instr: ~p"
+ "~n Modules: ~p", [Instr,Modules]),
+ Module = instruction_module(Instr),
+ d("update_modules -> Module: ~p", [Module]),
+ updated_modules(Instrs, [Module|Modules]).
+
+instruction_module({add_module, Module}) ->
+ Module;
+instruction_module({remove, {Module, _, _}}) ->
+ Module;
+instruction_module({load_module, Module, _, _, _}) ->
+ Module;
+instruction_module({update, Module, _, _, _, _}) ->
+ Module;
+instruction_module({apply, {Module, _, _}}) ->
+ Module;
+instruction_module(Instr) ->
+ d("instruction_module -> entry when unknown instruction with"
+ "~n Instr: ~p", [Instr]),
+ error({error, {unknown_instruction, Instr}}).
+
+
+%% Check that the modules handled in an instruction set for version X
+%% is a subset of the instruction set for version X-1.
+check_module_subset(Instructions) ->
+ do_check_module_subset(modules_of(Instructions)).
+
+do_check_module_subset([]) ->
+ ok;
+do_check_module_subset([_]) ->
+ ok;
+do_check_module_subset([{_V1, Mods1}|T]) ->
+ {V2, Mods2} = hd(T),
+ %% Check that the modules in V1 is a subset of V2
+ case do_check_module_subset2(Mods1, Mods2) of
+ ok ->
+ do_check_module_subset(T);
+ {error, Modules} ->
+ fail({subset_missing_instructions, V2, Modules})
+ end.
+
+do_check_module_subset2(Mods1, Mods2) ->
+ do_check_module_subset2(Mods1, Mods2, []).
+
+do_check_module_subset2([], _, []) ->
+ ok;
+do_check_module_subset2([], _, Acc) ->
+ {error, lists:reverse(Acc)};
+do_check_module_subset2([Mod|Mods], Mods2, Acc) ->
+ case lists:member(Mod, Mods2) of
+ true ->
+ do_check_module_subset2(Mods, Mods2, Acc);
+ false ->
+ do_check_module_subset2(Mods, Mods2, [Mod|Acc])
+ end.
+
+
+modules_of(Instructions) ->
+ modules_of(Instructions, []).
+
+modules_of([], Acc) ->
+ lists:reverse(Acc);
+modules_of([{V,Instructions}|T], Acc) ->
+ Mods = modules_of2(Instructions, []),
+ modules_of(T, [{V, Mods}|Acc]).
+
+modules_of2([], Acc) ->
+ lists:reverse(Acc);
+modules_of2([Instr|Instructions], Acc) ->
+ case module_of(Instr) of
+ {value, Mod} ->
+ modules_of2(Instructions, [Mod|Acc]);
+ false ->
+ modules_of2(Instructions, Acc)
+ end.
+
+module_of({add_module, Module}) ->
+ {value, Module};
+module_of({remove, {Module, _Pre, _Post}}) ->
+ {value, Module};
+module_of({load_module, Module, _Pre, _Post, _Depend}) ->
+ {value, Module};
+module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
+ {value, Module};
+module_of(_) ->
+ false.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% The version is a string consting of numbers separated by dots: "."
+%% Example: "3.3.3"
+%%
+check_version(V) when is_list(V) ->
+ case do_check_version(string:tokens(V, [$.])) of
+ ok ->
+ ok;
+ {error, BadVersionPart} ->
+ throw({error, {bad_version, V, BadVersionPart}})
+ end;
+check_version(V) ->
+ error({bad_version, V}).
+
+do_check_version([]) ->
+ ok;
+do_check_version([H|T]) ->
+ case (catch list_to_integer(H)) of
+ I when is_integer(I) ->
+ do_check_version(T);
+ _ ->
+ {error, H}
+ end.
+
+check_module(M, Modules) when is_atom(M) ->
+ case lists:member(M,Modules) of
+ true ->
+ ok;
+ false ->
+ error({unknown_module, M, Modules})
+ end;
+check_module(M, _) ->
+ error({bad_module, M}).
+
+
+check_module_depend(M, [], _) when is_atom(M) ->
+ d("check_module_depend -> entry with"
+ "~n M: ~p", [M]),
+ ok;
+check_module_depend(M, Deps, Modules) when is_atom(M) andalso is_list(Deps) ->
+ d("check_module_depend -> entry with"
+ "~n M: ~p"
+ "~n Deps: ~p"
+ "~n Modules: ~p", [M, Deps, Modules]),
+ case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of
+ [] ->
+ ok;
+ Unknown ->
+ error({unknown_depend_modules, Unknown})
+ end;
+check_module_depend(_M, D, _Modules) ->
+ d("check_module_depend -> entry when bad depend with"
+ "~n D: ~p", [D]),
+ error({bad_depend, D}).
+
+
+check_no_remove_depends(_Module, []) ->
+ ok;
+check_no_remove_depends(Module, [Instr|Instrs]) ->
+ check_no_remove_depend(Module, Instr),
+ check_no_remove_depends(Module, Instrs).
+
+check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) ->
+ case lists:member(Module, Depend) of
+ true ->
+ error({removed_module_in_depend, load_module, Mod, Module});
+ false ->
+ ok
+ end;
+check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) ->
+ case lists:member(Module, Depend) of
+ true ->
+ error({removed_module_in_depend, update, Mod, Module});
+ false ->
+ ok
+ end;
+check_no_remove_depend(_, _) ->
+ ok.
+
+
+check_change(soft) ->
+ ok;
+check_change({advanced, _Something}) ->
+ ok;
+check_change(Change) ->
+ error({bad_change, Change}).
+
+
+check_purge(soft_purge) ->
+ ok;
+check_purge(brutal_purge) ->
+ ok;
+check_purge(Purge) ->
+ error({bad_purge, Purge}).
+
+
+check_apply(Module, Function, Args) ->
+ case (catch Module:module_info()) of
+ Info when is_list(Info) ->
+ check_exported(Function, Args, Info);
+ {'EXIT', {undef, _}} ->
+ error({not_existing_module, Module})
+ end.
+
+check_exported(Function, Args, Info) ->
+ case lists:keysearch(exports, 1, Info) of
+ {value, {exports, FuncList}} ->
+ Arity = length(Args),
+ Arities = [A || {F, A} <- FuncList, F == Function],
+ case lists:member(Arity, Arities) of
+ true ->
+ ok;
+ false ->
+ error({not_exported_function, Function, Arity})
+ end;
+ _ ->
+ error({bad_export, Info})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+error(Reason) ->
+ throw({error, Reason}).
+
+fail(Reason) ->
+ exit({suite_failed, Reason}).
+
+key1search(Key, L) ->
+ case lists:keysearch(Key, 1, L) of
+ undefined ->
+ fail({not_found, Key, L});
+ {value, {Key, Value}} ->
+ Value
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+d(F, A) ->
+ d(false, F, A).
+
+d(true, F, A) ->
+ io:format(F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
+
diff --git a/lib/megaco/test/megaco_binary_term_id_test.erl b/lib/megaco/test/megaco_binary_term_id_test.erl
new file mode 100644
index 0000000000..da4e69c617
--- /dev/null
+++ b/lib/megaco/test/megaco_binary_term_id_test.erl
@@ -0,0 +1,1012 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+
+-module(megaco_binary_term_id_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/engine/megaco_message_internal.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([t/0]).
+
+%% Test suite exports
+-export([all/1, encode_first/1, decode_first/1,
+ init_per_testcase/2, fin_per_testcase/2]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([te01/1,te02/1,te03/1,te04/1,te05/1,
+ te06/1,te07/1,te08/1,te09/1,te10/1,
+ te11/1,te12/1,te13/1,te14/1,te15/1,
+ te16/1,te17/1,te18/1,te19/1]).
+-export([td01/1,td02/1,td03/1,td04/1,td05/1,td06/1]).
+
+
+%% ---------------------------------------------------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ encode_first,
+ decode_first
+ ].
+
+encode_first(suite) ->
+ encode_first_cases().
+
+decode_first(suite) ->
+ decode_first_cases().
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+t() ->
+ display([do(Case) || Case <- cases()]),
+ ok.
+
+
+cases() -> encode_first_cases() ++ decode_first_cases().
+
+encode_first_cases() -> [te01,te02,te03,te04,te05,
+ te06,te07,te08,te09,te10,
+ te11,te12,te13,te14,te15,
+ te16,te17,te18,te19].
+decode_first_cases() -> [td01,td02,td03,td04,td05,td06].
+
+do(Case) ->
+ case doc(Case) of
+ {'EXIT',_} ->
+ {Case,error};
+ Description ->
+ io:format("test case ~p~n",[Case]),
+ case suite(Case) of
+ {'EXIT',Reason} ->
+ Res = check_result(Case,Description,ok,{error,Reason}),
+ {Case,Res};
+ {Expected,Result} ->
+ Res = check_result(Case,Description,Expected,Result),
+ {Case,Res}
+ end
+ end.
+
+doc(Case) -> (catch apply(?MODULE,Case,[doc])).
+suite(Case) -> (catch apply(?MODULE,Case,[])).
+
+display(R) ->
+ [display(Case,Result) || {Case,Result} <- R].
+
+display(C,error) ->
+ io:format("Test case ~p failed~n",[C]);
+display(C,warning) ->
+ io:format("Test case ~p conspicuous~n",[C]);
+display(C,ok) ->
+ io:format("Test case ~p succeeded~n",[C]).
+
+check(D,ok,{ok,T1,T2,T3}) ->
+ Result = case check_ok_result(T1,T3) of
+ ok ->
+ ok;
+ {error,Reason} ->
+ io:format(" => inconsistent result"
+ "~n Start and end record differ"
+ "~n ~s"
+ "~n ~s"
+ "~n ~w"
+ "~n",
+ [D,Reason,T2]),
+ warning
+ end,
+ Result;
+check(D,error,{ok,T1,T2,T3}) ->
+ io:format(" => failed"
+ "~n ~s"
+ "~n ~p"
+ "~n ~p"
+ "~n ~p"
+ "~n",
+ [D,T1,T2,T3]),
+ error;
+check(_D,error,{error,_Reason}) ->
+ ok;
+check(D,ok,{error,Reason}) ->
+ io:format(" => failed"
+ "~n ~s"
+ "~n Failed for reason"
+ "~n ~p"
+ "~n",
+ [D,Reason]),
+ error.
+
+check_result(_C,D,ok,{ok,T1,T2,T3}) ->
+ Result = case check_ok_result(T1,T3) of
+ ok ->
+ io:format(" => succeeded"
+ "~n ~s"
+ "~n ~p"
+ "~n ~w"
+ "~n ~p",
+ [D,T1,T2,T3]),
+ ok;
+ {error,Reason} ->
+ io:format(" => inconsistent result"
+ "~n Start and end record differ"
+ "~n ~s"
+ "~n ~s"
+ "~n ~w",
+ [D,Reason,T2]),
+ warning
+ end,
+ io:format("~n~n--------------------~n",[]),
+ Result;
+check_result(_C,D,error,{ok,T1,T2,T3}) ->
+ io:format(" => failed"
+ "~n ~s"
+ "~n ~p"
+ "~n ~p"
+ "~n ~p"
+ "~n~n--------------------~n",
+ [D,T1,T2,T3]),
+ error;
+check_result(_C,D,error,{error,Reason}) ->
+ io:format(" => succeeded"
+ "~n ~s"
+ "~n Operation failed (expectedly) for reason"
+ "~n ~p"
+ "~n~n--------------------~n",
+ [D,Reason]),
+ ok;
+check_result(_C,D,ok,{error,Reason}) ->
+ io:format(" => failed"
+ "~n ~s"
+ "~n Failed for reason"
+ "~n ~p"
+ "~n~n--------------------~n",
+ [D,Reason]),
+ error.
+
+check_ok_result(R,R) when is_record(R,megaco_term_id) ->
+ ok; % Same record type and same record content
+check_ok_result(S,E) when is_record(S,megaco_term_id) andalso
+ is_record(E,megaco_term_id) ->
+ Reason = check_megaco_term_id_record(S,E),
+ {error,Reason}; % Same record type but different record content
+check_ok_result(R,R) when is_record(R,'TerminationID') ->
+ ok;
+check_ok_result(S,E) when is_record(S,'TerminationID') andalso
+ is_record(E,'TerminationID') ->
+ Reason = check_TerminationID_record(S,E),
+ {error,Reason}; % Same record type but different record content
+check_ok_result(_S,_E) ->
+ {error,"NOT THE SAME RECORD TYPES"}. % OOPS, Not even the same record type
+
+check_megaco_term_id_record(#megaco_term_id{contains_wildcards = Cw1,
+ id = Id1},
+ #megaco_term_id{contains_wildcards = Cw2,
+ id = Id2}) ->
+ Result = case check_megaco_term_id_cw(Cw1,Cw2) of
+ ok ->
+ check_megaco_term_id_id(Id1,Id2);
+ {error,R1} ->
+ R2 = check_megaco_term_id_id(Id1,Id2),
+ io_lib:format("~s~s",[R1,R2])
+ end,
+ lists:flatten(Result).
+
+check_megaco_term_id_cw(Cw,Cw) ->
+ ok;
+check_megaco_term_id_cw(Cw1,Cw2) ->
+ R = io_lib:format("~n The 'contains_wildcard' property of the start"
+ "~n megaco_term_id record "
+ "~n has value ~w "
+ "~n but the end record "
+ "~n has value ~w",
+ [Cw1,Cw2]),
+ {error,R}.
+
+check_megaco_term_id_id(Id,Id) ->
+ ok;
+check_megaco_term_id_id(Id1,Id2) ->
+ R = io_lib:format("~n The 'id' property of the start"
+ "~n megaco_term_id record "
+ "~n has value ~w "
+ "~n but the end record "
+ "~n has value ~w",
+ [Id1,Id2]),
+ {error,R}.
+
+
+check_TerminationID_record(#'TerminationID'{wildcard = W1, id = Id1},
+ #'TerminationID'{wildcard = W2, id = Id2}) ->
+ Result = case check_TerminationID_w(W1,W2) of
+ ok ->
+ check_TerminationID_id(Id1,Id2);
+ {error,R1} ->
+ R2 = check_TerminationID_id(Id1,Id2),
+ io_lib:format("~s~s",[R1,R2])
+ end,
+ lists:flatten(Result).
+
+check_TerminationID_w(W,W) ->
+ ok;
+check_TerminationID_w(W1,W2) ->
+ R = io_lib:format("~n The 'wildcard' property of the start"
+ "~n 'TerminationID' record "
+ "~n has value ~w "
+ "~n but the end record "
+ "~n has value ~w",
+ [W1,W2]),
+ {error,R}.
+
+check_TerminationID_id(Id,Id) ->
+ ok;
+check_TerminationID_id(Id1,Id2) ->
+ R = io_lib:format("~n The 'id' property of the start"
+ "~n 'TerminationID' record "
+ "~n has value ~w "
+ "~n but the end record "
+ "~n has value ~w",
+ [Id1,Id2]),
+ {error,R}.
+
+
+%% --------------------------------------------------------
+%% Start test cases
+%% --------------------------------------------------------
+
+%% basic_enc_dec01
+te01(doc) ->
+ "Basic encoding & then decoding test [1,1]\n (asn -> binary -> asn)";
+
+te01(suite) ->
+ [];
+
+te01(Config) when is_list(Config) ->
+ {Exp,Res} = te01(),
+ ok = check(te01(doc),Exp,Res).
+
+
+te01() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid01()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec02
+te02(doc) ->
+ "Basic encoding & then decoding test [1,2]";
+
+te02(suite) ->
+ [];
+
+te02(Config) when is_list(Config) ->
+ {Exp,Res} = te02(),
+ ok = check(te02(doc),Exp,Res).
+
+te02() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid02()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec03
+te03(doc) ->
+ "Basic encoding & then decoding test [1,3]";
+
+te03(suite) ->
+ [];
+
+te03(Config) when is_list(Config) ->
+ {Exp,Res} = te03(),
+ ok = check(te03(doc),Exp,Res).
+
+te03() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid03()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec04
+te04(doc) ->
+ "Basic encoding & then decoding test [1,4]\n (asn -> binary -> asn)";
+
+te04(suite) ->
+ [];
+
+te04(Config) when is_list(Config) ->
+ {Exp,Res} = te04(),
+ ok = check(te04(doc),Exp,Res).
+
+te04() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid04()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec05
+te05(doc) ->
+ "Basic encoding & then decoding test [1,5]\n (asn -> binary -> asn)";
+
+te05(suite) ->
+ [];
+
+te05(Config) when is_list(Config) ->
+ {Exp,Res} = te05(),
+ ok = check(te05(doc),Exp,Res).
+
+te05() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid05()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% no_wildcard_spec_but_fond_some_enc_dec
+te06(doc) ->
+ "Specified NO wildcards, but found some just the same [1,6]\n (asn -> binary -> asn)";
+
+te06(suite) ->
+ [];
+
+te06(Config) when is_list(Config) ->
+ {Exp,Res} = te06(),
+ ok = check(te06(doc),Exp,Res).
+
+te06() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid06()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% invalid_char_enc_dec
+te07(doc) ->
+ "Invalid character found (2) [1,7]\n (asn -> binary -> asn)";
+
+te07(suite) ->
+ [];
+
+te07(Config) when is_list(Config) ->
+ {Exp,Res} = te07(),
+ ok = check(te07(doc),Exp,Res).
+
+te07() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid07()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% erroneous_first_level_length_enc_dec01
+te08(doc) ->
+ "Erroneous length of first level (a character after wildcard) [1,8]\n (asn -> binary -> asn)";
+
+te08(suite) ->
+ [];
+
+te08(Config) when is_list(Config) ->
+ {Exp,Res} = te08(),
+ ok = check(te08(doc),Exp,Res).
+
+te08() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid08()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% erroneous_first_level_length_enc_dec02
+te09(doc) ->
+ "Erroneous length of first level (a character after last valid) [1,9]\n (asn -> binary -> asn)";
+
+te09(suite) ->
+ [];
+
+te09(Config) when is_list(Config) ->
+ {Exp,Res} = te09(),
+ ok = check(te09(doc),Exp,Res).
+
+te09() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid09()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard01
+te10(doc) ->
+ "Basic encode & decode with one recursive wildcard [1,10]\n (asn -> binary -> asn)\n (NOTE THAT THIS SHOULD LATER BE A LEVEL WILDCARD)";
+
+te10(suite) ->
+ [];
+
+te10(Config) when is_list(Config) ->
+ {Exp,Res} = te10(),
+ ok = check(te10(doc),Exp,Res).
+
+te10() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid10()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard02
+te11(doc) ->
+ "Basic encode & decode with one recursive wildcard [1,11]\n (asn -> binary -> asn)";
+
+te11(suite) ->
+ [];
+
+te11(Config) when is_list(Config) ->
+ {Exp,Res} = te11(),
+ ok = check(te11(doc),Exp,Res).
+
+te11() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid11()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard03
+te12(doc) ->
+ "Basic encode & decode with one recursive wildcard [1,12]\n (asn -> binary -> asn)";
+
+te12(suite) ->
+ [];
+
+te12(Config) when is_list(Config) ->
+ {Exp,Res} = te12(),
+ ok = check(te12(doc),Exp,Res).
+
+te12() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid12()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard04
+te13(doc) ->
+ "Basic encode & decode with one recursive wildcard [1,13]\n (asn -> binary -> asn)";
+
+te13(suite) ->
+ [];
+
+te13(Config) when is_list(Config) ->
+ {Exp,Res} = te13(),
+ ok = check(te13(doc),Exp,Res).
+
+te13() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid13()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard05
+te14(doc) ->
+ "Basic encode & decode with one recursive wildcard [2,13]\n (asn -> binary -> asn)";
+
+te14(suite) ->
+ [];
+
+te14(Config) when is_list(Config) ->
+ {Exp,Res} = te14(),
+ ok = check(te14(doc),Exp,Res).
+
+te14() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config2(),mtid13()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_wildcard_1level
+te15(doc) ->
+ "Basic encode & decode with one wildcard in the first level\nand then one empty level [1,15]\n (asn -> binary -> asn)";
+
+te15(suite) ->
+ [];
+
+te15(Config) when is_list(Config) ->
+ {Exp,Res} = te15(),
+ ok = check(te15(doc),Exp,Res).
+
+te15() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config1(),mtid15()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard06
+te16(doc) ->
+ "Basic encode & decode with one recursive wildcard [2,15]\n (asn -> binary -> asn)";
+
+te16(suite) ->
+ [];
+
+te16(Config) when is_list(Config) ->
+ {Exp,Res} = te16(),
+ ok = check(te16(doc),Exp,Res).
+
+te16() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config2(),mtid15()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard07
+te17(doc) ->
+ "Basic encode & decode with one recursive wildcard [2,11]\n (asn -> binary -> asn)";
+
+te17(suite) ->
+ [];
+
+te17(Config) when is_list(Config) ->
+ {Exp,Res} = te17(),
+ ok = check(te17(doc),Exp,Res).
+
+te17() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config2(),mtid11()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard08
+te18(doc) ->
+ "Basic encode & decode with one recursive wildcard [4,16]\n (asn -> binary -> asn)";
+
+te18(suite) ->
+ [];
+
+te18(Config) when is_list(Config) ->
+ {Exp,Res} = te18(),
+ ok = check(te18(doc),Exp,Res).
+
+te18() ->
+ put(encode_debug,dbg),
+ put(decode_debug,dbg),
+ Res = encode_decode(config4(),mtid16()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_enc_dec_with_one_rec_wildcard09
+te19(doc) ->
+ "Basic encode & decode with one recursive wildcard [4,17]\n (asn -> binary -> asn)";
+
+te19(suite) ->
+ [];
+
+te19(Config) when is_list(Config) ->
+ {Exp,Res} = te19(),
+ ok = check(te19(doc),Exp,Res).
+
+te19() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = encode_decode(config4(),mtid17()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% root_term_dec_enc
+td01(doc) ->
+ "Root termination decoding & then encoding test [1,1]\n (binary -> asn -> binary)";
+
+td01(suite) ->
+ [];
+
+td01(Config) when is_list(Config) ->
+ {Exp,Res} = td01(),
+ ok = check(td01(doc),Exp,Res).
+
+td01() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config1(),atid1()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% One byte to much (should be two bytes but is three)
+%% basic_dec_enc01
+td02(doc) ->
+ "Basic decoding & then encoding test [1,2]\n (binary -> asn -> binary)";
+
+td02(suite) ->
+ [];
+
+td02(Config) when is_list(Config) ->
+ {Exp,Res} = td02(),
+ ok = check(td02(doc),Exp,Res).
+
+td02() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config1(),atid2()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {error,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_dec_enc02
+td03(doc) ->
+ "Basic decoding & then encoding test [2,2]\n (binary -> asn -> binary)";
+
+td03(suite) ->
+ [];
+
+td03(Config) when is_list(Config) ->
+ {Exp,Res} = td03(),
+ ok = check(td03(doc),Exp,Res).
+
+td03() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config2(),atid2()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_dec_enc03
+td04(doc) ->
+ "Basic decoding & then encoding test [2,3]\n (binary -> asn -> binary)";
+
+td04(suite) ->
+ [];
+
+td04(Config) when is_list(Config) ->
+ {Exp,Res} = td04(),
+ ok = check(td04(doc),Exp,Res).
+
+td04() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config2(),atid3()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_dec_enc04
+td05(doc) ->
+ "Basic decoding & then encoding test [2,4]\n (binary -> asn -> binary)";
+
+td05(suite) ->
+ [];
+
+td05(Config) when is_list(Config) ->
+ {Exp,Res} = td05(),
+ ok = check(td05(doc),Exp,Res).
+
+td05() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config2(),atid4()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+
+%% basic_dec_enc05
+td06(doc) ->
+ "Basic decoding & then encoding test [3,5]\n (binary -> asn -> binary)";
+
+td06(suite) ->
+ [];
+
+td06(Config) when is_list(Config) ->
+ {Exp,Res} = td06(),
+ ok = check(td06(doc),Exp,Res).
+
+td06() ->
+ %% put(encode_debug,dbg),
+ %% put(decode_debug,dbg),
+ Res = decode_encode(config3(),atid5()),
+ erase(encode_debug),
+ erase(decode_debug),
+ {ok,Res}.
+
+
+%% --------------------------------------------------------
+%% --------------------------------------------------------
+
+encode_decode(C,T) ->
+ case encode(C,T) of
+ {ok,T1} ->
+ case decode(C,T1) of
+ {ok,T2} ->
+ {ok,T,T1,T2};
+ {error,R2} ->
+ {error,{decode_error,T,T1,R2}};
+ {exit,E2} ->
+ {error,{decode_exit,T,T1,E2}}
+ end;
+ {error,R1} ->
+ {error,{encode_error,T,R1}};
+ {exit,E1} ->
+ {error,{encode_exit,T,E1}}
+ end.
+
+decode_encode(C,T) ->
+ case decode(C,T) of
+ {ok,T1} ->
+ case encode(C,T1) of
+ {ok,T2} ->
+ {ok,T,T1,T2};
+ {error,R2} ->
+ {error,{encode_error,T,T1,R2}};
+ {exit,E2} ->
+ {error,{encode_exit,T,T1,E2}}
+ end;
+ {error,R1} ->
+ {error,{decode_error,T,R1}};
+ {exit,E1} ->
+ {error,{decode_exit,T,E1}}
+ end.
+
+%% ------------------
+
+config1() -> [3,8,5].
+config2() -> [3,5,4,8,4].
+config3() -> [3,5,4,16,4].
+config4() -> [8,8,8]. % Default config
+
+mtid01() ->
+ #megaco_term_id{contains_wildcards = false,
+ id = [[$1,$0,$1],
+ [$1,$1,$0,$1,$0,$0,$0,$1],
+ [$1,$1,$0,$1,$1]]}.
+mtid02() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$$],[$1,$1,$0,$1,$$],[$1,$1,$*]]}.
+mtid03() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$1],[$1,$0,$1,$$],[$1,$1,$*]]}.
+mtid04() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$$],[$1,$1,$0,$1,$$],[$1,$1,$1,$0,$0]]}.
+mtid05() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$1],[$1,$1,$0,$1,$$],[$1,$1,$1,$0,$0]]}.
+mtid06() ->
+ #megaco_term_id{contains_wildcards = false,
+ id = [[$1,$0,$$],[$1,$1,$0,$1,$$],[$1,$1,$*]]}.
+mtid07() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$*],[$1,2,$0,$1,$$],[$1,$1,$1,$0,$0]]}.
+mtid08() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$*,$1],[$1,$1,$0,$1,$$],[$1,$1,$1,$0,$0]]}.
+mtid09() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$0,$1],[$1,$1,$0,$1,$$],[$1,$1,$1,$0,$0]]}.
+mtid10() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$1],[$1,$0,$1,$$],[$$]]}.
+mtid11() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$1],[$1,$0,$1,$$]]}.
+mtid12() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$1],[$1,$0,$1,$0,$1,$1,$$]]}.
+mtid13() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$*]]}.
+%% Empty last level
+%% mtid14() ->
+%% #megaco_term_id{contains_wildcards = true,
+%% id = [[$1,$0,$*],[$1,$0,$0,$$],[]]}.
+
+%% Empty second level and missing last level
+mtid15() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[$1,$0,$*],[]]}.
+%% Megaco all wildcard termination id
+mtid16() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_all]]}.
+%% Megaco choose wildcard termination id
+mtid17() ->
+ #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]}.
+
+aroot() ->
+ #'TerminationID'{wildcard = [],
+ id = [16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF]}.
+atid1() -> aroot().
+atid2() ->
+ #'TerminationID'{wildcard = [],
+ id = [2#00000001, 02#00011110, 2#0]}.
+atid3() ->
+ #'TerminationID'{wildcard = [[2#00010111], [2#00000111]],
+ id = [2#0, 2#00011110, 2#0]}.
+atid4() ->
+ #'TerminationID'{wildcard = [[2#01001111]],
+ id = [2#0000001, 2#0, 2#0]}.
+%%
+atid5() ->
+ #'TerminationID'{wildcard = [[2#01001111]],
+ id = [2#00000001, 2#00110011,
+ 2#00000000, 2#00000000]}.
+
+%%--
+
+
+%% ------------------
+
+encode(C,T) ->
+ encode(get(encode_debug),C,T).
+
+encode(L,C,T) ->
+ put(dsev,L),
+ Res = encode1(C,T),
+ erase(dsev),
+ Res.
+
+encode1(C,T) ->
+ case (catch megaco_binary_term_id:encode(C,T)) of
+ {'EXIT',Reason} ->
+ {exit,Reason};
+ Else ->
+ Else
+ end.
+
+decode(C,T) ->
+ decode(get(decode_debug),C,T).
+
+decode(L,C,T) ->
+ put(dsev,L),
+ Res = decode1(C,T),
+ erase(dsev),
+ Res.
+
+decode1(C,T) ->
+ case (catch megaco_binary_term_id:decode(C,T)) of
+ {'EXIT',Reason} ->
+ {exit,Reason};
+ Else ->
+ Else
+ end.
+
+
+
+
diff --git a/lib/megaco/test/megaco_call_flow_test.erl b/lib/megaco/test/megaco_call_flow_test.erl
new file mode 100644
index 0000000000..a25a7924e8
--- /dev/null
+++ b/lib/megaco/test/megaco_call_flow_test.erl
@@ -0,0 +1,1767 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding of the sample call flows Megaco/H.248
+%%----------------------------------------------------------------------
+%% megaco_call_flow_test:pretty_text().
+%% megaco_call_flow_test:compact_text().
+%% megaco_call_flow_test:bin().
+%% megaco_call_flow_test:asn1_ber().
+%% megaco_call_flow_test:asn1_ber_bin().
+%% megaco_call_flow_test:asn1_per().
+%% megaco_call_flow_test:erl_dist().
+%% megaco_call_flow_test:compressed_erl_dist().
+%% megaco_call_flow_test:gnuplot_gif().
+%% megaco_call_flow_test:gnuplot_size_gif().
+%% megaco_call_flow_test:gnuplot_enc_time_gif().
+%% megaco_call_flow_test:gnuplot_dec_time_gif().
+%% megaco_call_flow_test:gnuplot_code_time_gif().
+%%----------------------------------------------------------------------
+
+-module(megaco_call_flow_test).
+
+-compile(export_all).
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include("megaco_test_lib.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ compact
+ ].
+
+flex(suite) ->
+ [
+ pretty_flex,
+ compact_flex
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per
+ ].
+
+pretty(suite) ->
+ [];
+pretty(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ pretty_text().
+
+compact(suite) ->
+ [];
+compact(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ compact_text().
+
+pretty_flex(suite) ->
+ [];
+pretty_flex(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ pretty_flex().
+
+compact_flex(suite) ->
+ [];
+compact_flex(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ compact_flex().
+
+bin(suite) ->
+ [];
+bin(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ bin().
+
+ber(suite) ->
+ [];
+ber(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ asn1_ber().
+
+ber_bin(suite) ->
+ [];
+ber_bin(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ asn1_ber_bin().
+
+per(suite) ->
+ [];
+per(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ asn1_per().
+
+standard_erl(suite) ->
+ [];
+standard_erl(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ standard_erl().
+
+compressed_erl(suite) ->
+ [];
+compressed_erl(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ compressed_erl().
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(PP(Name, Val), #'PropertyParm'{name = Name, value = [Val]}).
+-define(SP(Name, Val), #'StatisticsParameter'{statName = Name, statValue = [Val]}) .
+
+names() ->
+ [
+ msg1, msg2, msg3, msg4, msg5a, msg5b, msg6, msg7, msg9, msg10,
+ msg11, msg12, msg13, msg14, msg15, msg16, msg17a, msg17b,
+ msg18a, msg18b, msg18c, msg18d, msg19a, msg19b, msg20, msg21,
+ msg22a, msg22b, msg23a, msg23b
+ ].
+
+%% In this example, MG1 has the IP address 124.124.124.222, MG2 is
+%% 125.125.125.111, and the MGC is 123.123.123.4. The default Megaco port
+%% is 55555 for all three.
+
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+%% -define(A4444, ["00000000"]).
+%% -define(A4445, ["00001111"]).
+%% -define(A5555, ["11110000"]).
+%% -define(A5556, ["11111111"]).
+
+request(Mid, TransId, ContextId, CmdReq) when is_list(CmdReq) ->
+ Actions = [#'ActionRequest'{contextId = ContextId,
+ commandRequests = CmdReq}],
+ Req = {transactions,
+ [{transactionRequest,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions}}]},
+ #'MegacoMessage'{mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Req}}.
+
+reply(Mid, TransId, ContextId, CmdReply) when is_list(CmdReply) ->
+ Actions = [#'ActionReply'{contextId = ContextId,
+ commandReply = CmdReply}],
+ Req = {transactions,
+ [{transactionReply,
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = {actionReplies, Actions}}}]},
+ #'MegacoMessage'{mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Req}}.
+
+%%----------------------------------------------------------------------
+%% 1. An MG registers with an MGC using the ServiceChange command:
+%%
+%% MG1 to MGC:
+%% "MEGACO/1 [124.124.124.222]
+%% Transaction = 9998 {
+%% Context = - {
+%% ServiceChange = ROOT {Services {
+%% Method=Restart,
+%% ServiceChangeAddress=55555, Profile=ResGW/1}
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg1() ->
+ msg1(?MG1_MID_NO_PORT).
+msg1(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = #'ServiceChangeProfile'{profileName = "resgw",
+ version = 1},
+ Parm = #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeAddress = Address,
+ serviceChangeReason = ["901 mg cold boot"],
+ %% BUGBUG: Mandatory reason missing in spec
+ serviceChangeProfile = Profile},
+ Req = #'ServiceChangeRequest'{terminationID = [?megaco_root_termination_id],
+ serviceChangeParms = Parm},
+ CmdReq = #'CommandRequest'{command = {serviceChangeReq, Req}},
+ request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%%
+%% 2. The MGC sends a reply:
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Reply = 9998 {
+%% Context = - {ServiceChange = ROOT {
+%% Services {ServiceChangeAddress=55555, Profile=ResGW/1} } }
+%% }
+%%----------------------------------------------------------------------
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = #'ServiceChangeProfile'{profileName = "resgw",
+ version = 1},
+ Parm = #'ServiceChangeResParm'{serviceChangeAddress = Address,
+ serviceChangeProfile = Profile},
+ Reply = #'ServiceChangeReply'{terminationID = [?megaco_root_termination_id],
+ serviceChangeResult = {serviceChangeResParms,
+ Parm}},
+ reply(Mid, 9998, ?megaco_null_context_id, [{serviceChangeReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 3. The MGC programs a Termination in the NULL context. The
+%% terminationId is A4444, the streamId is 1, the requestId in the
+%% Events descriptor is 2222. The mId is the identifier of the sender
+%% of this message, in this case, it is the IP address and port
+%% [123.123.123.4]:55555. Mode for this stream is set to
+%% SendReceive. "al" is the analog line supervision package.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 9999 {
+%% Context = - {
+%% Modify = A4444 {
+%% Media { Stream = 1 {
+%% LocalControl {
+%% Mode = SendReceive,
+%% tdmc/gain=2, ; in dB,
+%% tdmc/ec=G165
+%% },
+%% Local {
+%% v=0
+%% c=IN IP4 $
+%% m=audio $ RTP/AVP 0
+%% a=fmtp:PCMU VAD=X-NNVAD ; special voice activity
+%% ; detection algorithm
+%% }
+%% }
+%% },
+%% Events = 2222 {al/of}
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg3() ->
+ msg3(?MGC_MID).
+msg3(Mid) ->
+ msg3(Mid, ?A4444).
+msg3(Mid, Tid) ->
+ Gain = ?PP("tdmc/gain", "2"),
+ %% Ec = ?PP("tdmc/ec", "G165"),
+ Ec = ?PP("tdmc/ec", "g165"), %% BUGBUG: should be case insensitive
+ LCD = #'LocalControlDescriptor'{streamMode = sendRecv,
+ propertyParms = [Gain, Ec]},
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 $ "),
+ M = ?PP("m", "audio $ RTP/AVP 0"),
+ A = ?PP("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = #'LocalRemoteDescriptor'{propGrps = [[V, C, M, A]]},
+ Parms = #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ ReqEvent = #'RequestedEvent'{pkgdName = "al/of",
+ evParList = []},
+ EventsDesc = #'EventsDescriptor'{requestID = 2222,
+ eventList = [ReqEvent]},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = Tid}],
+ descriptors = [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]},
+ CmdReq = #'CommandRequest'{command = {modReq, AmmReq}},
+ request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% The dialplan script could have been loaded into the MG previously.
+%% Its function would be to wait for the OffHook, turn on dialtone and
+%% start collecting DTMF digits. However in this example, we use the
+%% digit map, which is put into place after the offhook is detected (step
+%% 5 below).
+%%
+%%
+%% Note that the embedded EventsDescriptor could have been used to
+%% combine steps 3 and 4 with steps 8 and 9, eliminating steps 6 and 7.
+%%
+%%
+%% 4. The MG1 accepts the Modify with this reply:
+%%
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 9999 {
+%% Context = - {Modify = A4444}
+%% }
+%%----------------------------------------------------------------------
+
+msg4() ->
+ msg4(?MG1_MID).
+msg4(Mid) ->
+ msg4(Mid, ?A4444).
+msg4(Mid, Tid) ->
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = Tid}]},
+ reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 5. A similar exchange happens between MG2 and the MGC, resulting in an
+%% idle Termination called A5555.
+%%----------------------------------------------------------------------
+
+msg5a() ->
+ msg5a(?MGC_MID).
+msg5a(Mid) ->
+ msg3(Mid, ?A4444).
+
+msg5b() ->
+ msg5b(?MG2_MID).
+msg5b(Mid) ->
+ msg4(Mid, ?A5555).
+
+%%----------------------------------------------------------------------
+%% A.1.2 Collecting Originator Digits and Initiating Termination
+%%
+%% The following builds upon the previously shown conditions. It
+%% illustrates the transactions from the Media Gateway Controller and
+%% originating Media Gateway (MG1) to get the originating Termination
+%% (A4444) through the stages of digit collection required to initiate a
+%% connection to the terminating Media Gateway (MG2).
+%%
+%% 6. MG1 detects an offhook event from User 1 and reports it to the
+%% Media Gateway Controller via the Notify Command.
+%%
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Transaction = 10000 {
+%% Context = - {
+%% Notify = A4444 {ObservedEvents =2222 {
+%% 19990729T22000000:al/of}}
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg6() ->
+ msg6(?MG1_MID).
+msg6(Mid) ->
+ TimeStamp = #'TimeNotation'{date = "19990729",
+ time = "22000000"},
+ Event = #'ObservedEvent'{eventName = "al/of",
+ timeNotation = TimeStamp,
+ eventParList = []},
+ Desc = #'ObservedEventsDescriptor'{requestId = 2222,
+ observedEventLst = [Event]},
+ NotifyReq = #'NotifyRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ observedEventsDescriptor = Desc},
+ CmdReq = #'CommandRequest'{command = {notifyReq, NotifyReq}},
+ request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% 7. And the Notify is acknowledged.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Reply = 10000 {
+%% Context = - {Notify = A4444}
+%% }
+%%----------------------------------------------------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = #'NotifyReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 8. The MGC Modifies the termination to play dial tone, and to look for
+%% digits now. There is also an embedded event to stop dialtone upon
+%% detection of the first digit. dd is the DTMF Detection package, and
+%% ce is the completion event.
+%%----------------------------------------------------------------------
+
+%% BUGBUG: Example missing in spec
+
+%%----------------------------------------------------------------------
+%% 9.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 10001 {
+%% Context = - {
+%% Modify = A4444 {
+%% Events = 2223 {
+%% al/on, dd/ce {DigitMap=Dialplan0}
+%% },
+%% Signals {cg/dt},
+%% DigitMap= Dialplan0{
+%% (0S| 00S|[1-7]xLxx|8Lxxxxxxx|#xxxxxxx|*xx|9L1xxxxxxxxxx|9L011x.S)}
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg9() ->
+ msg9(?MGC_MID).
+msg9(Mid) ->
+ Name = "dialplan00",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = #'DigitMapValue'{digitMapBody = Body},
+ On = #'RequestedEvent'{pkgdName = "al/on", evParList = []},
+ Action = #'RequestedActions'{eventDM = {digitMapName, Name}},
+ Ce = #'RequestedEvent'{pkgdName = "dd/ce",
+ eventAction = Action,
+ evParList = []},
+ EventsDesc = #'EventsDescriptor'{requestID = 2223,
+ eventList = [On, Ce]},
+ Signal = #'Signal'{signalName = "cg/rt", sigParList = []},
+ DigMapDesc = #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ descriptors = [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]},
+ CmdReq = #'CommandRequest'{command = {modReq, AmmReq}},
+ request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% 10. And the Modify is acknowledged.
+%%
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 10001 {
+%% Context = - {Modify = A4444}
+%% }
+%%----------------------------------------------------------------------
+
+msg10() ->
+ msg10(?MG1_MID).
+msg10(Mid) ->
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ reply(Mid, 10001, ?megaco_null_context_id, [{modReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 11. Next, digits are accumulated by MG1 as they are dialed by User 1.
+%% Dialtone is stopped upon detection of the first digit, using the
+%% embedded event in step 8. When an appropriate match is made of
+%% collected digits against the currently programmed Dialplan for
+%% A4444, another Notify is sent to the Media Gateway Controller.
+%%
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Transaction = 10002 {
+%% Context = - {
+%% Notify = A4444 {ObservedEvents =2223 {
+%% 19990729T22010001:dd/ce{ds="916135551212"}}}
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ TimeStamp = #'TimeNotation'{date = "19990729",
+ time = "22010001"},
+ Parm = #'EventParameter'{eventParameterName = "ds",
+ value = ["916135551212"]},
+ %% BUGBUG: Quoted string or safe char?
+ Event = #'ObservedEvent'{eventName = "dd/ce",
+ timeNotation = TimeStamp,
+ eventParList = [Parm]},
+ Desc = #'ObservedEventsDescriptor'{requestId = 2223,
+ observedEventLst = [Event]},
+ NotifyReq = #'NotifyRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ observedEventsDescriptor = Desc},
+ CmdReq = #'CommandRequest'{command = {notifyReq, NotifyReq}},
+ request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% 12. And the Notify is acknowledged.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Reply = 10002 {
+%% Context = - {Notify = A4444}
+%% }
+%%----------------------------------------------------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ Reply = #'NotifyReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ reply(Mid, 10002, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 13. The controller then analyses the digits and determines that a
+%% connection needs to be made from MG1 to MG2. Both the TDM
+%% termination A4444, and an RTP termination are added to a new
+%% context in MG1. Mode is ReceiveOnly since Remote descriptor values
+%% are not yet specified. Preferred codecs are in the MGC's preferred
+%% order of choice.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 10003 {
+%% Context = $ {
+%% Add = A4444,
+%% Add = $ {
+%% Media {
+%% Stream = 1 {
+%% LocalControl {
+%% Mode = ReceiveOnly,
+%%
+%% nt/jit=40, ; in ms
+%% },
+%% Local {
+%% v=0
+%% c=IN IP4 $
+%% m=audio $ RTP/AVP 4
+%% a=ptime:30
+%% v=0
+%% c=IN IP4 $
+%% m=audio $ RTP/AVP 0
+%% }
+%% }
+%% }
+%% }
+%% }
+%% }
+%%
+%% NOTE - The MGC states its prefrred parameter values as a series of
+%% sdp blocks in Local. The MG fills in the Local Descriptor in the
+%% Reply.
+%%----------------------------------------------------------------------
+
+msg13() ->
+ msg13(?MGC_MID).
+msg13(Mid) ->
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ descriptors = []},
+ CmdReq = #'CommandRequest'{command = {addReq, AmmReq}},
+ Jit = ?PP("nt/jit", "40"),
+ LCD = #'LocalControlDescriptor'{streamMode = recvOnly,
+ propertyParms = [Jit]},
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 $ "),
+ M = ?PP("m", "audio $ RTP/AVP 4"),
+ A = ?PP("a", "ptime:30"),
+ V2 = ?PP("v", "0"),
+ C2 = ?PP("c", "IN IP4 $ "),
+ M2 = ?PP("m", "audio $ RTP/AVP 0"),
+ LD = #'LocalRemoteDescriptor'{propGrps = [[V, C, M, A], [V2, C2, M2]]},
+ Parms = #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = #'AmmRequest'{terminationID = [ChooseTid],
+ descriptors = [{mediaDescriptor, MediaDesc}]},
+ CmdReq2 = #'CommandRequest'{command = {addReq, AmmReq2}},
+ request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+%%----------------------------------------------------------------------
+%% 14. MG1 acknowledges the new Termination and fills in the Local IP
+%% address and UDP port. It also makes a choice for the codec based
+%% on the MGC preferences in Local. MG1 sets the RTP port to 2222.
+%%
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 10003 {
+%% Context = 2000 {
+%% Add = A4444,
+%% Add=A4445{
+%% Media {
+%% Stream = 1 {
+%% Local {
+%% v=0
+%% c=IN IP4 124.124.124.222
+%% m=audio 2222 RTP/AVP 4
+%% a=ptime:30
+%% a=recvonly
+%% } ; RTP profile for G.723 is 4
+%% }
+%% }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg14() ->
+ msg14(?MG1_MID).
+msg14(Mid) ->
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 124.124.124.222"),
+ M = ?PP("m", "audio 2222 RTP/AVP 4"),
+ A = ?PP("a", "a=ptime:30"),
+ A2= ?PP("a", "recvonly"),
+ LD = #'LocalRemoteDescriptor'{propGrps = [[V, C, M, A, A2]]},
+ Parms = #'StreamParms'{localDescriptor = LD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ Reply2 = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4445}],
+ terminationAudit = [{mediaDescriptor, MediaDesc}]},
+ reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+%%----------------------------------------------------------------------
+%% 15. The MGC will now associate A5555 with a new Context on MG2, and
+%% establish an RTP Stream (i.e, A5556 will be assigned), SendReceive
+%% connection through to the originating user, User 1. The MGC also
+%% sets ring on A5555.
+%%
+%% MGC to MG2:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 50003 {
+%% Context = $ {
+%% Add = A5555 { Media {
+%% Stream = 1 {
+%% LocalControl {Mode = SendReceive} }},
+%% Signals {al/ri}
+%% },
+%% Add = $ {Media {
+%% Stream = 1 {
+%% LocalControl {
+%% Mode = SendReceive,
+%% nt/jit=40 ; in ms
+%% },
+%% Local {
+%% v=0
+%% c=IN IP4 $
+%% m=audio $ RTP/AVP 4
+%% a=ptime:30
+%% },
+%% Remote {
+%% v=0
+%% c=IN IP4 124.124.124.222
+%% m=audio 2222 RTP/AVP 4
+%% a=ptime:30
+%% } ; RTP profile for G.723 is 4
+%% }
+%% }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg15() ->
+ msg15(?MGC_MID).
+msg15(Mid) ->
+ LCD = #'LocalControlDescriptor'{streamMode = sendRecv,
+ propertyParms = []},
+ Parms = #'StreamParms'{localControlDescriptor = LCD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ Signal = #'Signal'{signalName = "al/ri",
+ sigParList = []},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A5555}],
+ descriptors = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}]},
+ CmdReq = #'CommandRequest'{command = {addReq, AmmReq}},
+ Jit = ?PP("nt/jit", "40"),
+ LCD2 = #'LocalControlDescriptor'{streamMode = sendRecv,
+ propertyParms = [Jit]},
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 $ "),
+ M = ?PP("m", "audio $ RTP/AVP 4"),
+ A = ?PP("a", "ptime:30"),
+ LD2 = #'LocalRemoteDescriptor'{propGrps = [[V, C, M, A]]},
+ V2 = ?PP("v", "0"),
+ C2 = ?PP("c", "IN IP4 124.124.124.222"),
+ M2 = ?PP("m", "audio 2222 RTP/AVP 4"),
+ RD2 = #'LocalRemoteDescriptor'{propGrps = [[V2, C2, M2]]},
+ Parms2 = #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2},
+ StreamDesc2 = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms2},
+ MediaDesc2 = #'MediaDescriptor'{streams = {multiStream, [StreamDesc2]}},
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = #'AmmRequest'{terminationID = [ChooseTid],
+ descriptors = [{mediaDescriptor, MediaDesc2}]},
+ CmdReq2 = #'CommandRequest'{command = {addReq, AmmReq2}},
+ request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+%%----------------------------------------------------------------------
+%% 16. This is acknowledged. The stream port number is different from the
+%% control port number. In this case it is 1111 (in the SDP).
+%%
+%% MG2 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 50003 {
+%% Context = 5000 {
+%% Add = A5556{
+%% Media {
+%% Stream = 1 {
+%% Local {
+%% v=0
+%% c=IN IP4 125.125.125.111
+%% m=audio 1111 RTP/AVP 4
+%% }
+%% } ; RTP profile for G723 is 4
+%% }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 125.125.125.111"),
+ M = ?PP("m", "audio 1111 RTP/AVP 4"),
+ LD = #'LocalRemoteDescriptor'{propGrps = [[V, C, M]]},
+ Parms = #'StreamParms'{localDescriptor = LD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A5556}],
+ terminationAudit = [{mediaDescriptor, MediaDesc}]},
+ reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 17. The above IPAddr and UDPport need to be given to MG1 now.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 10005 {
+%% Context = 2000 {
+%% Modify = A4444 {
+%% Signals {cg/rt}
+%% },
+%% Modify = A4445 {
+%% Media {
+%% Stream = 1 {
+%% Remote {
+%% v=0
+%% c=IN IP4 125.125.125.111
+%% m=audio 1111 RTP/AVP 4
+%% }
+%% } ; RTP profile for G723 is 4
+%% }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg17a() ->
+ msg17a(?MGC_MID).
+msg17a(Mid) ->
+ Signal = #'Signal'{signalName = "cg/rt", sigParList = []},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ descriptors = [{signalsDescriptor, [{signal, Signal}]}]},
+ CmdReq = #'CommandRequest'{command = {modReq, AmmReq}},
+
+ V = ?PP("v", "0"),
+ C = ?PP("c", "IN IP4 125.125.125.111"),
+ M = ?PP("m", "audio 1111 RTP/AVP 4"),
+ RD2 = #'LocalRemoteDescriptor'{propGrps = [[V, C, M]]},
+ Parms2 = #'StreamParms'{remoteDescriptor = RD2},
+ StreamDesc2 = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms2},
+ MediaDesc2 = #'MediaDescriptor'{streams = {multiStream, [StreamDesc2]}},
+ AmmReq2 = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4445}],
+ descriptors = [{mediaDescriptor, MediaDesc2}]},
+ CmdReq2 = #'CommandRequest'{command = {modReq, AmmReq2}},
+ request(Mid, 10005, 2000, [CmdReq, CmdReq2]).
+
+%%----------------------------------------------------------------------
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 10005 {
+%% Context = 2000 {Modify = A4444, Modify = A4445}
+%% }
+%%----------------------------------------------------------------------
+
+msg17b() ->
+ msg17b(?MG1_MID).
+msg17b(Mid) ->
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ Reply2 = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4445}]},
+ reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+%%----------------------------------------------------------------------
+%% 18. The two gateways are now connected and User 1 hears the
+%% RingBack. The MG2 now waits until User2 picks up the receiver and
+%% then the two-way call is established.
+%%
+%% MG2 to MGC:
+%% MEGACO/1 [125.125.125.111]:55555
+%% Transaction = 50005 {
+%% Context = 5000 {
+%% Notify = A5555 {ObservedEvents =1234 {
+%% 19990729T22020002:al/of}}
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg18a() ->
+ msg18a(?MG2_MID).
+msg18a(Mid) ->
+ TimeStamp = #'TimeNotation'{date = "19990729",
+ time = "22020002"},
+ Event = #'ObservedEvent'{eventName = "al/of",
+ timeNotation = TimeStamp,
+ eventParList = []},
+ Desc = #'ObservedEventsDescriptor'{requestId = 1234,
+ observedEventLst = [Event]},
+ NotifyReq = #'NotifyRequest'{terminationID = [#megaco_term_id{id = ?A5555}],
+ observedEventsDescriptor = Desc},
+ CmdReq = #'CommandRequest'{command = {notifyReq, NotifyReq}},
+ request(Mid, 50005, 5000, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% MGC to MG2:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Reply = 50005 {
+%% Context = - {Notify = A5555}
+%% }
+%%----------------------------------------------------------------------
+
+msg18b() ->
+ msg18b(?MGC_MID).
+msg18b(Mid) ->
+ Reply = #'NotifyReply'{terminationID = [#megaco_term_id{id = ?A5555}]},
+ reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% MGC to MG2:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 50006 {
+%% Context = 5000 {
+%% Modify = A5555 {
+%% Events = 1235 {al/on},
+%% Signals { } ; to turn off ringing
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg18c() ->
+ msg18c(?MGC_MID).
+msg18c(Mid) ->
+ On = #'RequestedEvent'{pkgdName = "al/on", evParList = []},
+ EventsDesc = #'EventsDescriptor'{requestID = 1235,
+ eventList = [On]},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A5555}],
+ descriptors = [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]},
+ CmdReq = #'CommandRequest'{command = {modReq, AmmReq}},
+ request(Mid, 50006, 5000, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% MG2 to MGC:
+%% MEGACO/1 [125.125.125.111]:55555
+%% Reply = 50006 {
+%% Context = 5000 {Modify = A4445}
+%% }
+%%----------------------------------------------------------------------
+
+msg18d() ->
+ msg18d(?MG2_MID).
+msg18d(Mid) ->
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4445}]},
+ reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 19. Change mode on MG1 to SendReceive, and stop the ringback.
+%%
+%% MGC to MG1:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 10006 {
+%% Context = 2000 {
+%% Modify = A4445 {
+%% Media {
+%% Stream = 1 {
+%% LocalControl {
+%% Mode=SendReceive
+%% }
+%% }
+%% }
+%% },
+%% Modify = A4444 {
+%% Signals { }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg19a() ->
+ msg19a(?MGC_MID).
+msg19a(Mid) ->
+ LCD = #'LocalControlDescriptor'{streamMode = sendRecv,
+ propertyParms = []},
+ Parms = #'StreamParms'{localControlDescriptor = LCD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = Parms},
+ MediaDesc = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ AmmReq = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4445}],
+ descriptors = [{mediaDescriptor, MediaDesc}]},
+ CmdReq = #'CommandRequest'{command = {modReq, AmmReq}},
+ AmmReq2 = #'AmmRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
+ descriptors = [{signalsDescriptor, []}]},
+ CmdReq2 = #'CommandRequest'{command = {modReq, AmmReq2}},
+ request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+%%----------------------------------------------------------------------
+%% MG1 to MGC:
+%% MEGACO/1 [124.124.124.222]:55555
+%% Reply = 10006 {
+%% Context = 2000 {Modify = A4445, Modify = A4444}}
+%%----------------------------------------------------------------------
+
+msg19b() ->
+ msg19b(?MG1_MID).
+msg19b(Mid) ->
+ Reply = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4445}]},
+ Reply2= #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A4444}]},
+ reply(Mid, 10006, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+%%----------------------------------------------------------------------
+%% 20. The MGC decides to Audit the RTP termination on MG2.
+%%
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 50007 {
+%% Context = - {AuditValue = A5556{
+%% Audit{Media, DigitMap, Events, Signals, Packages, Statistics }}
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = #'AuditDescriptor'{auditToken = Tokens},
+ Req = #'AuditRequest'{terminationID = #megaco_term_id{id = ?A5556},
+ auditDescriptor = AuditDesc},
+ CmdReq = #'CommandRequest'{command = {auditValueRequest, Req}},
+ request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% 21. The MG2 replies. An RTP termination has no events nor signals, so
+%% these are left out in the reply .
+%%
+%% MEGACO/1 [125.125.125.111]:55555
+%% Reply = 50007 {
+%% Context = - {
+%% AuditValue = A5556 {
+%% Media {
+%% Stream = 1 {
+%% LocalControl { Mode = SendReceive,
+%% nt/jit=40 },
+%% Local {
+%% v=0
+%% c=IN IP4 125.125.125.111
+%% m=audio 1111 RTP/AVP 4
+%% a=ptime:30
+%% },
+%% Remote {
+%% v=0
+%% c=IN IP4 124.124.124.222
+%% m=audio 2222 RTP/AVP 4
+%% a=ptime:30
+%% } } },
+%% Packages {nt-1, rtp-1},
+%% Statistics { rtp/ps=1200, ; packets sent
+%% nt/os=62300, ; octets sent
+%% rtp/pr=700, ; packets received
+%% nt/or=45100, ; octets received
+%% rtp/pl=0.2, ; % packet loss
+%% rtp/jit=20,
+%% rtp/delay=40 } ; avg latency
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg21() ->
+ msg21(?MG2_MID).
+msg21(Mid) ->
+ Jit = ?PP("nt/jit", "40"),
+ LCD = #'LocalControlDescriptor'{streamMode = sendRecv,
+ propertyParms = [Jit]},
+ LDV = ?PP("v", "0"),
+ LDC = ?PP("c", "IN IP4 125.125.125.111"),
+ LDM = ?PP("m", "audio 1111 RTP/AVP 4"),
+ LDA = ?PP("a", "ptime:30"),
+ LD = #'LocalRemoteDescriptor'{propGrps = [[LDV, LDC, LDM, LDA]]},
+ RDV = ?PP("v", "0"),
+ RDC = ?PP("c", "IN IP4 124.124.124.222"),
+ RDM = ?PP("m", "audio 2222 RTP/AVP 4"),
+ RDA = ?PP("a", "ptime:30"),
+ RD = #'LocalRemoteDescriptor'{propGrps = [[RDV, RDC, RDM, RDA]]},
+ StreamParms = #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD},
+ StreamDesc = #'StreamDescriptor'{streamID = 1,
+ streamParms = StreamParms},
+ Media = #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}},
+ PackagesItem = #'PackagesItem'{packageName = "nt",
+ packageVersion = 1},
+ PackagesItem2 = #'PackagesItem'{packageName = "rtp",
+ packageVersion = 1},
+ Stat = ?SP("rtp/ps","1200"),
+ Stat2 = ?SP("nt/os","62300"),
+ Stat3 = ?SP("rtp/pr","700"),
+ Stat4 = ?SP("nt/or","45100"),
+ Stat5 = ?SP("rtp/pl","0.2"),
+ Stat6 = ?SP("rtp/jit","20"),
+ Stat7 = ?SP("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult, #'AuditResult'{terminationID = #megaco_term_id{id = ?A5556},
+ terminationAuditResult = Audits}},
+ reply(Mid, 50007, ?megaco_null_context_id, [{auditValueReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 22. When the MGC receives an onhook signal from one of the MGs, it
+%% brings down the call. In this example, the user at MG2 hangs up first.
+%%
+%% MG2 to MGC:
+%% MEGACO/1 [125.125.125.111]:55555
+%% Transaction = 50008 {
+%% Context = 5000 {
+%% Notify = A5555 {ObservedEvents =1235 {
+%% 19990729T24020002:al/on}
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg22a() ->
+ msg22a(?MG2_MID).
+msg22a(Mid) ->
+ TimeStamp = #'TimeNotation'{date = "19990729",
+ time = "24020002"},
+ Event = #'ObservedEvent'{eventName = "al/on",
+ timeNotation = TimeStamp,
+ eventParList = []},
+ Desc = #'ObservedEventsDescriptor'{requestId = 1235,
+ observedEventLst = [Event]},
+ NotifyReq = #'NotifyRequest'{terminationID = [#megaco_term_id{id = ?A5555}],
+ observedEventsDescriptor = Desc},
+ CmdReq = #'CommandRequest'{command = {notifyReq, NotifyReq}},
+ request(Mid, 50008, 5000, [CmdReq]).
+
+%%----------------------------------------------------------------------
+%% MGC to MG2:
+%% MEGACO/1 [123.123.123.4]:55555
+%% Reply = 50008 {
+%% Context = - {Notify = A5555}
+%% }
+%%----------------------------------------------------------------------
+
+msg22b() ->
+ msg22b(?MGC_MID).
+msg22b(Mid) ->
+ Reply = #'NotifyReply'{terminationID = [#megaco_term_id{id = ?A5555}]},
+ reply(Mid, 50008, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+%%----------------------------------------------------------------------
+%% 23. The MGC now sends both MGs a Subtract to take down the call. Only
+%% the subtracts to MG2 are shown here. Each termination has its own
+%% set of statistics that it gathers. An MGC may not need to request
+%% both to be returned. A5555 is a physical termination, and A5556 is
+%% an RTP termination.
+%%
+%% MGC to MG2:
+%%
+%% MEGACO/1 [123.123.123.4]:55555
+%% Transaction = 50009 {
+%% Context = 5000 {
+%% Subtract = A5555 {Audit{Statistics}},
+%% Subtract = A5556 {Audit{Statistics}}
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg23a() ->
+ msg23a(?MGC_MID).
+msg23a(Mid) ->
+ CommonAuditDesc = #'AuditDescriptor'{auditToken = [statsToken]},
+ SubReq = #'SubtractRequest'{terminationID = [#megaco_term_id{id = ?A5555}],
+ auditDescriptor = CommonAuditDesc},
+ SubReq2 = #'SubtractRequest'{terminationID = [#megaco_term_id{id = ?A5556}],
+ auditDescriptor = CommonAuditDesc},
+ CmdReq = #'CommandRequest'{command = {subtractReq, SubReq}},
+ CmdReq2 = #'CommandRequest'{command = {subtractReq, SubReq2}},
+ request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+%%
+%%----------------------------------------------------------------------
+%% MG2 to MGC:
+%%
+%% MEGACO/1 [125.125.125.111]:55555
+%% Reply = 50009 {
+%% Context = 5000 {
+%% Subtract = A5555 {
+%% Statistics {
+%% nt/os=45123, ; Octets Sent
+%% nt/dur=40 ; in seconds
+%% }
+%% },
+%% Subtract = A5556 {
+%% Statistics {
+%% rtp/ps=1245, ; packets sent
+%% nt/os=62345, ; octets sent
+%% rtp/pr=780, ; packets received
+%% nt/or=45123, ; octets received
+%% rtp/pl=10, ; % packets lost
+%% rtp/jit=27,
+%% rtp/delay=48 ; average latency
+%% }
+%% }
+%% }
+%% }
+%%----------------------------------------------------------------------
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ Stat11 = ?SP("nt/os","45123"),
+ Stat12 = ?SP("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A5555}],
+ terminationAudit = [{statisticsDescriptor, Stats1}]},
+ Stat21 = ?SP("rtp/ps","1245"),
+ Stat22 = ?SP("nt/os", "62345"),
+ Stat23 = ?SP("rtp/pr", "780"),
+ Stat24 = ?SP("nt/or", "45123"),
+ Stat25 = ?SP("rtp/pl", "10"),
+ Stat26 = ?SP("rtp/jit", "27"),
+ Stat27 = ?SP("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = #'AmmsReply'{terminationID = [#megaco_term_id{id = ?A5556}],
+ terminationAudit = [{statisticsDescriptor, Stats2}]},
+ reply(Mid, 50009, 5000, [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+%%----------------------------------------------------------------------
+%% 24. The MGC now sets up both MG1 and MG2 to be ready to detect the
+%% next off-hook event. See step 1. Note that this could be the
+%% default state of a termination in the null context, and if this
+%% were the case, no message need be sent from the MGC to the
+%% MG. Once a termination returns to the null context, it goes back
+%% to the default termination values for that termination.
+%%----------------------------------------------------------------------
+
+%% BUGBUG: Example missing in spec
+
+%%----------------------------------------------------------------------
+%% Testing
+%%----------------------------------------------------------------------
+
+messages() ->
+ [{Slogan, catch ?MODULE:Slogan()} || Slogan <- names()].
+
+encoders() ->
+ [
+ {megaco_pretty_text_encoder, [], []},
+ {megaco_compact_text_encoder, [], []},
+ {megaco_binary_encoder, [], [native]},
+ %% {megaco_ber_encoder, [], [native]},
+ %% {megaco_ber_bin_encoder, [], [native]},
+ {megaco_per_encoder, [], [native]},
+ {megaco_erl_dist_encoder, [], []},
+ {megaco_erl_dist_encoder, [compressed], [compressed]}
+ ].
+
+
+pretty_mod({Mod, Opt, _Opt2}) ->
+ case Mod of
+ megaco_pretty_text_encoder when Opt == [flex] -> pretty_flex;
+ megaco_compact_text_encoder when Opt == [flex] -> compact_flex;
+ megaco_pretty_text_encoder -> pretty_text;
+ megaco_compact_text_encoder -> compact_text;
+ megaco_binary_encoder -> asn1_ber;
+ megaco_ber_encoder -> asn1_ber_old;
+ megaco_ber_bin_encoder -> asn1_ber_bin;
+ megaco_per_encoder -> asn1_per;
+ megaco_erl_dist_encoder when Opt == [] -> standard_erl;
+ megaco_erl_dist_encoder when Opt == [compressed] -> compressed_erl;
+ Ugly -> Ugly
+ end.
+
+%%----------------------------------------------------------------------
+%% Run specific encoder for all test cases
+%%----------------------------------------------------------------------
+
+pretty_text() ->
+ Default = [],
+ Encoder = {megaco_pretty_text_encoder, Default, Default},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+compact_text() ->
+ Default = [],
+ Encoder = {megaco_compact_text_encoder, Default, Default},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+pretty_flex() ->
+ Default = [flex],
+ Encoder = {megaco_pretty_text_encoder, Default, Default},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+compact_flex() ->
+ Default = [flex],
+ Encoder = {megaco_compact_text_encoder, Default, Default},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+bin() ->
+ Default = [],
+ Native = [native],
+ Encoder = {megaco_binary_encoder, Default, Native},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+asn1_ber() ->
+ Default = [],
+ Native = [native],
+ Encoder = {megaco_ber_encoder, Default, Native},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+asn1_ber_bin() ->
+ Default = [],
+ Native = [native],
+ Encoder = {megaco_ber_bin_encoder, Default, Native},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+asn1_per() ->
+ Default = [],
+ Native = [native],
+ Encoder = {megaco_per_encoder, Default, Native},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+standard_erl() ->
+ Config = [],
+ Encoder = {megaco_erl_dist_encoder, Config, Config},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+compressed_erl() ->
+ Config = [compressed],
+ Encoder = {megaco_erl_dist_encoder, Config, Config},
+ All = [encode(Slogan, Msg, Encoder) || {Slogan, Msg} <- messages()],
+ compute_res(All).
+
+encode(Slogan, DecodedMsg, {Mod, Opt, _Opt2} = _Encoder) ->
+ Main = "==================================================",
+ Sub = "--------------------------------------------------",
+ case catch Mod:encode_message(Opt, DecodedMsg) of
+ {ok, EncodedMsg} when is_binary(EncodedMsg) ->
+ Sz = size(EncodedMsg),
+ ok = io:format("~w ~s ~w bytes~n",
+ [Slogan, Main, Sz]),
+ catch io:format("~n~s~n", [(catch binary_to_list(EncodedMsg))]),
+ case catch Mod:decode_message(Opt, EncodedMsg) of
+ {ok, ReDecodedMsg} ->
+ fmt(Slogan, DecodedMsg, ReDecodedMsg);
+ {error, {Line, _, Reason}} when is_integer(Line)->
+ ?ERROR([{Slogan, Line, decode_failed}, {error, Reason}, {encoded, EncodedMsg}, DecodedMsg]),
+ io:format("~n~w <ERROR> #~w: ~w~n",
+ [Slogan, Line, Reason]);
+ Other ->
+ ?ERROR([{Slogan, 0, decode_failed}, Other, {encoded, EncodedMsg}, DecodedMsg]),
+ io:format("~n~w <ERROR> ~w~n", [Slogan, Other])
+ end,
+ Sz;
+ Other ->
+ ?ERROR([{Slogan, encode_failed}, Other, DecodedMsg]),
+ ok = io:format("~w ~s~n~p~n<ERROR> ~s~n~p~n",
+ [Slogan, Main, DecodedMsg, Sub, Other]),
+ {Slogan, {encode_message, Other}}
+ end.
+
+fmt(_Slogan, Msg, Msg) ->
+ ok;
+fmt(Slogan, {'MegacoMessage', A, {'Message', V, MID, {transactions, [{T, Old}]}}},
+ {'MegacoMessage', A, {'Message', V, MID, {transactions, [{T, New}]}}}) ->
+ fmt(Slogan, Old, New);
+fmt(Slogan, Old, New) ->
+ PrettyOld = lists:flatten(io_lib:format("~p", [Old])),
+ PrettyNew = lists:flatten(io_lib:format("~p", [New])),
+ fmt_diff(Slogan, Old, New, PrettyOld, PrettyNew, []).
+
+fmt_diff(Slogan, Old, New, [H | OldRest], [H | NewRest], Common) ->
+ fmt_diff(Slogan, Old, New, OldRest, NewRest, [H | Common]);
+fmt_diff(Slogan, Old, New, OldRest, NewRest, Common) ->
+ RevCommon = lists:reverse(Common),
+ ?ERROR([{Slogan, decode_mismatch}, {old, Old}, {new, New}]),
+ Sub = "--------------------------------------------------",
+ io:format("~n~w COMMON ~s~n~s~n", [Slogan, Sub, RevCommon]),
+ io:format("~n~w OLD ~s~n~s~n", [Slogan, Sub, OldRest]),
+ io:format("~n~w NEW ~s~n~s~n", [Slogan, Sub, NewRest]).
+
+compute_res(All) ->
+ compute_res(All, [], 0).
+
+compute_res([H | T], Bad, Sum) when is_integer(H) ->
+ compute_res(T, Bad, Sum + H);
+compute_res([H | T], Bad, Sum) ->
+ compute_res(T, [H | Bad], Sum);
+compute_res([], Bad, Sum) ->
+ ok = io:format("#bytes: ~w; errors: ~p~n", [Sum, Bad]).
+
+%%----------------------------------------------------------------------
+%% Compute sizes of encoded messages
+%%----------------------------------------------------------------------
+
+msg_sizes() ->
+ Encoders = encoders(),
+ msg_sizes(Encoders).
+
+%% Returns a list of {MessageSlogan, MessageSizes} where
+%% MessageSizes is the result from msg_sizes/2
+msg_sizes(Encoders) ->
+ [{S, msg_sizes(Msg, Encoders)} || {S, Msg} <- messages()].
+
+%% Returns a list of {Encoder, Res} tuples
+%% where Res either is the message size (integer)
+%% or an error atom
+msg_sizes(DecodedMsg, Encoders) ->
+ [abs_msg_size(DecodedMsg, E) || E <- Encoders].
+
+abs_msg_size(DecodedMsg, {Mod, Opt, _Opt2} = Encoder) ->
+ case catch Mod:encode_message(Opt, DecodedMsg) of
+ {ok, EncodedMsg} when is_binary(EncodedMsg) ->
+ {Encoder, size(EncodedMsg)};
+ Error ->
+ {Encoder, {bad_encoder, Error}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Compute time for encoding messages
+%%----------------------------------------------------------------------
+
+encoding_times() ->
+ Encoders = encoders(),
+ encoding_times(Encoders).
+
+%% Returns a list of {MessageSlogan, EncodingTimes} where
+%% EncodingTimes is the result from encoding_times/2
+encoding_times(Encoders) ->
+ [{Slogan, encoding_times(Msg, Encoders)} || {Slogan, Msg} <- messages()].
+
+%% Returns a list of {Encoder, Res} tuples
+%% where Res either is the encoding time (integer)
+%% or an error atom
+encoding_times(DecodedMsg, Encoders) ->
+ [{E, encoding_time(encoding_msg(DecodedMsg, E))} || E <- Encoders].
+
+encoding_msg(DecodedMsg, {Mod, Opt, Opt2} = Encoder) ->
+ {ok, EncodedMsg} = Mod:encode_message(Opt, DecodedMsg),
+ {ok, DecodedMsg2} = Mod:decode_message(Opt2, EncodedMsg),
+ {Encoder, DecodedMsg2}.
+
+encoding_time({{Mod, _Opt, Opt2} = Encoder, DecodedMsg}) ->
+ meter(fun() -> {ok, _} = Mod:encode_message(Opt2, DecodedMsg) end, Encoder).
+
+%%----------------------------------------------------------------------
+%% Compute time for decoding messages
+%%----------------------------------------------------------------------
+
+decoding_times() ->
+ Decoders = encoders(),
+ decoding_times(Decoders).
+
+%% Returns a list of {MessageSlogan, DecodingTimes} where
+%% DecodingTimes is the result from decoding_times/2
+decoding_times(Decoders) ->
+ [{Slogan, decoding_times(Msg, Decoders)} || {Slogan, Msg} <- messages()].
+
+%% Returns a list of {Decoder, Res} tuples
+%% where Res either is the decoding time (integer)
+%% or an error atom
+decoding_times(DecodedMsg, Encoders) ->
+ [{E, decoding_time(decoding_msg(DecodedMsg, E))} || E <- Encoders].
+
+decoding_msg(DecodedMsg, {Mod, Opt, _Opt2} = Encoder) ->
+ {ok, EncodedMsg} = Mod:encode_message(Opt, DecodedMsg),
+ {Encoder, EncodedMsg}.
+
+decoding_time({{Mod, _Opt, Opt2} = Encoder, EncodedMsg}) ->
+ meter(fun() -> {ok, _} = Mod:decode_message(Opt2, EncodedMsg) end, Encoder).
+
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+
+coding_times() ->
+ Coders = encoders(),
+ coding_times(Coders).
+
+%% Returns a list of {MessageSlogan, DecodingTimes} where
+%% DecodingTimes is the result from decoding_times/2
+coding_times(Coders) ->
+ [{Slogan, coding_times(Msg, Coders)} || {Slogan, Msg} <- messages()].
+
+%% Returns a list of {Decoder, Res} tuples
+%% where Res either is the decoding time (integer)
+%% or an error atom
+coding_times(DecodedMsg, Coders) ->
+ [{E, coding_time(coding_msg(DecodedMsg, E))} || E <- Coders].
+
+coding_msg(DecodedMsg, {Mod, Opt, _Opt2} = Encoder) ->
+ {ok, EncodedMsg} = Mod:encode_message(Opt, DecodedMsg),
+ {Encoder, EncodedMsg}.
+
+coding_time({{Mod, _Opt, Opt2} = Encoder, EncodedMsg}) ->
+ Fun = fun() ->
+ {ok, DecodedMsg} = Mod:decode_message(Opt2, EncodedMsg),
+ {ok, _} = Mod:encode_message(Opt2, DecodedMsg)
+ end,
+ meter(Fun, Encoder).
+
+%%----------------------------------------------------------------------
+%% Return size statistics as term
+%%----------------------------------------------------------------------
+
+size_stat() ->
+ Encoders = encoders(),
+ MsgSizes = msg_sizes(Encoders),
+ stat(Encoders, MsgSizes).
+
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+
+gnuplot_gif() ->
+ [
+ {size, gnuplot_size_gif()},
+ {encoding, gnuplot_enc_time_gif()},
+ {decoding, gnuplot_dec_time_gif()},
+ {coding, gnuplot_code_time_gif()}
+ ].
+
+%%----------------------------------------------------------------------
+%% Generate GIF picture from size statistics with gnuplot
+%%----------------------------------------------------------------------
+
+gnuplot_size_gif() ->
+ {ok, _Cwd} = file:get_cwd(),
+ TmpDir = "megaco_encoded_size.tmp",
+ GifFile = "megaco_encoded_size.gif",
+ Header =
+ ["set title \"Size comparison of Megaco/H.248 encoding formats\"\n",
+ "set timestamp top\n",
+ "set terminal gif\n",
+ "set xlabel \"Test cases from Appendix A\"\n",
+ "set ylabel \"Message size in bytes\"\n",
+ "set rmargin 10\n",
+ "set key left top Left\n",
+ "set output \"", GifFile, "\"\n\n"],
+ Encoders = encoders(),
+ Stat = msg_sizes(Encoders),
+ BatchFile = gnuplot_dir(TmpDir, Header, Encoders, Stat),
+ Cmd = "cd " ++ TmpDir ++ "; gnuplot " ++ BatchFile,
+ os:cmd(Cmd),
+ ok = io:format("~n~s~nxv ~s~n", [Cmd, filename:join([TmpDir, GifFile])]),
+ stat(Encoders, Stat).
+
+%%----------------------------------------------------------------------
+%% Return encoding time statistics as term
+%%----------------------------------------------------------------------
+
+encoding_times_stat() ->
+ Encoders = encoders(),
+ EncodingTimes = encoding_times(Encoders),
+ stat(Encoders, EncodingTimes).
+
+%%----------------------------------------------------------------------
+%% Return encoding time statistics as term
+%%----------------------------------------------------------------------
+
+decoding_times_stat() ->
+ Encoders = encoders(),
+ DecodingTimes = decoding_times(Encoders),
+ stat(Encoders, DecodingTimes).
+
+%%----------------------------------------------------------------------
+%% Return encoding time statistics as term
+%%----------------------------------------------------------------------
+
+coding_times_stat() ->
+ Encoders = encoders(),
+ CodingTimes = coding_times(Encoders),
+ stat(Encoders, CodingTimes).
+
+%%----------------------------------------------------------------------
+%% Generate GIF picture from encoding time statistics with gnuplot
+%%----------------------------------------------------------------------
+
+gnuplot_enc_time_gif() ->
+ {ok, _Cwd} = file:get_cwd(),
+ TmpDir = "megaco_encoding_time.tmp",
+ GifFile = "megaco_encoding_time.gif",
+ Header =
+ ["set title \"Encoding time comparison of Megaco/H.248 encoding formats\"\n",
+ "set timestamp top\n",
+ "set terminal gif\n",
+ "set xlabel \"Test cases from Appendix A\"\n",
+ "set ylabel \"Time for encoding in micro seconds\"\n",
+ "set rmargin 10\n",
+ "set key left top Left\n",
+ "set output \"", GifFile, "\"\n\n"],
+ Encoders = encoders(),
+ Stat = encoding_times(Encoders),
+ BatchFile = gnuplot_dir(TmpDir, Header, Encoders, Stat),
+ Cmd = "cd " ++ TmpDir ++ "; gnuplot " ++ BatchFile,
+ os:cmd(Cmd),
+ ok = io:format("~n~s~nxv ~s~n", [Cmd, filename:join([TmpDir, GifFile])]),
+ stat(Encoders, Stat).
+
+%%----------------------------------------------------------------------
+%% Generate GIF picture from decoding time statistics with gnuplot
+%%----------------------------------------------------------------------
+
+gnuplot_dec_time_gif() ->
+ {ok, _Cwd} = file:get_cwd(),
+ TmpDir = "megaco_decoding_time.tmp",
+ GifFile = "megaco_decoding_time.gif",
+ Header =
+ ["set title \"Decoding time comparison of Megaco/H.248 encoding formats\"\n",
+ "set timestamp top\n",
+ "set terminal gif\n",
+ "set xlabel \"Test cases from Appendix A\"\n",
+ "set ylabel \"Time for decoding in micro seconds\"\n",
+ "set rmargin 10\n",
+ "set key left top Left\n",
+ "set output \"", GifFile, "\"\n\n"],
+ Encoders = encoders(),
+ Stat = decoding_times(Encoders),
+ BatchFile = gnuplot_dir(TmpDir, Header, Encoders, Stat),
+ Cmd = "cd " ++ TmpDir ++ "; gnuplot " ++ BatchFile,
+ os:cmd(Cmd),
+ ok = io:format("~n~s~nxv ~s~n", [Cmd, filename:join([TmpDir, GifFile])]),
+ stat(Encoders, Stat).
+
+%%----------------------------------------------------------------------
+%% Generate GIF picture from decoding time statistics with gnuplot
+%%----------------------------------------------------------------------
+
+gnuplot_code_time_gif() ->
+ {ok, _Cwd} = file:get_cwd(),
+ TmpDir = "megaco_coding_time.tmp",
+ GifFile = "megaco_coding_time.gif",
+ Header =
+ ["set title \"Encoding + decoding time comparison of Megaco/H.248 encoding formats\"\n",
+ "set timestamp top\n",
+ "set terminal gif\n",
+ "set xlabel \"Test cases from Appendix A\"\n",
+ "set ylabel \"Time for encoding+decoding in micro seconds\"\n",
+ "set rmargin 10\n",
+ "set key left top Left\n",
+ "set output \"", GifFile, "\"\n\n"],
+ Encoders = encoders(),
+ Stat = coding_times(Encoders),
+ BatchFile = gnuplot_dir(TmpDir, Header, Encoders, Stat),
+ Cmd = "cd " ++ TmpDir ++ "; gnuplot " ++ BatchFile,
+ os:cmd(Cmd),
+ ok = io:format("~n~s~nxv ~s~n", [Cmd, filename:join([TmpDir, GifFile])]),
+ stat(Encoders, Stat).
+
+%%----------------------------------------------------------------------
+%% Encode asn.1 messages
+%%----------------------------------------------------------------------
+
+gen_byte_msg(Msg, {Mod, Opt, _Opt2} = _Encoder) ->
+ {ok, EncodedMsg} = Mod:encode_message(Opt, Msg),
+ EncodedMsg.
+
+%%----------------------------------------------------------------------
+%% Gen the C header file content as a binary
+%%----------------------------------------------------------------------
+
+gen_header_file_binary([]) ->
+ ok;
+gen_header_file_binary([{S, B}| Rest]) ->
+ file:write_file(atom_to_list(S), B),
+ gen_header_file_binary(Rest).
+
+%%----------------------------------------------------------------------
+%% Generate headerfile for asn.1 BER test in C
+%%----------------------------------------------------------------------
+
+gen_ber_header() ->
+ Encoder = {megaco_ber_encoder, [], []},
+ L = [{S, gen_byte_msg(Msg, Encoder)} || {S, Msg} <- messages()],
+ gen_header_file_binary(L).
+
+%%----------------------------------------------------------------------
+%% Generate headerfile for asn.1 BER test in C
+%%----------------------------------------------------------------------
+gen_ber_bin_header() ->
+ Encoder = {megaco_ber_bin_encoder, [], []},
+ L = [{S, gen_byte_msg(Msg, Encoder)} || {S, Msg} <- messages()],
+ gen_header_file_binary(L).
+
+%%----------------------------------------------------------------------
+%% Generate headerfile for asn.1 PER test in C
+%%----------------------------------------------------------------------
+gen_per_header() ->
+ Encoder = {megaco_per_encoder, [], []},
+ L = [{S, gen_byte_msg(Msg, Encoder)} || {S, Msg} <- messages()],
+ gen_header_file_binary(L).
+
+%%----------------------------------------------------------------------
+%% Execute a fun a number of times and return avg in millis
+%%----------------------------------------------------------------------
+
+meter(Fun, Encoder) ->
+ MaxTime = timer:seconds(5),
+ Rep = 2,
+ M = pretty_mod(Encoder),
+ io:format("~p:\t", [M]),
+ Times = [single_meter(Fun, MaxTime, {M, N}) || N <- lists:seq(1, Rep)],
+ Min = lists:min(Times),
+ Max = lists:max(Times),
+ Median = lists:nth((Rep + 1) div 2, lists:sort(Times)),
+ io:format("(median=~p, diff=~p)~n", [Median, Max - Min]),
+ Median.
+
+single_meter(Fun, MaxTime, Tag) ->
+ Pid = spawn_link(?MODULE, single_meter, [self(), Fun, MaxTime, Tag]),
+ receive
+ {meter, Pid, Time} ->
+ io:format("~p \t", [Time]),
+ Time;
+ {'EXIT', Pid, Reason} ->
+ {bad_result, Reason}
+ end.
+
+single_meter(Parent, Fun, Expected, _Tag) ->
+ erlang:statistics(runtime),
+ erlang:send_after(Expected, self(), return_count),
+ Count = count(Fun, 1),
+ {_, Actual} = erlang:statistics(runtime),
+ %% Diff = Actual - Expected,
+ Micros = trunc((Actual / Count) * 1000),
+ Parent ! {meter, self(), Micros},
+ unlink(Parent),
+ exit(normal).
+
+count(Fun, N) ->
+ Fun(),
+ receive
+ return_count ->
+ N
+ after 0 ->
+ count(Fun, N + 1)
+ end.
+
+stat(Encoders, Stat) ->
+ Fun =
+ fun({_Mod, _Opt, _Opt2} = E) ->
+ List = lists:flatten([[Val || {E2, Val} <- Info, E2 == E] ||
+ {_Slogan, Info} <- Stat]),
+ Max = lists:max(List),
+ Min = lists:min(List),
+ case catch lists:sum(List) of
+ {'EXIT', _} ->
+ {E, bad, List};
+ Sum when is_integer(Sum) ->
+ N = length(List),
+ {E, [{min, Min}, {avg, Sum div N}, {max, Max}]}
+ end
+ end,
+ lists:map(Fun, Encoders).
+
+gnuplot_dir(Dir, Header, Encoders, Stat) ->
+ file:make_dir(Dir),
+ {Names, Arrows} = gnuplot_data(Encoders, Dir, Stat, 1, [], []),
+ [H | T] = [lists:concat(["\"", N, "\" with linespoints"]) || N <- Names],
+ Plots = [[", ", Plot] || Plot <- T],
+ IoList = [Header, Arrows, "\nplot ", H, Plots, "\n\nshow output\n"],
+ Bin = list_to_binary(IoList),
+ BatchFile = "gnuplot.batch",
+ file:write_file(filename:join(Dir, BatchFile), Bin),
+ BatchFile.
+
+gnuplot_data([], _Dir, _Stat, _Pos, Names, Arrows) ->
+ {lists:reverse(Names), lists:reverse(Arrows)};
+gnuplot_data([{Mod, _Opt, _Opt2} = E | Encoders], Dir, Stat, Pos, Names, Arrows) ->
+ Plot = fun({Msg, List}, {N, AccSz}) ->
+ {value, {_, Sz}} = lists:keysearch(E, 1, List),
+ ActualSz =
+ if
+ is_integer(Sz) ->
+ Sz;
+ true ->
+ ok = io:format("<ERROR> ~p(~p) -> ~p~n",
+ [Mod, Msg, Sz]),
+ 0
+ end,
+ Acc = {N + 1, [ActualSz | AccSz]},
+ {lists:concat([N + 1, " ", ActualSz, "\n"]), Acc}
+ end,
+ {Data, {N, Sizes}} = lists:mapfoldl(Plot, {0, []}, Stat),
+ Min = lists:min(Sizes),
+ Max = lists:max(Sizes),
+ Sum = lists:sum(Sizes),
+ Avg = Sum div N,
+ Len = length(Stat),
+ Pretty = pretty_mod(E),
+ Name = lists:concat([Pretty, " (", Min, ",", Avg, ",", Max, ")"]),
+ file:write_file(filename:join(Dir, Name), list_to_binary(Data)),
+ %%"plot \"-\" title \"", E, "\" with linespoints\n", Data, "e\n",
+ Arrow =
+ lists:concat(["set arrow from 1,", Avg,
+ " to ", Len, ", ", Avg,
+ " nohead lt ", Pos, "\n",
+ "set label \" ", Avg, " (avg)\" at ", Len, ",", Avg + 10, "\n"]),
+ gnuplot_data(Encoders, Dir, Stat, Pos + 1, [Name | Names], [Arrow | Arrows]).
diff --git a/lib/megaco/test/megaco_codec_flex_lib.erl b/lib/megaco/test/megaco_codec_flex_lib.erl
new file mode 100644
index 0000000000..de76956711
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_flex_lib.erl
@@ -0,0 +1,174 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility module used by the codec suites when testing flex
+%% configured text codec(s).
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_flex_lib).
+
+%% ----
+
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([
+ init/1,
+ finish/1,
+ scanner_conf/1,
+ start/0,
+ stop/1
+ ]).
+
+-export([
+ handler/1
+ ]).
+
+
+%% ----
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(Config) when is_list(Config) ->
+ Flag = process_flag(trap_exit, true),
+ Res = (catch start()),
+ process_flag(trap_exit, Flag),
+ case Res of
+ {error, Reason} ->
+ skip(Reason);
+ {ok, FlexConfig} ->
+ [{flex_scanner, FlexConfig} | Config]
+ end.
+
+
+finish(Config) when is_list(Config) ->
+ case lists:keysearch(flex_scanner, 1, Config) of
+ {value, {flex_scanner, {Pid, _Conf}}} ->
+ stop(Pid),
+ lists:keydelete(flex_scanner, 1, Config);
+ false ->
+ Config
+ end.
+
+
+start() ->
+ Pid = proc_lib:spawn(?MODULE, handler, [self()]),
+ receive
+ {flex_scanner_started, Pid, Conf} ->
+ {ok, {Pid, Conf}};
+ {flex_scanner_error, {failed_loading_flex_scanner_driver, Reason}} ->
+ ?LOG("start_flex_scanner -> failed loading flex scanner driver: "
+ "~n Reason: ~p~n", [Reason]),
+ {error, {failed_loading_flex_scanner_driver, Reason}};
+ {flex_scanner_error, Reason} ->
+ ?LOG("start_flex_scanner -> error: "
+ "~n Reason: ~p~n", [Reason]),
+ {error, {failed_loading_flex_scanner_driver, Reason}}
+ after 10000 ->
+ exit(Pid, kill),
+ {error, {failed_starting_flex_scanner, timeout}}
+ end.
+
+
+scanner_conf(Config) when is_list(Config) ->
+ case lists:keysearch(flex_scanner, 1, Config) of
+ {value, {flex_scanner, {Pid, Conf}}} ->
+ case ping_flex_scanner(Pid) of
+ ok ->
+ Conf;
+ Else ->
+ skip({no_response_from_flex_scanner_handler, Else})
+ end;
+ false ->
+ skip("Flex scanner driver not loaded")
+ end.
+
+
+ping_flex_scanner(Pid) ->
+ Pid ! {ping, self()},
+ receive
+ {pong, Pid} ->
+ ok
+ after 5000 ->
+ timeout
+ end.
+
+
+stop(Pid) ->
+ Pid ! stop.
+
+
+handler(Pid) ->
+ SMP = erlang:system_info(smp_support),
+ case (catch megaco_flex_scanner:start(SMP)) of
+ {ok, PortOrPorts} ->
+ Pid ! {flex_scanner_started, self(), {flex, PortOrPorts}},
+ handler(Pid, PortOrPorts);
+ {error, {load_driver, {open_error, Reason}}} ->
+ Error = {failed_loading_flex_scanner_driver, Reason},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error);
+ {error, {load_driver, Reason}} ->
+ Error = {failed_loading_flex_scanner_driver, Reason},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error);
+ Else ->
+ Error = {unknown_result_from_start_flex_scanner, Else},
+ Pid ! {flex_scanner_error, Error},
+ exit(Error)
+ end.
+
+handler(Pid, PortOrPorts) ->
+ receive
+ {ping, Pinger} ->
+ Pinger ! {pong, self()},
+ handler(Pid, PortOrPorts);
+ {'EXIT', Port, Reason} when (PortOrPorts =:= Port) ->
+ Pid ! {flex_scanner_exit, Reason},
+ exit({flex_scanner_exit, Reason});
+ {'EXIT', Port, Reason} when is_port(Port) ->
+ case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
+ true ->
+ Pid ! {flex_scanner_exit, Reason},
+ exit({flex_scanner_exit, Reason});
+ false ->
+ io:format("flex scanner handler got port exit "
+ "from unknown:"
+ "~n ~p: ~p", [Port, Reason]),
+ ok
+ end,
+ handler(Pid, PortOrPorts);
+ stop ->
+ megaco_flex_scanner:stop(PortOrPorts),
+ exit(normal);
+ Other ->
+ io:format("flex scanner handler got something:~n"
+ "~p", [Other]),
+ handler(Pid, PortOrPorts)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+skip(Reason) ->
+ megaco_codec_test_lib:skip(Reason).
+
diff --git a/lib/megaco/test/megaco_codec_mini_test.erl b/lib/megaco/test/megaco_codec_mini_test.erl
new file mode 100644
index 0000000000..e509739bb1
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_mini_test.erl
@@ -0,0 +1,220 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test mini encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_mini_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include_lib("megaco/include/megaco_message_v3.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ tickets/0,
+ tickets/1,
+ otp7672_msg01/1,
+ otp7672_msg02/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+
+%% ----
+
+-define(SET_DBG(S,D), begin put(severity, S), put(dbg, D) end).
+-define(RESET_DBG(), begin erase(severity), erase(dbg) end).
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ tickets
+ ].
+
+tickets(suite) ->
+ [
+ otp7672_msg01,
+ otp7672_msg02
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%%
+
+otp7672_msg01(suite) ->
+ [];
+otp7672_msg01(Config) when is_list(Config) ->
+ %% ?SET_DBG(trc, true),
+ d("otp7672_msg01 -> entry", []),
+ ok = otp7672( otp7672_msg01() ),
+ %% ?RESET_DBG(),
+ ok.
+
+otp7672_msg02(suite) ->
+ [];
+otp7672_msg02(Config) when is_list(Config) ->
+ %% ?SET_DBG(trc, true),
+ d("otp7672_msg02 -> entry", []),
+ ok = otp7672( otp7672_msg02() ),
+ %% ?RESET_DBG(),
+ ok.
+
+
+otp7672_msg01() ->
+ <<"!/1 <TEST> ">>.
+
+otp7672_msg02() ->
+ <<"!/1 <TE> ">>.
+
+otp7672(Msg) ->
+ case megaco_text_mini_decoder:decode_message([], Msg) of
+ {ok, M} ->
+ t("mini decode successfull: ~n~p", [M]),
+ ok;
+ Error ->
+ e("mini decode failed: ~n~p", [Error]),
+ {error, Error}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+%% l(F,A) ->
+%% p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s:" ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "TRC";
+image_of(dbg) ->
+ "DBG";
+image_of(log) ->
+ "LOG";
+image_of(err) ->
+ "ERR";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
diff --git a/lib/megaco/test/megaco_codec_prev3a_test.erl b/lib/megaco/test/megaco_codec_prev3a_test.erl
new file mode 100644
index 0000000000..696a72343c
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_prev3a_test.erl
@@ -0,0 +1,7350 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+-module(megaco_codec_prev3a_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+ flex_compact_dm_timers7/1,
+ flex_compact_dm_timers8/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4299_msg2/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5793_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp7431_msg01/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5085_msg8/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+ pretty_otp8114_msg01/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5085_msg8/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0]).
+
+
+%% ----
+
+-define(EC_V3, {version3,prev3a}).
+-define(EC, [?EC_V3]).
+
+-define(VERSION, 3).
+-define(VERSION_STR, "3").
+-define(MSG_LIB, megaco_test_msg_prev3a_lib).
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs = msgs1(text) ++ msgs4(text) ++ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs5(text) ++ msgs6(text),
+ megaco_codec_test_lib:display_text_messages(?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ flex_compact_tickets,
+ pretty_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4299_msg2,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5793_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03
+ ].
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
+
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5085_msg8,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05,
+ pretty_otp8114_msg01
+ ].
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs5(text),
+ %% Msgs = msgs6(text),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+%% Msgs = msgs5(text),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("flex_pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("flex_pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1(), [Conf]).
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(error, pretty_otp5085_msg2(), [Conf]).
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3(), [Conf]).
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4(), [Conf]).
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5(), [Conf]).
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6(), [Conf]).
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7(), [Conf]).
+
+flex_pretty_otp5085_msg8(suite) ->
+ [];
+flex_pretty_otp5085_msg8(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg8(), [Conf]).
+
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg1(), [Conf]).
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg2(), [Conf]).
+
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5601(ok, pretty_otp5601_msg1(), [Conf]).
+
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5793(ok, pretty_otp5793_msg1(), [Conf]).
+
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf) ->
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []);
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg2() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg3() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg4() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a}
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg5() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg6() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg7() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v}
+ }
+ }
+ }
+ }
+ }".
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs6(text),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,3}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({2,3,4}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,31}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({10,21,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({99,23,11}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers7(suite) ->
+ [];
+flex_compact_dm_timers7(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers7 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers8(suite) ->
+ [];
+flex_compact_dm_timers8(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("01", "09", "01", "02"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers8 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,9,1,2}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s", [T, S, L])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(T, S, L, Z) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s,Z:~s", [T, S, L,Z])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(TMRs) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [TMRs]),
+ lists:flatten(M).
+
+
+verify_dm_timers(TMRs, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ TMRs ->
+ ok;
+ {error, Reason} ->
+ exit({invalid_timer, {TMRs, Reason}});
+ TMRs1 ->
+ exit({invalid_timer_values, {TMRs, TMRs1}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts])
+ when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = asn1_NOVALUE} ->
+ {ok, {T, S, L}};
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = Z} ->
+ {ok, {T, S, L, Z}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ %% Msgs = msgs5(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ %% Msgs = msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(erlang) ++
+ msgs2(erlang) ++
+ msgs3(erlang) ++
+ msgs4(erlang) ++
+ msgs5(erlang) ++
+ msgs6(erlang),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+% put(severity,trc),
+% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+% erase(severity),
+% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+compact_otp4011(M) ->
+ d("compact_otp4011 -> entry with"
+ "~n M: '~s'", [M]),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ d("compact_otp4011 -> expected error result (so far)", []),
+ case lists:keysearch(reason,1,Error) of
+ {value, {reason,Reason}} ->
+ d("compact_otp4011 -> expected error: "
+ "~n Reason: ~p", [Reason]),
+ case Reason of
+ {0, megaco_text_parser_prev3a,
+ {do_merge_control_streamParms, [A,B]}}
+ when is_list(A) andalso is_record(B, 'LocalControlDescriptor') ->
+ case lists:keysearch(mode,1,A) of
+ {value, {mode, _Mode}}
+ when B#'LocalControlDescriptor'.streamMode =/= asn1_NOVALUE ->
+ d("compact_otp4011 -> expected error",[]),
+ ok;
+ Other ->
+ exit({unexpected_mode_reason, {A,B,Other}})
+ end;
+ Other ->
+ exit({unexpected_reason, Other})
+ end;
+
+ false ->
+ d("compact_otp4011 -> OUPS, wrong kind of error", []),
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ d("compact_otp4011 -> unexpected decode result: ~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/3 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Reason} when is_list(Reason) ->
+ {value, {reason, no_version_found, _}} =
+ lists:keysearch(reason, 1, Reason),
+ {value, {token, [{'SafeChars',_,"megcao/3"}|_]}} =
+ lists:keysearch(token, 1, Reason),
+ ok;
+ Else ->
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, M} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ t("compact_otp4085_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{999999, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> THE ACTUAL ERROR: "
+ "~n LINE NUMBER: 999999"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Module, Crap]),
+ %% ok;
+ exit({decode_failed_999999, Module, Crap});
+ {value, {reason,{Line, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Line, Module, Crap]),
+ ok;
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M1 = compact_otp4085_erroneous_msg() ++ "}",
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, M2} ->
+ l("compact_otp4085_msg1 -> successfull decode"
+ "~n M2: ~p", [M2]),
+ ok;
+ Else ->
+ e("compact_otp4085_msg1 -> decode error"
+ "~n Else: ~p", [Else]),
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4280_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _Msg} ->
+ ok;
+ {error, Error} when is_list(Error) ->
+ t("compact_otp4280_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{Line, Module, Reason} = R}} ->
+ t("compact_otp4280_msg1 -> "
+ "~n Line: ~w"
+ "~n Module: ~w"
+ "~n Reason: ~w", [Line, Module, Reason]),
+ exit({decode_failed, R});
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4299_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% Same message, but this time decoded using the flex scanner
+compact_otp4299_msg2(suite) ->
+ [];
+compact_otp4299_msg2(Config) when is_list(Config) ->
+ d("compact_otp4299_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+
+ {Pid, Conf} = compact_otp4299_msg2_init(),
+
+ M1 = compact_otp4299_msg(),
+ d("compact_otp4299_msg2 -> M1: ~n~s", [M1]),
+ Bin = list_to_binary(M1),
+ Res = decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], Bin),
+ compact_otp4299_msg2_finish(Pid),
+
+ case Res of
+ {ok, M2} ->
+ d("compact_otp4299_msg2 -> M2: ~n~p", [M2]),
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+compact_otp4299_msg2_init() ->
+ Flag = process_flag(trap_exit, true),
+ Res = (catch start_flex_scanner()),
+ process_flag(trap_exit, Flag),
+ case Res of
+ {error, Reason} ->
+ skip(Reason);
+ {ok, FlexConfig} ->
+ FlexConfig
+ end.
+
+compact_otp4299_msg2_finish(Pid) ->
+ stop_flex_scanner(Pid).
+
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/"
+ ?VERSION_STR
+ " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4359_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, #'MegacoMessage'{mess = Mess}} ->
+ {transactions, Trans} = Mess#'Message'.messageBody,
+ case Trans of
+ [{transactionRequest,#'TransactionRequest'{transactionId = asn1_NOVALUE}}] ->
+ ok;
+ _ ->
+ exit({unexpected_transactions, Trans})
+ end;
+ Else ->
+ t("compact_otp4359_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg0(), true).
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg1(), false).
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg2(), false).
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg3(), true).
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg4(), true).
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg5(), true).
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg6(), true).
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg7(), true).
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg8(), false).
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg9(), false).
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg10(), false).
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg11(), false).
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg12(), true).
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg20(), bad_mid_duplicate_padding).
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg21(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg22(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg23(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg24(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg25(), bad_mid_ip6addr_length).
+
+compact_otp4920_msg_1(M1, CheckEqual) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin1) of
+ {ok, Msg} ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, ?EC, Msg) of
+ {ok, Bin1} ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when CheckEqual == true ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, M1, M2});
+ {ok, _} ->
+ io:format(", encoded:", []),
+ ok;
+ Else ->
+ io:format(", encode failed:", []),
+ exit({unexpected_encode_result, Else})
+ end;
+ Else ->
+ io:format("decode failed:", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4920_msg_2(M1, ExpectedReason) ->
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, Msg} ->
+ io:format("unexpected successfull decode", []),
+ exit({unexpected_encode_ok, Msg});
+ {error, [{reason, {__Line, _Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ {error, [{reason, {_Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ Else ->
+ io:format("unexpected decode result", []),
+ exit({unexpected_decode_result, Else})
+
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg01(), error, ignore).
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg02(), ok, ok).
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok).
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok).
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok).
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok).
+
+compact_otp5186_msg_1(M1, DecodeExpect, EncodeExpect) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin1) of
+ {ok, Msg} when DecodeExpect == ok ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, ?EC, Msg) of
+ {ok, Bin1} when EncodeExpect == ok ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when EncodeExpect == ok ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, Msg, M1, M2});
+ {ok, Bin3} when EncodeExpect == error ->
+ M3 = binary_to_list(Bin3),
+ io:format(", unexpected encode:", []),
+ exit({unexpected_encode_success, Msg, M1, M3});
+ _Else when EncodeExpect == error ->
+ io:format(", encode failed ", []),
+ ok
+ end;
+ {ok, Msg} when DecodeExpect == error ->
+ io:format(" decoded", []),
+ exit({unexpected_decode_success, Msg});
+ _Else when DecodeExpect == error ->
+ io:format(" decode failed ", []),
+ ok;
+ Else when DecodeExpect == ok ->
+ io:format(" decode failed ", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp5186_msg_2(Msg1, EncodeExpect, DecodeExpect) ->
+ case encode_message(megaco_compact_text_encoder, ?EC, Msg1) of
+ {ok, Bin} when EncodeExpect == ok ->
+ io:format(" encoded", []),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, Msg1} when DecodeExpect == ok ->
+ io:format(", decoded - equal:", []),
+ ok;
+ {ok, Msg2} when DecodeExpect == ok ->
+ M = binary_to_list(Bin),
+ case (catch compact_otp5186_check_megamsg(Msg1, Msg2)) of
+ ok ->
+ io:format(", decoded - not equal - ok:", []),
+ ok;
+ {'EXIT', Reason} ->
+ io:format(", decoded - not equal:", []),
+ exit({messages_not_equal, M, Reason, Msg1, Msg2})
+ end;
+ {ok, Msg3} when DecodeExpect == error ->
+ M = binary_to_list(Bin),
+ io:format(", decoded:", []),
+ exit({unexpected_decode_success, M, Msg1, Msg3});
+ Else when DecodeExpect == ok ->
+ M = binary_to_list(Bin),
+ io:format(", decode failed ", []),
+ exit({unexpected_decode_success, Msg1, M, Else});
+ _Else when DecodeExpect == error ->
+ io:format(", decode failed ", []),
+ ok
+ end;
+ {ok, Bin} when EncodeExpect == error ->
+ M = binary_to_list(Bin),
+ io:format(" encoded", []),
+ exit({unexpected_encode_success, Msg1, M});
+ _Else when EncodeExpect == error ->
+ io:format(" encode failed ", []),
+ ok;
+ Else when EncodeExpect == ok ->
+ io:format(" encode failed ", []),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+%% --
+
+compact_otp5186_check_megamsg(M1, M1) ->
+ ok;
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH,
+ mess = M1},
+ #'MegacoMessage'{authHeader = AH,
+ mess = M2}) ->
+ compact_otp5186_check_mess(M1, M2);
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH1},
+ #'MegacoMessage'{authHeader = AH2}) ->
+ exit({not_equal, authHeader, AH1, AH2}).
+
+compact_otp5186_check_mess(M, M) ->
+ ok;
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId,
+ messageBody = B1},
+ #'Message'{version = V,
+ mId = MId,
+ messageBody = B2}) ->
+ compact_otp5186_check_body(B1, B2);
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId1},
+ #'Message'{version = V,
+ mId = MId2}) ->
+ exit({not_equal, mId, MId1, MId2});
+compact_otp5186_check_mess(#'Message'{version = V1,
+ mId = MId},
+ #'Message'{version = V2,
+ mId = MId}) ->
+ exit({not_equal, version, V1, V2}).
+
+compact_otp5186_check_body(B, B) ->
+ ok;
+compact_otp5186_check_body({transactions, T1}, {transactions, T2}) ->
+ compact_otp5186_check_trans(T1, T2);
+compact_otp5186_check_body({messageError, E1}, {messageError, E2}) ->
+ compact_otp5186_check_merr(E1, E2);
+compact_otp5186_check_body(B1, B2) ->
+ exit({not_equal, messageBody, B1, B2}).
+
+compact_otp5186_check_trans([], []) ->
+ ok;
+compact_otp5186_check_trans([], T2) ->
+ exit({not_equal, transactions, [], T2});
+compact_otp5186_check_trans(T1, []) ->
+ exit({not_equal, transactions, T1, []});
+compact_otp5186_check_trans([Tran1|Trans1], [Tran2|Trans2]) ->
+ compact_otp5186_check_trans(Trans1, Trans2),
+ compact_otp5186_check_transaction(Tran1, Tran2).
+
+compact_otp5186_check_merr(ME, ME) ->
+ ok;
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC,
+ errorText = ET1},
+ #'ErrorDescriptor'{errorCode = EC,
+ errorText = ET2}) ->
+ exit({not_equal, errorText, ET1, ET2});
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC1,
+ errorText = ET},
+ #'ErrorDescriptor'{errorCode = EC2,
+ errorText = ET}) ->
+ exit({not_equal, errorCode, EC1, EC2}).
+
+compact_otp5186_check_transaction(T, T) ->
+ ok;
+compact_otp5186_check_transaction({transactionReply, TR1},
+ {transactionReply, TR2}) ->
+ compact_otp5186_check_transRep(TR1, TR2);
+compact_otp5186_check_transaction(T1, T2) ->
+ exit({unexpected_transactions, T1, T2}).
+
+compact_otp5186_check_transRep(T, T) ->
+ ok;
+compact_otp5186_check_transRep(#'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR2}) ->
+ compact_otp5186_check_transRes(TR1, TR2);
+compact_otp5186_check_transRep(T1, T2) ->
+ exit({unexpected_transaction_reply, T1, T2}).
+
+compact_otp5186_check_transRes(TR, TR) ->
+ ok;
+compact_otp5186_check_transRes({actionReplies, AR1},
+ {actionReplies, AR2}) ->
+ compact_otp5186_check_actReps(AR1, AR2);
+compact_otp5186_check_transRes(TR1, TR2) ->
+ exit({unexpected_transaction_result, TR1, TR2}).
+
+compact_otp5186_check_actReps([], []) ->
+ ok;
+compact_otp5186_check_actReps(AR1, []) ->
+ exit({not_equal, actionReplies, AR1, []});
+compact_otp5186_check_actReps([], AR2) ->
+ exit({not_equal, actionReplies, [], AR2});
+compact_otp5186_check_actReps([AR1|ARs1], [AR2|ARs2]) ->
+ compact_otp5186_check_actRep(AR1, AR2),
+ compact_otp5186_check_actReps(ARs1, ARs2).
+
+compact_otp5186_check_actRep(AR, AR) ->
+ ok;
+compact_otp5186_check_actRep(#'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep2}) ->
+ compact_otp5186_check_cmdReps(CmdRep1, CmdRep2);
+compact_otp5186_check_actRep(AR1, AR2) ->
+ exit({unexpected_actionReply, AR1, AR2}).
+
+compact_otp5186_check_cmdReps([], []) ->
+ ok;
+compact_otp5186_check_cmdReps(CR1, []) ->
+ exit({not_equal, commandReplies, CR1, []});
+compact_otp5186_check_cmdReps([], CR2) ->
+ exit({not_equal, commandReplies, [], CR2});
+compact_otp5186_check_cmdReps([CR1|CRs1], [CR2|CRs2]) ->
+ compact_otp5186_check_cmdRep(CR1, CR2),
+ compact_otp5186_check_cmdReps(CRs1, CRs2).
+
+compact_otp5186_check_cmdRep(CR, CR) ->
+ ok;
+compact_otp5186_check_cmdRep({auditValueReply, AVR1},
+ {auditValueReply, AVR2}) ->
+ compact_otp5186_check_auditReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep({addReply, AVR1},
+ {addReply, AVR2}) ->
+ compact_otp5186_check_ammsReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep(CR1, CR2) ->
+ exit({unexpected_commandReply, CR1, CR2}).
+
+compact_otp5186_check_auditReply(AR, AR) ->
+ ok;
+compact_otp5186_check_auditReply({auditResult, AR1},
+ {auditResult, AR2}) ->
+ compact_otp5186_check_auditRes(AR1, AR2);
+compact_otp5186_check_auditReply(AR1, AR2) ->
+ exit({unexpected_auditReply, AR1, AR2}).
+
+compact_otp5186_check_ammsReply(AR, AR) ->
+ ok;
+compact_otp5186_check_ammsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = ID,
+ terminationAudit = TA2}) ->
+ %% This is just to simplify the test
+ F = fun(asn1_NOVALUE) -> [];
+ (E) -> E
+ end,
+ compact_otp5186_check_termAudit(F(TA1), F(TA2));
+compact_otp5186_check_ammsReply(AR1, AR2) ->
+ exit({unexpected_ammsReply, AR1, AR2}).
+
+compact_otp5186_check_auditRes(AR, AR) ->
+ ok;
+compact_otp5186_check_auditRes(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR2}) ->
+ compact_otp5186_check_termAuditRes(TAR1, TAR2);
+compact_otp5186_check_auditRes(AR1, AR2) ->
+ exit({unexpected_auditResult, AR1, AR2}).
+
+compact_otp5186_check_termAuditRes([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAuditRes(TAR1, []);
+compact_otp5186_check_termAuditRes(TAR1, []) ->
+ exit({not_equal, termAuditRes, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([], [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAuditRes([], TAR2);
+compact_otp5186_check_termAuditRes([], TAR2) ->
+ exit({not_equal, termAuditRes, [], TAR2});
+compact_otp5186_check_termAuditRes([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAuditRes(TAR1, TAR2).
+
+compact_otp5186_check_termAudit([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAudit(TAR1, []);
+compact_otp5186_check_termAudit(TAR1, []) ->
+ exit({not_equal, termAudit, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([],
+ [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAudit([], TAR2);
+compact_otp5186_check_termAudit([], TAR2) ->
+ exit({not_equal, termAudit, [], TAR2});
+compact_otp5186_check_termAudit([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAudit(TAR1, TAR2).
+
+compact_otp5186_check_auditRetParm(ARP, ARP) ->
+ ok;
+compact_otp5186_check_auditRetParm({emptyDescriptors, AD1},
+ {emptyDescriptors, AD2}) ->
+ compact_otp5186_check_auditDesc(AD1, AD2);
+compact_otp5186_check_auditRetParm(ARP1, ARP2) ->
+ exit({unexpected_auditRetParm, ARP1, ARP2}).
+
+compact_otp5186_check_auditDesc(AD, AD) ->
+ ok;
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = L1,
+ auditPropertyToken = asn1_NOVALUE},
+ #'AuditDescriptor'{auditToken = L2,
+ auditPropertyToken = asn1_NOVALUE}) ->
+ compact_otp5186_check_auditDesc_auditItems(L1, L2);
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT2}) ->
+ compact_otp5186_check_auditDesc_apt(APT1, APT2);
+compact_otp5186_check_auditDesc(AD1, AD2) ->
+ exit({unexpected_auditDesc, AD1, AD2}).
+
+compact_otp5186_check_auditDesc_auditItems([], []) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItems(AI1, []) ->
+ exit({not_equal, auditItems, AI1, []});
+compact_otp5186_check_auditDesc_auditItems([], AI2) ->
+ exit({not_equal, auditItems, [], AI2});
+compact_otp5186_check_auditDesc_auditItems([AI1|AIs1], [AI2|AIs2]) ->
+ compact_otp5186_check_auditDesc_auditItem(AI1, AI2),
+ compact_otp5186_check_auditDesc_auditItems(AIs1, AIs2).
+
+compact_otp5186_check_auditDesc_auditItem(AI, AI) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItem(AI1, AI2) ->
+ exit({not_equal, auditItem, AI1, AI2}).
+
+compact_otp5186_check_auditDesc_apt(APT, APT) ->
+ ok;
+compact_otp5186_check_auditDesc_apt(APT1, APT2) ->
+ exit({not_equal, auditPropertyToken, APT1, APT2}).
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5793(ok, pretty_otp5793_msg1()).
+
+compact_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_compact_text_encoder, Msg, []).
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg01()).
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg02()).
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg03()).
+
+compact_otp5993(Expected, Msg) ->
+ expect_codec(Expected, megaco_compact_text_encoder, Msg, []).
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ ok.
+
+compact_otp6017(BadCID) ->
+ Conf = ?EC,
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ exit({unexpected_reason, ActualReason});
+ false ->
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ exit({unexpected_decode_result, Crap})
+ end.
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "MEGACO/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+
+flex_compact_otp7431_msg01(suite) ->
+ [];
+flex_compact_otp7431_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg1(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, BinMsg),
+ ok = chk_MegacoMessage(Msg0, Msg1);
+ Else ->
+ t("pretty_otp4632_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg2(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, BinMsg),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder,
+ false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ Msg0 = Msg1,
+ ok;
+ Else ->
+ t("pretty_otp4632_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4632_msg4_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4_chk([], []) ->
+ exit(messages_not_eq);
+pretty_otp4632_msg4_chk([], Rest1) ->
+ exit({messages_not_eq1, Rest1});
+pretty_otp4632_msg4_chk(Rest0, []) ->
+ exit({messages_not_eq0, Rest0});
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest0],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1]) ->
+ ok;
+pretty_otp4632_msg4_chk([_|Rest0], [_|Rest1]) ->
+ pretty_otp4632_msg4_chk(Rest0,Rest1).
+
+
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg1(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg0) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, Bin),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4710_msg2_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(Msg,Msg) ->
+ ok;
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ io:format("pretty_otp4945_msg1 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeMethod]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason, serviceChangeMethod]} ->
+ ok;
+ {missing_required_serviceChangeParm, [serviceChangeMethod, serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg5(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_serviceChangeParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg5 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg6(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_serviceChangeParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg6 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4949_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_servChgReplyParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg2 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_servChgReplyParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg3 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = pretty_otp5068_msg1(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg) of
+ {error, Reason} ->
+% io:format("pretty_otp5068_msg1 -> "
+% "~n Reason: ~w"
+% "~n", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} ->
+% io:format("pretty_otp5068_msg1 -> successfull encode:"
+% "~n~s~n", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+% io:format("pretty_otp5068_msg1 -> ok~n", []),
+ ok;
+ Else ->
+% io:format("pretty_otp5068_msg1 -> ~n~p~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+}.
+
+
+
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1()).
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(error, pretty_otp5085_msg2()).
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3()).
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4()).
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5()).
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6()).
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7()).
+
+pretty_otp5085_msg8(suite) ->
+ [];
+pretty_otp5085_msg8(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+% put(severity, trc),
+ Res = (catch pretty_otp5085(ok, pretty_otp5085_msg8())),
+% erase(dbg),
+% erase(severity),
+ case Res of
+ ok ->
+ ok;
+ {'EXIT', Reason} ->
+ exit(Reason)
+ end.
+
+pretty_otp5085(Expected, Msg) ->
+ pretty_otp5085(Expected, Msg, []).
+
+pretty_otp5085(Expected, Msg, Conf) ->
+ t("pretty_otp5085 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5085 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5085 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5085 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5085 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5085 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5085 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5085 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg8() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 8,
+ emergency = true,
+ topologyReq =
+ [#'TopologyRequest'{terminationFrom = From1,
+ terminationTo = To1,
+ topologyDirection = bothway},
+ #'TopologyRequest'{terminationFrom = From2,
+ terminationTo = To2,
+ topologyDirection = oneway}
+ ],
+ iepsCallind = true,
+ contextProp = [cre_PropParm("tdmc/gain", "2")]},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg1()).
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg2()).
+
+pretty_otp5600(Expected, Msg) ->
+ pretty_otp5600(Expected, Msg, []).
+
+pretty_otp5600(Expected, Msg, Conf) ->
+ t("pretty_otp5600 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5600 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5600 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5600 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5600 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5600 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5600 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5600 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5601(ok, pretty_otp5601_msg1()).
+
+pretty_otp5601(Expected, Msg) ->
+ pretty_otp5601(Expected, Msg, []).
+
+pretty_otp5601(Expected, Msg, Conf) ->
+ t("pretty_otp5601 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5601 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5601 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5601 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5601 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5601 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5601 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5601 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5793(ok, pretty_otp5793_msg1()).
+
+pretty_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5793(Expected, Msg, Conf) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',3,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5882().
+
+pretty_otp5882() ->
+ otp5882(megaco_pretty_text_encoder, []).
+
+otp5882(Codec, Conf) ->
+ Msg = pretty_otp5882_msg01(),
+ case (catch encode_message(Codec, [?EC_V3|Conf], Msg)) of
+ {error, {message_encode_failed, {error, {ActualReason, _}}, _}} ->
+ case ActualReason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ exit({unexpected_error_actual_reason, ActualReason})
+ end;
+ {error, Reason} ->
+ exit({unexpected_error_reason, Reason});
+ {ok, Bin} ->
+ exit({unexpected_encode_sucess, binary_to_list(Bin)})
+ end.
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ %% erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490(Msg, Conf) ->
+ pretty_otp6490(Msg, Conf, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode) ->
+ pretty_otp6490(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp6490(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+otp6490(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ case (catch encode_message(Codec, [?EC_V3|Conf], Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ exit({unexpected_decode_result, Msg, Msg2});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode =:= ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_DigitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_DigitMapDesc(),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[],
+ asn1_NOVALUE}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+
+
+pretty_otp8114_msg01(suite) ->
+ [];
+pretty_otp8114_msg01(Config) when is_list(Config) ->
+ put(severity, trc),
+ put(dbg, true),
+ d("pretty_otp8114_msg01 -> entry", []),
+ ok = otp8114( pretty_otp8114_msg01(), megaco_pretty_text_encoder, ?EC),
+ erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp8114_msg01() ->
+ "MEGACO/" ?VERSION_STR " [10.10.10.10]:1234\nTransaction = 1 {\n\tContext =\n1 {\n\t\tModify = ip/1/1/1 {\n\t\t\tMedia {\n\t\t\t\tStream = 1\n{\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode =\nSendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 1\n{\n\t\t\t\tadid/ipstop\n{\n\t\t\t\t\tdt=30,\n\t\t\t\t\tdir=\"BOTH\"\n\t\t\t\t},\n\t\t\t\tg/cause\n\n\t\t\t}\n\t\t}\n\t}\n}".
+
+
+otp8114(InitialMessage, Codec, Conf) ->
+ Decode = fun(M) -> Codec:decode_message(Conf, M) end,
+ Encode = fun(B) -> Codec:encode_message(Conf, B) end,
+ InitialData = InitialMessage,
+ Instructions =
+ [
+ %% List to binary
+ megaco_codec_test_lib:expect_instruction(
+ "Convert (initial) message to a binary",
+ fun(Msg) when is_list(Msg) ->
+ %% io:format("~s~n", [Msg]),
+ {ok, list_to_binary(Msg)};
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ {ok, Bin};
+ (Bad, _Msg) ->
+ {error, {failed_to_binary, Bad}}
+ end),
+
+ %% Initial decode
+ megaco_codec_test_lib:expect_instruction(
+ "Decode (initial) message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {initial_decode_failed, Bad}}
+ end),
+
+ %% Encode
+ megaco_codec_test_lib:expect_instruction(
+ "Encode message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ %% io:format("~s~n", [binary_to_list(Bin)]),
+ {ok, Bin};
+ (Bad, _) ->
+ {error, {encode_failed, Bad}}
+ end),
+
+ %% Decode
+ megaco_codec_test_lib:expect_instruction(
+ "(final) Decode message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {decode_failed, Bad}}
+ end)
+ ],
+ megaco_codec_test_lib:expect_exec(Instructions, InitialData).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+expect_codec(Expect, Codec, Msg, Conf) ->
+ t("expect_codec -> entry with"
+ "~n Expect: ~p"
+ "~n Msg: ~p", [Expect, Msg]),
+ case (catch encode_message(Codec, [?EC_V3|Conf], Msg)) of
+ {error, _Reason} when Expect =:= error ->
+ d("expect_codec -> encode failed as expected"
+ "~n _Reason: ~w", [_Reason]),
+ ok;
+ {error, Reason} ->
+ e("expect_codec -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expect =:= error ->
+ e("expect_codec -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("expect_codec -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case (catch decode_message(Codec, false, [?EC_V3|Conf], Bin)) of
+ {ok, Msg} ->
+ d("expect_codec -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("expect_codec -> successfull decode"
+ " - but not equal", []),
+ chk_MegacoMessage(Msg, Msg2);
+ %% exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("expect_codec -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ e("expect_codec -> encode failed:~n~p", [Else]),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ [M || {_, M, _, _} <- msgs(text)].
+
+msgs(Encoding) ->
+ msgs1(Encoding) ++
+ msgs2(Encoding) ++ msgs3(Encoding) ++ msgs4(Encoding) ++
+ msgs5(Encoding) ++ msgs6(Encoding).
+
+msgs1(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+
+msgs2(_) ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, ?EC, M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+msgs4(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg51a, msg51a(), Plain, [{dbg, false}]},
+ {msg51b, msg51b(), Plain, [{dbg, false}]},
+ {msg51c, msg51c(), Plain, [{dbg, false}]},
+ {msg51d, msg51d(), Plain, [{dbg, false}]},
+ {msg51e, msg51e(), Plain, [{dbg, false}]},
+ {msg51f, msg51f(), Plain, [{dbg, false}]},
+ {msg51g, msg51g(), Plain, [{dbg, false}]},
+ {msg51h, msg51h(), Plain, [{dbg, false}]},
+ {msg51i, msg51i(), Plain, [{dbg, false}]},
+ {msg52, msg52(), Plain, [{dbg, false}]},
+ {msg53, msg53(), Plain, [{dbg, false}]},
+ {msg54a, msg54a(), Plain, [{dbg, false}]},
+ {msg54b, msg54b(), Plain, [{dbg, false}]},
+ {msg54c, msg54c(), Plain, [{dbg, false}]},
+ {msg55, msg55(), Plain, [{dbg, false}]},
+ {msg56, msg56(), Plain, [{dbg, false}]},
+ {msg57, msg57(), Plain, [{dbg, false}]},
+ {msg58a, msg58a(), Plain, [{dbg, false}]},
+ {msg58b, msg58b(), Plain, [{dbg, false}]}
+ ].
+
+
+msgs5(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ PlainEDFail =
+ fun(Codec, DD, Ver, EC, M) ->
+ Res =
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M),
+ case Res of
+ {error, {message_encode_failed, Reason, _M}} ->
+ case Reason of
+ {error, {{deprecated, _}, _}} ->
+ ok;
+ _ ->
+ Res
+ end;
+ _ ->
+ Res
+ end
+ end,
+
+ PlainDE =
+ fun(Codec, _DD, Ver, EC, B) ->
+ Res =
+ megaco_codec_test_lib:decode_message(Codec, false, Ver,
+ EC, B),
+ case Res of
+ {ok, M} ->
+ #'MegacoMessage'{mess = Mess} = M,
+ #'Message'{messageBody = {transactions, TRs}} = Mess,
+ [{transactionRequest, TR}] = TRs,
+ #'TransactionRequest'{actions = Actions} = TR,
+ [Action] = Actions,
+ #'ActionRequest'{commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {addReq,AmmReq} = Cmd,
+ #'AmmRequest'{descriptors = []} = AmmReq,
+ ok;
+ _ ->
+ Res
+ end
+ end,
+
+ Msgs =
+ [
+ {msg61a, msg61a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61b, msg61b(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61c, msg61c(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg62a, msg62a(), PlainEDFail, [{dbg,false}],[text,binary,erlang]},
+ {msg62b, msg62b(), PlainDE, [{dbg,false}],[text]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+msgs6(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ Msgs =
+ [
+ {msg71a, msg71a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b01, msg71b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b02, msg71b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b03, msg71b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b04, msg71b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b05, msg71b05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b06, msg71b06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b07, msg71b07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b08, msg71b08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b09, msg71b09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b10, msg71b10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b11, msg71b11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b12, msg71b12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b13, msg71b13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b14, msg71b14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b15, msg71b15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b16, msg71b16(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c01, msg71c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c02, msg71c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c03, msg71c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c04, msg71c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c05, msg71c05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c06, msg71c06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c07, msg71c07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c08, msg71c08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c09, msg71c09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d01, msg71d01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d02, msg71d02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a01, msg72a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a02, msg72a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a03, msg72a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b01, msg72b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b02, msg72b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b03, msg72b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c01, msg72c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c02, msg72c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c03, msg72c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73a, msg73a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b01, msg73b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b02, msg73b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c01, msg73c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c02, msg73c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a01, msg74a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a02, msg74a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a03, msg74a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a04, msg74a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a05, msg74a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a06, msg74a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a01, msg75a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a02, msg75a02(), Plain, [{dbg,false}],[text,binary,erlang]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = ?MSG_LIB:cre_ActionRequest(CtxId,CmdReqs),
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ megaco_trans_req(TransInfo, [Trans|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(Version, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(?VERSION, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Auth, Mess).
+
+msg_reply(Mid, TransId, Actions) ->
+ TR = cre_TransRep(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) ->
+ Action = cre_ActRep(ContextId, CmdReply),
+ Actions = [Action],
+ msg_reply(Mid, TransId, Actions).
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_MegacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_TransAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ReqEvent = cre_ReqedEv("al/of"),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ Msg = msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]),
+ Msg.
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ EventParm = cre_EvParm("strict",["exact"]),
+ ReqEvent = cre_ReqedEv("al/of", [EventParm]),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChResParm(Address,Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_EvParm("strict",["state"]),
+ On = cre_ReqedEv("al/on", [Strict]),
+ Name = "dialplan00",
+ Action = cre_ReqedActs(Name),
+ Ce = cre_ReqedEv("dd/ce", Action),
+ EventsDesc = cre_EvsDesc(2223,[On, Ce]),
+ Signal = cre_Sig("cg/rt"),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22010001"),
+ Parm = cre_EvParm("ds",["916135551212"]),
+ Event = cre_ObsEv("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_ObsEvsDesc(2223,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(recvOnly,[Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 $ "),
+ M2 = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_StreamParms(LCD, LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Signal = cre_Sig("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD2 = cre_LocalControlDesc(sendRecv, [Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ LD2 = cre_LocalRemoteDesc([[V, C, M, A]]),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_LocalRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_StreamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ Signal = cre_Sig("cg/rt"),
+ AmmReq1 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_CmdReq({modReq, AmmReq1}),
+
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_StreamParms(LCD),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms3 = cre_StreamParmsR(RD),
+ StreamDesc3 = cre_StreamDesc(2,Parms3),
+ MediaDesc3 = cre_MediaDesc(StreamDesc3),
+ AmmReq3 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_CmdReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22020002"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(1234,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_ReqedEv("al/on"),
+ EventsDesc = cre_EvsDesc(1235,[On]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_AuditDesc(Tokens),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(sendRecv,[Jit]),
+ LDV = cre_PropParm("v", "0"),
+ LDC = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_PropParm("a", "ptime:30"),
+ LD = cre_LocalRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_PropParm("v", "0"),
+ RDC = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_PropParm("a", "ptime:30"),
+ RD = cre_LocalRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_StreamParms(LCD,LD,RD),
+ StreamDesc = cre_StreamDesc(1,StreamParms),
+ Media = cre_MediaDesc(StreamDesc),
+ PackagesItem = cre_PkgsItem("nt",1),
+ PackagesItem2 = cre_PkgsItem("rtp",1),
+ Stat = cre_StatsParm("rtp/ps","1200"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_AuditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_CmdReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_NotifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_CmdReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_AuditDesc([statsToken]),
+ SubReq = cre_SubReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_SubReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_CmdReq({subtractReq, SubReq}),
+ CmdReq2 = cre_CmdReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_StatsParm("nt/os","45123"),
+ Stat12 = cre_StatsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_AmmsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_StatsParm("rtp/ps","1245"),
+ Stat22 = cre_StatsParm("nt/os", "62345"),
+ Stat23 = cre_StatsParm("rtp/pr", "780"),
+ Stat24 = cre_StatsParm("nt/or", "45123"),
+ Stat25 = cre_StatsParm("rtp/pl", "10"),
+ Stat26 = cre_StatsParm("rtp/jit", "27"),
+ Stat27 = cre_StatsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ Auth = cre_AuthHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+msg50(Mid, APT) ->
+ AD = cre_AuditDesc(asn1_NOVALUE, APT),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AD),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%% IndAudMediaDescriptor:
+msg51(Mid, IATSDorStream) ->
+ IAMD = cre_IndAudMediaDesc(IATSDorStream),
+ IAP = cre_IndAudParam(IAMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg51a() ->
+ msg51a(?MG2_MID).
+msg51a(Mid) ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51b() ->
+ msg51b(?MG2_MID).
+msg51b(Mid) ->
+ PP = cre_IndAudPropertyParm("nt/jit"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51c() ->
+ msg51c(?MG2_MID).
+msg51c(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, 'NULL'),
+ msg51(Mid, IATSD).
+
+msg51d() ->
+ msg51d(?MG2_MID).
+msg51d(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg51(Mid, IATSD).
+
+msg51e() ->
+ msg51e(?MG2_MID).
+msg51e(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc('NULL', asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51f() ->
+ msg51f(?MG2_MID).
+msg51f(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL',
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51g() ->
+ msg51g(?MG2_MID).
+msg51g(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ 'NULL', asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51h() ->
+ msg51h(?MG2_MID).
+msg51h(Mid) ->
+ Name = "nt/jit",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, [IAPP]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+msg51i() ->
+ msg51i(?MG2_MID).
+msg51i(Mid) ->
+ Name = "nt/jit",
+ Name2 = "tdmc/ec",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ IALCD = cre_IndAudLocalControlDesc('NULL', 'NULL', 'NULL',
+ [IAPP, IAPP2]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+%% IndAudEventsDescriptor:
+msg52() ->
+ msg52(?MG2_MID).
+msg52(Mid) ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ IAP = cre_IndAudParam(IAED),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudEventBufferDescriptor:
+msg53() ->
+ msg53(?MG2_MID).
+msg53(Mid) ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ IAP = cre_IndAudParam(IAEBD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudSignalsDescriptor:
+msg54(Mid, Sig) ->
+ IASD = cre_IndAudSigsDesc(Sig),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg54a() ->
+ msg54a(?MG2_MID).
+msg54a(Mid) ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54b() ->
+ msg54b(?MG2_MID).
+msg54b(Mid) ->
+ SN = "dg/d0",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54c() ->
+ msg54c(?MG2_MID).
+msg54c(Mid) ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg54(Mid, SSL).
+
+%% IndAudDigitMapDescriptor:
+msg55() ->
+ msg55(?MG2_MID).
+msg55(Mid) ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ IAP = cre_IndAudParam(IADMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudStatisticsDescriptor:
+msg56() ->
+ msg56(?MG2_MID).
+msg56(Mid) ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudPackagesDescriptor:
+msg57() ->
+ msg57(?MG2_MID).
+msg57(Mid) ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ IAP = cre_IndAudParam(IAPD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% Sum it up:
+msg58_iaMediaDesc_iap(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ cre_IndAudParam(IAMD).
+
+msg58_iaMediaDesc_iap_a() ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaMediaDesc_iap_b() ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaEvsDesc_iap() ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ cre_IndAudParam(IAED).
+
+msg58_iaEvBufDesc_iap() ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ cre_IndAudParam(IAEBD).
+
+msg58_iaSigsDesc_iap(S) ->
+ IASD = cre_IndAudSigsDesc(S),
+ cre_IndAudParam(IASD).
+
+msg58_iaSigsDesc_iap_a() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg58_iaSigsDesc_iap(Sig).
+
+msg58_iaSigsDesc_iap_b() ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg58_iaSigsDesc_iap(SSL).
+
+msg58_iaDigMapDesc_iap() ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ cre_IndAudParam(IADMD).
+
+msg58_iaStatsDesc_iap() ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ cre_IndAudParam(IASD).
+
+msg58_iaPacksDesc_iap() ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ cre_IndAudParam(IAPD).
+
+msg58a() ->
+ msg58a(?MG2_MID).
+msg58a(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_a(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_a(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+msg58b() ->
+ msg58b(?MG2_MID).
+msg58b(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_b(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_b(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Tests some of the changes in the v2 corr 1 (EmergencyOff and ModemDesc)
+
+%% Emergency On/Off (optional) tests
+msg61(EM) ->
+ TS = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TS),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ Cmd = ?MSG_LIB:cre_Command(notifyReq, NotReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CtxReq = ?MSG_LIB:cre_ContextRequest(15, EM),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CtxReq, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg61a() ->
+ msg61(false).
+
+msg61b() ->
+ msg61(true).
+
+msg61c() ->
+ msg61(asn1_NOVALUE).
+
+
+msg62a() ->
+ MT = ?MSG_LIB:cre_ModemType(v18),
+ PP = cre_PropParm("c", "IN IP4 $ "),
+ MD = ?MSG_LIB:cre_ModemDescriptor([MT], [PP]),
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(MD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AmmReq = ?MSG_LIB:cre_AmmRequest(TermIDs, [AmmDesc]),
+ Cmd = ?MSG_LIB:cre_Command(addReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ ActReq = ?MSG_LIB:cre_ActionRequest(2, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg62b() ->
+ MP =
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555
+Transaction = 9898 {
+ Context = 2 {
+ Add = 11111111/00000000/00000000 {
+ Modem[V18] {
+ tdmc/gain=2
+ }
+ }
+ }
+}",
+% MC =
+% "!/" ?VERSION_STR " [124.124.124.222]:55555\nT=9898{C=2{A=11111111/00000000/00000000{MD[V18]{tdmc/gain=2}}}}",
+ list_to_binary(MP).
+
+%% ActionRequest with various combinations of ContextRequest and
+%% ContextAttrAuditRequest
+msg71(CR, CAAR) ->
+ TS1 = cre_TimeNot("19990729", "22000000"),
+ TS2 = cre_TimeNot("19990729", "22000111"),
+ Event1 = cre_ObsEv("al/of",TS1),
+ Event2 = cre_ObsEv("al/on",TS2),
+ Desc1 = cre_ObsEvsDesc(2222,[Event1]),
+ Desc2 = cre_ObsEvsDesc(2222,[Event2]),
+ NR1 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc1),
+ NR2 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc2),
+ Cmd1 = ?MSG_LIB:cre_Command(notifyReq, NR1),
+ Cmd2 = ?MSG_LIB:cre_Command(notifyReq, NR2),
+ CR1 = cre_CmdReq(Cmd1),
+ CR2 = cre_CmdReq(Cmd2),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CR, CAAR, [CR1, CR2]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg71a() ->
+ CR = cre_ContextRequest(),
+ CAAR = cre_ContextAttrAuditRequest(),
+ msg71(CR, CAAR).
+
+msg71b(CR) ->
+ CAAR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71b01() ->
+ CR = cre_ContextRequest(15),
+ msg71b(CR).
+
+msg71b02() ->
+ CR = cre_ContextRequest(true),
+ msg71b(CR).
+
+msg71b03() ->
+ CR = cre_ContextRequest(false),
+ msg71b(CR).
+
+msg71b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(Top),
+ msg71b(CR).
+
+msg71b05() ->
+ CR = cre_ContextRequest(15, true),
+ msg71b(CR).
+
+msg71b06() ->
+ CR = cre_ContextRequest(15, false),
+ msg71b(CR).
+
+msg71b07() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, Top),
+ msg71b(CR).
+
+msg71b08() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top),
+ msg71b(CR).
+
+msg71b09() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, false, Top),
+ msg71b(CR).
+
+msg71b10() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, true),
+ msg71b(CR).
+
+msg71b11() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, false),
+ msg71b(CR).
+
+msg71b12() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b13() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, greaterThan),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b14() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","10"], range, true),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b15() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("nt/jit", ["40","50","50"], sublist, true),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b16() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+ msg71b(CR).
+
+msg71c(CAAR) ->
+ CR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71c01() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c02() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c03() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c04() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c05() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c06() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c07() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c08() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c09() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, CPA),
+ msg71c(CAAR).
+
+msg71d01() ->
+ CR = cre_ContextRequest(15, true),
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', 'NULL'),
+ msg71(CR, CAAR).
+
+msg71d02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_ContextAttrAuditRequest(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg72(ED, CR) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "a=ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdRep = [{addReply, Reply}, {addReply, Reply2}],
+ Action = cre_ActRep(2000, ED, CR, CmdRep),
+ msg_reply(?MGC_MID, 10003, [Action]).
+
+msg72a(CR) ->
+ ED = asn1_NOVALUE,
+ msg72(ED, CR).
+
+msg72a01() ->
+ CR = cre_ContextRequest(false),
+ msg72a(CR).
+
+msg72a02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(Top),
+ msg72a(CR).
+
+msg72a03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, Top),
+ msg72a(CR).
+
+msg72b(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC),
+ msg72(ED, CR).
+
+msg72b01() ->
+ CR = cre_ContextRequest(15, false),
+ msg72b(CR).
+
+msg72b02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, false, Top),
+ msg72b(CR).
+
+msg72b03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, true),
+ msg72b(CR).
+
+msg72c(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ET = ?MSG_LIB:cre_ErrorText("Just another error string"),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC, ET),
+ msg72(ED, CR).
+
+msg72c01() ->
+ CR = cre_ContextRequest(15),
+ msg72c(CR).
+
+msg72c02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg72c(CR).
+
+msg72c03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+ msg72c(CR).
+
+
+msg73() ->
+ Stat1 = cre_StatsParm("rtp/ps"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Stats = [Stat1, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ cre_StatsDesc(Stats).
+
+%% StatisticsDescriptor in AmmDescriptor
+msg73a() ->
+ StatDesc = msg73(),
+ AmmDesc = cre_AmmDesc(StatDesc),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmReq = cre_AmmReq(TermIDs, [AmmDesc]),
+ Cmd = cre_Cmd(addReq, AmmReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% StatisticsDescriptor in IndAudStreamParms
+msg73b1() ->
+ IASD = cre_IndAudStatsDesc("nt/dur"),
+ cre_IndAudStreamParms(IASD).
+
+msg73b2(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc([IAP]),
+ TermID = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ AudReq = cre_AuditReq(TermID, AD),
+ Cmd = cre_Cmd(auditValueRequest, AudReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7311),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7312),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73b01() ->
+ IASP = msg73b1(),
+ IAMD = cre_IndAudMediaDesc(IASP),
+ msg73b2(IAMD).
+
+msg73b02() ->
+ IASP = msg73b1(),
+ SID = cre_StreamID(303),
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg73b2(IAMD).
+
+%% StatisticsDescriptor in StreamParms
+msg73c1() ->
+ StatDesc = msg73(),
+ SP = cre_StreamParms(StatDesc),
+ SID = cre_StreamID(505),
+ cre_StreamDesc(SID, SP).
+
+msg73c2(MD) ->
+ ARP = cre_AuditRetParam(MD),
+ TA = cre_TermAudit([ARP]),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmsRep = cre_AmmsReply(TermIDs, TA),
+ CmdRep = cre_CmdRep(moveReply, AmmsRep),
+ CID = cre_CtxID(606),
+ ActRep = cre_ActRep(CID, [CmdRep]),
+ TransId = cre_TransId(8899),
+ TransRep = cre_TransRep(TransId, [ActRep]),
+ Trans = cre_Trans(TransRep),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73c01() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc(SD),
+ msg73c2(MD).
+
+msg73c02() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc([SD]),
+ msg73c2(MD).
+
+
+%% New Signal (direction and requestID); msg74
+msg74a1(D) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, asn1_NOVALUE).
+
+msg74a2(D, RID) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, RID).
+
+msg74a3(D, RID) ->
+ Name = "al/ri",
+ SID = cre_StreamID(7401),
+ ST = cre_SigType(brief),
+ Dur = 7499,
+ NC = cre_NotifCompl([onTimeOut,otherReason]),
+ KA = cre_BOOLEAN(true),
+ SPL = [],
+ Dir = cre_SigDir(D),
+ cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+msg74a4(Sig) ->
+ SR = cre_SigReq(Sig),
+ SD = cre_SigsDesc([SR]),
+ AD = cre_AmmDesc(SD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AR = cre_AmmReq(TermIDs, [AD]),
+ Cmd = cre_Cmd(modReq, AR),
+ cre_CmdReq(Cmd).
+
+msg74a01() ->
+ Sig = msg74a1(internal),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7411),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7421),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a02() ->
+ Sig = msg74a1(both),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7412),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7422),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a03() ->
+ RID = cre_ReqID(7433),
+ Sig = msg74a2(external, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7413),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7423),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a04() ->
+ RID = cre_ReqID(7434),
+ Sig = msg74a2(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7414),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7424),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a05() ->
+ RID = cre_ReqID(7435),
+ Sig = msg74a3(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7415),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7425),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a06() ->
+ RID = cre_ReqID(7436),
+ Sig = msg74a3(internal, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7416),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7426),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% New ServiceChangeParm (serviceChangeIncompleteFlag); msg75
+msg75a(IncFlag) ->
+ Method = cre_SvcChMethod(restart),
+ Address = cre_SvcChAddr(portNumber, ?DEFAULT_PORT),
+ Reason = "901 mg col boot",
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(Method, Address, [Reason], Profile, IncFlag),
+ TermIDs = [?megaco_root_termination_id],
+ Req = cre_SvcChReq(TermIDs, Parm),
+ Cmd = cre_Cmd(serviceChangeReq, Req),
+ CR = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7501),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7502),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg75a01() ->
+ msg75a(asn1_NOVALUE).
+
+msg75a02() ->
+ msg75a('NULL').
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 2),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+%% --------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+skip(Reason) ->
+ megaco_codec_test_lib:skip(Reason).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M1, M2) ->
+ ?MSG_LIB:chk_MegacoMessage(M1, M2).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_MegacoMessage(Auth, Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Auth, Mess).
+
+cre_MegacoMessage(V, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(V, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+cre_AuthHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_AuthHeader(SecParmIdx, SeqNum, AD).
+
+cre_AuthHeader(Idx, Num, D) ->
+ ?MSG_LIB:cre_AuthenticationHeader(Idx, Num, D).
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_TransRep(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions).
+
+cre_TransAck(First, Last) ->
+ ?MSG_LIB:cre_TransactionAck(First, Last).
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_ActRep(CtxId, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, CmdReps).
+
+cre_ActRep(CtxId, ED, CR, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, ED, CR, CmdReps).
+
+cre_CtxID(Id) ->
+ ?MSG_LIB:cre_ContextID(Id).
+
+cre_ContextRequest() ->
+ ?MSG_LIB:cre_ContextRequest().
+
+cre_ContextRequest(A) ->
+ ?MSG_LIB:cre_ContextRequest(A).
+
+cre_ContextRequest(A, B) ->
+ ?MSG_LIB:cre_ContextRequest(A, B).
+
+cre_ContextRequest(A, B, C) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C).
+
+cre_ContextRequest(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D).
+
+cre_ContextRequest(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D, E).
+
+cre_ContextAttrAuditRequest() ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest().
+
+% cre_ContextAttrAuditRequest(A) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A).
+
+% cre_ContextAttrAuditRequest(A, B) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A, B).
+
+cre_ContextAttrAuditRequest(A, B, C) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C).
+
+cre_ContextAttrAuditRequest(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D).
+
+cre_ContextAttrAuditRequest(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E).
+
+cre_TopologyRequest(From, To, Dir) ->
+ ?MSG_LIB:cre_TopologyRequest(From, To, Dir).
+
+%% Ind Aud related:
+
+cre_IndAudParam(IAP) ->
+ ?MSG_LIB:cre_IndAuditParameter(IAP).
+
+cre_IndAudMediaDesc(D) ->
+ ?MSG_LIB:cre_IndAudMediaDescriptor(D).
+
+cre_IndAudStreamDesc(SID, SP) ->
+ ?MSG_LIB:cre_IndAudStreamDescriptor(SID, SP).
+
+cre_IndAudStreamParms(LCD) ->
+ ?MSG_LIB:cre_IndAudStreamParms(LCD).
+
+cre_IndAudLocalControlDesc(SM, RV, RG, PP) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(SM, RV, RG, PP).
+
+cre_IndAudPropertyParm(Name) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name).
+
+cre_IndAudTermStateDesc(PP) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP).
+
+cre_IndAudTermStateDesc(PP, EBC, SS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS).
+
+cre_IndAudEvsDesc(RID, PN)
+ when is_integer(RID) ->
+ ?MSG_LIB:cre_IndAudEventsDescriptor(RID, PN).
+
+cre_IndAudEvBufDesc(EN, SID) ->
+ ?MSG_LIB:cre_IndAudEventBufferDescriptor(EN, SID).
+
+cre_IndAudSigsDesc(D) ->
+ ?MSG_LIB:cre_IndAudSignalsDescriptor(D).
+
+cre_IndAudSig(SN) ->
+ ?MSG_LIB:cre_IndAudSignal(SN).
+
+cre_IndAudSeqSigList(ID, SL) ->
+ ?MSG_LIB:cre_IndAudSeqSigList(ID, SL).
+
+cre_IndAudDigitMapDesc(DMN) ->
+ ?MSG_LIB:cre_IndAudDigitMapDescriptor(DMN).
+
+cre_IndAudStatsDesc(SN) ->
+ ?MSG_LIB:cre_IndAudStatisticsDescriptor(SN).
+
+cre_IndAudPkgsDesc(PN, PV) ->
+ ?MSG_LIB:cre_IndAudPackagesDescriptor(PN, PV).
+
+%% Parameter related
+cre_PropParm(Name, Val) ->
+ ?MSG_LIB:cre_PropertyParm(Name, [Val]).
+
+cre_PropParm(Name, Vals, Tag, EI) ->
+ ?MSG_LIB:cre_PropertyParm(Name, Vals, Tag, EI).
+
+
+%% Statistics related
+cre_StatsDesc(SPs) ->
+ ?MSG_LIB:cre_StatisticsDescriptor(SPs).
+
+cre_StatsParm(Name) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name).
+
+cre_StatsParm(Name, Val) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name, [Val]).
+
+
+% Event related
+cre_EvParm(Name, Val) ->
+ ?MSG_LIB:cre_EventParameter(Name, Val).
+
+cre_ObsEv(Name, Not) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Not).
+cre_ObsEv(Name, Not, Par) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Par, Not).
+
+cre_ReqedEv(Name) ->
+ ?MSG_LIB:cre_RequestedEvent(Name).
+cre_ReqedEv(Name, Action) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, Action).
+
+
+cre_ObsEvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_ObservedEventsDescriptor(Id, EvList).
+
+cre_EvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_EventsDescriptor(Id, EvList).
+
+
+%% Service change related
+cre_SvcChParm(M, A, R, P) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, P, R).
+
+cre_SvcChParm(M, A, R, P, IF) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, asn1_NOVALUE, P, R, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, IF).
+
+cre_SvcChResParm(A, P) ->
+ ?MSG_LIB:cre_ServiceChangeResParm(A, P).
+
+cre_SvcChReq(Tids, P) ->
+ ?MSG_LIB:cre_ServiceChangeRequest(Tids, P).
+
+cre_SvcChProf(Name, Ver) ->
+ ?MSG_LIB:cre_ServiceChangeProfile(Name, Ver).
+
+cre_SvcChAddr(Tag, Val) ->
+ ?MSG_LIB:cre_ServiceChangeAddress(Tag, Val).
+
+cre_SvcChMethod(M) ->
+ ?MSG_LIB:cre_ServiceChangeMethod(M).
+
+cre_SvcChRep(Tids, Res) ->
+ ?MSG_LIB:cre_ServiceChangeReply(Tids, Res).
+
+
+%% Stream related
+cre_StreamID(Id) ->
+ ?MSG_LIB:cre_StreamID(Id).
+
+cre_StreamParms(Lcd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd).
+cre_StreamParms(Lcd, Ld) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld).
+cre_StreamParms(Lcd, Ld, Rd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld, Rd).
+cre_StreamParmsL(Ld) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, Ld, asn1_NOVALUE).
+cre_StreamParmsR(Rd) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, asn1_NOVALUE, Rd).
+
+cre_StreamDesc(Id, P) ->
+ ?MSG_LIB:cre_StreamDescriptor(Id, P).
+
+
+%% "Local" related
+cre_LocalControlDesc(Mode) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode).
+cre_LocalControlDesc(Mode, Parms) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode, Parms).
+
+cre_LocalRemoteDesc(Grps) ->
+ ?MSG_LIB:cre_LocalRemoteDescriptor(Grps).
+
+
+%% DigitMap related
+cre_DigitMapDesc() ->
+ ?MSG_LIB:cre_DigitMapDescriptor().
+cre_DigitMapDesc(NameOrVal) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(NameOrVal).
+cre_DigitMapDesc(Name, Val) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(Name, Val).
+
+cre_DigitMapValue(Body) ->
+ ?MSG_LIB:cre_DigitMapValue(Body).
+
+cre_DigitMapValue(Body, Start, Short, Long) ->
+ ?MSG_LIB:cre_DigitMapValue(Start, Short, Long, Body).
+
+%% Media related
+cre_MediaDesc(SD) when is_record(SD, 'StreamDescriptor') ->
+ cre_MediaDesc([SD]);
+cre_MediaDesc(SDs) ->
+ ?MSG_LIB:cre_MediaDescriptor(SDs).
+
+
+%% Notify related
+cre_NotifyReq(Tids, EvsDesc) ->
+ ?MSG_LIB:cre_NotifyRequest(Tids, EvsDesc).
+
+cre_NotifyRep(Tids) ->
+ ?MSG_LIB:cre_NotifyReply(Tids).
+
+
+%% Subtract related
+cre_SubReq(Tids, Desc) ->
+ ?MSG_LIB:cre_SubtractRequest(Tids, Desc).
+
+
+%% Audit related
+cre_AuditDesc(Tokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens).
+
+cre_AuditDesc(Tokens, PropertTokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens, PropertTokens).
+
+cre_AuditReq(Tid, Desc) ->
+ ?MSG_LIB:cre_AuditRequest(Tid, Desc).
+
+cre_AuditRes(Tid, Res) ->
+ ?MSG_LIB:cre_AuditResult(Tid, Res).
+
+cre_TermAudit(ARP) ->
+ ?MSG_LIB:cre_TerminationAudit(ARP).
+
+cre_AuditRetParam(D) ->
+ ?MSG_LIB:cre_AuditReturnParameter(D).
+
+
+%% AMM/AMMS related
+cre_AmmDesc(D) ->
+ ?MSG_LIB:cre_AmmDescriptor(D).
+
+cre_AmmReq(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmRequest(Tids, Descs).
+
+cre_AmmsReply(Tids) ->
+ ?MSG_LIB:cre_AmmsReply(Tids).
+cre_AmmsReply(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmsReply(Tids, Descs).
+
+
+%% Command related
+cre_Cmd(Tag, Req) ->
+ ?MSG_LIB:cre_Command(Tag, Req).
+
+cre_CmdReq(Cmd) ->
+ ?MSG_LIB:cre_CommandRequest(Cmd).
+
+cre_CmdRep(Tag, Rep) ->
+ ?MSG_LIB:cre_CommandReply(Tag, Rep).
+
+
+%% Actions related
+cre_ReqedActs(DmName) ->
+ EDM = ?MSG_LIB:cre_EventDM(DmName),
+ ?MSG_LIB:cre_RequestedActions(EDM).
+
+
+%% Signal related
+cre_SigDir(D) ->
+ ?MSG_LIB:cre_SignalDirection(D).
+
+cre_Sig(Name) ->
+ cre_Sig(Name, []).
+
+cre_Sig(Name, SPL) ->
+ ?MSG_LIB:cre_Signal(Name, SPL).
+
+cre_Sig(Name, Dir, RID) ->
+ cre_Sig(Name, [], Dir, RID).
+
+cre_Sig(Name, SPL, Dir, RID) ->
+ cre_Sig(Name, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+cre_SigReq(S) ->
+ ?MSG_LIB:cre_SignalRequest(S).
+
+cre_NotifCompl(NC) ->
+ ?MSG_LIB:cre_NotifyCompletion(NC).
+
+cre_SigType(ST) ->
+ ?MSG_LIB:cre_SignalType(ST).
+
+cre_SigsDesc(D) ->
+ ?MSG_LIB:cre_SignalsDescriptor(D).
+
+%% Others
+cre_ReqID(RID) ->
+ ?MSG_LIB:cre_RequestID(RID).
+
+cre_TimeNot(D,T) ->
+ ?MSG_LIB:cre_TimeNotation(D, T).
+
+cre_PkgsItem(Name, Ver) ->
+ ?MSG_LIB:cre_PackagesItem(Name, Ver).
+
+cre_BOOLEAN(B) ->
+ ?MSG_LIB:cre_BOOLEAN(B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+start_flex_scanner() ->
+ megaco_codec_flex_lib:start().
+
+stop_flex_scanner(Pid) ->
+ megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+l(F,A) ->
+ p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s:" ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "TRC";
+image_of(dbg) ->
+ "DBG";
+image_of(log) ->
+ "LOG";
+image_of(err) ->
+ "ERR";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
diff --git a/lib/megaco/test/megaco_codec_prev3b_test.erl b/lib/megaco/test/megaco_codec_prev3b_test.erl
new file mode 100644
index 0000000000..b5fe4d2038
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_prev3b_test.erl
@@ -0,0 +1,7828 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+-module(megaco_codec_prev3b_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+ flex_compact_dm_timers7/1,
+ flex_compact_dm_timers8/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4299_msg2/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5793_msg01/1,
+ compact_otp5836_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp7431_msg01/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5085_msg8/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5803_msg01/1,
+ pretty_otp5803_msg02/1,
+ pretty_otp5805_msg01/1,
+ pretty_otp5836_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+ pretty_otp8114_msg01/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5085_msg8/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp5803_msg01/1,
+ flex_pretty_otp5803_msg02/1,
+ flex_pretty_otp5805_msg01/1,
+ flex_pretty_otp5836_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0, generate_text_messages/0]).
+
+
+%% ----
+
+-define(V3, prev3b).
+-define(EC_V3, {version3,?V3}).
+-define(EC, [?EC_V3]).
+
+-define(VERSION, 3).
+-define(VERSION_STR, "3").
+-define(MSG_LIB, megaco_test_msg_prev3b_lib).
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs = msgs1(text) ++ msgs4(text) ++ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs1(text),
+ %% Msgs = msgs4(text),
+ %% Msgs = msgs5(text),
+ %% Msgs = msgs6(text),
+ megaco_codec_test_lib:display_text_messages(?VERSION, ?EC, Msgs).
+
+
+generate_text_messages() ->
+ Msgs = msgs1(text) ++ msgs4(text) ++ msgs5(text) ++ msgs6(text),
+ megaco_codec_test_lib:generate_text_messages(?V3, ?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ flex_compact_tickets,
+ pretty_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4299_msg2,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5793_msg01,
+ compact_otp5836_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03
+ ].
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5085_msg8,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5803_msg01,
+ pretty_otp5803_msg02,
+ pretty_otp5805_msg01,
+ pretty_otp5836_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05,
+ pretty_otp8114_msg01
+ ].
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs1(text),
+ %% Msgs = msgs2(text),
+ %% Msgs = msgs3(text),
+ %% Msgs = msgs4(text),
+ %% Msgs = msgs5(text),
+ %% Msgs = msgs6(text),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case pretty_decode_message(false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("flex_pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("flex_pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1(), [Conf]).
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(error, pretty_otp5085_msg2(), [Conf]).
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3(), [Conf]).
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4(), [Conf]).
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5(), [Conf]).
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6(), [Conf]).
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7(), [Conf]).
+
+flex_pretty_otp5085_msg8(suite) ->
+ [];
+flex_pretty_otp5085_msg8(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg8(), [Conf]).
+
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg1(), [Conf]).
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg2(), [Conf]).
+
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5601(ok, pretty_otp5601_msg1(), [Conf]).
+
+
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5793(ok, pretty_otp5793_msg1(), [Conf]).
+
+
+flex_pretty_otp5803_msg01(suite) ->
+ [];
+flex_pretty_otp5803_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5803(pretty_otp5803_msg1(), [Conf]).
+
+flex_pretty_otp5803_msg02(suite) ->
+ [];
+flex_pretty_otp5803_msg02(Config) when is_list(Config) ->
+ d("flex_pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5803(pretty_otp5803_msg2(), [Conf]).
+
+
+flex_pretty_otp5805_msg01(suite) ->
+ [];
+flex_pretty_otp5805_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5805(pretty_otp5805_msg1(), [Conf]).
+
+
+flex_pretty_otp5836_msg01(suite) ->
+ [];
+flex_pretty_otp5836_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5836(compact_otp5836_msg1(), [Conf]).
+
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf) ->
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []);
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg2() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg3() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg4() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a}
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg5() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg6() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg7() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v}
+ }
+ }
+ }
+ }
+ }".
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ %% Msgs = msgs6(text),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(text) ++ msgs2(text) ++ msgs3(text) ++ msgs4(text) ++
+ msgs5(text) ++ msgs6(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,3}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({2,3,4}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,31}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({10,21,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({99,23,11}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers7(suite) ->
+ [];
+flex_compact_dm_timers7(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers7 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers8(suite) ->
+ [];
+flex_compact_dm_timers8(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("01", "09", "01", "02"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers8 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,9,1,2}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s", [T, S, L])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(T, S, L, Z) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s,Z:~s", [T, S, L,Z])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(TMRs) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [TMRs]),
+ lists:flatten(M).
+
+
+verify_dm_timers(TMRs, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ TMRs ->
+ ok;
+ {error, Reason} ->
+ exit({invalid_timer, {TMRs, Reason}});
+ TMRs1 ->
+ exit({invalid_timer_values, {TMRs, TMRs1}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts])
+ when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = asn1_NOVALUE} ->
+ {ok, {T, S, L}};
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = Z} ->
+ {ok, {T, S, L, Z}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ %% Msgs = msgs5(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ %% Msgs = msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(binary) ++ msgs4(binary) ++ msgs5(binary) ++ msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(erlang) ++
+ msgs2(erlang) ++
+ msgs3(erlang) ++
+ msgs4(erlang) ++
+ msgs5(erlang) ++
+ msgs6(erlang),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+% put(severity,trc),
+% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+% erase(severity),
+% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+ %% put(severity,trc),
+ %% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+compact_otp4011(M) ->
+ d("compact_otp4011 -> entry with"
+ "~n M: '~s'", [M]),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ d("compact_otp4011 -> expected error result (so far)", []),
+ case lists:keysearch(reason,1,Error) of
+ {value, {reason,Reason}} ->
+ d("compact_otp4011 -> expected error: "
+ "~n Reason: ~p", [Reason]),
+ case Reason of
+ {0, megaco_text_parser_prev3b,
+ {do_merge_control_streamParms, [A,B]}}
+ when is_list(A) andalso is_record(B, 'LocalControlDescriptor') ->
+ case lists:keysearch(mode,1,A) of
+ {value, {mode, _Mode}}
+ when B#'LocalControlDescriptor'.streamMode =/= asn1_NOVALUE ->
+ d("compact_otp4011 -> expected error",[]),
+ ok;
+ Other ->
+ exit({unexpected_mode_reason, {A,B,Other}})
+ end;
+ Other ->
+ exit({unexpected_reason, Other})
+ end;
+
+ false ->
+ d("compact_otp4011 -> OUPS, wrong kind of error", []),
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ d("compact_otp4011 -> unexpected decode result: ~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/3 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Reason} when is_list(Reason) ->
+ {value, {reason, no_version_found, _}} =
+ lists:keysearch(reason, 1, Reason),
+ {value, {token, [{'SafeChars',_,"megcao/3"}|_]}} =
+ lists:keysearch(token, 1, Reason),
+ ok;
+ Else ->
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, M} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ t("compact_otp4085_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{999999, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> THE ACTUAL ERROR: "
+ "~n LINE NUMBER: 999999"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Module, Crap]),
+ %% ok;
+ exit({decode_failed_999999, Module, Crap});
+ {value, {reason,{Line, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Line, Module, Crap]),
+ ok;
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M1 = compact_otp4085_erroneous_msg() ++ "}",
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, M2} ->
+ l("compact_otp4085_msg1 -> successfull decode"
+ "~n M2: ~p", [M2]),
+ ok;
+ Else ->
+ e("compact_otp4085_msg1 -> decode error"
+ "~n Else: ~p", [Else]),
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4280_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _Msg} ->
+ ok;
+ {error, Error} when is_list(Error) ->
+ t("compact_otp4280_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{Line, Module, Reason} = R}} ->
+ t("compact_otp4280_msg1 -> "
+ "~n Line: ~w"
+ "~n Module: ~w"
+ "~n Reason: ~w", [Line, Module, Reason]),
+ exit({decode_failed, R});
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4299_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% Same message, but this time decoded using the flex scanner
+compact_otp4299_msg2(suite) ->
+ [];
+compact_otp4299_msg2(Config) when is_list(Config) ->
+ d("compact_otp4299_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+
+ {Pid, Conf} = compact_otp4299_msg2_init(),
+
+ %% put(severity,trc),
+ %% put(dbg,true),
+
+ M1 = compact_otp4299_msg(),
+ d("compact_otp4299_msg2 -> M1: ~n~s", [M1]),
+ Bin = list_to_binary(M1),
+ Res = decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], Bin),
+ compact_otp4299_msg2_finish(Pid),
+
+ case Res of
+ {ok, M2} ->
+ d("compact_otp4299_msg2 -> M2: ~n~p", [M2]),
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+compact_otp4299_msg2_init() ->
+ Flag = process_flag(trap_exit, true),
+ Res = (catch start_flex_scanner()),
+ process_flag(trap_exit, Flag),
+ case Res of
+ {error, Reason} ->
+ skip(Reason);
+ {ok, FlexConfig} ->
+ FlexConfig
+ end.
+
+compact_otp4299_msg2_finish(Pid) ->
+ stop_flex_scanner(Pid).
+
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/"
+ ?VERSION_STR
+ " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4359_msg()),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, #'MegacoMessage'{mess = Mess}} ->
+ {transactions, Trans} = Mess#'Message'.messageBody,
+ case Trans of
+ [{transactionRequest,#'TransactionRequest'{transactionId = asn1_NOVALUE}}] ->
+ ok;
+ _ ->
+ exit({unexpected_transactions, Trans})
+ end;
+ Else ->
+ t("compact_otp4359_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg0(), true).
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg1(), false).
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg2(), false).
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg3(), true).
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg4(), true).
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg5(), true).
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg6(), true).
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg7(), true).
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg8(), false).
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg9(), false).
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg10(), false).
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg11(), false).
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg12(), true).
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg20(), bad_mid_duplicate_padding).
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg21(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg22(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg23(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg24(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg25(), bad_mid_ip6addr_length).
+
+compact_otp4920_msg_1(M1, CheckEqual) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin1) of
+ {ok, Msg} ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, ?EC, Msg) of
+ {ok, Bin1} ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when CheckEqual =:= true ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, M1, M2});
+ {ok, _} ->
+ io:format(", encoded:", []),
+ ok;
+ Else ->
+ io:format(", encode failed:", []),
+ exit({unexpected_encode_result, Else})
+ end;
+ Else ->
+ io:format("decode failed:", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4920_msg_2(M1, ExpectedReason) ->
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, Msg} ->
+ io:format("unexpected successfull decode", []),
+ exit({unexpected_encode_ok, Msg});
+ {error, [{reason, {__Line, _Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ {error, [{reason, {_Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ Else ->
+ io:format("unexpected decode result", []),
+ exit({unexpected_decode_result, Else})
+
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg01(), error, ignore).
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg02(), ok, ok).
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok).
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok).
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok).
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok).
+
+compact_otp5186_msg_1(M1, DecodeExpect, EncodeExpect) ->
+ Bin1 = list_to_binary(M1),
+ case compact_decode_message(false, ?EC, Bin1) of
+ {ok, Msg} when DecodeExpect =:= ok ->
+ io:format(" decoded", []),
+ case compact_encode_message(?EC, Msg) of
+ {ok, Bin1} when EncodeExpect =:= ok ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when EncodeExpect =:= ok ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, Msg, M1, M2});
+ {ok, Bin3} when EncodeExpect =:= error ->
+ M3 = binary_to_list(Bin3),
+ io:format(", unexpected encode:", []),
+ exit({unexpected_encode_success, Msg, M1, M3});
+ _Else when EncodeExpect =:= error ->
+ io:format(", encode failed ", []),
+ ok
+ end;
+ {ok, Msg} when DecodeExpect =:= error ->
+ io:format(" decoded", []),
+ exit({unexpected_decode_success, Msg});
+ _Else when DecodeExpect =:= error ->
+ io:format(" decode failed ", []),
+ ok;
+ Else when DecodeExpect =:= ok ->
+ io:format(" decode failed ", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp5186_msg_2(Msg1, EncodeExpect, DecodeExpect) ->
+ case encode_message(megaco_compact_text_encoder, ?EC, Msg1) of
+ {ok, Bin} when EncodeExpect =:= ok ->
+ io:format(" encoded", []),
+ case decode_message(megaco_compact_text_encoder, false, ?EC, Bin) of
+ {ok, Msg1} when DecodeExpect =:= ok ->
+ io:format(", decoded - equal:", []),
+ ok;
+ {ok, Msg2} when DecodeExpect =:= ok ->
+ M = binary_to_list(Bin),
+ case (catch compact_otp5186_check_megamsg(Msg1, Msg2)) of
+ ok ->
+ io:format(", decoded - not equal - ok:", []),
+ ok;
+ {'EXIT', Reason} ->
+ io:format(", decoded - not equal:", []),
+ exit({messages_not_equal, M, Reason, Msg1, Msg2})
+ end;
+ {ok, Msg3} when DecodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(", decoded:", []),
+ exit({unexpected_decode_success, M, Msg1, Msg3});
+ Else when DecodeExpect =:= ok ->
+ M = binary_to_list(Bin),
+ io:format(", decode failed ", []),
+ exit({unexpected_decode_success, Msg1, M, Else});
+ _Else when DecodeExpect =:= error ->
+ io:format(", decode failed ", []),
+ ok
+ end;
+ {ok, Bin} when EncodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(" encoded", []),
+ exit({unexpected_encode_success, Msg1, M});
+ _Else when EncodeExpect =:= error ->
+ io:format(" encode failed ", []),
+ ok;
+ Else when EncodeExpect =:= ok ->
+ io:format(" encode failed ", []),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+%% --
+
+compact_otp5186_check_megamsg(M1, M1) ->
+ ok;
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH,
+ mess = M1},
+ #'MegacoMessage'{authHeader = AH,
+ mess = M2}) ->
+ compact_otp5186_check_mess(M1, M2);
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH1},
+ #'MegacoMessage'{authHeader = AH2}) ->
+ exit({not_equal, authHeader, AH1, AH2}).
+
+compact_otp5186_check_mess(M, M) ->
+ ok;
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId,
+ messageBody = B1},
+ #'Message'{version = V,
+ mId = MId,
+ messageBody = B2}) ->
+ compact_otp5186_check_body(B1, B2);
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId1},
+ #'Message'{version = V,
+ mId = MId2}) ->
+ exit({not_equal, mId, MId1, MId2});
+compact_otp5186_check_mess(#'Message'{version = V1,
+ mId = MId},
+ #'Message'{version = V2,
+ mId = MId}) ->
+ exit({not_equal, version, V1, V2}).
+
+compact_otp5186_check_body(B, B) ->
+ ok;
+compact_otp5186_check_body({transactions, T1}, {transactions, T2}) ->
+ compact_otp5186_check_trans(T1, T2);
+compact_otp5186_check_body({messageError, E1}, {messageError, E2}) ->
+ compact_otp5186_check_merr(E1, E2);
+compact_otp5186_check_body(B1, B2) ->
+ exit({not_equal, messageBody, B1, B2}).
+
+compact_otp5186_check_trans([], []) ->
+ ok;
+compact_otp5186_check_trans([], T2) ->
+ exit({not_equal, transactions, [], T2});
+compact_otp5186_check_trans(T1, []) ->
+ exit({not_equal, transactions, T1, []});
+compact_otp5186_check_trans([Tran1|Trans1], [Tran2|Trans2]) ->
+ compact_otp5186_check_trans(Trans1, Trans2),
+ compact_otp5186_check_transaction(Tran1, Tran2).
+
+compact_otp5186_check_merr(ME, ME) ->
+ ok;
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC,
+ errorText = ET1},
+ #'ErrorDescriptor'{errorCode = EC,
+ errorText = ET2}) ->
+ exit({not_equal, errorText, ET1, ET2});
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC1,
+ errorText = ET},
+ #'ErrorDescriptor'{errorCode = EC2,
+ errorText = ET}) ->
+ exit({not_equal, errorCode, EC1, EC2}).
+
+compact_otp5186_check_transaction(T, T) ->
+ ok;
+compact_otp5186_check_transaction({transactionReply, TR1},
+ {transactionReply, TR2}) ->
+ compact_otp5186_check_transRep(TR1, TR2);
+compact_otp5186_check_transaction(T1, T2) ->
+ exit({unexpected_transactions, T1, T2}).
+
+compact_otp5186_check_transRep(T, T) ->
+ ok;
+compact_otp5186_check_transRep(#'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR2}) ->
+ compact_otp5186_check_transRes(TR1, TR2);
+compact_otp5186_check_transRep(T1, T2) ->
+ exit({unexpected_transaction_reply, T1, T2}).
+
+compact_otp5186_check_transRes(TR, TR) ->
+ ok;
+compact_otp5186_check_transRes({actionReplies, AR1},
+ {actionReplies, AR2}) ->
+ compact_otp5186_check_actReps(AR1, AR2);
+compact_otp5186_check_transRes(TR1, TR2) ->
+ exit({unexpected_transaction_result, TR1, TR2}).
+
+compact_otp5186_check_actReps([], []) ->
+ ok;
+compact_otp5186_check_actReps(AR1, []) ->
+ exit({not_equal, actionReplies, AR1, []});
+compact_otp5186_check_actReps([], AR2) ->
+ exit({not_equal, actionReplies, [], AR2});
+compact_otp5186_check_actReps([AR1|ARs1], [AR2|ARs2]) ->
+ compact_otp5186_check_actRep(AR1, AR2),
+ compact_otp5186_check_actReps(ARs1, ARs2).
+
+compact_otp5186_check_actRep(AR, AR) ->
+ ok;
+compact_otp5186_check_actRep(#'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep2}) ->
+ compact_otp5186_check_cmdReps(CmdRep1, CmdRep2);
+compact_otp5186_check_actRep(AR1, AR2) ->
+ exit({unexpected_actionReply, AR1, AR2}).
+
+compact_otp5186_check_cmdReps([], []) ->
+ ok;
+compact_otp5186_check_cmdReps(CR1, []) ->
+ exit({not_equal, commandReplies, CR1, []});
+compact_otp5186_check_cmdReps([], CR2) ->
+ exit({not_equal, commandReplies, [], CR2});
+compact_otp5186_check_cmdReps([CR1|CRs1], [CR2|CRs2]) ->
+ compact_otp5186_check_cmdRep(CR1, CR2),
+ compact_otp5186_check_cmdReps(CRs1, CRs2).
+
+compact_otp5186_check_cmdRep(CR, CR) ->
+ ok;
+compact_otp5186_check_cmdRep({auditValueReply, AVR1},
+ {auditValueReply, AVR2}) ->
+ compact_otp5186_check_auditReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep({addReply, AVR1},
+ {addReply, AVR2}) ->
+ compact_otp5186_check_ammsReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep(CR1, CR2) ->
+ exit({unexpected_commandReply, CR1, CR2}).
+
+compact_otp5186_check_auditReply(AR, AR) ->
+ ok;
+compact_otp5186_check_auditReply({auditResult, AR1},
+ {auditResult, AR2}) ->
+ compact_otp5186_check_auditRes(AR1, AR2);
+compact_otp5186_check_auditReply(AR1, AR2) ->
+ exit({unexpected_auditReply, AR1, AR2}).
+
+compact_otp5186_check_ammsReply(AR, AR) ->
+ ok;
+compact_otp5186_check_ammsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = ID,
+ terminationAudit = TA2}) ->
+ %% This is just to simplify the test
+ F = fun(asn1_NOVALUE) -> [];
+ (E) -> E
+ end,
+ compact_otp5186_check_termAudit(F(TA1), F(TA2));
+compact_otp5186_check_ammsReply(AR1, AR2) ->
+ exit({unexpected_ammsReply, AR1, AR2}).
+
+compact_otp5186_check_auditRes(AR, AR) ->
+ ok;
+compact_otp5186_check_auditRes(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR2}) ->
+ compact_otp5186_check_termAuditRes(TAR1, TAR2);
+compact_otp5186_check_auditRes(AR1, AR2) ->
+ exit({unexpected_auditResult, AR1, AR2}).
+
+compact_otp5186_check_termAuditRes([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAuditRes(TAR1, []);
+compact_otp5186_check_termAuditRes(TAR1, []) ->
+ exit({not_equal, termAuditRes, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([], [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAuditRes([], TAR2);
+compact_otp5186_check_termAuditRes([], TAR2) ->
+ exit({not_equal, termAuditRes, [], TAR2});
+compact_otp5186_check_termAuditRes([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAuditRes(TAR1, TAR2).
+
+compact_otp5186_check_termAudit([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAudit(TAR1, []);
+compact_otp5186_check_termAudit(TAR1, []) ->
+ exit({not_equal, termAudit, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([],
+ [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAudit([], TAR2);
+compact_otp5186_check_termAudit([], TAR2) ->
+ exit({not_equal, termAudit, [], TAR2});
+compact_otp5186_check_termAudit([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAudit(TAR1, TAR2).
+
+compact_otp5186_check_auditRetParm(ARP, ARP) ->
+ ok;
+compact_otp5186_check_auditRetParm({emptyDescriptors, AD1},
+ {emptyDescriptors, AD2}) ->
+ compact_otp5186_check_auditDesc(AD1, AD2);
+compact_otp5186_check_auditRetParm(ARP1, ARP2) ->
+ exit({unexpected_auditRetParm, ARP1, ARP2}).
+
+compact_otp5186_check_auditDesc(AD, AD) ->
+ ok;
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = L1,
+ auditPropertyToken = asn1_NOVALUE},
+ #'AuditDescriptor'{auditToken = L2,
+ auditPropertyToken = asn1_NOVALUE}) ->
+ compact_otp5186_check_auditDesc_auditItems(L1, L2);
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT2}) ->
+ compact_otp5186_check_auditDesc_apt(APT1, APT2);
+compact_otp5186_check_auditDesc(AD1, AD2) ->
+ exit({unexpected_auditDesc, AD1, AD2}).
+
+compact_otp5186_check_auditDesc_auditItems([], []) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItems(AI1, []) ->
+ exit({not_equal, auditItems, AI1, []});
+compact_otp5186_check_auditDesc_auditItems([], AI2) ->
+ exit({not_equal, auditItems, [], AI2});
+compact_otp5186_check_auditDesc_auditItems([AI1|AIs1], [AI2|AIs2]) ->
+ compact_otp5186_check_auditDesc_auditItem(AI1, AI2),
+ compact_otp5186_check_auditDesc_auditItems(AIs1, AIs2).
+
+compact_otp5186_check_auditDesc_auditItem(AI, AI) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItem(AI1, AI2) ->
+ exit({not_equal, auditItem, AI1, AI2}).
+
+compact_otp5186_check_auditDesc_apt(APT, APT) ->
+ ok;
+compact_otp5186_check_auditDesc_apt(APT1, APT2) ->
+ exit({not_equal, auditPropertyToken, APT1, APT2}).
+
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5793(ok, pretty_otp5793_msg1()).
+
+compact_otp5793(Expected, Msg) ->
+ expect_codec_e(Expected, megaco_compact_text_encoder, Msg, []).
+
+
+compact_otp5836_msg01(suite) ->
+ [];
+compact_otp5836_msg01(Config) when is_list(Config) ->
+ d("compact_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ compact_otp5836(ok, compact_otp5836_msg1()).
+
+compact_otp5836(Expected, Msg) ->
+ expect_codec_e(Expected, megaco_compact_text_encoder, Msg, []).
+
+
+compact_otp5836_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 3,
+ {deviceName,"bs_sbg_4/34"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 12,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 4294967295,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {error, {'ErrorDescriptor', 431, asn1_NOVALUE}}}
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg01()).
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg02()).
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg03()).
+
+compact_otp5993(Expected, Msg) ->
+ expect_codec_e(Expected, megaco_compact_text_encoder, Msg, []).
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ ok.
+
+compact_otp6017(BadCID) ->
+ Conf = ?EC,
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ exit({unexpected_reason, ActualReason});
+ false ->
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ exit({unexpected_decode_result, Crap})
+ end.
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "MEGACO/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+flex_compact_otp7431_msg01(suite) ->
+ [];
+flex_compact_otp7431_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg1(),
+ case pretty_encode_message(?EC, Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, BinMsg),
+ ok = chk_MegacoMessage(Msg0, Msg1);
+ Else ->
+ t("pretty_otp4632_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg2(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, BinMsg),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder,
+ false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ Msg0 = Msg1,
+ ok;
+ Else ->
+ t("pretty_otp4632_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4632_msg4_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4_chk([], []) ->
+ exit(messages_not_eq);
+pretty_otp4632_msg4_chk([], Rest1) ->
+ exit({messages_not_eq1, Rest1});
+pretty_otp4632_msg4_chk(Rest0, []) ->
+ exit({messages_not_eq0, Rest0});
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest0],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1]) ->
+ ok;
+pretty_otp4632_msg4_chk([_|Rest0], [_|Rest1]) ->
+ pretty_otp4632_msg4_chk(Rest0,Rest1).
+
+
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg1(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg0) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ ?EC, Bin),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, ?EC, Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4710_msg2_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(Msg,Msg) ->
+ ok;
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ io:format("pretty_otp4945_msg1 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeMethod]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason, serviceChangeMethod]} ->
+ ok;
+ {missing_required_serviceChangeParm, [serviceChangeMethod, serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg5(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_serviceChangeParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg5 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg6(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_serviceChangeParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg6 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4949_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_servChgReplyParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg2 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_servChgReplyParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg3 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = pretty_otp5068_msg1(),
+ case encode_message(megaco_pretty_text_encoder, ?EC, Msg) of
+ {error, Reason} ->
+% io:format("pretty_otp5068_msg1 -> "
+% "~n Reason: ~w"
+% "~n", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} ->
+% io:format("pretty_otp5068_msg1 -> successfull encode:"
+% "~n~s~n", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, ?EC, Bin) of
+ {ok, _} ->
+% io:format("pretty_otp5068_msg1 -> ok~n", []),
+ ok;
+ Else ->
+% io:format("pretty_otp5068_msg1 -> ~n~p~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+}.
+
+
+
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1()).
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(error, pretty_otp5085_msg2()).
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3()).
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4()).
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5()).
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6()).
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7()).
+
+pretty_otp5085_msg8(suite) ->
+ [];
+pretty_otp5085_msg8(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+% put(severity, trc),
+ Res = (catch pretty_otp5085(ok, pretty_otp5085_msg8())),
+% erase(dbg),
+% erase(severity),
+ case Res of
+ ok ->
+ ok;
+ {'EXIT', Reason} ->
+ exit(Reason)
+ end.
+
+pretty_otp5085(Expected, Msg) ->
+ pretty_otp5085(Expected, Msg, []).
+
+pretty_otp5085(Expected, Msg, Conf) ->
+ t("pretty_otp5085 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5085 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5085 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5085 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5085 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5085 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5085 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5085 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg8() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 8,
+ emergency = true,
+ topologyReq =
+ [#'TopologyRequest'{terminationFrom = From1,
+ terminationTo = To1,
+ topologyDirection = bothway},
+ #'TopologyRequest'{terminationFrom = From2,
+ terminationTo = To2,
+ topologyDirection = oneway}
+ ],
+ iepscallind = true,
+ contextProp = [cre_PropParm("tdmc/gain", "2")]},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg1()).
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg2()).
+
+pretty_otp5600(Expected, Msg) ->
+ pretty_otp5600(Expected, Msg, []).
+
+pretty_otp5600(Expected, Msg, Conf) ->
+ t("pretty_otp5600 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5600 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5600 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5600 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5600 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5600 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5600 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5600 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5601(ok, pretty_otp5601_msg1()).
+
+pretty_otp5601(Expected, Msg) ->
+ pretty_otp5601(Expected, Msg, []).
+
+pretty_otp5601(Expected, Msg, Conf) ->
+ t("pretty_otp5601 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, [?EC_V3|Conf], Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5601 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5601 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5601 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5601 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5601 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5601 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5601 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(severity,trc),
+% put(dbg,true),
+ pretty_otp5793(ok, pretty_otp5793_msg1()).
+
+pretty_otp5793(Expected, Msg) ->
+ expect_codec_e(Expected, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5793(Expected, Msg, Conf) ->
+ expect_codec_e(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',3,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+
+pretty_otp5803_msg01(suite) ->
+ [];
+pretty_otp5803_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5803(pretty_otp5803_msg1()).
+
+pretty_otp5803_msg02(suite) ->
+ [];
+pretty_otp5803_msg02(Config) when is_list(Config) ->
+ d("pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5803(pretty_otp5803_msg2()).
+
+pretty_otp5803(Msg) ->
+ expect_codec_d(ok, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5803(Msg, Conf) ->
+ expect_codec_d(ok, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5803_msg1() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ },
+ Stream=2{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+pretty_otp5803_msg2() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+pretty_otp5805_msg01(suite) ->
+ [];
+pretty_otp5805_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ pretty_otp5805(pretty_otp5805_msg1()).
+
+pretty_otp5805(Msg) ->
+ expect_codec_d(error, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5805(Msg, Conf) ->
+ expect_codec_d(error, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5805_msg1() ->
+"MEGACO/4 [134.138.234.29]
+Transaction=1{
+ Context=*{
+ AuditValue=ip/0/*{
+ Audit{}
+ }
+ }
+}".
+
+
+pretty_otp5836_msg01(suite) ->
+ [];
+pretty_otp5836_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ pretty_otp5836(compact_otp5836_msg1()).
+
+pretty_otp5836(Msg) ->
+ expect_codec_e(ok, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5836(Msg, Conf) ->
+ expect_codec_e(ok, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5882().
+
+pretty_otp5882() ->
+ otp5882(megaco_pretty_text_encoder, []).
+
+otp5882(Codec, Conf) ->
+ Msg = pretty_otp5882_msg01(),
+ case (catch encode_message(Codec, [?EC_V3|Conf], Msg)) of
+ {error, {message_encode_failed, {error, {ActualReason, _}}, _}} ->
+ case ActualReason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ exit({unexpected_error_actual_reason, ActualReason})
+ end;
+ {error, Reason} ->
+ exit({unexpected_error_reason, Reason});
+ {ok, Bin} ->
+ exit({unexpected_encode_sucess, binary_to_list(Bin)})
+ end.
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ %% erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490(Msg, Conf) ->
+ pretty_otp6490(Msg, Conf, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode) ->
+ pretty_otp6490(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp6490(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+otp6490(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ case (catch encode_message(Codec, [?EC_V3|Conf], Msg)) of
+ {error, _Reason} when ExpectedEncode == error ->
+ ok;
+ {error, Reason} when ExpectedEncode == ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode == error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode == ok ->
+ case decode_message(Codec, false, [?EC_V3|Conf], Bin) of
+ {ok, Msg} when ExpectedDecode == ok ->
+ ok;
+ {ok, Msg} when ExpectedDecode == error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode == ok ->
+ exit({unexpected_decode_result, Msg, Msg2});
+ {ok, Msg2} when ExpectedDecode == error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode == error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_DigitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_DigitMapDesc(),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[],
+ asn1_NOVALUE}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+
+
+pretty_otp8114_msg01(suite) ->
+ [];
+pretty_otp8114_msg01(Config) when is_list(Config) ->
+ put(severity, trc),
+ put(dbg, true),
+ d("pretty_otp8114_msg01 -> entry", []),
+ ok = otp8114( pretty_otp8114_msg01(), megaco_pretty_text_encoder, ?EC),
+ erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp8114_msg01() ->
+ "MEGACO/" ?VERSION_STR " [10.10.10.10]:1234\nTransaction = 1 {\n\tContext =\n1 {\n\t\tModify = ip/1/1/1 {\n\t\t\tMedia {\n\t\t\t\tStream = 1\n{\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode =\nSendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 1\n{\n\t\t\t\tadid/ipstop\n{\n\t\t\t\t\tdt=30,\n\t\t\t\t\tdir=\"BOTH\"\n\t\t\t\t},\n\t\t\t\tg/cause\n\n\t\t\t}\n\t\t}\n\t}\n}".
+
+
+otp8114(InitialMessage, Codec, Conf) ->
+ Decode = fun(M) -> Codec:decode_message(Conf, M) end,
+ Encode = fun(B) -> Codec:encode_message(Conf, B) end,
+ InitialData = InitialMessage,
+ Instructions =
+ [
+ %% List to binary
+ megaco_codec_test_lib:expect_instruction(
+ "Convert (initial) message to a binary",
+ fun(Msg) when is_list(Msg) ->
+ %% io:format("~s~n", [Msg]),
+ {ok, list_to_binary(Msg)};
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ {ok, Bin};
+ (Bad, _Msg) ->
+ {error, {failed_to_binary, Bad}}
+ end),
+
+ %% Initial decode
+ megaco_codec_test_lib:expect_instruction(
+ "Decode (initial) message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {initial_decode_failed, Bad}}
+ end),
+
+ %% Encode
+ megaco_codec_test_lib:expect_instruction(
+ "Encode message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ %% io:format("~s~n", [binary_to_list(Bin)]),
+ {ok, Bin};
+ (Bad, _) ->
+ {error, {encode_failed, Bad}}
+ end),
+
+ %% Decode
+ megaco_codec_test_lib:expect_instruction(
+ "(final) Decode message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {decode_failed, Bad}}
+ end)
+ ],
+ megaco_codec_test_lib:expect_exec(Instructions, InitialData).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+expect_codec_e(error, Codec, Msg, Conf) ->
+ Exec =
+ [
+ {1, "Encode (initial) message",
+ fun(M) ->
+ (catch encode_message(Codec, [?EC_V3|Conf], M))
+ end,
+ fun({error, _}, _) ->
+ {ok, done};
+ ({ok, Bin}, _) ->
+ {error, {unexpected_encode_success, binary_to_list(Bin)}};
+ (Else, _) ->
+ {error, {unexpected_encode_result, Else}}
+ end}
+ ],
+ exec(Exec, Msg);
+
+expect_codec_e(ok, Codec, Msg, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Exec =
+ [
+ {1, "Encode (initial) message",
+ fun(M) ->
+ (catch encode_message(Codec, Conf, M))
+ end,
+ fun({ok, Bin}, M) ->
+ {ok, {Bin, M}};
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Else, _) ->
+ {error, {unexpected_encode_result, Else}}
+ end},
+ {2, "Decode message",
+ fun({Bin, _}) ->
+ (catch decode_message(Codec, false, Conf, Bin))
+ end,
+ fun({ok, Msg1}, {_, Msg1}) ->
+ {ok, done};
+ ({ok, Msg2}, {_, Msg1}) ->
+ case (catch chk_MegacoMessage(Msg1, Msg2)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ (Else, _) ->
+ {error, {unexpected_decode_result, Else}}
+ end}
+ ],
+ exec(Exec, Msg).
+
+
+expect_codec_d(error, Codec, Msg, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Exec =
+ [
+ {1, "Decode (initial) message",
+ fun(Bin) ->
+ (catch decode_message(Codec, false, Conf, Bin))
+ end,
+ fun({error, _}, _) ->
+ {ok, done};
+ ({ok, DecMsg}, _) ->
+ {error, {unexpected_decode_success, DecMsg}};
+ (Else, _) ->
+ {error, {unexpected_decode_result, Else}}
+ end}
+ ],
+ exec(Exec, list_to_binary(Msg));
+
+expect_codec_d(ok, Codec, Msg, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Exec =
+ [
+ {1, "Decode (initial) message",
+ fun(Bin) ->
+ (catch decode_message(Codec, false, Conf, Bin))
+ end,
+ fun({ok, DecMsg}, Bin) ->
+ {ok, {DecMsg, Bin}};
+ ({error, R}, _) ->
+ {Line, Mod, Reason} =
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, {L, M, Raw}}} when is_list(Raw) ->
+ {L, M, lists:flatten(Raw)};
+ {value, {reason, {L, M, Raw}}} ->
+ {L, M, Raw}
+ end,
+ {value, {token, Tokens}} = lists:keysearch(token, 1, R),
+ {error, {unexpected_decode_failure, {Mod, Line, Reason, Tokens}}};
+ (Else, _) ->
+ {error, {unexpected_decode_result, Else}}
+ end},
+ {2, "Encode message",
+ fun({DecMsg, _}) ->
+ (catch encode_message(Codec, Conf, DecMsg))
+ end,
+ fun({ok, Bin}, {_, Bin}) ->
+ {ok, done};
+ ({ok, Bin}, {DecMsg, _}) ->
+ {ok, {DecMsg, Bin}};
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Else, _) ->
+ {error, {unexpected_encode_result, Else}}
+ end},
+ {3, "Decode message (if binaries not equal)",
+ fun(done) ->
+ done;
+ ({_, Bin}) ->
+ (catch decode_message(Codec, false, Conf, Bin))
+ end,
+ fun(done, _) ->
+ {ok, done};
+ ({ok, DecMsg}, {DecMsg, _}) ->
+ {ok, done};
+ ({ok, DecMsg2}, {DecMsg1, _}) ->
+ case (catch chk_MegacoMessage(DecMsg1, DecMsg2)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ ({error, Reason}, _) ->
+ {error, {unexpected_decode_failure, Reason}};
+ (Else, _) ->
+ {error, {unexpected_decode_result, Else}}
+ end}
+ ],
+ exec(Exec, list_to_binary(Msg)).
+
+
+exec([], _) ->
+ io:format("~n", []),
+ ok;
+exec([{Num, _Desc, Cmd, Verify}|T], Data) ->
+ io:format("~n Exec command ~w: ~s => ", [Num, _Desc]),
+ case Verify((catch Cmd(Data)), Data) of
+ {ok, NewData} ->
+ io:format("ok", []),
+ exec(T, NewData);
+ {error, Reason} ->
+ io:format("error", []),
+ {error, {Num, Reason}}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ [M || {_, M, _, _} <- msgs(text)].
+
+msgs(Encoding) ->
+ msgs1(Encoding) ++
+ msgs2(Encoding) ++ msgs3(Encoding) ++ msgs4(Encoding) ++
+ msgs5(Encoding) ++ msgs6(Encoding).
+
+msgs1(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+
+msgs2(_) ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, ?EC, M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+msgs4(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg51a, msg51a(), Plain, [{dbg, false}]},
+ {msg51b, msg51b(), Plain, [{dbg, false}]},
+ {msg51c, msg51c(), Plain, [{dbg, false}]},
+ {msg51d, msg51d(), Plain, [{dbg, false}]},
+ {msg51e, msg51e(), Plain, [{dbg, false}]},
+ {msg51f, msg51f(), Plain, [{dbg, false}]},
+ {msg51g, msg51g(), Plain, [{dbg, false}]},
+ {msg51h, msg51h(), Plain, [{dbg, false}]},
+ {msg51i, msg51i(), Plain, [{dbg, false}]},
+ {msg52, msg52(), Plain, [{dbg, false}]},
+ {msg53, msg53(), Plain, [{dbg, false}]},
+ {msg54a, msg54a(), Plain, [{dbg, false}]},
+ {msg54b, msg54b(), Plain, [{dbg, false}]},
+ {msg54c, msg54c(), Plain, [{dbg, false}]},
+ {msg55, msg55(), Plain, [{dbg, false}]},
+ {msg56, msg56(), Plain, [{dbg, false}]},
+ {msg57, msg57(), Plain, [{dbg, false}]},
+ {msg58a, msg58a(), Plain, [{dbg, false}]},
+ {msg58b, msg58b(), Plain, [{dbg, false}]}
+ ].
+
+
+msgs5(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ PlainEDFail =
+ fun(Codec, DD, Ver, EC, M) ->
+ Res =
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M),
+ case Res of
+ {error, {message_encode_failed, Reason, _M}} ->
+ case Reason of
+ {error, {{deprecated, _}, _}} ->
+ ok;
+ _ ->
+ Res
+ end;
+ _ ->
+ Res
+ end
+ end,
+
+ PlainDE =
+ fun(Codec, _DD, Ver, EC, B) ->
+ Res =
+ megaco_codec_test_lib:decode_message(Codec, false, Ver,
+ EC, B),
+ case Res of
+ {ok, M} ->
+ #'MegacoMessage'{mess = Mess} = M,
+ #'Message'{messageBody = {transactions, TRs}} = Mess,
+ [{transactionRequest, TR}] = TRs,
+ #'TransactionRequest'{actions = Actions} = TR,
+ [Action] = Actions,
+ #'ActionRequest'{commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {addReq,AmmReq} = Cmd,
+ #'AmmRequest'{descriptors = []} = AmmReq,
+ ok;
+ _ ->
+ Res
+ end
+ end,
+
+ Msgs =
+ [
+ {msg61a, msg61a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61b, msg61b(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61c, msg61c(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg62a, msg62a(), PlainEDFail, [{dbg,false}],[text,binary,erlang]},
+ {msg62b, msg62b(), PlainDE, [{dbg,false}],[text]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+msgs6(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ Msgs =
+ [
+ {msg71a, msg71a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b01, msg71b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b02, msg71b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b03, msg71b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b04, msg71b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b05, msg71b05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b06, msg71b06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b07, msg71b07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b08, msg71b08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b09, msg71b09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b10, msg71b10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b11, msg71b11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b12, msg71b12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b13, msg71b13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b14, msg71b14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b15, msg71b15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b16, msg71b16(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b17, msg71b17(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b18, msg71b18(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c01, msg71c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c02, msg71c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c03, msg71c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c04, msg71c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c05, msg71c05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c06, msg71c06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c07, msg71c07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c08, msg71c08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c09, msg71c09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d01, msg71d01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d02, msg71d02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d03, msg71d03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a01, msg72a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a02, msg72a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a03, msg72a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b01, msg72b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b02, msg72b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b03, msg72b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b04, msg72b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c01, msg72c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c02, msg72c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c03, msg72c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c04, msg72c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73a, msg73a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b01, msg73b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b02, msg73b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c01, msg73c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c02, msg73c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a01, msg74a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a02, msg74a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a03, msg74a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a04, msg74a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a05, msg74a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a06, msg74a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a01, msg75a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a02, msg75a02(), Plain, [{dbg,false}],[text,binary,erlang]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = ?MSG_LIB:cre_ActionRequest(CtxId,CmdReqs),
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ megaco_trans_req(TransInfo, [Trans|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(Version, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(?VERSION, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Auth, Mess).
+
+msg_reply(Mid, TransId, Actions) ->
+ TR = cre_TransRep(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) ->
+ Action = cre_ActRep(ContextId, CmdReply),
+ Actions = [Action],
+ msg_reply(Mid, TransId, Actions).
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_MegacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_TransAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ReqEvent = cre_ReqedEv("al/of"),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ Msg = msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]),
+ Msg.
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ EventParm = cre_EvParm("strict",["exact"]),
+ ReqEvent = cre_ReqedEv("al/of", [EventParm]),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChResParm(Address,Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_EvParm("strict",["state"]),
+ On = cre_ReqedEv("al/on", [Strict]),
+ Name = "dialplan00",
+ Action = cre_ReqedActs(Name),
+ Ce = cre_ReqedEv("dd/ce", Action),
+ EventsDesc = cre_EvsDesc(2223,[On, Ce]),
+ Signal = cre_Sig("cg/rt"),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22010001"),
+ Parm = cre_EvParm("ds",["916135551212"]),
+ Event = cre_ObsEv("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_ObsEvsDesc(2223,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(recvOnly,[Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 $ "),
+ M2 = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_StreamParms(LCD, LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Signal = cre_Sig("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD2 = cre_LocalControlDesc(sendRecv, [Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ LD2 = cre_LocalRemoteDesc([[V, C, M, A]]),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_LocalRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_StreamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ Signal = cre_Sig("cg/rt"),
+ AmmReq1 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_CmdReq({modReq, AmmReq1}),
+
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_StreamParms(LCD),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms3 = cre_StreamParmsR(RD),
+ StreamDesc3 = cre_StreamDesc(2,Parms3),
+ MediaDesc3 = cre_MediaDesc(StreamDesc3),
+ AmmReq3 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_CmdReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22020002"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(1234,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_ReqedEv("al/on"),
+ EventsDesc = cre_EvsDesc(1235,[On]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_AuditDesc(Tokens),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(sendRecv,[Jit]),
+ LDV = cre_PropParm("v", "0"),
+ LDC = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_PropParm("a", "ptime:30"),
+ LD = cre_LocalRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_PropParm("v", "0"),
+ RDC = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_PropParm("a", "ptime:30"),
+ RD = cre_LocalRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_StreamParms(LCD,LD,RD),
+ StreamDesc = cre_StreamDesc(1,StreamParms),
+ Media = cre_MediaDesc(StreamDesc),
+ PackagesItem = cre_PkgsItem("nt",1),
+ PackagesItem2 = cre_PkgsItem("rtp",1),
+ Stat = cre_StatsParm("rtp/ps","1200"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_AuditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_CmdReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_NotifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_CmdReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_AuditDesc([statsToken]),
+ SubReq = cre_SubReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_SubReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_CmdReq({subtractReq, SubReq}),
+ CmdReq2 = cre_CmdReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_StatsParm("nt/os","45123"),
+ Stat12 = cre_StatsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_AmmsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_StatsParm("rtp/ps","1245"),
+ Stat22 = cre_StatsParm("nt/os", "62345"),
+ Stat23 = cre_StatsParm("rtp/pr", "780"),
+ Stat24 = cre_StatsParm("nt/or", "45123"),
+ Stat25 = cre_StatsParm("rtp/pl", "10"),
+ Stat26 = cre_StatsParm("rtp/jit", "27"),
+ Stat27 = cre_StatsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ Auth = cre_AuthHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+msg50(Mid, APT) ->
+ AD = cre_AuditDesc(asn1_NOVALUE, APT),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AD),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%% IndAudMediaDescriptor:
+msg51(Mid, IATSDorStream) ->
+ IAMD = cre_IndAudMediaDesc(IATSDorStream),
+ IAP = cre_IndAudParam(IAMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg51a() ->
+ msg51a(?MG2_MID).
+msg51a(Mid) ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51b() ->
+ msg51b(?MG2_MID).
+msg51b(Mid) ->
+ PP = cre_IndAudPropertyParm("nt/jit"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51c() ->
+ msg51c(?MG2_MID).
+msg51c(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, 'NULL'),
+ msg51(Mid, IATSD).
+
+msg51d() ->
+ msg51d(?MG2_MID).
+msg51d(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg51(Mid, IATSD).
+
+msg51e() ->
+ msg51e(?MG2_MID).
+msg51e(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc('NULL', asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51f() ->
+ msg51f(?MG2_MID).
+msg51f(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL',
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51g() ->
+ msg51g(?MG2_MID).
+msg51g(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ 'NULL', asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51h() ->
+ msg51h(?MG2_MID).
+msg51h(Mid) ->
+ Name = "nt/jit",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, [IAPP]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+msg51i() ->
+ msg51i(?MG2_MID).
+msg51i(Mid) ->
+ Name = "nt/jit",
+ Name2 = "tdmc/ec",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ IALCD = cre_IndAudLocalControlDesc('NULL', 'NULL', 'NULL',
+ [IAPP, IAPP2]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+%% IndAudEventsDescriptor:
+msg52() ->
+ msg52(?MG2_MID).
+msg52(Mid) ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ IAP = cre_IndAudParam(IAED),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudEventBufferDescriptor:
+msg53() ->
+ msg53(?MG2_MID).
+msg53(Mid) ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ IAP = cre_IndAudParam(IAEBD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudSignalsDescriptor:
+msg54(Mid, Sig) ->
+ IASD = cre_IndAudSigsDesc(Sig),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg54a() ->
+ msg54a(?MG2_MID).
+msg54a(Mid) ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54b() ->
+ msg54b(?MG2_MID).
+msg54b(Mid) ->
+ SN = "dg/d0",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54c() ->
+ msg54c(?MG2_MID).
+msg54c(Mid) ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg54(Mid, SSL).
+
+%% IndAudDigitMapDescriptor:
+msg55() ->
+ msg55(?MG2_MID).
+msg55(Mid) ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ IAP = cre_IndAudParam(IADMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudStatisticsDescriptor:
+msg56() ->
+ msg56(?MG2_MID).
+msg56(Mid) ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudPackagesDescriptor:
+msg57() ->
+ msg57(?MG2_MID).
+msg57(Mid) ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ IAP = cre_IndAudParam(IAPD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% Sum it up:
+msg58_iaMediaDesc_iap(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ cre_IndAudParam(IAMD).
+
+msg58_iaMediaDesc_iap_a() ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaMediaDesc_iap_b() ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaEvsDesc_iap() ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ cre_IndAudParam(IAED).
+
+msg58_iaEvBufDesc_iap() ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ cre_IndAudParam(IAEBD).
+
+msg58_iaSigsDesc_iap(S) ->
+ IASD = cre_IndAudSigsDesc(S),
+ cre_IndAudParam(IASD).
+
+msg58_iaSigsDesc_iap_a() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg58_iaSigsDesc_iap(Sig).
+
+msg58_iaSigsDesc_iap_b() ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg58_iaSigsDesc_iap(SSL).
+
+msg58_iaDigMapDesc_iap() ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ cre_IndAudParam(IADMD).
+
+msg58_iaStatsDesc_iap() ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ cre_IndAudParam(IASD).
+
+msg58_iaPacksDesc_iap() ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ cre_IndAudParam(IAPD).
+
+msg58a() ->
+ msg58a(?MG2_MID).
+msg58a(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_a(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_a(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+msg58b() ->
+ msg58b(?MG2_MID).
+msg58b(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_b(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_b(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Tests some of the changes in the v2 corr 1 (EmergencyOff and ModemDesc)
+
+%% Emergency On/Off (optional) tests
+msg61(EM) ->
+ TS = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TS),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ Cmd = ?MSG_LIB:cre_Command(notifyReq, NotReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CtxReq = ?MSG_LIB:cre_ContextRequest(15, EM),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CtxReq, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg61a() ->
+ msg61(false).
+
+msg61b() ->
+ msg61(true).
+
+msg61c() ->
+ msg61(asn1_NOVALUE).
+
+
+msg62a() ->
+ MT = ?MSG_LIB:cre_ModemType(v18),
+ PP = cre_PropParm("c", "IN IP4 $ "),
+ MD = ?MSG_LIB:cre_ModemDescriptor([MT], [PP]),
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(MD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AmmReq = ?MSG_LIB:cre_AmmRequest(TermIDs, [AmmDesc]),
+ Cmd = ?MSG_LIB:cre_Command(addReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ ActReq = ?MSG_LIB:cre_ActionRequest(2, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg62b() ->
+ MP =
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555
+Transaction = 9898 {
+ Context = 2 {
+ Add = 11111111/00000000/00000000 {
+ Modem[V18] {
+ tdmc/gain=2
+ }
+ }
+ }
+}",
+% MC =
+% "!/" ?VERSION_STR " [124.124.124.222]:55555\nT=9898{C=2{A=11111111/00000000/00000000{MD[V18]{tdmc/gain=2}}}}",
+ list_to_binary(MP).
+
+%% ActionRequest with various combinations of ContextRequest and
+%% ContextAttrAuditRequest
+msg71(CR, CAAR) ->
+ TS1 = cre_TimeNot("19990729", "22000000"),
+ TS2 = cre_TimeNot("19990729", "22000111"),
+ Event1 = cre_ObsEv("al/of",TS1),
+ Event2 = cre_ObsEv("al/on",TS2),
+ Desc1 = cre_ObsEvsDesc(2222,[Event1]),
+ Desc2 = cre_ObsEvsDesc(2222,[Event2]),
+ NR1 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc1),
+ NR2 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc2),
+ Cmd1 = ?MSG_LIB:cre_Command(notifyReq, NR1),
+ Cmd2 = ?MSG_LIB:cre_Command(notifyReq, NR2),
+ CR1 = cre_CmdReq(Cmd1),
+ CR2 = cre_CmdReq(Cmd2),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CR, CAAR, [CR1, CR2]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg71a() ->
+ CR = cre_ContextRequest(),
+ CAAR = cre_ContextAttrAuditRequest(),
+ msg71(CR, CAAR).
+
+msg71b(CR) ->
+ CAAR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71b01() ->
+ CR = cre_ContextRequest(15),
+ msg71b(CR).
+
+msg71b02() ->
+ CR = cre_ContextRequest(true),
+ msg71b(CR).
+
+msg71b03() ->
+ CR = cre_ContextRequest(false),
+ msg71b(CR).
+
+msg71b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(Top),
+ msg71b(CR).
+
+msg71b05() ->
+ CR = cre_ContextRequest(15, true),
+ msg71b(CR).
+
+msg71b06() ->
+ CR = cre_ContextRequest(15, false),
+ msg71b(CR).
+
+msg71b07() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, Top),
+ msg71b(CR).
+
+msg71b08() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top),
+ msg71b(CR).
+
+msg71b09() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, false, Top),
+ msg71b(CR).
+
+msg71b10() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, true),
+ msg71b(CR).
+
+msg71b11() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, false),
+ msg71b(CR).
+
+msg71b12() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b13() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, greaterThan),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b14() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","10"], range, true),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b15() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("nt/jit", ["40","50","50"], sublist, true),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b16() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+ msg71b(CR).
+
+msg71b17() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, false),
+ msg71b(CR).
+
+msg71b18() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, false, Props),
+ msg71b(CR).
+
+msg71c(CAAR) ->
+ CR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71c01() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c02() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c03() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c04() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c05() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c06() ->
+ CAAR = cre_ContextAttrAuditRequest(asn1_NOVALUE, 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c07() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c08() ->
+ CAAR = cre_ContextAttrAuditRequest('NULL', asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c09() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, CPA),
+ msg71c(CAAR).
+
+msg71d01() ->
+ CR = cre_ContextRequest(15, true),
+ CAAR = cre_ContextAttrAuditRequest('NULL', 'NULL', 'NULL'),
+ msg71(CR, CAAR).
+
+msg71d02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_ContextAttrAuditRequest(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg71d03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, false, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_ContextAttrAuditRequest(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg72(ED, CR) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "a=ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdRep = [{addReply, Reply}, {addReply, Reply2}],
+ Action = cre_ActRep(2000, ED, CR, CmdRep),
+ msg_reply(?MGC_MID, 10003, [Action]).
+
+msg72a(CR) ->
+ ED = asn1_NOVALUE,
+ msg72(ED, CR).
+
+msg72a01() ->
+ CR = cre_ContextRequest(false),
+ msg72a(CR).
+
+msg72a02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(Top),
+ msg72a(CR).
+
+msg72a03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, Top),
+ msg72a(CR).
+
+msg72b(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC),
+ msg72(ED, CR).
+
+msg72b01() ->
+ CR = cre_ContextRequest(15, false),
+ msg72b(CR).
+
+msg72b02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, false, Top),
+ msg72b(CR).
+
+msg72b03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, true),
+ msg72b(CR).
+
+msg72b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_ContextRequest(15, true, Top, false),
+ msg72b(CR).
+
+msg72c(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ET = ?MSG_LIB:cre_ErrorText("Just another error string"),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC, ET),
+ msg72(ED, CR).
+
+msg72c01() ->
+ CR = cre_ContextRequest(15),
+ msg72c(CR).
+
+msg72c02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, Props),
+ msg72c(CR).
+
+msg72c03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, true, Props),
+ msg72c(CR).
+
+msg72c04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_ContextRequest(15, true, Top, false, Props),
+ msg72c(CR).
+
+
+msg73() ->
+ Stat1 = cre_StatsParm("rtp/ps"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Stats = [Stat1, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ cre_StatsDesc(Stats).
+
+%% StatisticsDescriptor in AmmDescriptor
+msg73a() ->
+ StatDesc = msg73(),
+ AmmDesc = cre_AmmDesc(StatDesc),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmReq = cre_AmmReq(TermIDs, [AmmDesc]),
+ Cmd = cre_Cmd(addReq, AmmReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% StatisticsDescriptor in IndAudStreamParms
+msg73b1() ->
+ IASD = cre_IndAudStatsDesc("nt/dur"),
+ cre_IndAudStreamParms(IASD).
+
+msg73b2(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc([IAP]),
+ TermID = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ AudReq = cre_AuditReq(TermID, AD),
+ Cmd = cre_Cmd(auditValueRequest, AudReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7311),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7312),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73b01() ->
+ IASP = msg73b1(),
+ IAMD = cre_IndAudMediaDesc(IASP),
+ msg73b2(IAMD).
+
+msg73b02() ->
+ IASP = msg73b1(),
+ SID = cre_StreamID(303),
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg73b2(IAMD).
+
+%% StatisticsDescriptor in StreamParms
+msg73c1() ->
+ StatDesc = msg73(),
+ SP = cre_StreamParms(StatDesc),
+ SID = cre_StreamID(505),
+ cre_StreamDesc(SID, SP).
+
+msg73c2(MD) ->
+ ARP = cre_AuditRetParam(MD),
+ TA = cre_TermAudit([ARP]),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmsRep = cre_AmmsReply(TermIDs, TA),
+ CmdRep = cre_CmdRep(moveReply, AmmsRep),
+ CID = cre_CtxID(606),
+ ActRep = cre_ActRep(CID, [CmdRep]),
+ TransId = cre_TransId(8899),
+ TransRep = cre_TransRep(TransId, [ActRep]),
+ Trans = cre_Trans(TransRep),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73c01() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc(SD),
+ msg73c2(MD).
+
+msg73c02() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc([SD]),
+ msg73c2(MD).
+
+
+%% New Signal (direction and requestID); msg74
+msg74a1(D) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, asn1_NOVALUE).
+
+msg74a2(D, RID) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, RID).
+
+msg74a3(D, RID) ->
+ Name = "al/ri",
+ SID = cre_StreamID(7401),
+ ST = cre_SigType(brief),
+ Dur = 7499,
+ NC = cre_NotifCompl([onTimeOut,otherReason]),
+ KA = cre_BOOLEAN(true),
+ SPL = [],
+ Dir = cre_SigDir(D),
+ cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+msg74a4(Sig) ->
+ SR = cre_SigReq(Sig),
+ SD = cre_SigsDesc([SR]),
+ AD = cre_AmmDesc(SD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AR = cre_AmmReq(TermIDs, [AD]),
+ Cmd = cre_Cmd(modReq, AR),
+ cre_CmdReq(Cmd).
+
+msg74a01() ->
+ Sig = msg74a1(internal),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7411),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7421),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a02() ->
+ Sig = msg74a1(both),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7412),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7422),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a03() ->
+ RID = cre_ReqID(7433),
+ Sig = msg74a2(external, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7413),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7423),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a04() ->
+ RID = cre_ReqID(7434),
+ Sig = msg74a2(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7414),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7424),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a05() ->
+ RID = cre_ReqID(7435),
+ Sig = msg74a3(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7415),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7425),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a06() ->
+ RID = cre_ReqID(7436),
+ Sig = msg74a3(internal, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7416),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7426),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% New ServiceChangeParm (serviceChangeIncompleteFlag); msg75
+msg75a(IncFlag) ->
+ Method = cre_SvcChMethod(restart),
+ Address = cre_SvcChAddr(portNumber, ?DEFAULT_PORT),
+ Reason = "901 mg col boot",
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(Method, Address, [Reason], Profile, IncFlag),
+ TermIDs = [?megaco_root_termination_id],
+ Req = cre_SvcChReq(TermIDs, Parm),
+ Cmd = cre_Cmd(serviceChangeReq, Req),
+ CR = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7501),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7502),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg75a01() ->
+ msg75a(asn1_NOVALUE).
+
+msg75a02() ->
+ msg75a('NULL').
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 2),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+%% --------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+skip(Reason) ->
+ megaco_codec_test_lib:skip(Reason).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_decode_message(DynamicDecode, Conf, Bin) ->
+ decode_message(megaco_pretty_text_encoder, DynamicDecode, Conf, Bin).
+
+compact_decode_message(DynamicDecode, Conf, Bin) ->
+ decode_message(megaco_compact_text_encoder, DynamicDecode, Conf, Bin).
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+
+pretty_encode_message(Conf, Msg) ->
+ encode_message(megaco_pretty_text_encoder, Conf, Msg).
+
+compact_encode_message(Conf, Msg) ->
+ encode_message(megaco_compact_text_encoder, Conf, Msg).
+
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M1, M2) ->
+ ?MSG_LIB:chk_MegacoMessage(M1, M2).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_MegacoMessage(Auth, Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Auth, Mess).
+
+cre_MegacoMessage(V, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(V, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+cre_AuthHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_AuthHeader(SecParmIdx, SeqNum, AD).
+
+cre_AuthHeader(Idx, Num, D) ->
+ ?MSG_LIB:cre_AuthenticationHeader(Idx, Num, D).
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_TransRep(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions).
+
+cre_TransAck(First, Last) ->
+ ?MSG_LIB:cre_TransactionAck(First, Last).
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_ActRep(CtxId, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, CmdReps).
+
+cre_ActRep(CtxId, ED, CR, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, ED, CR, CmdReps).
+
+cre_CtxID(Id) ->
+ ?MSG_LIB:cre_ContextID(Id).
+
+cre_ContextRequest() ->
+ ?MSG_LIB:cre_ContextRequest().
+
+cre_ContextRequest(A) ->
+ ?MSG_LIB:cre_ContextRequest(A).
+
+cre_ContextRequest(A, B) ->
+ ?MSG_LIB:cre_ContextRequest(A, B).
+
+cre_ContextRequest(A, B, C) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C).
+
+cre_ContextRequest(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D).
+
+cre_ContextRequest(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D, E).
+
+cre_ContextAttrAuditRequest() ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest().
+
+% cre_ContextAttrAuditRequest(A) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A).
+
+% cre_ContextAttrAuditRequest(A, B) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A, B).
+
+cre_ContextAttrAuditRequest(A, B, C) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C).
+
+cre_ContextAttrAuditRequest(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D).
+
+cre_ContextAttrAuditRequest(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E).
+
+cre_TopologyRequest(From, To, Dir) ->
+ ?MSG_LIB:cre_TopologyRequest(From, To, Dir).
+
+%% Ind Aud related:
+
+cre_IndAudParam(IAP) ->
+ ?MSG_LIB:cre_IndAuditParameter(IAP).
+
+cre_IndAudMediaDesc(D) ->
+ ?MSG_LIB:cre_IndAudMediaDescriptor(D).
+
+cre_IndAudStreamDesc(SID, SP) ->
+ ?MSG_LIB:cre_IndAudStreamDescriptor(SID, SP).
+
+cre_IndAudStreamParms(LCD) ->
+ ?MSG_LIB:cre_IndAudStreamParms(LCD).
+
+cre_IndAudLocalControlDesc(SM, RV, RG, PP) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(SM, RV, RG, PP).
+
+cre_IndAudPropertyParm(Name) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name).
+
+cre_IndAudTermStateDesc(PP) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP).
+
+cre_IndAudTermStateDesc(PP, EBC, SS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS).
+
+cre_IndAudEvsDesc(RID, PN)
+ when is_integer(RID) ->
+ ?MSG_LIB:cre_IndAudEventsDescriptor(RID, PN).
+
+cre_IndAudEvBufDesc(EN, SID) ->
+ ?MSG_LIB:cre_IndAudEventBufferDescriptor(EN, SID).
+
+cre_IndAudSigsDesc(D) ->
+ ?MSG_LIB:cre_IndAudSignalsDescriptor(D).
+
+cre_IndAudSig(SN) ->
+ ?MSG_LIB:cre_IndAudSignal(SN).
+
+cre_IndAudSeqSigList(ID, SL) ->
+ ?MSG_LIB:cre_IndAudSeqSigList(ID, SL).
+
+cre_IndAudDigitMapDesc(DMN) ->
+ ?MSG_LIB:cre_IndAudDigitMapDescriptor(DMN).
+
+cre_IndAudStatsDesc(SN) ->
+ ?MSG_LIB:cre_IndAudStatisticsDescriptor(SN).
+
+cre_IndAudPkgsDesc(PN, PV) ->
+ ?MSG_LIB:cre_IndAudPackagesDescriptor(PN, PV).
+
+%% Parameter related
+cre_PropParm(Name, Val) ->
+ ?MSG_LIB:cre_PropertyParm(Name, [Val]).
+
+cre_PropParm(Name, Vals, Tag, EI) ->
+ ?MSG_LIB:cre_PropertyParm(Name, Vals, Tag, EI).
+
+
+%% Statistics related
+cre_StatsDesc(SPs) ->
+ ?MSG_LIB:cre_StatisticsDescriptor(SPs).
+
+cre_StatsParm(Name) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name).
+
+cre_StatsParm(Name, Val) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name, [Val]).
+
+
+% Event related
+cre_EvParm(Name, Val) ->
+ ?MSG_LIB:cre_EventParameter(Name, Val).
+
+cre_ObsEv(Name, Not) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Not).
+cre_ObsEv(Name, Not, Par) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Par, Not).
+
+cre_ReqedEv(Name) ->
+ ?MSG_LIB:cre_RequestedEvent(Name).
+cre_ReqedEv(Name, Action) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, Action).
+
+
+cre_ObsEvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_ObservedEventsDescriptor(Id, EvList).
+
+cre_EvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_EventsDescriptor(Id, EvList).
+
+
+%% Service change related
+cre_SvcChParm(M, A, R, P) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, P, R).
+
+cre_SvcChParm(M, A, R, P, IF) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, asn1_NOVALUE, P, R, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, IF).
+
+cre_SvcChResParm(A, P) ->
+ ?MSG_LIB:cre_ServiceChangeResParm(A, P).
+
+cre_SvcChReq(Tids, P) ->
+ ?MSG_LIB:cre_ServiceChangeRequest(Tids, P).
+
+cre_SvcChProf(Name, Ver) ->
+ ?MSG_LIB:cre_ServiceChangeProfile(Name, Ver).
+
+cre_SvcChAddr(Tag, Val) ->
+ ?MSG_LIB:cre_ServiceChangeAddress(Tag, Val).
+
+cre_SvcChMethod(M) ->
+ ?MSG_LIB:cre_ServiceChangeMethod(M).
+
+cre_SvcChRep(Tids, Res) ->
+ ?MSG_LIB:cre_ServiceChangeReply(Tids, Res).
+
+
+%% Stream related
+cre_StreamID(Id) ->
+ ?MSG_LIB:cre_StreamID(Id).
+
+cre_StreamParms(Lcd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd).
+cre_StreamParms(Lcd, Ld) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld).
+cre_StreamParms(Lcd, Ld, Rd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld, Rd).
+cre_StreamParmsL(Ld) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, Ld, asn1_NOVALUE).
+cre_StreamParmsR(Rd) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, asn1_NOVALUE, Rd).
+
+cre_StreamDesc(Id, P) ->
+ ?MSG_LIB:cre_StreamDescriptor(Id, P).
+
+
+%% "Local" related
+cre_LocalControlDesc(Mode) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode).
+cre_LocalControlDesc(Mode, Parms) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode, Parms).
+
+cre_LocalRemoteDesc(Grps) ->
+ ?MSG_LIB:cre_LocalRemoteDescriptor(Grps).
+
+
+%% DigitMap related
+cre_DigitMapDesc() ->
+ ?MSG_LIB:cre_DigitMapDescriptor().
+cre_DigitMapDesc(NameOrVal) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(NameOrVal).
+cre_DigitMapDesc(Name, Val) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(Name, Val).
+
+cre_DigitMapValue(Body) ->
+ ?MSG_LIB:cre_DigitMapValue(Body).
+
+cre_DigitMapValue(Body, Start, Short, Long) ->
+ ?MSG_LIB:cre_DigitMapValue(Start, Short, Long, Body).
+
+%% Media related
+cre_MediaDesc(SD) when is_record(SD, 'StreamDescriptor') ->
+ cre_MediaDesc([SD]);
+cre_MediaDesc(SDs) ->
+ ?MSG_LIB:cre_MediaDescriptor(SDs).
+
+
+%% Notify related
+cre_NotifyReq(Tids, EvsDesc) ->
+ ?MSG_LIB:cre_NotifyRequest(Tids, EvsDesc).
+
+cre_NotifyRep(Tids) ->
+ ?MSG_LIB:cre_NotifyReply(Tids).
+
+
+%% Subtract related
+cre_SubReq(Tids, Desc) ->
+ ?MSG_LIB:cre_SubtractRequest(Tids, Desc).
+
+
+%% Audit related
+cre_AuditDesc(Tokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens).
+
+cre_AuditDesc(Tokens, PropertTokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens, PropertTokens).
+
+cre_AuditReq(Tid, Desc) ->
+ ?MSG_LIB:cre_AuditRequest(Tid, Desc).
+
+cre_AuditRes(Tid, Res) ->
+ ?MSG_LIB:cre_AuditResult(Tid, Res).
+
+cre_TermAudit(ARP) ->
+ ?MSG_LIB:cre_TerminationAudit(ARP).
+
+cre_AuditRetParam(D) ->
+ ?MSG_LIB:cre_AuditReturnParameter(D).
+
+
+%% AMM/AMMS related
+cre_AmmDesc(D) ->
+ ?MSG_LIB:cre_AmmDescriptor(D).
+
+cre_AmmReq(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmRequest(Tids, Descs).
+
+cre_AmmsReply(Tids) ->
+ ?MSG_LIB:cre_AmmsReply(Tids).
+cre_AmmsReply(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmsReply(Tids, Descs).
+
+
+%% Command related
+cre_Cmd(Tag, Req) ->
+ ?MSG_LIB:cre_Command(Tag, Req).
+
+cre_CmdReq(Cmd) ->
+ ?MSG_LIB:cre_CommandRequest(Cmd).
+
+cre_CmdRep(Tag, Rep) ->
+ ?MSG_LIB:cre_CommandReply(Tag, Rep).
+
+
+%% Actions related
+cre_ReqedActs(DmName) ->
+ EDM = ?MSG_LIB:cre_EventDM(DmName),
+ ?MSG_LIB:cre_RequestedActions(EDM).
+
+
+%% Signal related
+cre_SigDir(D) ->
+ ?MSG_LIB:cre_SignalDirection(D).
+
+cre_Sig(Name) ->
+ cre_Sig(Name, []).
+
+cre_Sig(Name, SPL) ->
+ ?MSG_LIB:cre_Signal(Name, SPL).
+
+cre_Sig(Name, Dir, RID) ->
+ cre_Sig(Name, [], Dir, RID).
+
+cre_Sig(Name, SPL, Dir, RID) ->
+ cre_Sig(Name, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+cre_SigReq(S) ->
+ ?MSG_LIB:cre_SignalRequest(S).
+
+cre_NotifCompl(NC) ->
+ ?MSG_LIB:cre_NotifyCompletion(NC).
+
+cre_SigType(ST) ->
+ ?MSG_LIB:cre_SignalType(ST).
+
+cre_SigsDesc(D) ->
+ ?MSG_LIB:cre_SignalsDescriptor(D).
+
+%% Others
+cre_ReqID(RID) ->
+ ?MSG_LIB:cre_RequestID(RID).
+
+cre_TimeNot(D,T) ->
+ ?MSG_LIB:cre_TimeNotation(D, T).
+
+cre_PkgsItem(Name, Ver) ->
+ ?MSG_LIB:cre_PackagesItem(Name, Ver).
+
+cre_BOOLEAN(B) ->
+ ?MSG_LIB:cre_BOOLEAN(B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+start_flex_scanner() ->
+ megaco_codec_flex_lib:start().
+
+stop_flex_scanner(Pid) ->
+ megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+l(F,A) ->
+ p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s:" ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "TRC";
+image_of(dbg) ->
+ "DBG";
+image_of(log) ->
+ "LOG";
+image_of(err) ->
+ "ERR";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
diff --git a/lib/megaco/test/megaco_codec_prev3c_test.erl b/lib/megaco/test/megaco_codec_prev3c_test.erl
new file mode 100644
index 0000000000..813d0cf57d
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_prev3c_test.erl
@@ -0,0 +1,8336 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_prev3c_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+ flex_compact_dm_timers7/1,
+ flex_compact_dm_timers8/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5793_msg01/1,
+ compact_otp5836_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp4299_msg1/1,
+ flex_compact_otp7431_msg01/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5085_msg8/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5803_msg01/1,
+ pretty_otp5803_msg02/1,
+ pretty_otp5805_msg01/1,
+ pretty_otp5836_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+ pretty_otp8114_msg01/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5085_msg8/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp5803_msg01/1,
+ flex_pretty_otp5803_msg02/1,
+ flex_pretty_otp5805_msg01/1,
+ flex_pretty_otp5836_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0, generate_text_messages/0]).
+
+
+%% ----
+
+-define(V3, prev3c).
+-define(EC_V3, {version3,?V3}).
+-define(EC, [?EC_V3]).
+
+-define(VERSION, 3).
+-define(VERSION_STR, "3").
+-define(MSG_LIB, megaco_test_msg_prev3c_lib).
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs =
+ msgs1a(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ megaco_codec_test_lib:display_text_messages(?VERSION, ?EC, Msgs).
+
+
+generate_text_messages() ->
+ Msgs =
+ msgs1a(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ megaco_codec_test_lib:generate_text_messages(?V3, ?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ flex_compact_tickets,
+ pretty_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5793_msg01,
+ compact_otp5836_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03
+ ].
+
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
+
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5085_msg8,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5803_msg01,
+ pretty_otp5803_msg02,
+ pretty_otp5805_msg01,
+ pretty_otp5836_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05,
+ pretty_otp8114_msg01
+ ].
+
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ %% Msgs = msgs1a(text),
+ %% Msgs = msgs1b(text),
+ %% Msgs = msgs35525(text),
+ %% Msgs = msgs5(text),
+ %% Msgs = msgs6(text),
+ %% Msgs = msgs7(text),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ %% Msgs = msgs7(text),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,3}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({2,3,4}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,31}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({10,21,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({99,23,11}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers7(suite) ->
+ [];
+flex_compact_dm_timers7(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers7 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers8(suite) ->
+ [];
+flex_compact_dm_timers8(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("01", "09", "01", "02"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers8 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,9,1,2}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s", [T, S, L])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(T, S, L, Z) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s,Z:~s", [T, S, L,Z])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(TMRs) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [TMRs]),
+ lists:flatten(M).
+
+
+verify_dm_timers(TMRs, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ TMRs ->
+ ok;
+ {error, Reason} ->
+ exit({invalid_timer, {TMRs, Reason}});
+ TMRs1 ->
+ exit({invalid_timer_values, {TMRs, TMRs1}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts])
+ when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = asn1_NOVALUE} ->
+ {ok, {T, S, L}};
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = Z} ->
+ {ok, {T, S, L, Z}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary),
+ %% Msgs = msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary),
+ %% Msgs = msgs7(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(erlang) ++
+ msgs1b(erlang) ++
+ msgs3525(erlang) ++
+ msgs5(erlang) ++
+ msgs6(erlang) ++
+ msgs7(erlang),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+%%
+
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4011(Msg) ->
+ compact_otp4011(Msg, ?EC).
+
+compact_otp4011(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4011_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4011_chk1(R1) ->
+ case lists:keysearch(reason, 1, R1) of
+ {value, {reason, R2}} ->
+ compact_otp4011_chk2(R2);
+ false ->
+ {error, {unexpected_result, R1}}
+ end.
+
+compact_otp4011_chk2({0, ParserMod, {ParserFunc, [A, B]}})
+ when (ParserMod =:= megaco_text_parser_prev3c) andalso
+ (ParserFunc =:= do_merge_control_streamParms) andalso
+ is_list(A) andalso
+ is_record(B, 'LocalControlDescriptor') ->
+ SM = B#'LocalControlDescriptor'.streamMode,
+ case lists:keysearch(mode, 1, A) of
+ {value, {mode, _Mode}} when SM /= asn1_NOVALUE ->
+ ok;
+ {value, {mode, _Mode}} ->
+ {error, {unexpected_streamMode_reason, {A, B}}};
+ false ->
+ {error, {unexpected_mode_reason, {A, B}}}
+ end;
+compact_otp4011_chk2(Bad) ->
+ {error, {unexpected_reason, Bad}}.
+
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/3 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ ok = compact_otp4013(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4013(Msg) ->
+ compact_otp4013(Msg, ?EC).
+
+compact_otp4013(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4013_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4013_chk1(Reason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, no_version_found, _}} ->
+ case lists:keysearch(token, 1, Reason) of
+ {value, {token, [{'SafeChars',_,"megcao/3"}|_]}} ->
+ ok;
+ {value, {token, Tokens}} ->
+ {error, {unexpected_tokens, Tokens}};
+ false ->
+ {error, {tokens_not_found, Reason}}
+ end;
+ {value, {reason, BadReason, _}} ->
+ {error, {unexpected_reason, BadReason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ ok = compact_otp4085_1(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4085_1(Msg) ->
+ compact_otp4085_1(Msg, ?EC).
+
+compact_otp4085_1(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4085_1_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4085_1_chk1(Reason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {Line, Module, Crap}}} when is_integer(Line) and
+ is_atom(Module) ->
+ Crap2 =
+ case (catch lists:flatten(Crap)) of
+ L when is_list(L) ->
+ L;
+ _ ->
+ Crap
+ end,
+ t("compact_otp4085_1_chk1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap2: ~p", [Line, Module, Crap2]),
+ ok;
+ {value, BadReason} ->
+ e("compact_otp4085_1_chk1 -> error: "
+ "~n BadReason: ~p", [BadReason]),
+ {error, {unexpected_reason, Reason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg() ++ "}",
+ ok = compact_otp4085_2(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4085_2(Msg) ->
+ compact_otp4085_2(Msg, ?EC).
+
+compact_otp4085_2(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4280_msg(),
+ ok = compact_otp4280(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4280(Msg) ->
+ compact_otp4280(Msg, ?EC).
+
+compact_otp4280(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+%%
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4299_msg(),
+ ok = compact_otp4299(Msg),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4299(Msg) ->
+ compact_otp4299(Msg, ?EC).
+
+compact_otp4299(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/"
+ ?VERSION_STR
+ " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4359_msg(),
+ ok = compact_otp4359(Msg),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4359(Msg) ->
+ compact_otp4359(Msg, ?EC).
+
+compact_otp4359(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ compact_otp4359_chk(M);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4359_chk(#'MegacoMessage'{mess = Mess}) ->
+ case Mess#'Message'.messageBody of
+ {transactions, Trans} ->
+ case Trans of
+ [{transactionRequest, TR}] ->
+ case TR of
+ #'TransactionRequest'{transactionId = asn1_NOVALUE} ->
+ ok;
+ _ ->
+ {error, {unexpected_trans_req, TR}}
+ end;
+ _ ->
+ {error, {unexpected_trans, Trans}}
+ end;
+ Body ->
+ {error, {unexpected_messageBody, Body}}
+ end.
+
+
+%% --------------------------------------------------------------
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg0() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg5() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg6() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg7() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg8() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg9() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg10() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg11() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg12() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg20(), bad_mid_duplicate_padding),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg21(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg22(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg23(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg24(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg25(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+compact_otp4920(Msg, ExpectedReason) ->
+ compact_otp4920(Msg, ?EC, ExpectedReason).
+
+compact_otp4920(Msg, Conf, ExpectedReason) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4920_chk(Reason, ExpectedReason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4920_chk(Reason, ExpectedReason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {__Line, _Mod, ActualReason}}} ->
+ case element(1, ActualReason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ {error, {unexpected_decode_reason,
+ {ActualReason, ExpectedReason}}}
+ end;
+ {value, {reason, {_Mod, ActualReason}}} ->
+ case element(1, ActualReason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ {error, {unexpected_decode_reason,
+ {ActualReason, ExpectedReason}}}
+ end;
+ {value, UnknownReason} ->
+ {error, {unexpected_decode_reason, UnknownReason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_error( compact_otp5186_msg01() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp5186_msg02() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg03() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg04() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg05() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg06() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok(pretty_otp5793_msg1()),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5836_msg01(suite) ->
+ [];
+compact_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok(compact_otp5836_msg1()),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+compact_otp5836_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 3,
+ {deviceName,"bs_sbg_4/34"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 12,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 4294967295,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {error, {'ErrorDescriptor', 431, asn1_NOVALUE}}}
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg01() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg02() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg03() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ ok.
+
+compact_otp6017(BadCID) ->
+ Conf = ?EC,
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ exit({unexpected_reason, ActualReason});
+ false ->
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ exit({unexpected_decode_result, Crap})
+ end.
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "MEGACO/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+flex_compact_otp4299_msg1(suite) ->
+ [];
+flex_compact_otp4299_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4299_msg(),
+ Conf = flex_scanner_conf(Config),
+ ok = compact_otp4299(Msg, [?EC_V3,Conf]),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+flex_compact_otp7431_msg01(suite) ->
+ [];
+flex_compact_otp7431_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4632_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4632_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp4632_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(B2, B1) -> pretty_otp4632_msg4_chk(B1, B2) end,
+ ok = ticket_pretty_decode_encode_only(pretty_otp4632_msg4(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+pretty_otp4632_msg4_chk(B1, B2) when is_binary(B1) and is_binary(B2) ->
+ S1 = binary_to_list(B1),
+ S2 = binary_to_list(B2),
+ %% io:format("~n"
+ %% "S1: ~s~n"
+ %% "S2: ~s~n", [S1, S2]),
+ pretty_otp4632_msg4_chk(S1, S2);
+
+pretty_otp4632_msg4_chk([], []) ->
+ messages_not_eq;
+pretty_otp4632_msg4_chk([], Rest2) ->
+ {messages_not_eq2, Rest2};
+pretty_otp4632_msg4_chk(Rest1, []) ->
+ {messages_not_eq1, Rest1};
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest2]) ->
+ ok;
+pretty_otp4632_msg4_chk([_H1|Rest1], [_H2|Rest2]) ->
+ pretty_otp4632_msg4_chk(Rest1, Rest2).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4710_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(B1, B2) -> pretty_otp4710_msg2_chk(B1, B2) end,
+ ok = ticket_pretty_decode_encode_only(pretty_otp4710_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(B1, B2) when is_binary(B1) and is_binary(B2) ->
+ S1 = binary_to_list(B1),
+ S2 = binary_to_list(B2),
+ pretty_otp4710_msg2_chk(S1, S2);
+
+pretty_otp4710_msg2_chk(Msg, Msg) ->
+ ok;
+
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg1_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg1(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg1_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeReason],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg2_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg2_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeMethod],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg3_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg3(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg3_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeReason, serviceChangeMethod],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp4945_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg5_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg5(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg5_chk(R) when is_list(R) ->
+ Check = fun({at_most_once_serviceChangeParm, {profile, _, _}}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg6_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg6(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg6_chk(R) when is_list(R) ->
+ Check = fun({not_both_address_mgcid_serviceChangeParm, _, _}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_chk({missing_required_serviceChangeParm, Missing},
+ ExpMissing) when is_list(Missing) ->
+ case ExpMissing -- Missing of
+ [] ->
+ ok;
+ Diff ->
+ {error, {unexpected_missing_serviceChangeParm, Diff}}
+ end;
+pretty_otp4945_chk(Reason, _ExpMissing) ->
+ {error, {unexpected_reason, Reason}}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp4949_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4949_msg2_chk(R) end,
+ ok = ticket_pretty_decode_error( pretty_otp4949_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+pretty_otp4949_msg2_chk(R) when is_list(R) ->
+ Check = fun({at_most_once_servChgReplyParm, {profile, _, _}}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4949_msg3_chk(R) end,
+ ok = ticket_pretty_decode_error( pretty_otp4949_msg3(), Check ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4949_msg3_chk(R) when is_list(R) ->
+ Check = fun({not_both_address_mgcid_servChgReplyParm, _, _}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp5042_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_only( pretty_otp5068_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+}.
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg5() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg6() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg7() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg8(suite) ->
+ [];
+pretty_otp5085_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg8() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg8() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 8,
+ emergency = true,
+ topologyReq =
+ [#'TopologyRequest'{terminationFrom = From1,
+ terminationTo = To1,
+ topologyDirection = bothway},
+ #'TopologyRequest'{terminationFrom = From2,
+ terminationTo = To2,
+ topologyDirection = oneway}
+ ],
+ iepscallind = true,
+ contextProp = [cre_PropParm("tdmc/gain", "2")]},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5601_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5793_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',3,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5803_msg01(suite) ->
+ [];
+pretty_otp5803_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5803_msg1() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ },
+ Stream=2{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+pretty_otp5803_msg02(suite) ->
+ [];
+pretty_otp5803_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5803_msg2() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5805_msg01(suite) ->
+ [];
+pretty_otp5805_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_error( pretty_otp5805_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5805_msg1() ->
+"MEGACO/4 [134.138.234.29]
+Transaction=1{
+ Context=*{
+ AuditValue=ip/0/*{
+ Audit{}
+ }
+ }
+}".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5836_msg01(suite) ->
+ [];
+pretty_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( compact_otp5836_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp5882_msg01_chk(R) end,
+ ok = ticket_pretty_encode_error( pretty_otp5882_msg01(), Check ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5882_msg01_chk({message_encode_failed, {error, {Reason, _}}, _}) ->
+ case Reason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ {error, {unexpected_error_actual_reason, Reason}}
+ end;
+pretty_otp5882_msg01_chk(Reason) ->
+ {error, {unexpected_reason, Reason}}.
+
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_DigitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_DigitMapDesc(),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[],
+ asn1_NOVALUE}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+
+
+pretty_otp8114_msg01(suite) ->
+ [];
+pretty_otp8114_msg01(Config) when is_list(Config) ->
+ put(severity, trc),
+ put(dbg, true),
+ d("pretty_otp8114_msg01 -> entry", []),
+ ok = otp8114( pretty_otp8114_msg01(), megaco_pretty_text_encoder, ?EC),
+ erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp8114_msg01() ->
+ "MEGACO/" ?VERSION_STR " [10.10.10.10]:1234\nTransaction = 1 {\n\tContext =\n1 {\n\t\tModify = ip/1/1/1 {\n\t\t\tMedia {\n\t\t\t\tStream = 1\n{\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode =\nSendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 1\n{\n\t\t\t\tadid/ipstop\n{\n\t\t\t\t\tdt=30,\n\t\t\t\t\tdir=\"BOTH\"\n\t\t\t\t},\n\t\t\t\tg/cause\n\n\t\t\t}\n\t\t}\n\t}\n}".
+
+
+otp8114(InitialMessage, Codec, Conf) ->
+ Decode = fun(M) -> Codec:decode_message(Conf, M) end,
+ Encode = fun(B) -> Codec:encode_message(Conf, B) end,
+ InitialData = InitialMessage,
+ Instructions =
+ [
+ %% List to binary
+ megaco_codec_test_lib:expect_instruction(
+ "Convert (initial) message to a binary",
+ fun(Msg) when is_list(Msg) ->
+ %% io:format("~s~n", [Msg]),
+ {ok, list_to_binary(Msg)};
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ {ok, Bin};
+ (Bad, _Msg) ->
+ {error, {failed_to_binary, Bad}}
+ end),
+
+ %% Initial decode
+ megaco_codec_test_lib:expect_instruction(
+ "Decode (initial) message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {initial_decode_failed, Bad}}
+ end),
+
+ %% Encode
+ megaco_codec_test_lib:expect_instruction(
+ "Encode message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ %% io:format("~s~n", [binary_to_list(Bin)]),
+ {ok, Bin};
+ (Bad, _) ->
+ {error, {encode_failed, Bad}}
+ end),
+
+ %% Decode
+ megaco_codec_test_lib:expect_instruction(
+ "(final) Decode message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {decode_failed, Bad}}
+ end)
+ ],
+ megaco_codec_test_lib:expect_exec(Instructions, InitialData).
+
+
+%% ==============================================================
+%%
+%% F l e x P r e t t y T e s t c a s e s
+%%
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp5042_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg8(suite) ->
+ [];
+flex_pretty_otp5085_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg2(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5601_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5793_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5803_msg01(suite) ->
+ [];
+flex_pretty_otp5803_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5803_msg02(suite) ->
+ [];
+flex_pretty_otp5803_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg2(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5805_msg01(suite) ->
+ [];
+flex_pretty_otp5805_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_error( pretty_otp5805_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5836_msg01(suite) ->
+ [];
+flex_pretty_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( compact_otp5836_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [?EC_V3,Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf) ->
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []);
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg2() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg3() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg4() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a}
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg5() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg6() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg7() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v}
+ }
+ }
+ }
+ }
+ }".
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ [M || {_, M, _, _} <- msgs(text)].
+
+msgs(Encoding) ->
+ msgs1a(Encoding) ++
+ msgs1b(Encoding) ++
+ msgs3525(Encoding) ++
+ msgs5(Encoding) ++
+ msgs6(Encoding) ++
+ msgs7(Encoding).
+
+msgs1a(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+
+msgs1b(_) ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3525(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, ?EC, M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+msgs5(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg51a, msg51a(), Plain, [{dbg, false}]},
+ {msg51b, msg51b(), Plain, [{dbg, false}]},
+ {msg51c, msg51c(), Plain, [{dbg, false}]},
+ {msg51d, msg51d(), Plain, [{dbg, false}]},
+ {msg51e, msg51e(), Plain, [{dbg, false}]},
+ {msg51f, msg51f(), Plain, [{dbg, false}]},
+ {msg51g, msg51g(), Plain, [{dbg, false}]},
+ {msg51h, msg51h(), Plain, [{dbg, false}]},
+ {msg51i, msg51i(), Plain, [{dbg, false}]},
+ {msg52, msg52(), Plain, [{dbg, false}]},
+ {msg53, msg53(), Plain, [{dbg, false}]},
+ {msg54a, msg54a(), Plain, [{dbg, false}]},
+ {msg54b, msg54b(), Plain, [{dbg, false}]},
+ {msg54c, msg54c(), Plain, [{dbg, false}]},
+ {msg55, msg55(), Plain, [{dbg, false}]},
+ {msg56, msg56(), Plain, [{dbg, false}]},
+ {msg57, msg57(), Plain, [{dbg, false}]},
+ {msg58a, msg58a(), Plain, [{dbg, false}]},
+ {msg58b, msg58b(), Plain, [{dbg, false}]}
+ ].
+
+
+msgs6(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ PlainEDFail =
+ fun(Codec, DD, Ver, EC, M) ->
+ Res =
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M),
+ case Res of
+ {error, {message_encode_failed, Reason, _M}} ->
+ case Reason of
+ {error, {{deprecated, _}, _}} ->
+ ok;
+ _ ->
+ Res
+ end;
+ _ ->
+ Res
+ end
+ end,
+
+ PlainDE =
+ fun(Codec, _DD, Ver, EC, B) ->
+ Res =
+ megaco_codec_test_lib:decode_message(Codec, false, Ver,
+ EC, B),
+ case Res of
+ {ok, M} ->
+ #'MegacoMessage'{mess = Mess} = M,
+ #'Message'{messageBody = {transactions, TRs}} = Mess,
+ [{transactionRequest, TR}] = TRs,
+ #'TransactionRequest'{actions = Actions} = TR,
+ [Action] = Actions,
+ #'ActionRequest'{commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {addReq,AmmReq} = Cmd,
+ #'AmmRequest'{descriptors = []} = AmmReq,
+ ok;
+ _ ->
+ Res
+ end
+ end,
+
+ Msgs =
+ [
+ {msg61a, msg61a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61b, msg61b(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61c, msg61c(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg62a, msg62a(), PlainEDFail, [{dbg,false}],[text,binary,erlang]},
+ {msg62b, msg62b(), PlainDE, [{dbg,false}],[text]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+msgs7(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ Msgs =
+ [
+ {msg71a, msg71a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b01, msg71b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b02, msg71b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b03, msg71b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b04, msg71b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b05, msg71b05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b06, msg71b06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b07, msg71b07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b08, msg71b08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b09, msg71b09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b10, msg71b10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b11, msg71b11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b12, msg71b12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b13, msg71b13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b14, msg71b14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b15, msg71b15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b16, msg71b16(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b17, msg71b17(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b18, msg71b18(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b19, msg71b19(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b20, msg71b20(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b21, msg71b21(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b22, msg71b22(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c01, msg71c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c02, msg71c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c03, msg71c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c04, msg71c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c05, msg71c05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c06, msg71c06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c07, msg71c07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c08, msg71c08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c09, msg71c09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c10, msg71c10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c11, msg71c11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c12, msg71c12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c13, msg71c13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c14, msg71c14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c15, msg71c15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d01, msg71d01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d02, msg71d02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d03, msg71d03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d04, msg71d04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a01, msg72a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a02, msg72a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a03, msg72a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b01, msg72b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b02, msg72b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b03, msg72b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b04, msg72b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c01, msg72c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c02, msg72c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c03, msg72c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c04, msg72c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73a, msg73a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b01, msg73b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b02, msg73b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c01, msg73c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c02, msg73c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a01, msg74a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a02, msg74a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a03, msg74a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a04, msg74a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a05, msg74a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a06, msg74a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a01, msg75a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a02, msg75a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76a01, msg76a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76a02, msg76a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76b01, msg76b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ %% {msg76b02, msg76b02(), Plain, [{dbg,true}],[text,binary,erlang]},
+ {msg77a01, msg77a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a01, msg78a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a02, msg78a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a03, msg78a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a04, msg78a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a05, msg78a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a06, msg78a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a07, msg78a07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a08, msg78a08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a09, msg78a09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg79a01, msg79a01(), Plain, [{dbg,false}],[text,binary,erlang]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = ?MSG_LIB:cre_ActionRequest(CtxId,CmdReqs),
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ megaco_trans_req(TransInfo, [Trans|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(Version, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(?VERSION, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Auth, Mess).
+
+msg_reply(Mid, TransId, Actions) ->
+ TR = cre_TransRep(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) ->
+ Action = cre_ActRep(ContextId, CmdReply),
+ Actions = [Action],
+ msg_reply(Mid, TransId, Actions).
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_MegacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_TransAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ReqEvent = cre_ReqEv("al/of"),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ Msg = msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]),
+ Msg.
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ EventParm = cre_EvParm("strict",["exact"]),
+ ReqEvent = cre_ReqEv("al/of", [EventParm]),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChResParm(Address,Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_EvParm("strict",["state"]),
+ On = cre_ReqEv("al/on", [Strict]),
+ Name = "dialplan00",
+ EDM = cre_EvDM(Name),
+ Action = cre_ReqActs(EDM),
+ Ce = cre_ReqEv("dd/ce", Action),
+ EventsDesc = cre_EvsDesc(2223, [On, Ce]),
+ Signal = cre_Sig("cg/rt"),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22010001"),
+ Parm = cre_EvParm("ds",["916135551212"]),
+ Event = cre_ObsEv("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_ObsEvsDesc(2223,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(recvOnly,[Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 $ "),
+ M2 = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_StreamParms(LCD, LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Signal = cre_Sig("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD2 = cre_LocalControlDesc(sendRecv, [Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ LD2 = cre_LocalRemoteDesc([[V, C, M, A]]),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_LocalRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_StreamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ Signal = cre_Sig("cg/rt"),
+ AmmReq1 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_CmdReq({modReq, AmmReq1}),
+
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_StreamParms(LCD),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms3 = cre_StreamParmsR(RD),
+ StreamDesc3 = cre_StreamDesc(2,Parms3),
+ MediaDesc3 = cre_MediaDesc(StreamDesc3),
+ AmmReq3 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_CmdReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22020002"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(1234,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_ReqEv("al/on"),
+ EventsDesc = cre_EvsDesc(1235,[On]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_AuditDesc(Tokens),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(sendRecv,[Jit]),
+ LDV = cre_PropParm("v", "0"),
+ LDC = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_PropParm("a", "ptime:30"),
+ LD = cre_LocalRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_PropParm("v", "0"),
+ RDC = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_PropParm("a", "ptime:30"),
+ RD = cre_LocalRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_StreamParms(LCD,LD,RD),
+ StreamDesc = cre_StreamDesc(1,StreamParms),
+ Media = cre_MediaDesc(StreamDesc),
+ PackagesItem = cre_PkgsItem("nt",1),
+ PackagesItem2 = cre_PkgsItem("rtp",1),
+ Stat = cre_StatsParm("rtp/ps","1200"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_AuditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_CmdReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_NotifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_CmdReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_AuditDesc([statsToken]),
+ SubReq = cre_SubReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_SubReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_CmdReq({subtractReq, SubReq}),
+ CmdReq2 = cre_CmdReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_StatsParm("nt/os","45123"),
+ Stat12 = cre_StatsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_AmmsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_StatsParm("rtp/ps","1245"),
+ Stat22 = cre_StatsParm("nt/os", "62345"),
+ Stat23 = cre_StatsParm("rtp/pr", "780"),
+ Stat24 = cre_StatsParm("nt/or", "45123"),
+ Stat25 = cre_StatsParm("rtp/pl", "10"),
+ Stat26 = cre_StatsParm("rtp/jit", "27"),
+ Stat27 = cre_StatsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ Auth = cre_AuthHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+msg50(Mid, APT) ->
+ AD = cre_AuditDesc(asn1_NOVALUE, APT),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AD),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%% IndAudMediaDescriptor:
+msg51(Mid, IATSDorStream) ->
+ IAMD = cre_IndAudMediaDesc(IATSDorStream),
+ IAP = cre_IndAudParam(IAMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg51a() ->
+ msg51a(?MG2_MID).
+msg51a(Mid) ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51b() ->
+ msg51b(?MG2_MID).
+msg51b(Mid) ->
+ PP = cre_IndAudPropertyParm("nt/jit"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51c() ->
+ msg51c(?MG2_MID).
+msg51c(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, 'NULL'),
+ msg51(Mid, IATSD).
+
+msg51d() ->
+ msg51d(?MG2_MID).
+msg51d(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg51(Mid, IATSD).
+
+msg51e() ->
+ msg51e(?MG2_MID).
+msg51e(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc('NULL', asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51f() ->
+ msg51f(?MG2_MID).
+msg51f(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL',
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51g() ->
+ msg51g(?MG2_MID).
+msg51g(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ 'NULL', asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51h() ->
+ msg51h(?MG2_MID).
+msg51h(Mid) ->
+ Name = "nt/jit",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, [IAPP]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+msg51i() ->
+ msg51i(?MG2_MID).
+msg51i(Mid) ->
+ Name = "nt/jit",
+ Name2 = "tdmc/ec",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ IALCD = cre_IndAudLocalControlDesc('NULL', 'NULL', 'NULL',
+ [IAPP, IAPP2]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+%% IndAudEventsDescriptor:
+msg52() ->
+ msg52(?MG2_MID).
+msg52(Mid) ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ IAP = cre_IndAudParam(IAED),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudEventBufferDescriptor:
+msg53() ->
+ msg53(?MG2_MID).
+msg53(Mid) ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ IAP = cre_IndAudParam(IAEBD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudSignalsDescriptor:
+msg54(Mid, Sig) ->
+ IASD = cre_IndAudSigsDesc(Sig),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg54a() ->
+ msg54a(?MG2_MID).
+msg54a(Mid) ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54b() ->
+ msg54b(?MG2_MID).
+msg54b(Mid) ->
+ SN = "dg/d0",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54c() ->
+ msg54c(?MG2_MID).
+msg54c(Mid) ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg54(Mid, SSL).
+
+%% IndAudDigitMapDescriptor:
+msg55() ->
+ msg55(?MG2_MID).
+msg55(Mid) ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ IAP = cre_IndAudParam(IADMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudStatisticsDescriptor:
+msg56() ->
+ msg56(?MG2_MID).
+msg56(Mid) ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudPackagesDescriptor:
+msg57() ->
+ msg57(?MG2_MID).
+msg57(Mid) ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ IAP = cre_IndAudParam(IAPD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% Sum it up:
+msg58_iaMediaDesc_iap(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ cre_IndAudParam(IAMD).
+
+msg58_iaMediaDesc_iap_a() ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaMediaDesc_iap_b() ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaEvsDesc_iap() ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ cre_IndAudParam(IAED).
+
+msg58_iaEvBufDesc_iap() ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ cre_IndAudParam(IAEBD).
+
+msg58_iaSigsDesc_iap(S) ->
+ IASD = cre_IndAudSigsDesc(S),
+ cre_IndAudParam(IASD).
+
+msg58_iaSigsDesc_iap_a() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg58_iaSigsDesc_iap(Sig).
+
+msg58_iaSigsDesc_iap_b() ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg58_iaSigsDesc_iap(SSL).
+
+msg58_iaDigMapDesc_iap() ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ cre_IndAudParam(IADMD).
+
+msg58_iaStatsDesc_iap() ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ cre_IndAudParam(IASD).
+
+msg58_iaPacksDesc_iap() ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ cre_IndAudParam(IAPD).
+
+msg58a() ->
+ msg58a(?MG2_MID).
+msg58a(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_a(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_a(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+msg58b() ->
+ msg58b(?MG2_MID).
+msg58b(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_b(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_b(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Tests some of the changes in the v2 corr 1 (EmergencyOff and ModemDesc)
+
+%% Emergency On/Off (optional) tests
+msg61(EM) ->
+ TS = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TS),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ Cmd = ?MSG_LIB:cre_Command(notifyReq, NotReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CtxReq = cre_CtxReq(15, EM),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CtxReq, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg61a() ->
+ msg61(false).
+
+msg61b() ->
+ msg61(true).
+
+msg61c() ->
+ msg61(asn1_NOVALUE).
+
+
+msg62a() ->
+ MT = ?MSG_LIB:cre_ModemType(v18),
+ PP = cre_PropParm("c", "IN IP4 $ "),
+ MD = ?MSG_LIB:cre_ModemDescriptor([MT], [PP]),
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(MD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AmmReq = ?MSG_LIB:cre_AmmRequest(TermIDs, [AmmDesc]),
+ Cmd = ?MSG_LIB:cre_Command(addReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ ActReq = ?MSG_LIB:cre_ActionRequest(2, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg62b() ->
+ MP =
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555
+Transaction = 9898 {
+ Context = 2 {
+ Add = 11111111/00000000/00000000 {
+ Modem[V18] {
+ tdmc/gain=2
+ }
+ }
+ }
+}",
+% MC =
+% "!/" ?VERSION_STR " [124.124.124.222]:55555\nT=9898{C=2{A=11111111/00000000/00000000{MD[V18]{tdmc/gain=2}}}}",
+ list_to_binary(MP).
+
+%% ActionRequest with various combinations of ContextRequest and
+%% ContextAttrAuditRequest
+msg71(CR, CAAR) ->
+ TS1 = cre_TimeNot("19990729", "22000000"),
+ TS2 = cre_TimeNot("19990729", "22000111"),
+ Event1 = cre_ObsEv("al/of",TS1),
+ Event2 = cre_ObsEv("al/on",TS2),
+ Desc1 = cre_ObsEvsDesc(2222,[Event1]),
+ Desc2 = cre_ObsEvsDesc(2222,[Event2]),
+ NR1 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc1),
+ NR2 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc2),
+ Cmd1 = ?MSG_LIB:cre_Command(notifyReq, NR1),
+ Cmd2 = ?MSG_LIB:cre_Command(notifyReq, NR2),
+ CR1 = cre_CmdReq(Cmd1),
+ CR2 = cre_CmdReq(Cmd2),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CR, CAAR, [CR1, CR2]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg71a() ->
+ CR = cre_CtxReq(),
+ CAAR = cre_CtxAttrAuditReq(),
+ msg71(CR, CAAR).
+
+msg71b(CR) ->
+ CAAR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71b01() ->
+ CR = cre_CtxReq(15),
+ msg71b(CR).
+
+msg71b02() ->
+ CR = cre_CtxReq(true),
+ msg71b(CR).
+
+msg71b03() ->
+ CR = cre_CtxReq(false),
+ msg71b(CR).
+
+msg71b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(Top),
+ msg71b(CR).
+
+msg71b05() ->
+ CR = cre_CtxReq(15, true),
+ msg71b(CR).
+
+msg71b06() ->
+ CR = cre_CtxReq(15, false),
+ msg71b(CR).
+
+msg71b07() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, Top),
+ msg71b(CR).
+
+msg71b08() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top),
+ msg71b(CR).
+
+msg71b09() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b10() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = onewayboth,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b11() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = onewayexternal,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b12() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, true),
+ msg71b(CR).
+
+msg71b13() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg71b(CR).
+
+msg71b14() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b15() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, greaterThan),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b16() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","10"], range, true),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b17() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("nt/jit", ["40","50","50"], sublist, true),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b18() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+ msg71b(CR).
+
+msg71b19() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg71b(CR).
+
+msg71b20() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+ msg71b(CR).
+
+msg71b21() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, CIDs),
+ msg71b(CR).
+
+msg71b22() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, Props, CIDs),
+ msg71b(CR).
+
+msg71c(CAAR) ->
+ CR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71c01() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c02() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c03() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c04() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c05() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c06() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c07() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c08() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c09() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA),
+ msg71c(CAAR).
+
+msg71c10() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA, SPrio),
+ msg71c(CAAR).
+
+msg71c11() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c12() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = false,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps),
+ msg71c(CAAR).
+
+msg71c13() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = false,
+ SIeps = true,
+ SLog = cre_SelectLogic(andAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71c(CAAR).
+
+msg71c14() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = true,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71c(CAAR).
+
+msg71c15() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SLog),
+ msg71c(CAAR).
+
+msg71d01() ->
+ CR = cre_CtxReq(15, true),
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', 'NULL'),
+ msg71(CR, CAAR).
+
+msg71d02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg71d03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg71d04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, Props, CIDs),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = true,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71(CR, CAAR).
+
+msg72(ED, CR) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "a=ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdRep = [{addReply, Reply}, {addReply, Reply2}],
+ Action = cre_ActRep(2000, ED, CR, CmdRep),
+ msg_reply(?MGC_MID, 10003, [Action]).
+
+msg72a(CR) ->
+ ED = asn1_NOVALUE,
+ msg72(ED, CR).
+
+msg72a01() ->
+ CR = cre_CtxReq(false),
+ msg72a(CR).
+
+msg72a02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(Top),
+ msg72a(CR).
+
+msg72a03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, Top),
+ msg72a(CR).
+
+msg72b(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC),
+ msg72(ED, CR).
+
+msg72b01() ->
+ CR = cre_CtxReq(15, false),
+ msg72b(CR).
+
+msg72b02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg72b(CR).
+
+msg72b03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, true),
+ msg72b(CR).
+
+msg72b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg72b(CR).
+
+msg72c(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ET = ?MSG_LIB:cre_ErrorText("Just another error string"),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC, ET),
+ msg72(ED, CR).
+
+msg72c01() ->
+ CR = cre_CtxReq(15),
+ msg72c(CR).
+
+msg72c02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg72c(CR).
+
+msg72c03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+ msg72c(CR).
+
+msg72c04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+ msg72c(CR).
+
+
+msg73() ->
+ Stat1 = cre_StatsParm("rtp/ps"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Stats = [Stat1, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ cre_StatsDesc(Stats).
+
+%% StatisticsDescriptor in AmmDescriptor
+msg73a() ->
+ StatDesc = msg73(),
+ AmmDesc = cre_AmmDesc(StatDesc),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmReq = cre_AmmReq(TermIDs, [AmmDesc]),
+ Cmd = cre_Cmd(addReq, AmmReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% StatisticsDescriptor in IndAudStreamParms
+msg73b1() ->
+ IASD = cre_IndAudStatsDesc("nt/dur"),
+ cre_IndAudStreamParms(IASD).
+
+msg73b2(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc([IAP]),
+ TermID = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ AudReq = cre_AuditReq(TermID, AD),
+ Cmd = cre_Cmd(auditValueRequest, AudReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7311),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7312),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73b01() ->
+ IASP = msg73b1(),
+ IAMD = cre_IndAudMediaDesc(IASP),
+ msg73b2(IAMD).
+
+msg73b02() ->
+ IASP = msg73b1(),
+ SID = cre_StreamID(303),
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg73b2(IAMD).
+
+%% StatisticsDescriptor in StreamParms
+msg73c1() ->
+ StatDesc = msg73(),
+ SP = cre_StreamParms(StatDesc),
+ SID = cre_StreamID(505),
+ cre_StreamDesc(SID, SP).
+
+msg73c2(MD) ->
+ ARP = cre_AuditRetParam(MD),
+ TA = cre_TermAudit([ARP]),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmsRep = cre_AmmsReply(TermIDs, TA),
+ CmdRep = cre_CmdRep(moveReply, AmmsRep),
+ CID = cre_CtxID(606),
+ ActRep = cre_ActRep(CID, [CmdRep]),
+ TransId = cre_TransId(8899),
+ TransRep = cre_TransRep(TransId, [ActRep]),
+ Trans = cre_Trans(TransRep),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73c01() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc(SD),
+ msg73c2(MD).
+
+msg73c02() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc([SD]),
+ msg73c2(MD).
+
+
+%% New Signal (direction and requestID); msg74
+msg74a1(D) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, asn1_NOVALUE).
+
+msg74a2(D, RID) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, RID).
+
+msg74a3(D, RID) ->
+ Name = "al/ri",
+ SID = cre_StreamID(7401),
+ ST = cre_SigType(brief),
+ Dur = 7499,
+ NC = cre_NotifCompl([onTimeOut,otherReason]),
+ KA = cre_BOOLEAN(true),
+ SPL = [],
+ Dir = cre_SigDir(D),
+ cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+msg74a4(Sig) ->
+ SR = cre_SigReq(Sig),
+ SD = cre_SigsDesc([SR]),
+ AD = cre_AmmDesc(SD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AR = cre_AmmReq(TermIDs, [AD]),
+ Cmd = cre_Cmd(modReq, AR),
+ cre_CmdReq(Cmd).
+
+msg74a01() ->
+ Sig = msg74a1(internal),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7411),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7421),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a02() ->
+ Sig = msg74a1(both),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7412),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7422),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a03() ->
+ RID = cre_ReqID(7433),
+ Sig = msg74a2(external, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7413),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7423),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a04() ->
+ RID = cre_ReqID(7434),
+ Sig = msg74a2(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7414),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7424),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a05() ->
+ RID = cre_ReqID(7435),
+ Sig = msg74a3(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7415),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7425),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a06() ->
+ RID = cre_ReqID(7436),
+ Sig = msg74a3(internal, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7416),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7426),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% New ServiceChangeParm (serviceChangeIncompleteFlag); msg75
+msg75a(IncFlag) ->
+ Method = cre_SvcChMethod(restart),
+ Address = cre_SvcChAddr(portNumber, ?DEFAULT_PORT),
+ Reason = "901 mg col boot",
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(Method, Address, [Reason], Profile, IncFlag),
+ TermIDs = [?megaco_root_termination_id],
+ Req = cre_SvcChReq(TermIDs, Parm),
+ Cmd = cre_Cmd(serviceChangeReq, Req),
+ CR = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7501),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7502),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg75a01() ->
+ msg75a(asn1_NOVALUE).
+
+msg75a02() ->
+ msg75a('NULL').
+
+
+msg76(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc(asn1_NOVALUE, [IAP]),
+ AR = cre_AuditReq(#megaco_term_id{id = ?A5556}, AD),
+ CR = cre_CmdReq({auditValueRequest, AR}),
+ msg_request(?MG2_MID, 50076, ?megaco_null_context_id, [CR]).
+
+%% IndAudLocalControlDescriptor and IndAudPropertyParm
+msg76a(IALCD) when is_record(IALCD, 'IndAudLocalControlDescriptor') ->
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg76(IAMD).
+
+msg76a01() ->
+ Name1 = "nt/jit",
+ IAPP1 = cre_IndAudPropertyParm(Name1),
+ Name2 = "tdmc/ec",
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ SMS = cre_StreamMode(recvOnly),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL', 'NULL',
+ [IAPP1, IAPP2], SMS),
+ msg76a(IALCD).
+
+msg76a02() ->
+ Name1 = "tdmc/gain",
+ PP1 = cre_PropParm("tdmc/gain", "2"),
+ IAPP1 = cre_IndAudPropertyParm(Name1, PP1),
+ Name2 = "tdmc/gain",
+ PP2 = cre_PropParm("tdmc/gain", "3"),
+ IAPP2 = cre_IndAudPropertyParm(Name2, PP2),
+ SMS = cre_StreamMode(recvOnly),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL', 'NULL',
+ [IAPP1, IAPP2], SMS),
+ msg76a(IALCD).
+
+%% IndAudTerminationStateDescription + ServiceState
+msg76b(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ msg76(IAMD).
+
+msg76b01() ->
+ SSS = cre_ServiceState(outOfSvc),
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, asn1_NOVALUE, SSS),
+ msg76b(IATSD).
+
+%% msg76b02() ->
+%% PP = cre_PropParm("tdmc/gain", "2"),
+%% IAPP = cre_IndAudPropertyParm("nt/jit", PP),
+%% IAPPs = [IAPP],
+%% SSS = cre_ServiceState(outOfSvc),
+%% IATSD = cre_IndAudTermStateDesc(IAPPs, 'NULL', asn1_NOVALUE, SSS),
+%% msg76b(IATSD).
+
+msg77a01() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN, 7701),
+ msg54(?MG2_MID, Sig).
+
+
+msg78a(Events) ->
+ EventsDesc = cre_EvsDesc(2223, Events),
+ Signal = cre_Sig("cg/rt"),
+ Name = "dialplan00",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ DigitMapValue = cre_DigitMapValue(Body),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MG2_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg78a01() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict", ["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7801,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ NB2 = cre_NotifBehav(notifyImmediate, 'NULL'),
+ RED2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, RED2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a02() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7802,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ NB2 = cre_NotifBehav(neverNotify, 'NULL'),
+ RED2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, RED2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a03() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7803,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ RED2 = cre_RegEmbedDesc(),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a04() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7814, [SRE2]),
+ RED2 = cre_RegEmbedDesc(SED2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7824, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a05() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7805,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SD2 = cre_SigsDesc(),
+ RED2 = cre_RegEmbedDesc(SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a06() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7816, [SRE2]),
+ Sig2 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR2 = cre_SigReq(Sig2),
+ SRs2 = [SR2],
+ SD2 = cre_SigsDesc(SRs2),
+ RED2 = cre_RegEmbedDesc(SED2, SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7826, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a07() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7817, [SRE2]),
+ Sig2 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR2 = cre_SigReq(Sig2),
+ SRs2 = [SR2],
+ SD2 = cre_SigsDesc(SRs2),
+ RED2 = cre_RegEmbedDesc(SED2, SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = 'NULL',
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7827, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a08() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+
+ Sig21 = cre_Sig("al/ri", both, asn1_NOVALUE),
+ SR21 = cre_SigReq(Sig21),
+ SRs21 = [SR21],
+ SD21 = cre_SigsDesc(SRs21),
+ RED21 = cre_RegEmbedDesc(SD21),
+ NB21 = cre_NotifBehav(notifyRegulated, RED21),
+ SRA2 = cre_SecReqActs(KA2, EDM2, asn1_NOVALUE, NB21, 'NULL'),
+ SRE2 = cre_SecReqEv("al/of", 7816, SRA2),
+ SED2 = cre_SecEvsDesc(7826, [SRE2]),
+
+ Sig22 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR22 = cre_SigReq(Sig22),
+ SRs22 = [SR22],
+ SD22 = cre_SigsDesc(SRs22),
+ RED22 = cre_RegEmbedDesc(SED2, SD22),
+ NB22 = cre_NotifBehav(notifyRegulated, RED22),
+ REvD2 = 'NULL',
+
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB22, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7836, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a09() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+
+ SID21 = cre_StreamID(7819),
+ ST21 = cre_SigType(timeOut),
+ Dur21 = 7898,
+ NC21 = cre_NotifCompl([onTimeOut, onInterruptByEvent, otherReason]),
+ KA21 = cre_BOOLEAN(false),
+ SPL21 = [],
+ Dir21 = cre_SigDir(both),
+ RID21 = cre_ReqID(7829),
+
+ Sig21 = cre_Sig("cg/rt", SID21, ST21, Dur21, NC21, KA21, SPL21, Dir21,
+ RID21, 7839),
+ SR21 = cre_SigReq(Sig21),
+ SRs21 = [SR21],
+ SD21 = cre_SigsDesc(SRs21),
+ RED21 = cre_RegEmbedDesc(SD21),
+ NB21 = cre_NotifBehav(notifyRegulated, RED21),
+
+ SRA2 = cre_SecReqActs(KA2, EDM2, asn1_NOVALUE, NB21, 'NULL'),
+ SRE2 = cre_SecReqEv("al/of", 7849, SRA2),
+ SED2 = cre_SecEvsDesc(7859, [SRE2]),
+
+ SID22 = cre_StreamID(7869),
+ ST22 = cre_SigType(brief),
+ Dur22 = 17809,
+ NC22 = cre_NotifCompl([onTimeOut, otherReason]),
+ KA22 = cre_BOOLEAN(true),
+ SPL22 = [],
+ Dir22 = cre_SigDir(external),
+ RID22 = cre_ReqID(7879),
+
+ Sig22 = cre_Sig("cg/rt", SID22, ST22, Dur22, NC22, KA22, SPL22, Dir22,
+ RID22, 7889),
+ SR22 = cre_SigReq(Sig22),
+ SRs22 = [SR22],
+ SD22 = cre_SigsDesc(SRs22),
+ RED22 = cre_RegEmbedDesc(SED2, SD22),
+
+ NB22 = cre_NotifBehav(notifyRegulated, RED22),
+ REvD2 = 'NULL',
+
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB22, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7899, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+
+msg79a01() ->
+ TID1 = #megaco_term_id{id = ?A4444},
+ TID2 = #megaco_term_id{id = ?A4445},
+ TID3 = #megaco_term_id{id = ?A5555},
+ TIDs = cre_TermIDList([TID1, TID2, TID3]),
+ ErC = cre_ErrCode(?megaco_not_ready),
+ ErD = cre_ErrDesc(ErC),
+ ARP1 = cre_AuditRetParam(ErD),
+ RE = cre_ReqEv("al/of"),
+ EvD = cre_EvsDesc(7911,[RE]),
+ ARP2 = cre_AuditRetParam(EvD),
+ Tks = [mediaToken, digitMapToken, statsToken, packagesToken],
+ AD = cre_AuditDesc(Tks),
+ ARP3 = cre_AuditRetParam(AD),
+ TAR = cre_TermAudit([ARP1, ARP2, ARP3]),
+ TLAR = cre_TermListAuditRes(TIDs, TAR),
+ AudR = cre_AuditRep(TLAR),
+ CR = cre_CmdRep(auditValueReply, AudR),
+ ActR = cre_ActRep(7921, [CR]),
+ Acts = [ActR],
+ msg_reply(?MG2_MID, 7931, Acts).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 2),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+%% --------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% skip(Reason) ->
+%% megaco_codec_test_lib:skip(Reason).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ticket_compact_encode_decode_ok(Msg) ->
+ ticket_compact_encode_decode_ok(Msg, []).
+
+ticket_compact_encode_decode_ok(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_encode_decode_ok(Msg, Codec, Conf).
+
+ticket_pretty_encode_decode_ok(Msg) ->
+ ticket_pretty_encode_decode_ok(Msg, []).
+
+ticket_pretty_encode_decode_ok(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_ok(Msg, Codec, Conf).
+
+ticket_encode_decode_ok(Msg, Codec, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M1, M2) -> chk_MegacoMessage(M1, M2) end,
+ megaco_codec_test_lib:expect_encode_decode(Msg, Encode, Decode, Check).
+
+%% --
+
+%% ticket_compact_encode_error(Msg) ->
+%% ticket_compact_encode_error(Msg, []).
+
+%% ticket_compact_encode_error(Msg, Conf) ->
+%% Codec = megaco_compact_text_encoder,
+%% ticket_encode_error(Msg, Codec, Conf).
+
+%% ticket_pretty_encode_error(Msg) ->
+%% ticket_pretty_encode_error(Msg, []).
+
+ticket_pretty_encode_error(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_error(Msg, Codec, Conf);
+ticket_pretty_encode_error(Msg, Check) when is_function(Check) ->
+ ticket_pretty_encode_error(Msg, [], Check).
+
+ticket_pretty_encode_error(Msg, Conf, Check) when is_function(Check) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_error(Msg, Codec, Conf, Check).
+
+ticket_encode_error(Msg, Codec, Conf) when is_list(Conf) ->
+ Check = fun(_) -> ok end, % Only called when encode failes
+ ticket_encode_error(Msg, Codec, Conf, Check).
+
+ticket_encode_error(Msg, Codec, Conf0, Check) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ megaco_codec_test_lib:expect_encode(Msg, Encode, Check).
+
+%% --
+
+ticket_compact_decode_encode_ok(Msg) ->
+ ticket_compact_decode_encode_ok(Msg, []).
+
+ticket_compact_decode_encode_ok(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_decode_encode_ok(Msg, Codec, Conf).
+
+ticket_pretty_decode_encode_ok(Msg) ->
+ ticket_pretty_decode_encode_ok(Msg, []).
+
+ticket_pretty_decode_encode_ok(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_encode_ok(Msg, Codec, Conf).
+
+ticket_decode_encode_ok(Msg, Codec, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Check = fun(M1, M2) -> chk_MegacoMessage(M1, M2) end,
+ megaco_codec_test_lib:expect_decode_encode(Msg, Decode, Encode, Check).
+
+%% --
+
+ticket_pretty_decode_encode_only(Msg, Check) ->
+ ticket_pretty_decode_encode_only(Msg, Check, []).
+
+ticket_pretty_decode_encode_only(Msg, Check, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_encode_only(Msg, Codec, Check, Conf).
+
+ticket_decode_encode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ megaco_codec_test_lib:expect_decode_encode_only(Msg, Decode, Encode,
+ Check).
+
+%% --
+
+ticket_pretty_encode_decode_only(Msg) ->
+ ticket_pretty_encode_decode_only(Msg, []).
+
+ticket_pretty_encode_decode_only(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_only(Msg, Codec, Conf);
+ticket_pretty_encode_decode_only(Msg, Check) when is_function(Check) ->
+ ticket_pretty_encode_decode_only(Msg, Check, []).
+
+ticket_pretty_encode_decode_only(Msg, Check, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_only(Msg, Codec, Check, Conf).
+
+ticket_encode_decode_only(Msg, Codec, Conf) ->
+ Check = fun(_) -> ok end,
+ ticket_encode_decode_only(Msg, Codec, Check, Conf).
+
+ticket_encode_decode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_encode_decode_only(Msg, Encode, Decode,
+ Check).
+
+%% --
+
+ticket_pretty_decode_only(Msg) ->
+ ticket_pretty_decode_only(Msg, []).
+
+ticket_pretty_decode_only(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_only(Msg, Codec, Conf).
+
+ticket_decode_only(Msg, Codec, Conf) ->
+ Check = fun(_) -> ok end,
+ ticket_decode_only(Msg, Codec, Check, Conf).
+
+ticket_decode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+ticket_check_decode_only_error_reason(R, Check)
+ when is_list(R) and is_function(Check) ->
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, Reason}} ->
+ Check(Reason);
+ false ->
+ {error, {reason_not_found, R}}
+ end.
+
+
+%% --
+
+ticket_compact_decode_error(Msg) ->
+ ticket_compact_decode_error(Msg, []).
+
+ticket_compact_decode_error(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf).
+
+ticket_pretty_decode_error(Msg) ->
+ ticket_pretty_decode_error(Msg, []).
+
+ticket_pretty_decode_error(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf);
+ticket_pretty_decode_error(Msg, Check) when is_function(Check) ->
+ ticket_pretty_decode_error(Msg, [], Check).
+
+ticket_pretty_decode_error(Msg, Conf, Check) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf, Check).
+
+ticket_decode_error(Msg, Codec, Conf) ->
+ Check = fun(X) ->
+ d("decode error reason: ~n~p~n", [X]),
+ ok
+ end, % Only called when decode failes
+ ticket_decode_error(Msg, Codec, Conf, Check).
+
+ticket_decode_error(Msg, Codec, Conf0, Check) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+%% --
+
+%% ticket_expect_exec(Instructions, Msg) ->
+%% megaco_codec_test_lib:expect_exec(Instructions, Msg).
+
+%% ticket_expect_instruction(Desc, Cmd, Verify) ->
+%% megaco_codec_test_lib:expect_instruction(Desc, Cmd, Verify).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% pretty_decode_message(DynamicDecode, Conf, Bin) ->
+%% decode_message(megaco_pretty_text_encoder, DynamicDecode, Conf, Bin).
+
+%% compact_decode_message(DynamicDecode, Conf, Bin) ->
+%% decode_message(megaco_compact_text_encoder, DynamicDecode, Conf, Bin).
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+
+%% pretty_encode_message(Conf, Msg) ->
+%% encode_message(megaco_pretty_text_encoder, Conf, Msg).
+
+%% compact_encode_message(Conf, Msg) ->
+%% encode_message(megaco_compact_text_encoder, Conf, Msg).
+
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M1, M2) ->
+ ?MSG_LIB:chk_MegacoMessage(M1, M2).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_MegacoMessage(Auth, Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Auth, Mess).
+
+cre_MegacoMessage(V, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(V, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+cre_AuthHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_AuthHeader(SecParmIdx, SeqNum, AD).
+
+cre_AuthHeader(Idx, Num, D) ->
+ ?MSG_LIB:cre_AuthenticationHeader(Idx, Num, D).
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_TransRep(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions).
+
+cre_TransAck(First, Last) ->
+ ?MSG_LIB:cre_TransactionAck(First, Last).
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_ActRep(CtxId, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, CmdReps).
+
+cre_ActRep(CtxId, ED, CR, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, ED, CR, CmdReps).
+
+cre_CtxReq() ->
+ ?MSG_LIB:cre_ContextRequest().
+
+cre_CtxReq(A) ->
+ ?MSG_LIB:cre_ContextRequest(A).
+
+cre_CtxReq(A, B) ->
+ ?MSG_LIB:cre_ContextRequest(A, B).
+
+cre_CtxReq(A, B, C) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C).
+
+cre_CtxReq(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D).
+
+cre_CtxReq(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D, E).
+
+cre_CtxReq(Prio, Em, Top, Ieps, CtxProp, CtxList) ->
+ ?MSG_LIB:cre_ContextRequest(Prio, Em, Top, Ieps, CtxProp, CtxList).
+
+cre_CtxAttrAuditReq() ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest().
+
+% cre_CtxAttrAuditReq(A) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A).
+
+% cre_CtxAttrAuditReq(A, B) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A, B).
+
+cre_CtxAttrAuditReq(A, B, C) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C).
+
+cre_CtxAttrAuditReq(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D).
+
+cre_CtxAttrAuditReq(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SPrio).
+
+cre_CtxAttrAuditReq(A, B, C, D, E, F, G) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E, F, G).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio, SEm, SIeps) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SPrio, SEm, SIeps).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio, SEm, SIeps, SLog) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SPrio, SEm, SIeps, SLog).
+
+cre_TopologyRequest(From, To, Dir) ->
+ ?MSG_LIB:cre_TopologyRequest(From, To, Dir).
+
+%% Ind Aud related:
+
+cre_IndAudParam(IAP) ->
+ ?MSG_LIB:cre_IndAuditParameter(IAP).
+
+cre_IndAudMediaDesc(D) ->
+ ?MSG_LIB:cre_IndAudMediaDescriptor(D).
+
+cre_IndAudStreamDesc(SID, SP) ->
+ ?MSG_LIB:cre_IndAudStreamDescriptor(SID, SP).
+
+cre_IndAudStreamParms(LCD) ->
+ ?MSG_LIB:cre_IndAudStreamParms(LCD).
+
+cre_IndAudLocalControlDesc(A, B, C, D) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(A, B, C, D).
+
+cre_IndAudLocalControlDesc(SM, RV, RG, PP, SMS) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS).
+
+cre_IndAudPropertyParm(Name) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name).
+
+cre_IndAudPropertyParm(Name, PP) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name, PP).
+
+cre_IndAudTermStateDesc(PP) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP).
+
+cre_IndAudTermStateDesc(PP, EBC, SS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS).
+
+cre_IndAudTermStateDesc(PP, EBC, SS, SSS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS, SSS).
+
+cre_IndAudEvsDesc(RID, PN)
+ when is_integer(RID) ->
+ ?MSG_LIB:cre_IndAudEventsDescriptor(RID, PN).
+
+cre_IndAudEvBufDesc(EN, SID) ->
+ ?MSG_LIB:cre_IndAudEventBufferDescriptor(EN, SID).
+
+cre_IndAudSigsDesc(D) ->
+ ?MSG_LIB:cre_IndAudSignalsDescriptor(D).
+
+cre_IndAudSig(SN) ->
+ ?MSG_LIB:cre_IndAudSignal(SN).
+
+cre_IndAudSig(SN, SigRID) ->
+ ?MSG_LIB:cre_IndAudSignal(SN, SigRID).
+
+cre_IndAudSeqSigList(ID, SL) ->
+ ?MSG_LIB:cre_IndAudSeqSigList(ID, SL).
+
+cre_IndAudDigitMapDesc(DMN) ->
+ ?MSG_LIB:cre_IndAudDigitMapDescriptor(DMN).
+
+cre_IndAudStatsDesc(SN) ->
+ ?MSG_LIB:cre_IndAudStatisticsDescriptor(SN).
+
+cre_IndAudPkgsDesc(PN, PV) ->
+ ?MSG_LIB:cre_IndAudPackagesDescriptor(PN, PV).
+
+%% Parameter related
+cre_PropParm(Name, Val) ->
+ ?MSG_LIB:cre_PropertyParm(Name, [Val]).
+
+cre_PropParm(Name, Vals, Tag, EI) ->
+ ?MSG_LIB:cre_PropertyParm(Name, Vals, Tag, EI).
+
+
+%% Statistics related
+cre_StatsDesc(SPs) ->
+ ?MSG_LIB:cre_StatisticsDescriptor(SPs).
+
+cre_StatsParm(Name) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name).
+
+cre_StatsParm(Name, Val) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name, [Val]).
+
+
+% Event related
+cre_EvParm(Name, Val) ->
+ ?MSG_LIB:cre_EventParameter(Name, Val).
+
+cre_ObsEv(Name, Not) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Not).
+cre_ObsEv(Name, Not, Par) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Par, Not).
+
+cre_ReqEv(Name) ->
+ ?MSG_LIB:cre_RequestedEvent(Name).
+cre_ReqEv(Name, EPL) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, EPL).
+cre_ReqEv(Name, SID, RA, EPL) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, SID, RA, EPL).
+
+
+cre_ObsEvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_ObservedEventsDescriptor(Id, EvList).
+
+cre_EvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_EventsDescriptor(Id, EvList).
+
+
+%% Service change related
+cre_SvcChParm(M, A, R, P) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, P, R).
+
+cre_SvcChParm(M, A, R, P, IF) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, asn1_NOVALUE, P, R, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, IF).
+
+cre_SvcChResParm(A, P) ->
+ ?MSG_LIB:cre_ServiceChangeResParm(A, P).
+
+cre_SvcChReq(Tids, P) ->
+ ?MSG_LIB:cre_ServiceChangeRequest(Tids, P).
+
+cre_SvcChProf(Name, Ver) ->
+ ?MSG_LIB:cre_ServiceChangeProfile(Name, Ver).
+
+cre_SvcChAddr(Tag, Val) ->
+ ?MSG_LIB:cre_ServiceChangeAddress(Tag, Val).
+
+cre_SvcChMethod(M) ->
+ ?MSG_LIB:cre_ServiceChangeMethod(M).
+
+cre_SvcChRep(Tids, Res) ->
+ ?MSG_LIB:cre_ServiceChangeReply(Tids, Res).
+
+
+%% Stream related
+cre_StreamID(Id) ->
+ ?MSG_LIB:cre_StreamID(Id).
+
+cre_StreamParms(Lcd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd).
+cre_StreamParms(Lcd, Ld) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld).
+cre_StreamParms(Lcd, Ld, Rd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld, Rd).
+cre_StreamParmsL(Ld) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, Ld, asn1_NOVALUE).
+cre_StreamParmsR(Rd) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, asn1_NOVALUE, Rd).
+
+cre_StreamDesc(Id, P) ->
+ ?MSG_LIB:cre_StreamDescriptor(Id, P).
+
+
+%% "Local" related
+cre_LocalControlDesc(Mode) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode).
+cre_LocalControlDesc(Mode, Parms) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode, Parms).
+
+cre_LocalRemoteDesc(Grps) ->
+ ?MSG_LIB:cre_LocalRemoteDescriptor(Grps).
+
+
+%% DigitMap related
+cre_DigitMapDesc() ->
+ ?MSG_LIB:cre_DigitMapDescriptor().
+cre_DigitMapDesc(NameOrVal) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(NameOrVal).
+cre_DigitMapDesc(Name, Val) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(Name, Val).
+
+cre_DigitMapValue(Body) ->
+ ?MSG_LIB:cre_DigitMapValue(Body).
+
+cre_DigitMapValue(Body, Start, Short, Long) ->
+ ?MSG_LIB:cre_DigitMapValue(Start, Short, Long, Body).
+
+%% Media related
+cre_MediaDesc(SD) when is_record(SD, 'StreamDescriptor') ->
+ cre_MediaDesc([SD]);
+cre_MediaDesc(SDs) ->
+ ?MSG_LIB:cre_MediaDescriptor(SDs).
+
+
+%% Notify related
+cre_NotifyReq(Tids, EvsDesc) ->
+ ?MSG_LIB:cre_NotifyRequest(Tids, EvsDesc).
+
+cre_NotifyRep(Tids) ->
+ ?MSG_LIB:cre_NotifyReply(Tids).
+
+
+%% Subtract related
+cre_SubReq(Tids, Desc) ->
+ ?MSG_LIB:cre_SubtractRequest(Tids, Desc).
+
+
+%% Audit related
+cre_AuditDesc(Tokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens).
+
+cre_AuditDesc(Tokens, PropertTokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens, PropertTokens).
+
+cre_AuditReq(Tid, Desc) ->
+ ?MSG_LIB:cre_AuditRequest(Tid, Desc).
+
+cre_AuditRep(AR) ->
+ ?MSG_LIB:cre_AuditReply(AR).
+
+cre_AuditRes(Tid, Res) ->
+ ?MSG_LIB:cre_AuditResult(Tid, Res).
+
+cre_TermAudit(ARP) ->
+ ?MSG_LIB:cre_TerminationAudit(ARP).
+
+cre_AuditRetParam(D) ->
+ ?MSG_LIB:cre_AuditReturnParameter(D).
+
+cre_TermListAuditRes(TIDs, TA) ->
+ ?MSG_LIB:cre_TermListAuditResult(TIDs, TA).
+
+%% AMM/AMMS related
+cre_AmmDesc(D) ->
+ ?MSG_LIB:cre_AmmDescriptor(D).
+
+cre_AmmReq(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmRequest(Tids, Descs).
+
+cre_AmmsReply(Tids) ->
+ ?MSG_LIB:cre_AmmsReply(Tids).
+cre_AmmsReply(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmsReply(Tids, Descs).
+
+
+%% Command related
+cre_Cmd(Tag, Req) ->
+ ?MSG_LIB:cre_Command(Tag, Req).
+
+cre_CmdReq(Cmd) ->
+ ?MSG_LIB:cre_CommandRequest(Cmd).
+
+cre_CmdRep(Tag, Rep) ->
+ ?MSG_LIB:cre_CommandReply(Tag, Rep).
+
+
+%% Actions related
+cre_ReqActs(A) ->
+ ?MSG_LIB:cre_RequestedActions(A).
+
+cre_ReqActs(KA, EDM, SE, SD, NB, RED) ->
+ ?MSG_LIB:cre_RequestedActions(KA, EDM, SE, SD, NB, RED).
+
+%% cre_SecReqActs() ->
+%% ?MSG_LIB:cre_SecondRequestedActions().
+
+%% cre_SecReqActs(A) ->
+%% ?MSG_LIB:cre_SecondRequestedActions(A).
+
+cre_SecReqActs(KA, EDM, SD, NB, RED) ->
+ ?MSG_LIB:cre_SecondRequestedActions(KA, EDM, SD, NB, RED).
+
+cre_EvDM(Name) when is_list(Name) ->
+ ?MSG_LIB:cre_EventDM(Name).
+
+cre_RegEmbedDesc() ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor().
+
+cre_RegEmbedDesc(D) ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor(D).
+
+cre_RegEmbedDesc(SED, SD) ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor(SED, SD).
+
+%% cre_SecEvsDesc(REDs) ->
+%% ?MSG_LIB:cre_SecondEventsDescriptor(REDs).
+
+cre_SecEvsDesc(RID, REDs) ->
+ ?MSG_LIB:cre_SecondEventsDescriptor(RID, REDs).
+
+cre_SecReqEv(N) ->
+ cre_SecReqEv(N, []).
+
+cre_SecReqEv(N, EPL) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(N, EPL).
+
+cre_SecReqEv(N, SID, EA) when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'SecondRequestedActions') ->
+ cre_SecReqEv(N, SID, EA, []);
+cre_SecReqEv(A, B, C) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(A, B, C).
+
+cre_SecReqEv(N, SID, EA, EPL) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(N, SID, EA, EPL).
+
+%% Signal related
+cre_SigsDesc() ->
+ cre_SigsDesc([]).
+
+cre_SigsDesc(SRs) ->
+ ?MSG_LIB:cre_SignalsDescriptor(SRs).
+
+cre_SigDir(D) ->
+ ?MSG_LIB:cre_SignalDirection(D).
+
+cre_Sig(Name) ->
+ cre_Sig(Name, []).
+
+cre_Sig(Name, SPL) ->
+ ?MSG_LIB:cre_Signal(Name, SPL).
+
+cre_Sig(Name, Dir, RID) ->
+ cre_Sig(Name, [], Dir, RID).
+
+cre_Sig(Name, SPL, Dir, RID) ->
+ cre_Sig(Name, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD).
+
+cre_SigReq(S) ->
+ ?MSG_LIB:cre_SignalRequest(S).
+
+cre_NotifBehav(Tag, Val) ->
+ ?MSG_LIB:cre_NotifyBehaviour(Tag, Val).
+
+cre_NotifCompl(NC) ->
+ ?MSG_LIB:cre_NotifyCompletion(NC).
+
+cre_SigType(ST) ->
+ ?MSG_LIB:cre_SignalType(ST).
+
+
+%% Others
+cre_ErrCode(EC) ->
+ ?MSG_LIB:cre_ErrorCode(EC).
+
+cre_ErrDesc(EC) ->
+ ?MSG_LIB:cre_ErrorDescriptor(EC).
+
+cre_TermIDList(TIDs) ->
+ ?MSG_LIB:cre_TerminationIDList(TIDs).
+
+cre_ServiceState(SS) ->
+ ?MSG_LIB:cre_ServiceState(SS).
+
+cre_StreamMode(SS) ->
+ ?MSG_LIB:cre_StreamMode(SS).
+
+cre_SelectLogic(Tag) ->
+ ?MSG_LIB:cre_SelectLogic(Tag).
+
+cre_CtxID(CID) ->
+ ?MSG_LIB:cre_ContextID(CID).
+
+cre_ReqID(RID) ->
+ ?MSG_LIB:cre_RequestID(RID).
+
+cre_TimeNot(D,T) ->
+ ?MSG_LIB:cre_TimeNotation(D, T).
+
+cre_PkgsItem(Name, Ver) ->
+ ?MSG_LIB:cre_PackagesItem(Name, Ver).
+
+cre_BOOLEAN(B) ->
+ ?MSG_LIB:cre_BOOLEAN(B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+%% start_flex_scanner() ->
+%% megaco_codec_flex_lib:start().
+
+%% stop_flex_scanner(Pid) ->
+%% megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+%% l(F,A) ->
+%% p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s:" ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "TRC";
+image_of(dbg) ->
+ "DBG";
+image_of(log) ->
+ "LOG";
+image_of(err) ->
+ "ERR";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
diff --git a/lib/megaco/test/megaco_codec_test.erl b/lib/megaco/test/megaco_codec_test.erl
new file mode 100644
index 0000000000..d247959cc5
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_test.erl
@@ -0,0 +1,63 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test application config
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+init() ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:flush().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ codec
+ ].
+
+codec(suite) ->
+ [{megaco_codec_mini_test, all},
+ {megaco_codec_v1_test, all},
+ {megaco_codec_v2_test, all},
+ {megaco_codec_prev3a_test, all},
+ {megaco_codec_prev3b_test, all},
+ {megaco_codec_prev3c_test, all},
+ {megaco_codec_v3_test, all}].
+
diff --git a/lib/megaco/test/megaco_codec_test_lib.erl b/lib/megaco/test/megaco_codec_test_lib.erl
new file mode 100644
index 0000000000..66e8a52a24
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_test_lib.erl
@@ -0,0 +1,1024 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test library module for Megaco/H.248 encode/decode
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_test_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([
+ skip/1,
+
+ display_text_messages/2, display_text_messages/3,
+ generate_text_messages/4,
+ test_msgs/6,
+
+ plain_decode_encode/5,
+ plain_encode_decode/5,
+ trans_first_encode_decode/5,
+ actions_first_encode_decode/5,
+ action_first_encode_decode/5,
+
+ encode_message/4,
+ decode_message/5, decode_message/6,
+
+ expect_instruction/3,
+ expect_encode/3,
+ expect_encode_only/3,
+ expect_encode_decode/4,
+ expect_encode_decode_only/4,
+ expect_decode/3,
+ expect_decode_only/3,
+ expect_decode_encode/4,
+ expect_decode_encode_only/4,
+ expect_exec/2
+ ]).
+
+
+-record(expect_instruction,
+ {
+ %% Short description of what this instruction does
+ description, % string()
+
+ %% The actual instruction
+ command, % function(Data) -> term()
+
+ %% Verification function of the instruction
+ verify % function(Res, Data) -> {ok, NewData} | {error, Reason}
+ }
+ ).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_text_messages(V, Msgs) ->
+ display_text_messages(V, [], Msgs).
+
+display_text_messages(_, _, []) ->
+ ok;
+display_text_messages(V, EC, [{Name, Msg, _ED, _Conf}|Msgs]) ->
+ (catch display_text_message(Name, EC, Msg, V)),
+ display_text_messages(V, EC, Msgs).
+
+
+display_text_message(Name, EC, Msg, V) when is_tuple(Msg) ->
+ io:format("~n(Erlang) message ~p:~n~p~n", [Name, Msg]),
+ case (catch megaco_pretty_text_encoder:encode_message(EC,V,Msg)) of
+ {'EXIT', _R} ->
+ io:format("~nPretty encoded: failed (exit)~n", []);
+ {error, {{deprecated, PWhat}, _}} ->
+ io:format("~nPretty encoded: deprecated~n~p~n", [PWhat]),
+ throw(continue);
+ {error, PReason} ->
+ io:format("~nPretty encoded: failed (error)~n~p~n", [PReason]),
+ throw(continue);
+ {ok, Pretty} ->
+ io:format("~nPretty encoded:~n~s~n", [binary_to_list(Pretty)])
+ end,
+ case (catch megaco_compact_text_encoder:encode_message(EC,V,Msg)) of
+ {'EXIT', _} ->
+ io:format("~nCompact encoded: failed~n", []);
+ {error, {{deprecated, CWhat}, _}} ->
+ io:format("~nPretty encoded: deprecated~n~p~n", [CWhat]);
+ {ok, Compact} ->
+ io:format("~nCompact encoded:~n~s~n", [binary_to_list(Compact)])
+ end;
+display_text_message(_, _, _, _) ->
+ skipping.
+
+generate_text_messages(DirName, V, EC, Msgs) when is_atom(DirName) ->
+ generate_text_messages(atom_to_list(DirName), V, EC, Msgs);
+generate_text_messages(DirName, V, EC, Msgs) when is_list(DirName) ->
+ DirPath = filename:join(["/tmp", DirName]),
+ case file:make_dir(DirPath) of
+ ok ->
+ generate_text_messages2(DirPath, V, EC, Msgs);
+ {error, eexist} ->
+ generate_text_messages2(DirPath, V, EC, Msgs);
+ {error, Reason} ->
+ io:format("Failed creating directory ~s: ~p~n", [DirPath, Reason]),
+ ok
+ end.
+
+generate_text_messages2(_, _, _, []) ->
+ ok;
+generate_text_messages2(Dir, V, EC, [{Name, Msg, _ED, _Conf}|Msgs]) ->
+ (catch generate_text_message(Dir, Name, EC, Msg, V)),
+ generate_text_messages2(Dir, V, EC, Msgs).
+
+generate_text_message(Dir, Name, EC, Msg, V) ->
+ io:format("~p: ", [Name]),
+ case (catch megaco_pretty_text_encoder:encode_message(EC,V,Msg)) of
+ {'EXIT', EReason} ->
+ io:format("failed encoding [exit]: ~n~p~n", [EReason]),
+ throw(continue);
+ {error, {{deprecated, PWhat}, _}} ->
+ io:format("failed encoding [deprecated]: ~n~p~n", [PWhat]),
+ throw(continue);
+ {error, PReason} ->
+ io:format("failed encoding [error]: ~n~p~n", [PReason]),
+ throw(continue);
+ {ok, Pretty} ->
+ io:format("encoded", []),
+ FName = filename:flatten([Name, ".txt"]),
+ Filename = filename:join([Dir, FName]),
+ case (catch file:open(Filename, [write])) of
+ {ok, Fd} ->
+ io:format(Fd, "~s", [binary_to_list(Pretty)]),
+ io:format(" - written to disk~n", []),
+ (catch file:close(Fd)),
+ ok;
+ {error, OReason} ->
+ io:format(" - failed writing to disk: "
+ "~n~p~n~s~n",
+ [OReason, binary_to_list(Pretty)]),
+ throw(continue)
+ end
+ end.
+
+test_msgs(Codec, DynamicDecode, Ver, EC, Check, Msgs)
+ when is_function(Check) andalso is_list(Msgs) ->
+ io:format("~n", []),
+ test_msgs(Codec, DynamicDecode, Ver, EC, Check, Msgs, []).
+
+test_msgs(_Codec, _DD, _Ver, _EC, _Check, [], []) ->
+ ok;
+test_msgs(_Codec, _DD, _Ver, _EC, _Check, [], Errs) ->
+ ?ERROR(lists:reverse(Errs));
+test_msgs(Codec, DD, Ver, EC, Check,
+ [{Name, {error, Error}, _ED, _Conf}|Msgs], Acc) ->
+ io:format("error~n", []),
+ test_msgs(Codec, DD, Ver, EC, Check, Msgs, [{Name, Error}|Acc]);
+test_msgs(Codec, DD, Ver, EC, Check,
+ [{Name, Msg, ED, Conf}|Msgs], Acc) ->
+ Dbg = test_msgs_debug(Conf),
+ put(dbg, Dbg),
+ io:format("~-16w ", [Name]),
+ case (catch encode_decode(ED, Check, Codec, DD, Ver, EC, Msg)) of
+ ok ->
+ io:format("ok~n", []),
+ erase(dbg),
+ test_msgs(Codec, DD, Ver, EC, Check, Msgs, Acc);
+ Error ->
+ io:format("error~n", []),
+ erase(dbg),
+ test_msgs(Codec, DD, Ver, EC, Check, Msgs, [{Name, Error}|Acc])
+ end.
+
+test_msgs_debug(Conf) ->
+ case lists:keysearch(dbg, 1, Conf) of
+ {value, {dbg, true}} ->
+ true;
+ _ ->
+ false
+ end.
+
+encode_decode(Func, Check, Codec, DynamicDecode, Ver, EC, Msg1)
+ when is_function(Func) ->
+ d("encode_decode -> entry with"
+ "~n Func: ~p"
+ "~n Check: ~p"
+ "~n Codec: ~p"
+ "~n DynamicDecode: ~p"
+ "~n Ver: ~p"
+ "~n EC: ~p",
+ [Func, Check, Codec, DynamicDecode, Ver, EC]),
+ case (catch Func(Codec, DynamicDecode, Ver, EC, Msg1)) of
+ {ok, Msg1} ->
+ d("encode_decode -> expected result"),
+ ok;
+ {ok, Msg2} ->
+ d("encode_decode -> unexpected result - check"),
+ case (catch Check(Msg1, Msg2)) of
+ ok ->
+ d("encode_decode -> check - ok"),
+ ok;
+ {error, Reason} ->
+ d("encode_decode -> check - error: "
+ "~n Reason: ~p", [Reason]),
+ {error, {Reason, Msg1, Msg2}};
+ Else ->
+ d("encode_decode -> check - failed: "
+ "~n Else: ~p", [Else]),
+ {error, {invalid_check_result, Else}}
+ end;
+ Else ->
+ d("encode_decode -> failed: "
+ "~n Else: ~p", [Else]),
+ Else
+ end.
+
+
+%% *** plain_encode_decode ***
+
+plain_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
+ d("plain_encode_decode -> entry with"
+ "~n Codec: ~p"
+ "~n DynamicDecode: ~p"
+ "~n Ver: ~p"
+ "~n EC: ~p", [Codec, DynamicDecode, Ver, EC]),
+ case (catch encode_message(Codec, Ver, EC, M1)) of
+ {ok, Bin} ->
+ d("plain_encode_decode -> encode - ok"),
+ decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
+ Error ->
+ d("plain_encode_decode -> encode - failed: "
+ "~n Error: ~p", [Error]),
+ Error
+ end.
+
+
+%% *** plain_decode_encode ***
+
+plain_decode_encode(Codec, DynamicDecode, Ver, EC, M) when is_list(M) ->
+ Bin = list_to_binary(M),
+ plain_decode_encode(Codec, DynamicDecode, Ver, EC, Bin);
+plain_decode_encode(Codec, DynamicDecode, Ver, EC, B) when is_binary(B) ->
+ case (catch decode_message(Codec, DynamicDecode, Ver, EC, B, true)) of
+ {ok, M} ->
+ encode_message(Codec, Ver, EC, M);
+ Error ->
+ Error
+ end.
+
+
+%% *** trans_first_encode_decode ***
+
+trans_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
+ d("trans_first_encode_decode -> entry"),
+ case (catch trans_first_encode_message(Codec, Ver, EC, M1)) of
+ {ok, Bin} ->
+ decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
+ Error ->
+ Error
+ end.
+
+trans_first_encode_message(Codec, Ver, EC, M1) ->
+ d("trans_first_encode_message -> entry"),
+ Mess1 = M1#'MegacoMessage'.mess,
+ {transactions, Trans1} = Mess1#'Message'.messageBody,
+ Trans2 = encode_transactions(Codec, Ver, EC, Trans1),
+ Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
+ M2 = M1#'MegacoMessage'{mess = Mess2},
+ encode_message(Codec, Ver, EC, M2).
+
+encode_transactions(Codec, Ver, EC, Trans) when is_list(Trans) ->
+ d("encode_transactions -> entry"),
+ [encode_transaction(Codec, Ver, EC, T) || T <- Trans].
+
+encode_transaction(Codec, Ver, EC, T) ->
+ d("encode_transaction -> entry"),
+ case (catch Codec:encode_transaction(EC, Ver, T)) of
+ {ok, EncodecTransactions} ->
+ EncodecTransactions;
+ Error ->
+ throw({error, {transaction_encode_failed, Error, T}})
+ end.
+
+
+%% *** actions_first_encode_decode ***
+
+actions_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
+ d("actions_first_encode_decode -> entry"),
+ case (catch actions_first_encode_message(Codec, Ver, EC, M1)) of
+ {ok, Bin} ->
+ decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
+ Error ->
+ Error
+ end.
+
+actions_first_encode_message(Codec, Ver, EC, M1) ->
+ d("actions_first_encode_message -> entry"),
+ Mess1 = M1#'MegacoMessage'.mess,
+ {transactions, Trans1} = Mess1#'Message'.messageBody,
+ Trans2 = encode_actions(Codec, Ver, EC, Trans1),
+ Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
+ M2 = M1#'MegacoMessage'{mess = Mess2},
+ encode_message(Codec, Ver, EC, M2).
+
+encode_actions(Codec, Ver, EC, Trans) when is_list(Trans) ->
+ d("encode_actions -> entry"),
+ [encode_actions1(Codec, Ver, EC, T) || T <- Trans].
+
+encode_actions1(Codec, Ver, EC, {transactionRequest, TR1}) ->
+ d("encode_actions1 -> entry"),
+ #'TransactionRequest'{actions = ARs} = TR1,
+ case (catch encode_action_requests(Codec, Ver, EC, ARs)) of
+ {ok, EncodedARs} ->
+ TR2 = TR1#'TransactionRequest'{actions = EncodedARs},
+ {transactionRequest, TR2};
+ Error ->
+ throw({error, {actions_encode_failed, Error, TR1}})
+ end.
+
+encode_action_requests(Codec, Ver, EC, ARs) ->
+ d("encode_action_requests -> entry"),
+ Codec:encode_action_requests(EC, Ver, ARs).
+
+
+%% *** action_first_encode_decode ***
+
+action_first_encode_decode(Codec, DynamicDecode, Ver, EC, M1) ->
+ d("action_first_encode_decode -> entry"),
+ case (catch action_first_encode_message(Codec, Ver, EC, M1)) of
+ {ok, Bin} ->
+ decode_message(Codec, DynamicDecode, Ver, EC, Bin, true);
+ Error ->
+ Error
+ end.
+
+action_first_encode_message(Codec, Ver, EC, M1) ->
+ d("action_first_encode_message -> entry"),
+ Mess1 = M1#'MegacoMessage'.mess,
+ {transactions, Trans1} = Mess1#'Message'.messageBody,
+ Trans2 = encode_action(Codec, Ver, EC, Trans1),
+ Mess2 = Mess1#'Message'{messageBody = {transactions, Trans2}},
+ M2 = M1#'MegacoMessage'{mess = Mess2},
+ encode_message(Codec, Ver, EC, M2).
+
+encode_action(Codec, Ver, EC, Trans) when is_list(Trans) ->
+ d("encode_action -> entry"),
+ [encode_action1(Codec, Ver, EC, T) || T <- Trans].
+
+encode_action1(Codec, Ver, EC, {transactionRequest, TR1}) ->
+ d("encode_action1 -> entry"),
+ #'TransactionRequest'{actions = ARs1} = TR1,
+ ARs2 = [encode_action_request(Codec, Ver, EC, AR) || AR <- ARs1],
+ TR2 = TR1#'TransactionRequest'{actions = ARs2},
+ {transactionRequest, TR2}.
+
+encode_action_request(Codec, Ver, EC, AR) ->
+ d("encode_action_request -> entry"),
+ case (catch Codec:encode_action_request(EC, Ver, AR)) of
+ {ok, Bin} ->
+ Bin;
+ Error ->
+ throw({error, {encode_action_request_failed, Error, AR}})
+ end.
+
+
+encode_message(Codec, Ver, EC, M) ->
+ d("encode_message -> entry with"
+ "~n Codec: ~p"
+ "~n Ver: ~p"
+ "~n EC: ~p"
+ "~n M: ~p", [Codec, Ver, EC, M]),
+%% case (catch Codec:encode_message(EC, Ver, M)) of
+%% {ok, Bin} ->
+%% d("encode_message -> encode - ok: "
+%% "~n~s", [binary_to_list(Bin)]),
+%% {ok, Bin};
+%% Error ->
+%% d("encode_message -> encode - failed"),
+%% throw({error, {message_encode_failed, Error, M}})
+%% end.
+ case (catch timer:tc(Codec, encode_message, [EC, Ver, M])) of
+ {Time, {ok, Bin}} ->
+ d("encode_message -> encode - ok after ~p: "
+ "~n~s", [Time, binary_to_list(Bin)]),
+ {ok, Bin};
+ {_Time, Error} ->
+ d("encode_message -> encode - failed"),
+ throw({error, {message_encode_failed, Error, M}})
+ end.
+
+decode_message(Codec, Dynamic, Ver, EC, M) ->
+ decode_message(Codec, Dynamic, Ver, EC, M, false).
+
+decode_message(Codec, true, _Ver, EC, M, _Timed) ->
+ d("decode_message -> entry - when using dynamic"),
+ Codec:decode_message(EC, dynamic, M);
+decode_message(Codec, _, Ver, EC, M, false) ->
+ d("decode_message -> entry with"
+ "~n Codec: ~p"
+ "~n Ver: ~p"
+ "~n EC: ~p", [Codec, Ver, EC]),
+ Codec:decode_message(EC, Ver, M);
+decode_message(Codec, _, Ver, EC, M, true) ->
+ d("decode_message -> entry with"
+ "~n Codec: ~p"
+ "~n Ver: ~p"
+ "~n EC: ~p", [Codec, Ver, EC]),
+ {Time, Result} = timer:tc(Codec, decode_message, [EC, Ver, M]),
+ io:format("~-8w", [Time]),
+ Result.
+
+
+%% =======================================================================
+
+%% ------------------------------------------------------------------
+%% Create an instruction record
+%% ------------------------------------------------------------------
+
+expect_instruction(Desc, Cmd, Verify)
+ when is_list(Desc) andalso is_function(Cmd) andalso is_function(Verify) ->
+ #expect_instruction{description = Desc,
+ command = Cmd,
+ verify = Verify}.
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_encode
+%% Parameters: Msg -> MegacoMessage
+%% Encode -> function/1
+%% Check -> function/1
+%% Description: This function simply encodes, with the Encode fun,
+%% and expects this to fail. The failure reason is
+%% checked with the Check fun.
+%% ------------------------------------------------------------------
+
+expect_encode(InitialData, Encode, Check)
+ when is_function(Encode) andalso is_function(Check) ->
+ Instructions =
+ [
+ %% Initial encode
+ expect_instruction(
+ "Encode (initial) message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({error, Reason}, _) ->
+ io:format("check error reason ", []),
+ case (catch Check(Reason)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ ({ok, Bin}, Msg) when is_binary(Bin) ->
+ M = binary_to_list(Bin),
+ {error, {unexpected_encode_success, {M, Msg}}};
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_encode_only
+%% Parameters: InitialData -> list() | binary()
+%% Encode -> function/1
+%% Check -> function/1
+%% Description: This function simply encodes, with the Encode fun,
+%% and expects it to succeed, which is checked by
+%% calling the Check fun with the resulting message.
+%% ------------------------------------------------------------------
+
+expect_encode_only(InitialData, Encode, Check)
+ when is_function(Encode) andalso is_function(Check) ->
+ Instructions =
+ [
+ %% Initial encode
+ expect_instruction(
+ "Encode (initial) message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ case (catch Check(Bin)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_encode_decode
+%% Parameters: InitialData -> MegacoMessage
+%% Encode -> function/1
+%% Decode -> function/1
+%% Check -> function/2
+%% Description: This function simply encodes, with the Encode fun, and
+%% then decodes, with the Decode fun, the megaco message.
+%% The resulting message should be identical, but if it
+%% is not, the messages are checked, with the Check fun.
+%% ------------------------------------------------------------------
+
+expect_encode_decode(InitialData, Encode, Decode, Check)
+ when is_function(Encode) andalso
+ is_function(Decode) andalso
+ is_function(Check) ->
+ Instructions =
+ [
+ %% Initial encode
+ expect_instruction(
+ "Encode (initial) message",
+ fun(M) when is_record(M, 'MegacoMessage') ->
+ (catch Encode(M));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, M) when is_binary(Bin) ->
+ {ok, {Bin, M}};
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end),
+
+ %% Decode the (encoded) message
+ expect_instruction(
+ "Decode message",
+ fun({Bin, _}) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg1}, {_Bin, Msg1})
+ when is_record(Msg1, 'MegacoMessage') ->
+ io:format("messages identical - done ", []),
+ {ok, done};
+ ({ok, Msg2}, {_Bin, Msg1}) ->
+ io:format("messages not identical - check - ", []),
+ case (catch Check(Msg1, Msg2)) of
+ ok ->
+ io:format("equal ", []),
+ {ok, done};
+ Error ->
+ io:format("not equal ", []),
+ io:format("~nError: ~p~n", [Error]),
+ Error
+ end;
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_encode_decode_only
+%% Parameters: InitialData -> MegacoMessage
+%% Encode -> function/1
+%% Decode -> function/1
+%% Check -> function/2
+%% Description: This function simply encodes, with the Encode fun,
+%% and then decodes, with the Decode fun, the megaco
+%% message and expects it to succeed. The resulting
+%% message is checked by calling the Check fun with the
+%% resulting message.
+%% ------------------------------------------------------------------
+
+expect_encode_decode_only(InitialData, Encode, Decode, Check)
+ when is_function(Encode) andalso
+ is_function(Decode) andalso
+ is_function(Check) ->
+ Instructions =
+ [
+ %% Initial encode
+ expect_instruction(
+ "Encode (initial) message",
+ fun(M) when is_record(M, 'MegacoMessage') ->
+ (catch Encode(M));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, M) when is_binary(Bin) ->
+ {ok, {Bin, M}};
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end),
+
+ %% Decode the (encoded) message
+ expect_instruction(
+ "Decode message",
+ fun({Bin, _}) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _B) when is_record(Msg, 'MegacoMessage') ->
+ io:format("decoded - now check ", []),
+ case (catch Check(Msg)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ ({error, R}, _) ->
+ {Line, Mod, Reason} =
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, {L, M, Raw}}}
+ when is_list(Raw) ->
+ {L, M, lists:flatten(Raw)};
+ {value, {reason, {L, M, Raw}}} ->
+ {L, M, Raw};
+ _ ->
+ {-1, undefined, R}
+ end,
+ Tokens =
+ case lists:keysearch(token, 1, R) of
+ {value, {token, T}} ->
+ T;
+ _ ->
+ undefined
+ end,
+ {error, {unexpected_decode_failure,
+ {Mod, Line, Reason, Tokens}}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_decode
+%% Parameters: InitialData -> list() | binary()
+%% Decode -> function/1
+%% Check -> function/1
+%% Description: This function simply decodes, with the Decode fun,
+%% and expects this to fail. The failure reason is
+%% checked with the Check fun.
+%% ------------------------------------------------------------------
+
+expect_decode(InitialData, Decode, Check)
+ when is_list(InitialData) ->
+ expect_decode(list_to_binary(InitialData), Decode, Check);
+expect_decode(InitialData, Decode, Check)
+ when is_function(Decode) andalso is_function(Check) ->
+ Instructions =
+ [
+ %% Initial decode
+ expect_instruction(
+ "Decode (initial) message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({error, Reason}, _) ->
+ io:format("check error reason - ", []),
+ case (catch Check(Reason)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ ({ok, Msg}, Bin) ->
+ io:format("unexpected decode success - ", []),
+ M = binary_to_list(Bin),
+ {error, {unexpected_decode_success, {Msg, M}}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_decode_only
+%% Parameters: InitialData -> list() | binary()
+%% Decode -> function/1
+%% Check -> function/2
+%% Description: This function simply decodes, with the Decode fun,
+%% and expects it to succeed, which is checked by
+%% calling the Check fun with the resulting message.
+%% ------------------------------------------------------------------
+
+expect_decode_only(InitialData, Decode, Check)
+ when is_list(InitialData) ->
+ expect_decode_only(list_to_binary(InitialData), Decode, Check);
+expect_decode_only(InitialData, Decode, Check)
+ when is_function(Decode) andalso is_function(Check) ->
+ Instructions =
+ [
+ %% Initial decode
+ expect_instruction(
+ "Decode (initial) message",
+ fun(B) when is_binary(B) ->
+ (catch Decode(B));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _B) when is_record(Msg, 'MegacoMessage') ->
+ case (catch Check(Msg)) of
+ ok ->
+ {ok, done};
+ Error ->
+ Error
+ end;
+ ({error, R}, _) ->
+ {Line, Mod, Reason} =
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, {L, M, Raw}}}
+ when is_list(Raw) ->
+ {L, M, lists:flatten(Raw)};
+ {value, {reason, {L, M, Raw}}} ->
+ {L, M, Raw};
+ _ ->
+ {-1, undefined, R}
+ end,
+ Tokens =
+ case lists:keysearch(token, 1, R) of
+ {value, {token, T}} ->
+ T;
+ _ ->
+ undefined
+ end,
+ {error, {unexpected_decode_failure,
+ {Mod, Line, Reason, Tokens}}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_decode_encode
+%% Parameters: InitialData -> list() | binary()
+%% Decode -> function/1
+%% Encode -> function/1
+%% Check -> function/2
+%% Description: This function simply decodes, with the Decode fun,
+%% and then encodes, with the Encode fun, the megaco
+%% message. The resulting binary message should be
+%% identical, but if it is not, the messages are
+%% decoded again and then if necessary checked, with
+%% the Check fun.
+%% ------------------------------------------------------------------
+
+expect_decode_encode(InitialData, Decode, Encode, Check)
+ when is_list(InitialData) ->
+ expect_decode_encode(list_to_binary(InitialData), Decode, Encode, Check);
+expect_decode_encode(InitialData, Decode, Encode, Check)
+ when is_function(Decode) andalso
+ is_function(Encode) andalso
+ is_function(Check) ->
+ Instructions =
+ [
+ %% Initial decode
+ expect_instruction(
+ "Decode (initial) message",
+ fun(B) when is_binary(B) ->
+ (catch Decode(B));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, B) when is_record(Msg, 'MegacoMessage') ->
+ {ok, {Msg, B}};
+ ({error, R}, _) ->
+ {Line, Mod, Reason} =
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, {L, M, Raw}}}
+ when is_list(Raw) ->
+ {L, M, lists:flatten(Raw)};
+ {value, {reason, {L, M, Raw}}} ->
+ {L, M, Raw};
+ _ ->
+ {-1, undefined, R}
+ end,
+ Tokens =
+ case lists:keysearch(token, 1, R) of
+ {value, {token, T}} ->
+ T;
+ _ ->
+ undefined
+ end,
+ {error, {unexpected_decode_failure,
+ {Mod, Line, Reason, Tokens}}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end),
+
+
+ %% Encode the (decoded) message
+ expect_instruction(
+ "Encode message",
+ fun({Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, B}, {_, B}) ->
+ io:format("binaries equal - done ", []),
+ {ok, done};
+ ({ok, B}, {Msg, _}) ->
+ {ok, {Msg, B}};
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end),
+
+
+ %% Fallback instruction in case encode produced
+ %% a binary not equal to the initial
+ expect_instruction(
+ "Decode message (if binaries not equal)",
+ fun(done) ->
+ done;
+ ({_Msg, B}) when is_binary(B) ->
+ (catch Decode(B));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, {Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
+ io:format("messages identical - done ", []),
+ {ok, done};
+ (done, _) ->
+ io:format("done ", []),
+ {ok, done};
+ ({ok, Msg2}, {Msg1, _}) ->
+ io:format("messages not identical - check - ", []),
+ case (catch Check(Msg1, Msg2)) of
+ ok ->
+ io:format("equal ", []),
+ {ok, done};
+ Error ->
+ io:format("not equal ", []),
+ Error
+ end;
+ ({error, Reason}, _) ->
+ {error, {unexpected_decode_failure, Reason}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_decode_encode_only
+%% Parameters: InitialData -> list() | binary()
+%% Decode -> function/1
+%% Encode -> function/1
+%% Check -> function/2
+%% Description: This function simply decodes, with the Decode fun,
+%% and then encodes, with the Encode fun, the megaco
+%% message. The resulting binary message is then checked
+%% with the Check fun.
+%% ------------------------------------------------------------------
+
+expect_decode_encode_only(InitialData, Decode, Encode, Check)
+ when is_list(InitialData) ->
+ expect_decode_encode_only(list_to_binary(InitialData),
+ Decode, Encode, Check);
+expect_decode_encode_only(InitialData, Decode, Encode, Check)
+ when is_function(Decode) andalso
+ is_function(Encode) andalso
+ is_function(Check) ->
+ Instructions =
+ [
+ %% Initial decode
+ expect_instruction(
+ "Decode (initial) message",
+ fun(B) when is_binary(B) ->
+ (catch Decode(B));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, B) when is_record(Msg, 'MegacoMessage') ->
+ {ok, {Msg, B}};
+ ({error, R}, _) ->
+ {Line, Mod, Reason} =
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, {L, M, Raw}}}
+ when is_list(Raw) ->
+ {L, M, lists:flatten(Raw)};
+ {value, {reason, {L, M, Raw}}} ->
+ {L, M, Raw};
+ _ ->
+ {-1, undefined, R}
+ end,
+ Tokens =
+ case lists:keysearch(token, 1, R) of
+ {value, {token, T}} ->
+ T;
+ _ ->
+ undefined
+ end,
+ {error, {unexpected_decode_failure,
+ {Mod, Line, Reason, Tokens}}};
+ (Crap, _) ->
+ {error, {unexpected_decode_result, Crap}}
+ end),
+
+
+ %% Encode the (decoded) message
+ expect_instruction(
+ "Encode message",
+ fun({Msg, _Bin}) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, B2}, {_, B1}) ->
+ io:format("encode ok - check bins - ", []),
+ case (catch Check(B1, B2)) of
+ ok ->
+ {ok, done};
+ Crap ->
+ {error, {unexpected_encode_check_result, Crap}}
+ end;
+ ({error, Reason}, _) ->
+ {error, {unexpected_encode_failure, Reason}};
+ (Crap, _) ->
+ {error, {unexpected_encode_result, Crap}}
+ end)
+ ],
+ expect_exec(Instructions, InitialData).
+
+
+
+%% ------------------------------------------------------------------
+%% Function: expect_exec
+%% Parameters: Instructions -> [instruction()]
+%% InitialData -> term()
+%% Description: This function is the engine in the codec test
+%% cases. It executes each instruction in turn.
+%% ------------------------------------------------------------------
+
+expect_exec(Instructions, InitialData) ->
+ expect_exec(Instructions, InitialData, 1).
+
+expect_exec([], _, _) ->
+ io:format("~n", []),
+ ok;
+expect_exec([#expect_instruction{description = Desc,
+ command = Cmd,
+ verify = Verify}|T], Data, Num) ->
+ io:format("~n Exec command ~w: ~s => ", [Num, Desc]),
+ case Verify((catch Cmd(Data)), Data) of
+ {ok, NewData} ->
+ io:format("ok", []),
+ expect_exec(T, NewData, Num+1);
+ {error, Reason} ->
+ io:format("error", []),
+ {error, {Num, Desc, Reason}}
+ end.
+
+%% =======================================================================
+
+skip({What, Why}) when is_atom(What) andalso is_list(Why) ->
+ Reason = lists:flatten(io_lib:format("~p: ~s", [What, Why])),
+ exit({skipped, Reason});
+skip({What, Why}) ->
+ Reason = lists:flatten(io_lib:format("~p: ~p", [What, Why])),
+ exit({skipped, Reason});
+skip(Reason) when is_list(Reason) ->
+ exit({skipped, Reason});
+skip(Reason1) ->
+ Reason2 = lists:flatten(io_lib:format("~p", [Reason1])),
+ exit({skipped, Reason2}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+%% ------------------------------------------------------------------
+%% Internal functions
+%% ------------------------------------------------------------------
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:~w:" ++ F ++ "~n", [?MODULE|A]);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl
new file mode 100644
index 0000000000..7f2af37282
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_v1_test.erl
@@ -0,0 +1,7305 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248 v1
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_v1_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+%% -export([msg/0]).
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4299_msg2/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5793_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp7431_msg01a/1,
+ flex_compact_otp7431_msg01b/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0, generate_text_messages/0]).
+
+
+-export([msg15b/0, msg22f/0]).
+
+-export([
+ %% Decode
+ profile_decode_compact_text_message/1,
+ profile_decode_compact_text_messages/0,
+ prof1/0, prof2/0,
+ profile_decode_compact_flex_text_message/1,
+ profile_decode_compact_flex_text_messages/0,
+ profile_decode_pretty_text_message/1,
+ profile_decode_pretty_text_messages/0,
+ profile_decode_pretty_flex_text_message/1,
+ profile_decode_pretty_flex_text_messages/0,
+
+ %% Encode
+ profile_encode_compact_text_messages/0,
+ profile_encode_pretty_text_messages/0
+ ]).
+
+
+%% ----
+
+-define(V1, v1).
+-define(EC, []).
+-define(VERSION, 1).
+-define(VERSION_STR, "1").
+-define(DEFAULT_PORT, 55555).
+-define(MSG_LIB, megaco_test_msg_v1_lib).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG3_MID, {ip6Address, #'IP6Address'{address = [0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs =
+ msgs1() ++
+ msgs3(),
+ megaco_codec_test_lib:display_text_messages(?VERSION, Msgs).
+
+
+generate_text_messages() ->
+ Msgs =
+ msgs1(),
+ megaco_codec_test_lib:generate_text_messages(?V1, ?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+prof1() ->
+ megaco_codec_v1_test:profile_decode_compact_text_message(msg10).
+
+prof2() ->
+ megaco_codec_v1_test:profile_decode_compact_flex_text_message(msg10).
+
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg01a)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg01b)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg02)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg10)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg11)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg12)).
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_message(msg13)).
+profile_decode_compact_text_message(MsgTag) when is_atom(MsgTag) ->
+ Config = [],
+ Slogan = list_to_atom("decode_compact_v1_" ++ atom_to_list(MsgTag)),
+ profile_decode_compact_text_message(Slogan, Config, MsgTag).
+
+profile_decode_compact_flex_text_message(MsgTag) when is_atom(MsgTag) ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = list_to_atom("decode_compact_flex_v1_" ++ atom_to_list(MsgTag)),
+ Res = profile_decode_compact_text_message(Slogan, [Config], MsgTag),
+ flex_finish(Conf),
+ Res.
+
+profile_decode_compact_text_message(Slogan, Config, MsgTag) ->
+ Codec = megaco_compact_text_encoder,
+ profile_decode_text_message(Slogan, Codec, Config, MsgTag).
+
+%% (catch megaco_codec_v1_test:profile_decode_pretty_text_message(msg01a)).
+%% (catch megaco_codec_v1_test:profile_decode_pretty_text_message(msg01b)).
+%% (catch megaco_codec_v1_test:profile_decode_pretty_text_message(msg02)).
+profile_decode_pretty_text_message(MsgTag) when is_atom(MsgTag) ->
+ Config = [],
+ Slogan = list_to_atom("decode_pretty_v1_" ++ atom_to_list(MsgTag)),
+ profile_decode_pretty_text_message(Slogan, Config, MsgTag).
+
+profile_decode_pretty_flex_text_message(MsgTag) when is_atom(MsgTag) ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = list_to_atom("decode_pretty_flex_v1_" ++ atom_to_list(MsgTag)),
+ Res = profile_decode_pretty_text_message(Slogan, [Config], MsgTag),
+ flex_finish(Conf),
+ Res.
+
+profile_decode_pretty_text_message(Slogan, Config, MsgTag) ->
+ Codec = megaco_pretty_text_encoder,
+ profile_decode_text_message(Slogan, Codec, Config, MsgTag).
+
+profile_decode_text_message(Slogan, Codec, Config, MsgTag) ->
+ Msgs = msgs1(),
+ case lists:keysearch(MsgTag, 1, Msgs) of
+ {value, Msg} ->
+ [Res] = profile_decode_text_messages(Slogan, Codec, Config, [Msg]),
+ Res;
+ false ->
+ {error, {no_such_message, MsgTag}}
+ end.
+
+
+%% (catch megaco_codec_v1_test:profile_decode_compact_text_messages()).
+profile_decode_compact_text_messages() ->
+ Config = [],
+ Slogan = decode_compact_v1,
+ profile_decode_compact_text_messages(Slogan, Config).
+
+%% (catch megaco_codec_v1_test:profile_decode_compact_flex_text_messages()).
+profile_decode_compact_flex_text_messages() ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = decode_compact_flex_v1,
+ Res = profile_decode_compact_text_messages(Slogan, [Config]),
+ flex_finish(Conf),
+ Res.
+
+profile_decode_compact_text_messages(Slogan, Config) ->
+ Codec = megaco_compact_text_encoder,
+ profile_decode_text_messages(Slogan, Codec, Config).
+
+%% (catch megaco_codec_v1_test:profile_decode_pretty_text_messages()).
+profile_decode_pretty_text_messages() ->
+ Config = [],
+ Slogan = decode_pretty_v1,
+ profile_decode_pretty_text_messages(Slogan, Config).
+
+%% (catch megaco_codec_v1_test:profile_decode_pretty_flex_text_messages()).
+profile_decode_pretty_flex_text_messages() ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = decode_pretty_flex_v1,
+ Res = profile_decode_pretty_text_messages(Slogan, [Config]),
+ flex_finish(Conf),
+ Res.
+
+
+profile_decode_pretty_text_messages(Slogan, Config) ->
+ Codec = megaco_pretty_text_encoder,
+ profile_decode_text_messages(Slogan, Codec, Config).
+
+profile_decode_text_messages(Slogan, Codec, Config) ->
+ Msgs = msgs1(),
+ profile_decode_text_messages(Slogan, Codec, Config, Msgs).
+
+profile_decode_text_messages(Slogan, Codec, Config, Msgs0) ->
+ Msgs = [Msg || {_, Msg, _, _} <- Msgs0],
+ EncodeRes = encode_text_messages(Codec, Config, Msgs, []),
+ Bins = [Bin || {ok, Bin} <- EncodeRes],
+ Fun = fun() ->
+ decode_text_messages(Codec, Config, Bins, [])
+ end,
+ %% Make a dry run, just to make sure all modules are loaded:
+ io:format("make a dry run..~n", []),
+ (catch Fun()),
+ io:format("make the run..~n", []),
+ megaco_profile:profile(Slogan, Fun).
+
+%% (catch megaco_codec_v1_test:profile_encode_compact_text_messages()).
+profile_encode_compact_text_messages() ->
+ Codec = megaco_compact_text_encoder,
+ Config = [],
+ Slogan = encode_compact_v1,
+ profile_encode_text_messages(Slogan, Codec, Config).
+
+%% (catch megaco_codec_v1_test:profile_encode_pretty_text_messages()).
+profile_encode_pretty_text_messages() ->
+ Codec = megaco_pretty_text_encoder,
+ Config = [],
+ Slogan = encode_pretty_v1,
+ profile_encode_text_messages(Slogan, Codec, Config).
+
+profile_encode_text_messages(Slogan, Codec, Config) ->
+ Msgs = msgs1(),
+ profile_encode_text_messages(Slogan, Codec, Config, Msgs).
+
+profile_encode_text_messages(Slogan, Codec, Config, Msgs0) ->
+ Msgs = [Msg || {_, Msg, _, _} <- Msgs0],
+ Fun = fun() ->
+ encode_text_messages(Codec, Config, Msgs, [])
+ end,
+ %% Make a dry run, just to make sure all modules are loaded:
+ io:format("make a dry run...~n", []),
+ (catch Fun()),
+ io:format("make the run...~n", []),
+ megaco_profile:profile(Slogan, Fun).
+
+encode_text_messages(_Codec, _Config, [], Acc) ->
+ Acc;
+encode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
+ Res = Codec:encode_message(Config, ?VERSION, Msg),
+ encode_text_messages(Codec, Config, Msgs, [Res | Acc]).
+
+decode_text_messages(_Codec, _Config, [], Acc) ->
+ Acc;
+decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
+ Res = Codec:decode_message(Config, dynamic, Msg),
+ decode_text_messages(Codec, Config, Msgs, [Res | Acc]).
+
+
+%% ----
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ pretty_tickets,
+ flex_compact_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4299_msg2,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5793_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03
+ ].
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7431_msg01a,
+ flex_compact_otp7431_msg01b,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
+
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05
+ ].
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ %% Msgs = msgs1(),
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [Conf], Msgs).
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_pretty_text_encoder, false, [Conf], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {not_an_integer, PropertyParm}} ->
+ exit({not_an_integer, PropertyParm});
+ _ ->
+ io:format("flex_pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("flex_pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1(), [Conf]).
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(error, pretty_otp5085_msg2(), [Conf]).
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3(), [Conf]).
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4(), [Conf]).
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5(), [Conf]).
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6(), [Conf]).
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7(), [Conf]).
+
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg1(), [Conf]).
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg2(), [Conf]).
+
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5601(ok, pretty_otp5601_msg1(), [Conf]).
+
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5793(ok, pretty_otp5793_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+%% put(severity,trc),
+%% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+%% put(severity,trc),
+%% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf) ->
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []),
+ ok;
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v= }
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v }
+ }
+ }
+ }
+ }
+}".
+
+flex_pretty_otp7431_msg7() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v}
+ }
+ }
+ }
+ }
+}".
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ %% Msgs = msgs1(),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(1,2,3, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(2,3,4, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(1,2,31, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(10,21,99, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(99,23,11, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers(77,9,1, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{T:~s,S:~s,L:~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [T, S, L]),
+ lists:flatten(M).
+
+
+verify_dm_timers(T,S,L, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ {T, S, L} ->
+ ok;
+ {T1, S1, L1} ->
+ exit({invalid_timer_values, {{T, S, L}, {T1, S1, L1}}});
+ {error, Reason} ->
+ exit({invalid_timer, {T, S, L, Reason}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts]) when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L} ->
+ {ok, {T, S, L}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1(),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+% put(severity,trc),
+% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR
+ " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M).
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR
+ " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR
+ " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+ %% put(severity,trc),
+ %% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+compact_otp4011(M) ->
+ d("compact_otp4011 -> entry with"
+ "~n M: '~s'", [M]),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ d("compact_otp4011 -> expected error result (so far)", []),
+ case lists:keysearch(reason,1,Error) of
+ {value, {reason,Reason}} ->
+ d("compact_otp4011 -> expected error: "
+ "~n Reason: ~p", [Reason]),
+ case Reason of
+ {0, megaco_text_parser_v1,
+ {do_merge_control_streamParms, [A,B]}}
+ when is_list(A) andalso is_record(B, 'LocalControlDescriptor') ->
+ case lists:keysearch(mode,1,A) of
+ {value, {mode, _Mode}}
+ when B#'LocalControlDescriptor'.streamMode =/= asn1_NOVALUE ->
+ d("compact_otp4011 -> expected error",[]),
+ ok;
+ Other ->
+ exit({unexpected_mode_reason, {A,B,Other}})
+ end;
+ Other ->
+ exit({unexpected_reason, Other})
+ end;
+
+ false ->
+ d("compact_otp4011 -> OUPS, wrong kind of error", []),
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ d("compact_otp4011 -> unexpected decode result: ~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/1 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Reason} when is_list(Reason) ->
+ {value, {reason, no_version_found, _}} =
+ lists:keysearch(reason, 1, Reason),
+ {value, {token, [{'SafeChars',_,"megcao/1"}|_]}} =
+ lists:keysearch(token, 1, Reason),
+ ok;
+ Else ->
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, M} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ t("compact_otp4085_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{999999, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> THE ACTUAL ERROR: "
+ "~n LINE NUMBER: 999999"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Module, Crap]),
+ %% ok;
+ exit({decode_failed_999999, Module, Crap});
+ {value, {reason,{Line, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Line, Module, Crap]),
+ ok;
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M1 = compact_otp4085_erroneous_msg() ++ "}",
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, M2} ->
+ l("compact_otp4085_msg1 -> successfull decode"
+ "~n M2: ~p", [M2]),
+ ok;
+ Else ->
+ e("compact_otp4085_msg1 -> decode error"
+ "~n Else: ~p", [Else]),
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4280_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _Msg} ->
+ ok;
+ {error, Error} when is_list(Error) ->
+ t("compact_otp4280_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{Line, Module, Reason} = R}} ->
+ t("compact_otp4280_msg1 -> "
+ "~n Line: ~w"
+ "~n Module: ~w"
+ "~n Reason: ~w", [Line, Module, Reason]),
+ exit({decode_failed, R});
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4299_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% Same message, but this time decoded using the flex scanner
+compact_otp4299_msg2(suite) ->
+ [];
+compact_otp4299_msg2(Config) when is_list(Config) ->
+ d("compact_otp4299_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+
+ {Pid, Conf} = compact_otp4299_msg2_init(),
+
+ Bin = list_to_binary(compact_otp4299_msg()),
+ Res = decode_message(megaco_compact_text_encoder, false, [Conf], Bin),
+ compact_otp4299_msg2_finish(Pid),
+
+ case Res of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+compact_otp4299_msg2_init() ->
+ Flag = process_flag(trap_exit, true),
+ Res = (catch start_flex_scanner()),
+ process_flag(trap_exit, Flag),
+ case Res of
+ {error, Reason} ->
+ skip(Reason);
+ {ok, FlexConfig} ->
+ FlexConfig
+ end.
+
+compact_otp4299_msg2_finish(Pid) ->
+ stop_flex_scanner(Pid).
+
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/" ?VERSION_STR " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4359_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, #'MegacoMessage'{mess = Mess}} ->
+ {transactions, Trans} = Mess#'Message'.messageBody,
+ case Trans of
+ [{transactionRequest,#'TransactionRequest'{transactionId = asn1_NOVALUE}}] ->
+ ok;
+ _ ->
+ exit({unexpected_transactions, Trans})
+ end;
+ Else ->
+ t("compact_otp4359_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg0(), true).
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg1(), false).
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg2(), false).
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg3(), true).
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg4(), true).
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg5(), true).
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg6(), true).
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg7(), true).
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg8(), false).
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg9(), false).
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg10(), false).
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg11(), false).
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg12(), true).
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg20(), bad_mid_duplicate_padding).
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg21(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg22(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg23(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg24(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg25(), bad_mid_ip6addr_length).
+
+compact_otp4920_msg_1(M1, CheckEqual) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin1) of
+ {ok, Msg} ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, [], Msg) of
+ {ok, Bin1} ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when CheckEqual =:= true ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, M1, M2});
+ {ok, _Bin2} ->
+ io:format(", encoded:", []),
+ ok;
+ Else ->
+ io:format(", encode failed:", []),
+ exit({unexpected_encode_result, Else})
+ end;
+ Else ->
+ io:format("decode failed:", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4920_msg_2(M1, ExpectedReason) ->
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg} ->
+ io:format("unexpected successfull decode", []),
+ exit({unexpected_encode_ok, Msg});
+ {error, [{reason, {__Line, _Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ {error, [{reason, {_Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ Else ->
+ io:format("unexpected decode result", []),
+ exit({unexpected_decode_result, Else})
+
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg01(), error, ignore).
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg02(), ok, ok).
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok).
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok).
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok).
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok).
+
+compact_otp5186_msg_1(M1, DecodeExpect, EncodeExpect) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin1) of
+ {ok, Msg} when DecodeExpect =:= ok ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, [], Msg) of
+ {ok, Bin1} when EncodeExpect =:= ok ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when EncodeExpect =:= ok ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, Msg, M1, M2});
+ {ok, Bin3} when EncodeExpect =:= error ->
+ M3 = binary_to_list(Bin3),
+ io:format(", unexpected encode:", []),
+ exit({unexpected_encode_success, Msg, M1, M3});
+ _Else when EncodeExpect =:= error ->
+ io:format(", encode failed ", []),
+ ok
+ end;
+ {ok, Msg} when DecodeExpect =:= error ->
+ io:format(" decoded", []),
+ exit({unexpected_decode_success, Msg});
+ _Else when DecodeExpect =:= error ->
+ io:format(" decode failed ", []),
+ ok;
+ Else when DecodeExpect =:= ok ->
+ io:format(" decode failed ", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp5186_msg_2(Msg1, EncodeExpect, DecodeExpect) ->
+ case encode_message(megaco_compact_text_encoder, [], Msg1) of
+ {ok, Bin} when EncodeExpect =:= ok ->
+ io:format(" encoded", []),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg1} when DecodeExpect =:= ok ->
+ io:format(", decoded - equal:", []),
+ ok;
+ {ok, Msg2} when DecodeExpect =:= ok ->
+ M = binary_to_list(Bin),
+ case (catch compact_otp5186_check_megamsg(Msg1, Msg2)) of
+ ok ->
+ io:format(", decoded - not equal - ok:", []),
+ ok;
+ {'EXIT', Reason} ->
+ io:format(", decoded - not equal:", []),
+ exit({messages_not_equal, M, Reason, Msg1, Msg2})
+ end;
+ {ok, Msg3} when DecodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(", decoded:", []),
+ exit({unexpected_decode_success, M, Msg1, Msg3});
+ Else when DecodeExpect =:= ok ->
+ M = binary_to_list(Bin),
+ io:format(", decode failed ", []),
+ exit({unexpected_decode_success, Msg1, M, Else});
+ _Else when DecodeExpect =:= error ->
+ io:format(", decode failed ", []),
+ ok
+ end;
+ {ok, Bin} when EncodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(" encoded", []),
+ exit({unexpected_encode_success, Msg1, M});
+ _Else when EncodeExpect =:= error ->
+ io:format(" encode failed ", []),
+ ok;
+ Else when EncodeExpect =:= ok ->
+ io:format(" encode failed ", []),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/1 <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/1 <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 1,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',1,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 1,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',1,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+%% --
+
+compact_otp5186_check_megamsg(M1, M1) ->
+ ok;
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH,
+ mess = M1},
+ #'MegacoMessage'{authHeader = AH,
+ mess = M2}) ->
+ compact_otp5186_check_mess(M1, M2);
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH1},
+ #'MegacoMessage'{authHeader = AH2}) ->
+ exit({not_equal, authHeader, AH1, AH2}).
+
+compact_otp5186_check_mess(M, M) ->
+ ok;
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId,
+ messageBody = B1},
+ #'Message'{version = V,
+ mId = MId,
+ messageBody = B2}) ->
+ compact_otp5186_check_body(B1, B2);
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId1},
+ #'Message'{version = V,
+ mId = MId2}) ->
+ exit({not_equal, mId, MId1, MId2});
+compact_otp5186_check_mess(#'Message'{version = V1,
+ mId = MId},
+ #'Message'{version = V2,
+ mId = MId}) ->
+ exit({not_equal, version, V1, V2}).
+
+compact_otp5186_check_body(B, B) ->
+ ok;
+compact_otp5186_check_body({transactions, T1}, {transactions, T2}) ->
+ compact_otp5186_check_trans(T1, T2);
+compact_otp5186_check_body({messageError, E1}, {messageError, E2}) ->
+ compact_otp5186_check_merr(E1, E2);
+compact_otp5186_check_body(B1, B2) ->
+ exit({not_equal, messageBody, B1, B2}).
+
+compact_otp5186_check_trans([], []) ->
+ ok;
+compact_otp5186_check_trans([], T2) ->
+ exit({not_equal, transactions, [], T2});
+compact_otp5186_check_trans(T1, []) ->
+ exit({not_equal, transactions, T1, []});
+compact_otp5186_check_trans([Tran1|Trans1], [Tran2|Trans2]) ->
+ compact_otp5186_check_trans(Trans1, Trans2),
+ compact_otp5186_check_transaction(Tran1, Tran2).
+
+compact_otp5186_check_merr(ME, ME) ->
+ ok;
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC,
+ errorText = ET1},
+ #'ErrorDescriptor'{errorCode = EC,
+ errorText = ET2}) ->
+ exit({not_equal, errorText, ET1, ET2});
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC1,
+ errorText = ET},
+ #'ErrorDescriptor'{errorCode = EC2,
+ errorText = ET}) ->
+ exit({not_equal, errorCode, EC1, EC2}).
+
+compact_otp5186_check_transaction(T, T) ->
+ ok;
+compact_otp5186_check_transaction({transactionReply, TR1},
+ {transactionReply, TR2}) ->
+ compact_otp5186_check_transRep(TR1, TR2);
+compact_otp5186_check_transaction(T1, T2) ->
+ exit({unexpected_transactions, T1, T2}).
+
+compact_otp5186_check_transRep(T, T) ->
+ ok;
+compact_otp5186_check_transRep(#'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR2}) ->
+ compact_otp5186_check_transRes(TR1, TR2);
+compact_otp5186_check_transRep(T1, T2) ->
+ exit({unexpected_transaction_reply, T1, T2}).
+
+compact_otp5186_check_transRes(TR, TR) ->
+ ok;
+compact_otp5186_check_transRes({actionReplies, AR1},
+ {actionReplies, AR2}) ->
+ compact_otp5186_check_actReps(AR1, AR2);
+compact_otp5186_check_transRes(TR1, TR2) ->
+ exit({unexpected_transaction_result, TR1, TR2}).
+
+compact_otp5186_check_actReps([], []) ->
+ ok;
+compact_otp5186_check_actReps(AR1, []) ->
+ exit({not_equal, actionReplies, AR1, []});
+compact_otp5186_check_actReps([], AR2) ->
+ exit({not_equal, actionReplies, [], AR2});
+compact_otp5186_check_actReps([AR1|ARs1], [AR2|ARs2]) ->
+ compact_otp5186_check_actRep(AR1, AR2),
+ compact_otp5186_check_actReps(ARs1, ARs2).
+
+compact_otp5186_check_actRep(AR, AR) ->
+ ok;
+compact_otp5186_check_actRep(#'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep2}) ->
+ compact_otp5186_check_cmdReps(CmdRep1, CmdRep2);
+compact_otp5186_check_actRep(AR1, AR2) ->
+ exit({unexpected_actionReply, AR1, AR2}).
+
+compact_otp5186_check_cmdReps([], []) ->
+ ok;
+compact_otp5186_check_cmdReps(CR1, []) ->
+ exit({not_equal, commandReplies, CR1, []});
+compact_otp5186_check_cmdReps([], CR2) ->
+ exit({not_equal, commandReplies, [], CR2});
+compact_otp5186_check_cmdReps([CR1|CRs1], [CR2|CRs2]) ->
+ compact_otp5186_check_cmdRep(CR1, CR2),
+ compact_otp5186_check_cmdReps(CRs1, CRs2).
+
+compact_otp5186_check_cmdRep(CR, CR) ->
+ ok;
+compact_otp5186_check_cmdRep({auditValueReply, AVR1},
+ {auditValueReply, AVR2}) ->
+ compact_otp5186_check_auditReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep({addReply, AVR1},
+ {addReply, AVR2}) ->
+ compact_otp5186_check_ammsReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep(CR1, CR2) ->
+ exit({unexpected_commandReply, CR1, CR2}).
+
+compact_otp5186_check_auditReply(AR, AR) ->
+ ok;
+compact_otp5186_check_auditReply({auditResult, AR1},
+ {auditResult, AR2}) ->
+ compact_otp5186_check_auditRes(AR1, AR2);
+compact_otp5186_check_auditReply(AR1, AR2) ->
+ exit({unexpected_auditReply, AR1, AR2}).
+
+compact_otp5186_check_ammsReply(AR, AR) ->
+ ok;
+compact_otp5186_check_ammsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = ID,
+ terminationAudit = TA2}) ->
+ %% This is just to simplify the test
+ F = fun(asn1_NOVALUE) -> [];
+ (E) -> E
+ end,
+ compact_otp5186_check_termAudit(F(TA1), F(TA2));
+compact_otp5186_check_ammsReply(AR1, AR2) ->
+ exit({unexpected_ammsReply, AR1, AR2}).
+
+compact_otp5186_check_auditRes(AR, AR) ->
+ ok;
+compact_otp5186_check_auditRes(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR2}) ->
+ compact_otp5186_check_termAuditRes(TAR1, TAR2);
+compact_otp5186_check_auditRes(AR1, AR2) ->
+ exit({unexpected_auditResult, AR1, AR2}).
+
+compact_otp5186_check_termAuditRes([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAuditRes(TAR1, []);
+compact_otp5186_check_termAuditRes(TAR1, []) ->
+ exit({not_equal, termAuditRes, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([], [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAuditRes([], TAR2);
+compact_otp5186_check_termAuditRes([], TAR2) ->
+ exit({not_equal, termAuditRes, [], TAR2});
+compact_otp5186_check_termAuditRes([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAuditRes(TAR1, TAR2).
+
+compact_otp5186_check_termAudit([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAudit(TAR1, []);
+compact_otp5186_check_termAudit(TAR1, []) ->
+ exit({not_equal, termAudit, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([],
+ [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAudit([], TAR2);
+compact_otp5186_check_termAudit([], TAR2) ->
+ exit({not_equal, termAudit, [], TAR2});
+compact_otp5186_check_termAudit([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAudit(TAR1, TAR2).
+
+compact_otp5186_check_auditRetParm(ARP, ARP) ->
+ ok;
+compact_otp5186_check_auditRetParm({emptyDescriptors, AD1},
+ {emptyDescriptors, AD2}) ->
+ compact_otp5186_check_auditDesc(AD1, AD2);
+compact_otp5186_check_auditRetParm(ARP1, ARP2) ->
+ exit({unexpected_auditRetParm, ARP1, ARP2}).
+
+compact_otp5186_check_auditDesc(AD, AD) ->
+ ok;
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = L1},
+ #'AuditDescriptor'{auditToken = L2}) ->
+ compact_otp5186_check_auditDesc_auditItems(L1, L2);
+compact_otp5186_check_auditDesc(AD1, AD2) ->
+ exit({unexpected_auditDesc, AD1, AD2}).
+
+compact_otp5186_check_auditDesc_auditItems([], []) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItems(AI1, []) ->
+ exit({not_equal, auditItems, AI1, []});
+compact_otp5186_check_auditDesc_auditItems([], AI2) ->
+ exit({not_equal, auditItems, [], AI2});
+compact_otp5186_check_auditDesc_auditItems([AI1|AIs1], [AI2|AIs2]) ->
+ compact_otp5186_check_auditDesc_auditItem(AI1, AI2),
+ compact_otp5186_check_auditDesc_auditItems(AIs1, AIs2).
+
+compact_otp5186_check_auditDesc_auditItem(AI, AI) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItem(AI1, AI2) ->
+ exit({not_equal, auditItem, AI1, AI2}).
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5793(ok, pretty_otp5793_msg1()).
+
+compact_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_compact_text_encoder, Msg, []).
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993_msg_1(compact_otp5993_msg01(), ok, ok).
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993_msg_1(compact_otp5993_msg02(), ok, ok).
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993_msg_1(compact_otp5993_msg03(), ok, ok).
+
+compact_otp5993_msg_1(Msg1, EncodeExpect, DecodeExpect) ->
+ case encode_message(megaco_compact_text_encoder, [], Msg1) of
+ {ok, Bin} when EncodeExpect =:= ok ->
+ io:format(" encoded", []),
+ %% io:format(" encoded:~n~s~n", [binary_to_list(Bin)]),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg1} when DecodeExpect =:= ok ->
+ io:format(", decoded - equal:", []),
+ ok;
+ {ok, Msg3} when DecodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(", decoded:", []),
+ exit({unexpected_decode_success, M, Msg1, Msg3});
+ Else when DecodeExpect =:= ok ->
+ M = binary_to_list(Bin),
+ io:format(", decode failed ", []),
+ exit({unexpected_decode_failure, Msg1, M, Else});
+ _Else when DecodeExpect =:= error ->
+ io:format(", decode failed ", []),
+ ok
+ end;
+ {ok, Bin} when EncodeExpect =:= error ->
+ M = binary_to_list(Bin),
+ io:format(" encoded", []),
+ exit({unexpected_encode_success, Msg1, M});
+ _Else when EncodeExpect =:= error ->
+ io:format(" encode failed ", []),
+ ok;
+ Else when EncodeExpect =:= ok ->
+ io:format(" encode failed ", []),
+ exit({unexpected_encode_result, Else})
+ end.
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ ok.
+
+compact_otp6017(BadCID) ->
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg} ->
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ exit({unexpected_reason, ActualReason});
+ false ->
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ exit({unexpected_decode_result, Crap})
+ end.
+
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "MEGACO/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+flex_compact_otp7431_msg01a(suite) ->
+ [];
+flex_compact_otp7431_msg01a(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01a -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1a(), [Conf]).
+
+flex_compact_otp7431_msg01b(suite) ->
+ [];
+flex_compact_otp7431_msg01b(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01b -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1b(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1a() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg1b() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+
+
+
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], BinMsg),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg2(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], BinMsg),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder,
+ false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ Msg0 = Msg1,
+ ok;
+ Else ->
+ t("pretty_otp4632_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4632_msg4_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4_chk([], []) ->
+ exit(messages_not_eq);
+pretty_otp4632_msg4_chk([], Rest1) ->
+ exit({messages_not_eq1, Rest1});
+pretty_otp4632_msg4_chk(Rest0, []) ->
+ exit({messages_not_eq0, Rest0});
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest0],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1]) ->
+ ok;
+pretty_otp4632_msg4_chk([_|Rest0], [_|Rest1]) ->
+ pretty_otp4632_msg4_chk(Rest0,Rest1).
+
+
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], Bin),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4710_msg2_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(Msg,Msg) ->
+ ok;
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ io:format("pretty_otp4945_msg1 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeMethod]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason, serviceChangeMethod]} ->
+ ok;
+ {missing_required_serviceChangeParm, [serviceChangeMethod, serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg5(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_serviceChangeParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg5 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg6(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_serviceChangeParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg6 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4949_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_servChgReplyParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg2 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_servChgReplyParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg3 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {not_an_integer, PropertyParm}} ->
+ exit({not_an_integer, PropertyParm});
+ _ ->
+ io:format("pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = pretty_otp5068_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg) of
+ {error, Reason} ->
+% io:format("pretty_otp5068_msg1 -> "
+% "~n Reason: ~w"
+% "~n", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} ->
+% io:format("pretty_otp5068_msg1 -> successfull encode:"
+% "~n~s~n", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin) of
+ {ok, _} ->
+% io:format("pretty_otp5068_msg1 -> ok~n", []),
+ ok;
+ Else ->
+ %% io:format("~npretty_otp5068_msg1 -> ~n~p~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE}}]}}}]}]}}}]}}}.
+
+
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1()).
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(error, pretty_otp5085_msg2()).
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3()).
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4()).
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5()).
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6()).
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7()).
+
+pretty_otp5085(Expected, Msg) ->
+ pretty_otp5085(Expected, Msg, []).
+
+pretty_otp5085(Expected, Msg, Conf) ->
+ t("pretty_otp5085 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5085 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5085 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5085 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5085 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5085 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5085 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5085 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_ammsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_notifyReply([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_ammsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_notifyReply([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_ammsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_notifyReply([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_notifyReply([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg1()).
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg2()).
+
+pretty_otp5600(Expected, Msg) ->
+ pretty_otp5600(Expected, Msg, []).
+
+pretty_otp5600(Expected, Msg, Conf) ->
+ t("pretty_otp5600 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5600 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5600 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5600 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5600 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5600 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5600 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5600 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5601(ok, pretty_otp5601_msg1()).
+
+pretty_otp5601(Expected, Msg) ->
+ pretty_otp5601(Expected, Msg, []).
+
+pretty_otp5601(Expected, Msg, Conf) ->
+ t("pretty_otp5601 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected =:= error ->
+ d("pretty_otp5601 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5601 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected =:= error ->
+ e("pretty_otp5601 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5601 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5601 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5601 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5601 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+% put(severity,trc),
+% put(dbg,true),
+ pretty_otp5793(ok, pretty_otp5793_msg1()).
+
+pretty_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5793(Expected, Msg, Conf) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',2,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]}]}}]}]}}}]}}}.
+
+
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5882().
+
+pretty_otp5882() ->
+ otp5882(megaco_pretty_text_encoder, []).
+
+otp5882(Codec, Conf) ->
+ Msg = pretty_otp5882_msg01(),
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, {message_encode_failed, {error, {ActualReason, _}}, _}} ->
+ case ActualReason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ exit({unexpected_error_actual_reason, ActualReason})
+ end;
+ {error, Reason} ->
+ exit({unexpected_error_reason, Reason});
+ {ok, Bin} ->
+ exit({unexpected_encode_sucess, binary_to_list(Bin)})
+ end.
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = cre_streamParms(LCD),
+ StreamDesc = cre_streamDesc(1, Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ ActReq = #'ActionRequest'{contextId = 5882,
+ commandRequests = [CmdReq]},
+ Actions = [ActReq],
+ TransReq = #'TransactionRequest'{transactionId = 5882,
+ actions = Actions},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Mid = ?MG1_MID,
+ megaco_message(?VERSION, Mid, Body).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ %% erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490(Msg, Conf) ->
+ pretty_otp6490(Msg, Conf, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode) ->
+ pretty_otp6490(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp6490(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+otp6490(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode == ok ->
+ ok;
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ exit({unexpected_decode_result, Msg, Msg2});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode =:= ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ io:format("otp7671 -> decoded:identical~n", []),
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4444}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_digitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_digitMapValue(Body),
+ DigitMapDesc = cre_digitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_digitMapValue(Body),
+ DigitMapDesc = cre_digitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_digitMapDesc(asn1_NOVALUE, asn1_NOVALUE),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[]}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = []} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+expect_codec(Expect, Codec, Msg, Conf) ->
+ t("expect_codec -> entry with"
+ "~n Expect: ~p"
+ "~n Msg: ~p", [Expect, Msg]),
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when Expect =:= error ->
+ d("expect_codec -> encode failed as expected"
+ "~n _Reason: ~w", [_Reason]),
+ ok;
+ {error, Reason} ->
+ e("expect_codec -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expect =:= error ->
+ e("expect_codec -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("expect_codec -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case (catch decode_message(Codec, false, Conf, Bin)) of
+ {ok, Msg} ->
+ d("expect_codec -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("expect_codec -> successfull decode"
+ " - but not equal", []),
+ chk_MegacoMessage(Msg, Msg2);
+ %% exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("expect_codec -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ e("expect_codec -> encode failed:~n~p", [Else]),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ Msgs = msgs1() ++ msgs2() ++ msgs3(),
+ [M || {_, M, _, _} <- Msgs].
+
+msgs1() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+msgs2() ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, [], M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = #'ActionRequest'{contextId = CtxId,
+ commandRequests = CmdReqs},
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TransReq = {transactionRequest,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions}},
+ megaco_trans_req(TransInfo, [TransReq|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ #'MegacoMessage'{mess = #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}}.
+
+megaco_message(Auth, Version, Mid, Body) ->
+ #'MegacoMessage'{authHeader = Auth,
+ mess = #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}}.
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(1, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) when is_list(CmdReq) ->
+ Actions = [#'ActionRequest'{contextId = ContextId,
+ commandRequests = CmdReq}],
+ Req = {transactions,
+ [{transactionRequest,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions}}]},
+ megaco_message(?VERSION, Mid, Req).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) when is_list(CmdReq) ->
+ Actions = [#'ActionRequest'{contextId = ContextId,
+ commandRequests = CmdReq}],
+ Req = {transactions,
+ [{transactionRequest,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions}}]},
+ megaco_message(Auth, ?VERSION, Mid, Req).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) when is_list(CmdReply) ->
+ ReplyData = [{ContextId, CmdReply}],
+ msg_replies(Mid, TransId, ReplyData).
+
+msg_replies(Mid, TransId, ReplyData) when is_list(ReplyData) ->
+ Actions = [cre_actionReply(ContextId, CmdReply) ||
+ {ContextId, CmdReply} <- ReplyData],
+ Req = {transactions,
+ [{transactionReply, cre_transactionReply(TransId, Actions)}]},
+ cre_megacoMessage(?VERSION, Mid, Req).
+
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_megacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_transactionAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_propertyParm("tdmc/gain", "2"),
+ Ec = cre_propertyParm("tdmc/ec", "g165"),
+ LCD = cre_localControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_propertyParm("v", "0"),
+ %% C = cre_propertyParm("c", "IN IP4 $ "),
+ C = cre_propertyParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_propertyParm("m", "audio $ RTP/AVP 0"),
+ A = cre_propertyParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_localRemoteDesc([[V, C, M, A]]),
+ Parms = cre_streamParms(LCD,LD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ ReqEvent = cre_requestedEvent("al/of"),
+ EventsDesc = cre_eventsDesc(2222,[ReqEvent]),
+ AmmReq = cre_ammReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_propertyParm("tdmc/gain", "2"),
+ Ec = cre_propertyParm("tdmc/ec", "g165"),
+ LCD = cre_localControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_propertyParm("v", "0"),
+ %% C = cre_propertyParm("c", "IN IP4 $ "),
+ C = cre_propertyParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_propertyParm("m", "audio $ RTP/AVP 0"),
+ A = cre_propertyParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_localRemoteDesc([[V, C, M, A]]),
+ Parms = cre_streamParms(LCD,LD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ EventParm = cre_eventParm("strict",["exact"]),
+ ReqEvent = cre_requestedEvent("al/of", [EventParm]),
+ EventsDesc = cre_eventsDesc(2222,[ReqEvent]),
+ AmmReq = cre_ammReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_timeNotation("19990729", "22000000"),
+ Event = cre_observedEvent("al/of",TimeStamp),
+ Desc = cre_observedEventsDesc(2222,[Event]),
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_serviceChangeProf("resgw",1),
+ Parm = cre_serviceChangeParm(restart,Address,[Reason],Profile),
+ Req = cre_serviceChangeReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_commandReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_serviceChangeProf("resgw",1),
+ Parm = cre_serviceChangeResParm(Address,Profile),
+ Reply = cre_serviceChangeReply([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_ammsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_notifyReply([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_eventParm("strict",["state"]),
+ On = cre_requestedEvent("al/on", [Strict]),
+ Name = "dialplan00",
+ Action = cre_requestedActions(Name),
+ Ce = cre_requestedEvent("dd/ce", Action),
+ EventsDesc = cre_eventsDesc(2223,[On, Ce]),
+ Signal = cre_signal("cg/rt"),
+ DigMapDesc = cre_digitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_digitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_digitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","22010001"),
+ Parm = cre_eventParm("ds",["916135551212"]),
+ Event = cre_observedEvent("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_observedEventsDesc(2223,[Event]),
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_commandReq({addReq, AmmReq}),
+ Jit = cre_propertyParm("nt/jit", "40"),
+ LCD = cre_localControlDesc(recvOnly,[Jit]),
+ V = cre_propertyParm("v", "0"),
+ C = cre_propertyParm("c", "IN IP4 $ "),
+ M = cre_propertyParm("m", "audio $ RTP/AVP 4"),
+ A = cre_propertyParm("a", "ptime:30"),
+ V2 = cre_propertyParm("v", "0"),
+ C2 = cre_propertyParm("c", "IN IP4 $ "),
+ M2 = cre_propertyParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_localRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_streamParms(LCD, LD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_ammReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_commandReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_propertyParm("v", "0"),
+ C = cre_propertyParm("c", "IN IP4 124.124.124.222"),
+ M = cre_propertyParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_propertyParm("a", "ptime:30"),
+ A2 = cre_propertyParm("a", "recvonly"),
+ LD = cre_localRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_streamParmsL(LD),
+ StreamDesc = cre_streamDesc(1, Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ Reply = cre_ammsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_ammsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_localControlDesc(sendRecv),
+ Parms = cre_streamParms(LCD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ Signal = cre_signal("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_commandReq({addReq, AmmReq}),
+ Jit = cre_propertyParm("nt/jit", "40"),
+ LCD2 = cre_localControlDesc(sendRecv, [Jit]),
+ V = cre_propertyParm("v", "0"),
+ C = cre_propertyParm("c", "IN IP4 $ "),
+ M = cre_propertyParm("m", "audio $ RTP/AVP 4"),
+ A = cre_propertyParm("a", "ptime:30"),
+ LD2 = cre_localRemoteDesc([[V, C, M, A]]),
+ V2 = cre_propertyParm("v", "0"),
+ C2 = cre_propertyParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_propertyParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_localRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_streamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_streamDesc(1,Parms2),
+ MediaDesc2 = cre_mediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_ammReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_commandReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_propertyParm("v", "0"),
+ C = cre_propertyParm("c", "IN IP4 125.125.125.111"),
+ M = cre_propertyParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_localRemoteDesc([[V, C, M]]),
+ Parms = cre_streamParmsL(LD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ Reply = cre_ammsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ Signal = cre_signal("cg/rt"),
+ AmmReq1 = cre_ammReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_commandReq({modReq, AmmReq1}),
+
+ Gain = cre_propertyParm("tdmc/gain", "2"),
+ Ec = cre_propertyParm("tdmc/ec", "g165"),
+ LCD = cre_localControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_streamParms(LCD),
+ StreamDesc2 = cre_streamDesc(1,Parms2),
+ MediaDesc2 = cre_mediaDesc(StreamDesc2),
+ AmmReq2 = cre_ammReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_commandReq({modReq, AmmReq2}),
+
+ V = cre_propertyParm("v", "0"),
+ C = cre_propertyParm("c", "IN IP4 125.125.125.111"),
+ M = cre_propertyParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_localRemoteDesc([[V, C, M]]),
+ Parms3 = cre_streamParmsR(RD),
+ StreamDesc3 = cre_streamDesc(1,Parms3),
+ MediaDesc3 = cre_mediaDesc(StreamDesc3),
+ AmmReq3 = cre_ammReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_commandReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_ammsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_ammsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+msg15b() ->
+ msg15b(?MG1_MID).
+
+msg15b(Mid) ->
+ %% We reuse the amms reply stuff
+ Reply1 = cre_ammsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_ammsReply([#megaco_term_id{id = ?A4445}]),
+ ActionReplyData =
+ [{modReply, Reply1}, {modReply, Reply2}],
+ ReplyData =
+ [{2001, ActionReplyData},
+ {2002, ActionReplyData},
+ {2003, ActionReplyData},
+ {2004, ActionReplyData},
+ {2005, ActionReplyData},
+ {2006, ActionReplyData},
+ {2007, ActionReplyData},
+ {2008, ActionReplyData},
+ {2009, ActionReplyData},
+ {2010, ActionReplyData},
+ {2011, ActionReplyData},
+ {2012, ActionReplyData},
+ {2013, ActionReplyData},
+ {2014, ActionReplyData},
+ {2015, ActionReplyData},
+ {2016, ActionReplyData},
+ {2017, ActionReplyData},
+ {2018, ActionReplyData},
+ {2019, ActionReplyData},
+ {2020, ActionReplyData},
+ {2021, ActionReplyData},
+ {2022, ActionReplyData},
+ {2023, ActionReplyData},
+ {2024, ActionReplyData},
+ {2025, ActionReplyData},
+ {2026, ActionReplyData},
+ {2027, ActionReplyData},
+ {2028, ActionReplyData},
+ {2029, ActionReplyData},
+ {2030, ActionReplyData},
+ {2031, ActionReplyData}],
+ msg_replies(Mid, 10005, ReplyData).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","22020002"),
+ Event = cre_observedEvent("al/of",TimeStamp),
+ Desc = cre_observedEventsDesc(1234,[Event]),
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_notifyReply([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_requestedEvent("al/on"),
+ EventsDesc = cre_eventsDesc(1235,[On]),
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_ammsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_localControlDesc(sendRecv),
+ Parms = cre_streamParms(LCD),
+ StreamDesc = cre_streamDesc(1,Parms),
+ MediaDesc = cre_mediaDesc(StreamDesc),
+ AmmReq = cre_ammReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_commandReq({modReq, AmmReq}),
+ AmmReq2 = cre_ammReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_commandReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_auditDesc(Tokens),
+ Req = cre_auditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_commandReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_propertyParm("nt/jit", "40"),
+ LCD = cre_localControlDesc(sendRecv,[Jit]),
+ LDV = cre_propertyParm("v", "0"),
+ LDC = cre_propertyParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_propertyParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_propertyParm("a", "ptime:30"),
+ LD = cre_localRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_propertyParm("v", "0"),
+ RDC = cre_propertyParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_propertyParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_propertyParm("a", "ptime:30"),
+ RD = cre_localRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_streamParms(LCD,LD,RD),
+ StreamDesc = cre_streamDesc(1,StreamParms),
+ Media = cre_mediaDesc(StreamDesc),
+ PackagesItem = cre_packagesItem("nt",1),
+ PackagesItem2 = cre_packagesItem("rtp",1),
+ Stat = cre_statisticsParm("rtp/ps","1200"),
+ Stat2 = cre_statisticsParm("nt/os","62300"),
+ Stat3 = cre_statisticsParm("rtp/pr","700"),
+ Stat4 = cre_statisticsParm("nt/or","45100"),
+ Stat5 = cre_statisticsParm("rtp/pl","0.2"),
+ Stat6 = cre_statisticsParm("rtp/jit","20"),
+ Stat7 = cre_statisticsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_auditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","24020002"),
+ Event = cre_observedEvent("al/on",TimeStamp),
+ Desc = cre_observedEventsDesc(1235,[Event]),
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","24020002"),
+ Event = cre_observedEvent("al/on",TimeStamp),
+ Desc = cre_observedEventsDesc(1235,[Event]),
+ NotifyReq1 = cre_notifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_commandReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_notifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_commandReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","24020002"),
+ Event = cre_observedEvent("al/on",TimeStamp),
+ Desc = cre_observedEventsDesc(1235,[Event]),
+ NotifyReq1 = cre_notifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_commandReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_notifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_commandReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_timeNotation("19990729","24020002"),
+ Event = cre_observedEvent("al/on",TimeStamp),
+ Desc = cre_observedEventsDesc(1235,[Event]),
+ NotifyReq1 = cre_notifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_commandReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_notifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_commandReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_notifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_commandReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_notifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_commandReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_auditDesc([statsToken]),
+ SubReq = cre_subtractReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_subtractReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_commandReq({subtractReq, SubReq}),
+ CmdReq2 = cre_commandReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_statisticsParm("nt/os","45123"),
+ Stat12 = cre_statisticsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_ammsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_statisticsParm("rtp/ps","1245"),
+ Stat22 = cre_statisticsParm("nt/os", "62345"),
+ Stat23 = cre_statisticsParm("rtp/pr", "780"),
+ Stat24 = cre_statisticsParm("nt/or", "45123"),
+ Stat25 = cre_statisticsParm("rtp/pl", "10"),
+ Stat26 = cre_statisticsParm("rtp/jit", "27"),
+ Stat27 = cre_statisticsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_ammsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_serviceChangeProf("resgw",1),
+ Parm = cre_serviceChangeParm(restart,Address,[Reason],Profile),
+ Req = cre_serviceChangeReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_commandReq({serviceChangeReq, Req}),
+ Auth = cre_authHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 1),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+%% --------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+skip(Reason) ->
+ megaco_codec_test_lib:skip(Reason).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M,M) when is_record(M,'MegacoMessage') ->
+ ok;
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type({'MegacoMessage', M1, M2}).
+
+chk_opt_AuthenticationHeader(A,A) ->
+ ok;
+chk_opt_AuthenticationHeader(A1,A2) ->
+ not_equal({auth,A1,A2}).
+
+chk_Message(M,M) when is_record(M,'Message') ->
+ ok;
+chk_Message(#'Message'{version = Version1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = Version2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ chk_version(Version1,Version2),
+ chk_MId(MID1,MID2),
+ chk_messageBody(Body1,Body2),
+ ok;
+chk_Message(M1,M2) ->
+ wrong_type({'Message',M1,M2}).
+
+
+chk_version(V,V) when is_integer(V) ->
+ ok;
+chk_version(V1,V2) when is_integer(V1) andalso is_integer(V2) ->
+ not_equal({version,V1,V2});
+chk_version(V1,V2) ->
+ wrong_type({integer,V1,V2}).
+
+
+chk_MId(M,M) ->
+ {equal,mid};
+chk_MId({Tag,M1},{Tag,M2}) ->
+ Res = chk_MId(Tag,M1,M2),
+ equal(Res);
+chk_MId(M1,M2) ->
+ not_equal({mid,M1,M2}).
+
+chk_MId(ip4Address,M1,M2) -> chk_IP4Address(M1, M2);
+chk_MId(ip6Address,M1,M2) -> chk_IP6Address(M1, M2);
+chk_MId(domainName,M1,M2) -> chk_DomainName(M1, M2);
+chk_MId(deviceName,M1,M2) -> chk_PathName(M1, M2);
+chk_MId(mtpAddress,M1,M2) -> chk_mtpAddress(M1, M2);
+chk_MId(Tag,M1,M2) ->
+ wrong_type({invalid_tag,Tag,M1,M2}).
+
+
+chk_IP4Address(M, M) ->
+ ok;
+chk_IP4Address(M1, M2) ->
+ not_equal({ip4Address,M1,M2}).
+
+chk_IP6Address(M, M) ->
+ ok;
+chk_IP6Address(M1, M2) ->
+ not_equal({ip6Address,M1,M2}).
+
+chk_DomainName(D, D) when is_record(D,'DomainName') ->
+ ok;
+chk_DomainName(#'DomainName'{name = Name1,
+ portNumber = Port1},
+ #'DomainName'{name = Name2,
+ portNumber = Port2}) ->
+ chk_DomainName_name(Name1,Name2),
+ chk_DomainName_opt_portNumber(Port1,Port2),
+ equal('DomainName');
+chk_DomainName(D1,D2) ->
+ wrong_type({'DomainName',D1,D2}).
+
+chk_DomainName_name(N,N) when is_list(N) ->
+ ok;
+chk_DomainName_name(N1,N2) when is_list(N1) andalso is_list(N2) ->
+ not_equal({'DomainName',name,N1,N2});
+chk_DomainName_name(N1,N2) ->
+ wrong_type({'DomainName',name,N1,N2}).
+
+chk_DomainName_opt_portNumber(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_DomainName_opt_portNumber(P,P)
+ when is_integer(P) andalso (P >= 0) ->
+ ok;
+chk_DomainName_opt_portNumber(P1,P2)
+ when (is_integer(P1) andalso (P1 >= 0) andalso
+ is_integer(P2) andalso (P2 >= 0)) ->
+ not_equal({'DomainName',portNumber,P1,P2});
+chk_DomainName_opt_portNumber(P1,P2) ->
+ wrong_type({'DomainName',portNumber,P1,P2}).
+
+
+chk_PathName(P, P) ->
+ ok;
+chk_PathName(P1, P2) ->
+ not_equal({pathname,P1,P2}).
+
+chk_mtpAddress(M, M) ->
+ ok;
+chk_mtpAddress(M1, M2) ->
+ not_equal({mtpAddress, M1, M2}).
+
+
+chk_messageBody({messageError, B},
+ {messageError, B}) when is_record(B,'ErrorDescriptor') ->
+ ok;
+chk_messageBody({messageError,B1},{messageError,B2}) ->
+ chk_ErrorDescriptor(B1,B2),
+ equal({messageBody, messageError});
+chk_messageBody({transactions,T},{transactions,T}) when is_list(T) ->
+ ok;
+chk_messageBody({transactions,T1},{transactions,T2}) ->
+ chk_transactions(T1,T2),
+ ok;
+chk_messageBody(B1,B2) ->
+ wrong_type({messageBody,B1,B2}).
+
+
+chk_transactions(T,T) when is_list(T) ->
+ ok;
+chk_transactions(T1,T2)
+ when is_list(T1) andalso is_list(T2) andalso (length(T1) =:= length(T2)) ->
+ chk_transactions1(T1,T2);
+chk_transactions(T1,T2)
+ when is_list(T1) andalso is_list(T2) ->
+ not_equal({transactions, T1, T2});
+chk_transactions(T1, T2) ->
+ wrong_type({transactions,T1,T2}).
+
+chk_transactions1([],[]) ->
+ equal(transactions);
+chk_transactions1([T|Ts1],[T|Ts2]) ->
+ chk_transactions1(Ts1,Ts2);
+chk_transactions1([T1|_Ts1],[T2|_Ts2]) ->
+ chk_transaction(T1,T2),
+ ok.
+
+chk_transaction(T,T) ->
+ ok;
+chk_transaction({transactionRequest,T1},{transactionRequest,T2}) ->
+ chk_transactionRequest(T1,T2),
+ ok;
+chk_transaction({transactionPending,T1},{transactionPending,T2}) ->
+ chk_transactionPending(T1,T2),
+ equal({transactionPending,T1,T2});
+chk_transaction({transactionReply,T1},{transactionReply,T2}) ->
+ chk_transactionReply(T1,T2),
+ equal({transactionReply,T1,T2});
+chk_transaction({transactionResponseAck,T1},{transactionResponseAck,T2}) ->
+ chk_transactionAck(T1,T2),
+ equal({transactionResponseAck,T1,T2});
+chk_transaction({Tag1,_T1},{Tag2,_T2}) ->
+ wrong_type({transaction_tag,Tag1,Tag2}).
+
+
+chk_transactionRequest(T,T) when is_record(T,'TransactionRequest') ->
+ ok;
+chk_transactionRequest(T1,T2) when is_record(T1,'TransactionRequest') andalso
+ is_record(T2,'TransactionRequest') ->
+ chk_transactionId(T1#'TransactionRequest'.transactionId,
+ T2#'TransactionRequest'.transactionId),
+ chk_actionRequests(T1#'TransactionRequest'.actions,
+ T2#'TransactionRequest'.actions),
+ ok;
+chk_transactionRequest(T1,T2) ->
+ wrong_type({transactionRequest,T1,T2}).
+
+
+chk_transactionPending(T,T) when is_record(T,'TransactionPending') ->
+ ok;
+chk_transactionPending(#'TransactionPending'{transactionId = Id1},
+ #'TransactionPending'{transactionId = Id2}) ->
+ chk_transactionId(Id1,Id2),
+ equal(transactionPending);
+chk_transactionPending(T1,T2) ->
+ wrong_type({transactionPending,T1,T2}).
+
+chk_transactionReply(T,T) when is_record(T,'TransactionReply') ->
+ ok;
+chk_transactionReply(#'TransactionReply'{transactionId = Id1,
+ immAckRequired = ImmAck1,
+ transactionResult = TransRes1},
+ #'TransactionReply'{transactionId = Id2,
+ immAckRequired = ImmAck2,
+ transactionResult = TransRes2}) ->
+ chk_transactionId(Id1,Id2),
+ ImmAck1 = ImmAck2,
+ chk_transactionReply_transactionResult(TransRes1,TransRes2),
+ equal(transactionReply);
+chk_transactionReply(T1,T2) ->
+ wrong_type({transactionReply,T1,T2}).
+
+chk_transactionReply_transactionResult(R,R) ->
+ ok;
+chk_transactionReply_transactionResult(R1,R2) ->
+ not_equal({transactionReply_transactionResult,R1,R2}).
+
+chk_transactionAck(T,T) when is_record(T,'TransactionAck') ->
+ ok;
+chk_transactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ chk_transactionId(F1,F2),
+ chk_opt_transactionId(L1,L2),
+ equal('TransactionAck');
+chk_transactionAck(T1,T2) ->
+ wrong_type({transactionAck,T1,T2}).
+
+
+chk_actionRequests(A,A) when is_list(A) andalso (length(A) =:= 0) ->
+ ok;
+chk_actionRequests(A,A) when is_list(A) ->
+ case hd(A) of
+ A when is_record(A,'ActionRequest') ->
+ ok;
+ Else ->
+ wrong_type({'ActionRequest',Else})
+ end;
+chk_actionRequests(A1,A2)
+ when is_list(A1) andalso is_list(A2) andalso (length(A1) =:= length(A2)) ->
+ chk_actionRequests1(A1,A2);
+chk_actionRequests(A1,A2) ->
+ wrong_type({actionRequests,A1,A2}).
+
+chk_actionRequests1([],[]) ->
+ equal(actionRequests);
+chk_actionRequests1([A|As1],[A|As2]) when is_record(A,'ActionRequest') ->
+ chk_actionRequests1(As1,As2);
+chk_actionRequests1([A1|_As1],[A2|_As2]) ->
+ chk_actionRequest(A1,A2),
+ ok.
+
+chk_actionRequest(A,A) when is_record(A,'ActionRequest') ->
+ ok;
+chk_actionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ t("chk_actionRequest -> entry with"
+ "~n CmdReqs1: ~p"
+ "~n CmdReqs2: ~p",[CmdReqs1,CmdReqs2]),
+ chk_contextId(Id1,Id2),
+ chk_opt_contextRequest(Req1,Req2),
+ chk_opt_contextAttrAuditReq(AuditReq1,AuditReq2),
+ chk_commandRequests(CmdReqs1,CmdReqs2),
+ ok.
+
+chk_contextId(Id,Id) when is_integer(Id) ->
+ ok;
+chk_contextId(Id1,Id2) when is_integer(Id1) andalso is_integer(Id2) ->
+ not_equal({contextId,Id1,Id2});
+chk_contextId(Id1,Id2) ->
+ wrong_type({contextId,Id1,Id2}).
+
+chk_opt_contextRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_contextRequest(R,R) when is_record(R,'ContextRequest') ->
+ ok;
+chk_opt_contextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1} = C1,
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2} = C2) ->
+ chk_contextRequest_priority(Prio1,Prio2),
+ chk_contextRequest_emergency(Em1,Em2),
+ chk_topologyRequest(TopReq1,TopReq2),
+ equal({'ContextRequest',C1,C2}).
+
+chk_contextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_contextRequest_priority(P,P) when is_integer(P) ->
+ ok;
+chk_contextRequest_priority(P1,P2) when is_integer(P1) andalso is_integer(P2) ->
+ not_equal({contextRequest_priority,P1,P2});
+chk_contextRequest_priority(P1,P2) ->
+ wrong_type({contextRequest_priority,P1,P2}).
+
+chk_contextRequest_emergency(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_contextRequest_emergency(true,true) ->
+ ok;
+chk_contextRequest_emergency(false,false) ->
+ ok;
+chk_contextRequest_emergency(E1,E2) ->
+ not_equal({contextRequest_emergency,E1,E2}).
+
+chk_topologyRequest(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_topologyRequest(T,T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_topologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = D1} = T1,
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = D2} = T2) ->
+ chk_terminationId(F1,F2),
+ chk_terminationId(T1,T2),
+ chk_topologyRequest_topologyDirection(D1,D2),
+ equal({'TopologyRequest',D1,D2}).
+
+chk_topologyRequest_topologyDirection(bothway,bothway) ->
+ ok;
+chk_topologyRequest_topologyDirection(isolate,isolate) ->
+ ok;
+chk_topologyRequest_topologyDirection(oneway,oneway) ->
+ ok;
+chk_topologyRequest_topologyDirection(D1,D2) ->
+ not_equal({topologyRequest_topologyDirection, D1, D2}).
+
+chk_opt_contextAttrAuditReq(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_contextAttrAuditReq(R,R) when is_record(R,'ContextAttrAuditRequest') ->
+ ok;
+chk_opt_contextAttrAuditReq(#'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1} = R1,
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2} = R2) ->
+ T1 = T2,
+ E1 = E2,
+ P1 = P2,
+ equal({'ContextAttrAuditRequest',R1,R2}).
+
+chk_commandRequests(C1,C2)
+ when is_list(C1) andalso is_list(C2) andalso (length(C1) =:= length(C2)) ->
+ t("chk_commandRequests -> entry with"
+ "~n C1: ~p"
+ "~n C2: ~p", [C1, C2]),
+ chk_commandRequests1(C1,C2);
+chk_commandRequests(C1,C2) ->
+ t("chk_commandRequests -> entry",[]),
+ wrong_type({commandRequests,C1,C2}).
+
+chk_commandRequests1([],[]) ->
+ ok;
+chk_commandRequests1([C1|Cs1],[C2|Cs2]) ->
+ chk_commandRequest(C1,C2),
+ chk_commandRequests1(Cs1,Cs2).
+
+chk_commandRequest(C,C) when is_record(C,'CommandRequest') ->
+ ok;
+chk_commandRequest(#'CommandRequest'{command = Cmd1,
+ optional = O1,
+ wildcardReturn = W1},
+ #'CommandRequest'{command = Cmd2,
+ optional = O2,
+ wildcardReturn = W2}) ->
+ t("chk_commandRequest -> entry with"
+ "~n C1: ~p"
+ "~n C2: ~p", [Cmd1, Cmd2]),
+ chk_commandRequest_command(Cmd1,Cmd2),
+ O1 = O2,
+ W1 = W2,
+ ok;
+chk_commandRequest(C1,C2) ->
+ wrong_type({commandRequest,C1,C2}).
+
+chk_commandRequest_command({addReq,C1},{addReq,C2}) ->
+ chk_AmmRequest(C1,C2);
+chk_commandRequest_command({moveReq,C1},{moveReq,C2}) ->
+ chk_AmmRequest(C1,C2);
+chk_commandRequest_command({modReq,C1},{modReq,C2}) ->
+ chk_AmmRequest(C1,C2);
+chk_commandRequest_command({subtractReq,C1},{subtractReq,C2}) ->
+ chk_SubtractRequest(C1,C2);
+chk_commandRequest_command({auditCapRequest,C1},{auditCapRequest,C2}) ->
+ chk_AuditRequest(C1,C2);
+chk_commandRequest_command({auditValueRequest,C1},{auditValueRequest,C2}) ->
+ chk_AuditRequest(C1,C2);
+chk_commandRequest_command({notifyReq,C1},{notifyReq,C2}) ->
+ chk_NotifyRequest(C1,C2);
+chk_commandRequest_command({serviceChangeReq,C1},{serviceChangeReq,C2}) ->
+ chk_ServiceChangeRequest(C1,C2);
+chk_commandRequest_command(C1,C2) ->
+ wrong_type({commandRequest_command,C1,C2}).
+
+
+chk_AmmRequest(R,R) when is_record(R,'AmmRequest') ->
+ ok;
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = D1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = D2}) ->
+ chk_terminationIds(Tids1,Tids2),
+ chk_AmmRequest_descriptors(D1,D2),
+ ok;
+chk_AmmRequest(R1,R2) ->
+ wrong_type({'AmmRequest',R1,R2}).
+
+chk_AmmRequest_descriptors([],[]) ->
+ ok;
+chk_AmmRequest_descriptors(D1,D2)
+ when is_list(D1) andalso is_list(D2) andalso (length(D1) =:= length(D2)) ->
+ chk_AmmRequest_descriptors1(D1,D2);
+chk_AmmRequest_descriptors(D1,D2) ->
+ wrong_type({ammRequest_descriptors,D1,D2}).
+
+chk_AmmRequest_descriptors1([],[]) ->
+ ok;
+chk_AmmRequest_descriptors1([D1|Ds1],[D2|Ds2]) ->
+ chk_AmmRequest_descriptor(D1,D2),
+ chk_AmmRequest_descriptors1(Ds1,Ds2).
+
+chk_AmmRequest_descriptor({mediaDescriptor,D1},{mediaDescriptor,D2}) ->
+ chk_MediaDescriptor(D1,D2);
+chk_AmmRequest_descriptor({modemDescriptor,D1},{modemDescriptor,D2}) ->
+ chk_ModemDescriptor(D1,D2);
+chk_AmmRequest_descriptor({muxDescriptor,D1},{muxDescriptor,D2}) ->
+ chk_MuxDescriptor(D1,D2);
+chk_AmmRequest_descriptor({eventsDescriptor,D1},{eventsDescriptor,D2}) ->
+ chk_EventsDescriptor(D1,D2);
+chk_AmmRequest_descriptor({eventBufferDescriptor,D1},{eventBufferDescriptor,D2}) ->
+ chk_EventBufferDescriptor(D1,D2);
+chk_AmmRequest_descriptor({signalsDescriptor,D1},{signalsDescriptor,D2}) ->
+ chk_SignalsDescriptor(D1,D2);
+chk_AmmRequest_descriptor({digitMapDescriptor,D1},{digitMapDescriptor,D2}) ->
+ chk_DigitMapDescriptor(D1,D2);
+chk_AmmRequest_descriptor({auditDescriptor,D1},{auditDescriptor,D2}) ->
+ chk_AuditDescriptor(D1,D2);
+chk_AmmRequest_descriptor({Tag1,_D1},{Tag2,_D2}) ->
+ wrong_type({ammRequest_descriptor_tag,Tag1,Tag2}).
+
+
+chk_SubtractRequest(R,R) when is_record(R,'SubtractRequest') ->
+ ok;
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = D1} = R1,
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = D2} = R2) ->
+ chk_terminationIds(Tids1, Tids2),
+ chk_opt_AuditDescriptor(D1, D2),
+ equal({'SubtractRequest',R1,R2});
+chk_SubtractRequest(R1,R2) ->
+ wrong_type({'SubtractRequest',R1,R2}).
+
+
+chk_AuditRequest(R,R) when is_record(R,'AuditRequest') ->
+ ok;
+chk_AuditRequest(#'AuditRequest'{terminationID = Tid1,
+ auditDescriptor = D1} = R1,
+ #'AuditRequest'{terminationID = Tid2,
+ auditDescriptor = D2} = R2) ->
+ chk_terminationId(Tid1,Tid2),
+ chk_AuditDescriptor(D1,D2),
+ equal({'AuditRequest',R1,R2});
+chk_AuditRequest(R1,R2) ->
+ wrong_type({'AuditRequest',R1,R2}).
+
+
+chk_NotifyRequest(R,R) when is_record(R,'NotifyRequest') ->
+ ok;
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = ObsDesc1,
+ errorDescriptor = ErrDesc1} = R1,
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = ObsDesc2,
+ errorDescriptor = ErrDesc2} = R2) ->
+ chk_terminationIds(Tids1,Tids2),
+ chk_ObservedEventsDescriptor(ObsDesc1,ObsDesc2),
+ chk_opt_ErrorDescriptor(ErrDesc1,ErrDesc2),
+ equal({'NotifyRequest',R1,R2});
+chk_NotifyRequest(R1,R2) ->
+ wrong_type({'NotifyRequest',R1,R2}).
+
+
+chk_ServiceChangeRequest(R,R) when is_record(R,'ServiceChangeRequest') ->
+ ok;
+chk_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = P1} = R1,
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = P2} = R2) ->
+ chk_terminationIds(Tids1,Tids2),
+ chk_ServiceChangeParm(P1,P2),
+ equal({'ServiceChangeRequest',R1,R2});
+chk_ServiceChangeRequest(R1,R2) ->
+ wrong_type({'ServiceChangeRequest',R1,R2}).
+
+
+chk_MediaDescriptor(D, D) when is_record(D,'MediaDescriptor') ->
+ ok;
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = Tsd1,
+ streams = S1} = D1,
+ #'MediaDescriptor'{termStateDescr = Tsd2,
+ streams = S2} = D2) ->
+%% io:format("chk_MediaDescriptor -> entry with"
+%% "~n Tsd1: ~p"
+%% "~n Tsd2: ~p"
+%% "~n S1: ~p"
+%% "~n S2: ~p"
+%% "~n", [Tsd1, Tsd2, S1, S2]),
+ chk_MediaDescriptor_tsd(Tsd1, Tsd2),
+ chk_MediaDescriptor_streams(S1, S2),
+ equal({'MediaDescriptor',D1,D2});
+chk_MediaDescriptor(D1,D2) ->
+ wrong_type({'MediaDescriptor',D1,D2}).
+
+chk_MediaDescriptor_tsd(D, D) ->
+ ok;
+chk_MediaDescriptor_tsd(D1, D2) ->
+ not_equal({termStateDescr, D1, D2}).
+
+chk_MediaDescriptor_streams({oneStream, S}, {oneStream, S}) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, S1}, {oneStream, S2}) ->
+ not_equal({oneStream, S1, S2});
+chk_MediaDescriptor_streams({multiStream, MS}, {multiStream, MS}) ->
+ ok;
+chk_MediaDescriptor_streams({multiStream, MS1}, {multiStream, MS2}) ->
+ chk_StreamDescriptors(MS1, MS2);
+chk_MediaDescriptor_streams(S1, S2) ->
+ not_equal({streams, S1, S2}).
+
+chk_StreamDescriptors([], []) ->
+ ok;
+chk_StreamDescriptors([SD1|MS1], [SD2|MS2]) ->
+ chk_StreamDescriptor(SD1, SD2),
+ chk_StreamDescriptors(MS1, MS2).
+
+chk_StreamDescriptor(SD, SD) when is_record(SD, 'StreamDescriptor') ->
+ ok;
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = SP1} = SD1,
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = SP2} = SD2) ->
+ SID1 = SID2,
+ chk_StreamParms(SP1, SP2),
+ equal({'StreamDescriptor',SD1, SD2});
+chk_StreamDescriptor(SD1, SD2) ->
+ wrong_type({'StreamDescriptor',SD1,SD2}).
+
+
+chk_StreamParms(SP, SP) when is_record(SP, 'StreamParms') ->
+ ok;
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1} = SP1,
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2} = SP2) ->
+ LCD1 = LCD2,
+ LD1 = LD2,
+ RD1 = RD2,
+ equal({'StreamParms', SP1, SP2});
+chk_StreamParms(SP1, SP2) ->
+ wrong_type({'StreamDescriptor', SP1, SP2}).
+
+chk_ModemDescriptor(D,D) when is_record(D,'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = T1,
+ mpl = P1} = D1,
+ #'ModemDescriptor'{mtl = T2,
+ mpl = P2} = D2) ->
+ T1 = T2,
+ P1 = P2,
+ equal({'ModemDescriptor',D1,D2});
+chk_ModemDescriptor(D1,D2) ->
+ wrong_type({'ModemDescriptor',D1,D2}).
+
+chk_MuxDescriptor(D,D) when is_record(D,'MuxDescriptor') ->
+ ok;
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = T1,
+ termList = I1} = D1,
+ #'MuxDescriptor'{muxType = T2,
+ termList = I2} = D2) ->
+ T1 = T2,
+ I1 = I2,
+ equal({'MuxDescriptor',D1,D2});
+chk_MuxDescriptor(D1,D2) ->
+ wrong_type({'MuxDescriptor',D1,D2}).
+
+chk_EventsDescriptor(D,D) when is_record(D,'EventsDescriptor') ->
+ ok;
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = I1,
+ eventList = E1} = D1,
+ #'EventsDescriptor'{requestID = I2,
+ eventList = E2} = D2) ->
+ I1 = I2,
+ E1 = E2,
+ equal({'EventsDescriptor',D1,D2});
+chk_EventsDescriptor(D1,D2) ->
+ wrong_type({'EventsDescriptor',D1,D2}).
+
+chk_EventBufferDescriptor(D1,D2)
+ when is_list(D1) andalso is_list(D2) andalso (length(D1) =:= length(D2)) ->
+ chk_EventBufferDescriptor1(D1,D2);
+chk_EventBufferDescriptor(D1,D2) ->
+ wrong_type({eventBufferDescriptor,D1,D2}).
+
+chk_EventBufferDescriptor1([],[]) ->
+ ok;
+chk_EventBufferDescriptor1([ES1|D1],[ES2|D2]) ->
+ chk_EventSpec(ES1,ES2),
+ chk_EventBufferDescriptor1(D1,D2).
+
+chk_EventSpec(ES,ES) when is_record(ES,'EventSpec') ->
+ ok;
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = I1,
+ eventParList = P1} = ES1,
+ #'EventSpec'{eventName = N2,
+ streamID = I2,
+ eventParList = P2} = ES2) ->
+ N1 = N2,
+ chk_opt_StreamId(I1,I2),
+ chk_EventParameters(P1,P2),
+ equal({'EventSpec',ES1,ES2});
+chk_EventSpec(ES1,ES2) ->
+ wrong_type({'EventSpec',ES1,ES2}).
+
+
+chk_opt_ErrorDescriptor(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_ErrorDescriptor(E1,E2) ->
+ chk_ErrorDescriptor(E1,E2).
+
+chk_ErrorDescriptor(E,E) when is_record(E,'ErrorDescriptor') ->
+ ok;
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1} = E1,
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2} = E2) ->
+ chk_ErrorCode(Code1,Code2),
+ chk_opt_ErrorText(Text1,Text2),
+ equal({'ErrorDescriptor',E1,E2});
+chk_ErrorDescriptor(E1,E2) ->
+ wrong_type({'ErrorDescriptor',E1,E2}).
+
+chk_ErrorCode(C,C) when is_integer(C) ->
+ ok;
+chk_ErrorCode(C1,C2) when is_integer(C1) andalso is_integer(C2) ->
+ not_equal({errorCode,C1,C2});
+chk_ErrorCode(C1,C2) ->
+ throw({wrong_type,{errorCode,C1,C2}}).
+
+chk_opt_ErrorText(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_ErrorText(T,T) when is_list(T) ->
+ ok;
+chk_opt_ErrorText(T1,T2) when is_list(T1) andalso is_list(T2) ->
+ not_equal({errorText,T1,T2});
+chk_opt_ErrorText(T1,T2) ->
+ wrong_type({errorText,T1,T2}).
+
+
+chk_SignalsDescriptor(D1,D2)
+ when is_list(D1) andalso is_list(D2) andalso (length(D1) =:= length(D2)) ->
+ chk_SignalsDescriptor1(D1,D2);
+chk_SignalsDescriptor(D1,D2) ->
+ wrong_type({signalsDescriptor,D1,D2}).
+
+chk_SignalsDescriptor1([],[]) ->
+ ok;
+chk_SignalsDescriptor1([S1|D1],[S2|D2]) ->
+ chk_SignalRequest(S1,S2),
+ chk_SignalsDescriptor1(D1,D2).
+
+chk_SignalRequest({signal,S1},{signal,S2}) ->
+ chk_Signal(S1,S2);
+chk_SignalRequest({seqSigList,S1},{seqSigList,S2}) ->
+ chk_SeqSignalList(S1,S2);
+chk_SignalRequest(R1,R2) ->
+ wrong_type({signalRequest,R1,R2}).
+
+chk_SeqSignalList(S,S) when is_record(S,'SeqSigList') ->
+ ok;
+chk_SeqSignalList(#'SeqSigList'{id = Id1,
+ signalList = SigList1} = S1,
+ #'SeqSigList'{id = Id2,
+ signalList = SigList2} = S2) ->
+ Id1 = Id2,
+ chk_Signals(SigList1,SigList2),
+ equal({'SeqSigList',S1,S2});
+chk_SeqSignalList(S1,S2) ->
+ wrong_type({'SeqSigList',S1,S2}).
+
+
+chk_Signals([],[]) ->
+ ok;
+chk_Signals([Sig1|Sigs1],[Sig2|Sigs2]) ->
+ chk_Signal(Sig1,Sig2),
+ chk_Signals(Sigs1,Sigs2).
+
+
+chk_Signal(S,S) when is_record(S,'Signal') ->
+ ok;
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = I1,
+ sigType = T1,
+ duration = D1,
+ notifyCompletion = C1,
+ keepActive = K1,
+ sigParList = P1} = S1,
+ #'Signal'{signalName = N2,
+ streamID = I2,
+ sigType = T2,
+ duration = D2,
+ notifyCompletion = C2,
+ keepActive = K2,
+ sigParList = P2} = S2) ->
+ N1 = N2,
+ chk_opt_StreamId(I1,I2),
+ chk_opt_SignalType(T1,T2),
+ chk_opt_duration(D1,D2),
+ chk_opt_NotifyCompletion(C1,C2),
+ chk_opt_keepAlive(K1,K2),
+ chk_sigParameters(P1,P2),
+ equal({'Signal',S1,S2});
+chk_Signal(S1,S2) ->
+ wrong_type({'Signal',S1,S2}).
+
+chk_DigitMapDescriptor(D,D) when is_record(D,'DigitMapDescriptor') ->
+ ok;
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = N1,
+ digitMapValue = V1},
+ #'DigitMapDescriptor'{digitMapName = N2,
+ digitMapValue = V2}) ->
+ chk_opt_digitMapName(N1,N2),
+ chk_opt_digitMapValue(V1,V2),
+ ok;
+chk_DigitMapDescriptor(D1,D2) ->
+ wrong_type({'DigitMapDescriptor',D1,D2}).
+
+chk_opt_digitMapName(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_digitMapName(N1,N2) ->
+ chk_digitMapName(N1,N2).
+
+chk_digitMapName(N,N) ->
+ ok;
+chk_digitMapName(N1,N2) ->
+ not_equal({digitMapName,N1,N2}).
+
+chk_opt_digitMapValue(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_digitMapValue(V1,V2) ->
+ chk_digitMapValue(V1,V2).
+
+chk_digitMapValue(V,V) when is_record(V,'DigitMapValue') ->
+ ok;
+chk_digitMapValue(#'DigitMapValue'{digitMapBody = Body1,
+ startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1},
+ #'DigitMapValue'{digitMapBody = Body2,
+ startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2}) ->
+ chk_digitMapValue_digitMapBody(Body1,Body2), % Could contain trailing '\n', ...
+ chk_opt_timer(Start1,Start2),
+ chk_opt_timer(Short1,Short2),
+ chk_opt_timer(Long1,Long2),
+ ok;
+chk_digitMapValue(V1,V2) ->
+ wrong_type({digitMapValue,V1,V2}).
+
+chk_digitMapValue_digitMapBody(B,B) when is_list(B) ->
+ ok;
+chk_digitMapValue_digitMapBody(B1, B2)
+ when is_list(B1) andalso is_list(B2) andalso (length(B1) > length(B2)) ->
+ case string:str(B2, B1) of
+ 0 ->
+ ok;
+ _ ->
+ not_equal({digitMapValue_digitMapBody,B1,B2})
+ end;
+chk_digitMapValue_digitMapBody(B1, B2)
+ when is_list(B1) andalso is_list(B2) andalso (length(B1) < length(B2)) ->
+ case string:str(B1, B2) of
+ 0 ->
+ ok;
+ _ ->
+ not_equal({digitMapValue_digitMapBody,B1,B2})
+ end;
+chk_digitMapValue_digitMapBody(B1,B2) when is_list(B1) andalso is_list(B2) ->
+ not_equal({digitMapValue_digitMapBody,B1,B2});
+chk_digitMapValue_digitMapBody(B1,B2) ->
+ wrong_type({digitMapValue_digitMapBody,B1,B2}).
+
+
+chk_opt_AuditDescriptor(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(D1,D2) ->
+ chk_AuditDescriptor(D1,D2).
+
+chk_AuditDescriptor(D,D) when is_record(D,'AuditDescriptor') ->
+ ok;
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = T1} = D1,
+ #'AuditDescriptor'{auditToken = T2} = D2) ->
+ chk_opt_auditToken(T1,T2),
+ equal({'AuditDescriptor',D1,D2});
+chk_AuditDescriptor(D1,D2) ->
+ wrong_type({'AuditDescriptor',D1,D2}).
+
+chk_opt_auditToken(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_auditToken(T1,T2) ->
+ chk_auditToken(T1,T2).
+
+chk_auditToken(T1,T2)
+ when is_list(T1) andalso is_list(T2) andalso (length(T1) =:= length(T2)) ->
+ chk_auditToken1(T1,T2);
+chk_auditToken(T1,T2) ->
+ wrong_type({auditToken,T1,T2}).
+
+chk_auditToken1([],[]) ->
+ ok;
+chk_auditToken1([H1|T1],[H2|T2]) ->
+ chk_auditToken2(H1,H2),
+ chk_auditToken1(T1,T2).
+
+chk_auditToken2(muxToken,muxToken) ->
+ ok;
+chk_auditToken2(modemToken,modemToken) ->
+ ok;
+chk_auditToken2(mediaToken,mediaToken) ->
+ ok;
+chk_auditToken2(eventsToken,eventsToken) ->
+ ok;
+chk_auditToken2(signalsToken,signalsToken) ->
+ ok;
+chk_auditToken2(digitMapToken,digitMapToken) ->
+ ok;
+chk_auditToken2(statsToken,statsToken) ->
+ ok;
+chk_auditToken2(observedEventsToken,observedEventsToken) ->
+ ok;
+chk_auditToken2(packagesToken,packagesToken) ->
+ ok;
+chk_auditToken2(eventBufferToken,eventBufferToken) ->
+ ok;
+chk_auditToken2(T1,T2) when is_atom(T1) andalso is_atom(T2) ->
+ not_equal({auditToken,T1,T2});
+chk_auditToken2(T1,T2) ->
+ wrong_type({auditToken,T1,T2}).
+
+chk_ObservedEventsDescriptor(D,D)
+ when is_record(D,'ObservedEventsDescriptor') ->
+ ok;
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = Id1,
+ observedEventLst = E1} = D1,
+ #'ObservedEventsDescriptor'{requestId = Id2,
+ observedEventLst = E2} = D2) ->
+ Id1 = Id2,
+ chk_ObservedEvents(E1,E2),
+ equal({'ObservedEventsDescriptor',D1,D2});
+chk_ObservedEventsDescriptor(D1,D2) ->
+ wrong_type({'ObservedEventsDescriptor',D1,D2}).
+
+
+chk_ObservedEvents(E1,E2)
+ when is_list(E1) andalso is_list(E2) andalso (length(E1) =:= length(E2)) ->
+ chk_ObservedEvents1(E1,E2);
+chk_ObservedEvents(E1,E2) ->
+ wrong_type({observedEvents,E1,E2}).
+
+
+chk_ObservedEvents1([],[]) ->
+ ok;
+chk_ObservedEvents1([Ev1|Evs1],[Ev2|Evs2]) ->
+ chk_ObservedEvent(Ev1,Ev2),
+ chk_ObservedEvents1(Evs1,Evs2).
+
+chk_ObservedEvent(#'ObservedEvent'{eventName = N1,
+ streamID = I1,
+ eventParList = P1,
+ timeNotation = T1} = E1,
+ #'ObservedEvent'{eventName = N2,
+ streamID = I2,
+ eventParList = P2,
+ timeNotation = T2} = E2) ->
+ N1 = N2,
+ chk_opt_StreamId(I1,I2),
+ chk_EventParameters(P1,P2),
+ chk_opt_TimeNotation(T1,T2),
+ equal({'ObservedEvent',E1,E2});
+chk_ObservedEvent(E1,E2) ->
+ wrong_type({'ObservedEvent',E1,E2}).
+
+
+chk_opt_TimeNotation(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(T1,T2) ->
+ chk_TimeNotation(T1,T2).
+
+chk_TimeNotation(T,T) when is_record(T,'TimeNotation') ->
+ ok;
+chk_TimeNotation(#'TimeNotation'{date = Date1,
+ time = Time1} = T1,
+ #'TimeNotation'{date = Date2,
+ time = Time2} = T2) ->
+ Date1 = Date2,
+ Time1 = Time2,
+ equal({'TimeNotation',T1,T2});
+chk_TimeNotation(T1,T2) ->
+ wrong_type({'TimeNotation',T1,T2}).
+
+
+chk_opt_timer(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_timer(T1,T2) ->
+ chk_timer(T1,T2).
+
+chk_timer(T,T) when is_integer(T) ->
+ {equal,timer};
+chk_timer(T1,T2) when is_integer(T1) andalso is_integer(T2) ->
+ throw({not_equal,{timer,T1,T2}});
+chk_timer(T1,T2) ->
+ throw({wrong_type,{timer,T1,T2}}).
+
+
+chk_opt_SignalType(asn1_NOVALUE,asn1_NOVALUE) ->
+ {equal,signalType};
+chk_opt_SignalType(T1,T2) ->
+ chk_SignalType(T1,T2).
+
+chk_SignalType(brief,brief) ->
+ {equal,signalType};
+chk_SignalType(onOffonOff,onOffonOff) ->
+ {equal,signalType};
+chk_SignalType(timeOut,timeOut) ->
+ {equal,signalType};
+chk_SignalType(T1,T2) ->
+ throw({wrong_type,{signalType,T1,T2}}).
+
+
+chk_opt_duration(asn1_NOVALUE,asn1_NOVALUE) ->
+ {equal,duration};
+chk_opt_duration(D1,D2) ->
+ chk_duration(D1,D2).
+
+chk_duration(D,D) when is_integer(D) ->
+ {equal,duration};
+chk_duration(D1,D2) when is_integer(D1) andalso is_integer(D2) ->
+ throw({not_equal,{duration,D1,D2}});
+chk_duration(D1,D2) ->
+ throw({wrong_type,{duration,D1,D2}}).
+
+
+chk_opt_NotifyCompletion(asn1_NOVALUE,asn1_NOVALUE) ->
+ {equal,notifyCompletion};
+chk_opt_NotifyCompletion(N1,N2) ->
+ chk_NotifyCompletion(N1,N2).
+
+chk_NotifyCompletion([],[]) ->
+ {equal,notifyCompletion};
+chk_NotifyCompletion([Item1|Items1],[Item2|Items2]) ->
+ chk_NotifyCompletion1(Item1,Item2),
+ chk_NotifyCompletion(Items1,Items2);
+chk_NotifyCompletion(C1,C2) ->
+ throw({wrong_type,{notifyCompletion,C1,C2}}).
+
+chk_NotifyCompletion1(onTimeOut,onTimeOut) ->
+ {equal,notifyCompletion_part};
+chk_NotifyCompletion1(onInterruptByEvent,onInterruptByEvent) ->
+ {equal,notifyCompletion_part};
+chk_NotifyCompletion1(onInterruptByNewSignalDescr,onInterruptByNewSignalDescr) ->
+ {equal,notifyCompletion_part};
+chk_NotifyCompletion1(otherReason,otherReason) ->
+ {equal,notifyCompletion_part};
+chk_NotifyCompletion1(C1,C2) ->
+ throw({wrong_type,{notifyCompletion_part,C1,C2}}).
+
+
+chk_opt_keepAlive(asn1_NOVALUE,asn1_NOVALUE) ->
+ {equal,keepAlive};
+chk_opt_keepAlive(K1,K2) ->
+ chk_keepAlive(K1,K2).
+
+chk_keepAlive(true,true) ->
+ ok;
+chk_keepAlive(false,false) ->
+ ok;
+chk_keepAlive(K1,K2) ->
+ wrong_type({keepAlive,K1,K2}).
+
+
+chk_ServiceChangeParm(P,P) when is_record(P,'ServiceChangeParm') ->
+ ok;
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Mid1,
+ timeStamp = T1} = P1,
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Mid2,
+ timeStamp = T2} = P2) ->
+ M1 = M2,
+ A1 = A2,
+ V1 = V2,
+ P1 = P2,
+ R1 = R2,
+ D1 = D2,
+ Mid1 = Mid2,
+ T1 = T2,
+ equal({'ServiceChangeParm',P1,P2});
+chk_ServiceChangeParm(P1,P2) ->
+ wrong_type({'ServiceChangeParm',P1,P2}).
+
+
+chk_sigParameters(S1,S2)
+ when is_list(S1) andalso is_list(S2) andalso (length(S1) =:= length(S2)) ->
+ chk_sigParameters1(S1,S2);
+chk_sigParameters(S1,S2) ->
+ wrong_type({sigParameters,S1,S2}).
+
+chk_sigParameters1([],[]) ->
+ ok;
+chk_sigParameters1([H1|T1],[H2|T2]) ->
+ chk_sigParameter(H1,H2),
+ chk_sigParameters1(T1,T2);
+chk_sigParameters1(P1,P2) ->
+ wrong_type({sigParameters,P1,P2}).
+
+chk_sigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = E1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = E2}) ->
+ N1 = N2,
+ chk_Value(V1,V2),
+ chk_opt_extraInfo(E1,E2),
+ ok;
+chk_sigParameter(P1,P2) ->
+ wrong_type({'SigParameter',P1,P2}).
+
+
+chk_opt_StreamId(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamId(I1,I2) ->
+ chk_StreamId(I1,I2).
+
+chk_StreamId(I,I) when is_integer(I) ->
+ ok;
+chk_StreamId(I1,I2) when is_integer(I1) andalso is_integer(I2) ->
+ not_equal({streamId,I1,I2});
+chk_StreamId(I1,I2) ->
+ wrong_type({streamId,I1,I2}).
+
+
+chk_EventParameters(EP1,EP2)
+ when is_list(EP1) andalso is_list(EP2) andalso (length(EP1) =:= length(EP2)) ->
+ chk_EventParameters1(EP1,EP2);
+chk_EventParameters(EP1,EP2) ->
+ wrong_type({eventParameters,EP1,EP2}).
+
+chk_EventParameters1([],[]) ->
+ ok;
+chk_EventParameters1([EP1|EPS1],[EP2|EPS2]) ->
+ chk_EventParameter(EP1,EP2),
+ chk_EventParameters1(EPS1,EPS2).
+
+chk_EventParameter(EP,EP) when is_record(EP,'EventParameter') ->
+ ok;
+chk_EventParameter(#'EventParameter'{eventParameterName = N1,
+ value = V1,
+ extraInfo = E1} = EP1,
+ #'EventParameter'{eventParameterName = N2,
+ value = V2,
+ extraInfo = E2} = EP2) ->
+ N1 = N2,
+ chk_Value(V1,V2),
+ chk_opt_extraInfo(E1,E2),
+ equal({'EventParameter',EP1,EP2});
+chk_EventParameter(EP1,EP2) ->
+ wrong_type({'EventParameter',EP1,EP2}).
+
+
+chk_Value(V,V) when is_list(V) ->
+ chk_Value(V);
+chk_Value(V1,V2)
+ when is_list(V1) andalso is_list(V2) andalso (length(V1) =:= length(V2)) ->
+ chk_Value1(V1,V2);
+chk_Value(V1,V2) ->
+ wrong_type({value,V1,V2}).
+
+chk_Value([]) ->
+ ok;
+chk_Value([H|T]) when is_list(H) ->
+ chk_Value(T);
+chk_Value([H|_T]) ->
+ wrong_type({value_part,H}).
+
+chk_Value1([],[]) ->
+ ok;
+chk_Value1([H|T1],[H|T2]) when is_list(H) ->
+ chk_Value1(T1,T2);
+chk_Value1([H|_T1],[H|_T2]) ->
+ wrong_type({value_part,H});
+chk_Value1([H1|_T1],[H2|_T2]) when is_list(H1) andalso is_list(H2) ->
+ not_equal({value_part,H1,H2});
+chk_Value1(V1,V2) ->
+ wrong_type({value,V1,V2}).
+
+
+chk_opt_extraInfo(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_extraInfo(E1,E2) ->
+ chk_extraInfo(E1,E2).
+
+chk_extraInfo({relation,greaterThan},{relation,greaterThan}) ->
+ ok;
+chk_extraInfo({relation,smallerThan},{relation,smallerThan}) ->
+ ok;
+chk_extraInfo({relation,unequalTo},{relation,unequalTo}) ->
+ ok;
+chk_extraInfo({range,true},{range,true}) ->
+ ok;
+chk_extraInfo({range,false},{range,false}) ->
+ ok;
+chk_extraInfo({sublist,true},{sublist,true}) ->
+ ok;
+chk_extraInfo({sublist,false},{sublist,false}) ->
+ ok;
+chk_extraInfo(E1,E2) ->
+ wrong_type({extraInfo,E1,E2}).
+
+
+chk_opt_transactionId(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_opt_transactionId(Id1,Id2) ->
+ chk_transactionId(Id1,Id2).
+
+chk_transactionId(Id,Id) when is_integer(Id) ->
+ ok;
+chk_transactionId(Id1,Id2) when is_integer(Id1) andalso is_integer(Id2) ->
+ not_equal({transactionId,Id1,Id2});
+chk_transactionId(Id1,Id2) ->
+ wrong_type({transactionId,Id1,Id2}).
+
+
+chk_terminationIds(Tids1,Tids2)
+ when is_list(Tids1) andalso is_list(Tids2) andalso (length(Tids1) =:= length(Tids2)) ->
+ chk_terminationIds1(Tids1,Tids2);
+chk_terminationIds(Tids1,Tids2) ->
+ wrong_type({terminationIds,Tids1,Tids2}).
+
+chk_terminationIds1([],[]) ->
+ ok;
+chk_terminationIds1([Tid1|Tids1],[Tid2|Tids2]) ->
+ chk_terminationId(Tid1,Tid2),
+ chk_terminationIds1(Tids1,Tids2).
+
+chk_terminationId(Id,Id) when is_record(Id,'TerminationID') ->
+ ok;
+chk_terminationId(Id,Id) when is_record(Id,megaco_term_id) ->
+ ok;
+chk_terminationId(#'TerminationID'{wildcard = W1,
+ id = I1} = Tid1,
+ #'TerminationID'{wildcard = W2,
+ id = I2} = Tid2) ->
+ chk_terminationId_wildcard(W1,W2),
+ chk_terminationId_id(I1,I2),
+ equal({'TerminationID',Tid1,Tid2});
+chk_terminationId(#megaco_term_id{contains_wildcards = W1,
+ id = I1} = Tid1,
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2} = Tid2) ->
+ chk_terminationId_wildcard(W1,W2),
+ chk_terminationId_id(I1,I2),
+ equal({megaco_term_id,Tid1,Tid2});
+chk_terminationId(Tid1,Tid2) ->
+ wrong_type({terminationId,Tid1,Tid2}).
+
+chk_terminationId_wildcard(W,W) ->
+ ok;
+chk_terminationId_wildcard(W1,W2) ->
+ not_equal({terminationId_wildcard,W1,W2}).
+
+chk_terminationId_id(I,I) ->
+ ok;
+chk_terminationId_id(I1,I2) ->
+ not_equal({terminationId_id,I1,I2}).
+
+
+equal(What) ->
+ error({equal, What}).
+
+not_equal(What) ->
+ error({not_equal, What}).
+
+wrong_type(What) ->
+ error({wrong_type, What}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_megacoMessage(V, Mid, Body) ->
+ #'MegacoMessage'{mess = #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}}.
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_authHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_authHeader(SecParmIdx, SeqNum, AD).
+
+cre_authHeader(Idx, Num, D) ->
+ #'AuthenticationHeader'{secParmIndex = Idx,
+ seqNum = Num,
+ ad = D}.
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_transactionReply(TransId, Actions) ->
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = {actionReplies, Actions}}.
+
+cre_transactionAck(Serial, Serial) ->
+ #'TransactionAck'{firstAck = Serial};
+cre_transactionAck(First, Last) ->
+ #'TransactionAck'{firstAck = First, lastAck = Last}.
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_actionReply(CtxId, CmdReply) ->
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdReply}.
+
+cre_CtxID(Id) ->
+ ?MSG_LIB:cre_ContextID(Id).
+
+%% Parameter related
+cre_propertyParm(Name, Val) ->
+ #'PropertyParm'{name = Name, value = [Val]}.
+
+
+%% Statistics related
+cre_statisticsParm(Name, Val) ->
+ #'StatisticsParameter'{statName = Name, statValue = [Val]}.
+
+
+% Event related
+cre_eventParm(Name, Val) ->
+ #'EventParameter'{eventParameterName = Name, value = Val}.
+
+cre_observedEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name, timeNotation = Not}.
+cre_observedEvent(Name, Not, Par) ->
+ #'ObservedEvent'{eventName = Name, timeNotation = Not, eventParList = Par}.
+
+cre_requestedEvent(Name) ->
+ #'RequestedEvent'{pkgdName = Name}.
+cre_requestedEvent(Name, ParList) when is_list(ParList) ->
+ #'RequestedEvent'{pkgdName = Name, evParList = ParList};
+cre_requestedEvent(Name, Action) when is_tuple(Action) ->
+ #'RequestedEvent'{pkgdName = Name, eventAction = Action}.
+
+
+cre_observedEventsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id, observedEventLst = EvList}.
+
+cre_eventsDesc(Id, EvList) ->
+ #'EventsDescriptor'{requestID = Id, eventList = EvList}.
+
+
+%% Service change related
+cre_serviceChangeParm(M,A,R,P) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M, serviceChangeAddress = A,
+ serviceChangeReason = R, serviceChangeProfile = P}.
+
+cre_serviceChangeResParm(A,P) ->
+ #'ServiceChangeResParm'{serviceChangeAddress = A,
+ serviceChangeProfile = P}.
+
+cre_serviceChangeReq(Tid, P) ->
+ #'ServiceChangeRequest'{terminationID = Tid, serviceChangeParms = P}.
+
+cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
+ #'ServiceChangeProfile'{profileName = Name, version = Ver}.
+
+cre_serviceChangeReply(Tid, Res) ->
+ #'ServiceChangeReply'{terminationID = Tid, serviceChangeResult = Res}.
+
+
+%% Stream related
+cre_streamParms(Lcd) ->
+ #'StreamParms'{localControlDescriptor = Lcd}.
+cre_streamParms(Lcd, Ld) ->
+ #'StreamParms'{localControlDescriptor = Lcd, localDescriptor = Ld}.
+cre_streamParms(Lcd, Ld, Rd) ->
+ #'StreamParms'{localControlDescriptor = Lcd,
+ localDescriptor = Ld,
+ remoteDescriptor = Rd}.
+cre_streamParmsL(Ld) ->
+ #'StreamParms'{localDescriptor = Ld}.
+cre_streamParmsR(Rd) ->
+ #'StreamParms'{remoteDescriptor = Rd}.
+
+cre_streamDesc(Id, P) ->
+ #'StreamDescriptor'{streamID = Id, streamParms = P}.
+
+
+%% "Local" related
+cre_localControlDesc(Mode) ->
+ #'LocalControlDescriptor'{streamMode = Mode}.
+cre_localControlDesc(Mode, Parms) ->
+ #'LocalControlDescriptor'{streamMode = Mode, propertyParms = Parms }.
+
+cre_localRemoteDesc(Grps) ->
+ #'LocalRemoteDescriptor'{propGrps = Grps}.
+
+
+%% DigitMap related
+cre_digitMapDesc(Value) when is_record(Value, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = Value};
+cre_digitMapDesc(Name) ->
+ #'DigitMapDescriptor'{digitMapName = Name}.
+
+cre_digitMapDesc(Name, Val) ->
+ #'DigitMapDescriptor'{digitMapName = Name, digitMapValue = Val}.
+
+cre_digitMapValue(Body) ->
+ #'DigitMapValue'{digitMapBody = Body}.
+
+cre_digitMapValue(Body, Start, Short, Long) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body}.
+
+%% Media related
+cre_mediaDesc(StreamDesc) ->
+ #'MediaDescriptor'{streams = {multiStream, [StreamDesc]}}.
+
+
+%% Notify related
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid, observedEventsDescriptor = EvsDesc}.
+
+cre_notifyReply(Tid) ->
+ #'NotifyReply'{terminationID = Tid}.
+
+
+%% Subtract related
+cre_subtractReq(Tid, Desc) ->
+ #'SubtractRequest'{terminationID = Tid, auditDescriptor = Desc}.
+
+
+%% Audit related
+cre_auditDesc(Tokens) ->
+ #'AuditDescriptor'{auditToken = Tokens}.
+
+cre_auditReq(Tid, Desc) ->
+ #'AuditRequest'{terminationID = Tid, auditDescriptor = Desc}.
+
+cre_auditRes(Tid, Res) ->
+ #'AuditResult'{terminationID = Tid, terminationAuditResult = Res}.
+
+
+%% AMM/AMMS related
+cre_ammReq(Tid, Descs) ->
+ #'AmmRequest'{terminationID = Tid, descriptors = Descs}.
+
+cre_ammsReply(Tid) ->
+ #'AmmsReply'{terminationID = Tid}.
+cre_ammsReply(Tid, Descs) ->
+ #'AmmsReply'{terminationID = Tid, terminationAudit = Descs}.
+
+
+%% Command related
+cre_commandReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+
+%% Actions related
+cre_requestedActions(DmName) ->
+ #'RequestedActions'{eventDM = {digitMapName, DmName}}.
+
+
+%% Signal related
+cre_signal(Name) ->
+ #'Signal'{signalName = Name}.
+
+
+%% Others
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_packagesItem(_Name, _Ver) ->
+ #'PackagesItem'{packageName = "nt", packageVersion = 1}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+start_flex_scanner() ->
+ megaco_codec_flex_lib:start().
+
+stop_flex_scanner(Pid) ->
+ megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+l(F,A) ->
+ p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s: " ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "T";
+image_of(dbg) ->
+ "D";
+image_of(log) ->
+ "L";
+image_of(err) ->
+ "E";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
+
diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl
new file mode 100644
index 0000000000..1df1c6c93b
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_v2_test.erl
@@ -0,0 +1,6992 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_v2_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+ flex_compact_dm_timers7/1,
+ flex_compact_dm_timers8/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4299_msg2/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5290_msg01/1,
+ compact_otp5290_msg02/1,
+ compact_otp5793_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+ compact_otp7138_msg01/1,
+ compact_otp7138_msg02/1,
+ compact_otp7457_msg01/1,
+ compact_otp7457_msg02/1,
+ compact_otp7457_msg03/1,
+ compact_otp7534_msg01/1,
+ compact_otp7576_msg01/1,
+ compact_otp7671_msg01/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp7138_msg01/1,
+ flex_compact_otp7138_msg02/1,
+ flex_compact_otp7431_msg01/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+ flex_compact_otp7457_msg01/1,
+ flex_compact_otp7457_msg02/1,
+ flex_compact_otp7457_msg03/1,
+ flex_compact_otp7534_msg01/1,
+ flex_compact_otp7573_msg01/1,
+ flex_compact_otp7576_msg01/1,
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7249_msg01/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0, generate_text_messages/0]).
+
+-export([
+ %% Decode
+ profile_decode_compact_text_message/1,
+ profile_decode_compact_text_messages/0,
+ profile_decode_compact_flex_text_messages/0,
+ profile_decode_pretty_text_message/1,
+ profile_decode_pretty_text_messages/0,
+ profile_decode_pretty_flex_text_messages/0,
+
+ %% Encode
+ profile_encode_compact_text_messages/0,
+ profile_encode_pretty_text_messages/0
+ ]).
+
+
+%% ----
+
+-define(V2, v2).
+-define(EC, []).
+-define(VERSION, 2).
+-define(VERSION_STR, "2").
+-define(MSG_LIB, megaco_test_msg_v2_lib).
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs =
+ msgs4() ++
+ msgs5(),
+ megaco_codec_test_lib:display_text_messages(?VERSION, Msgs).
+
+
+generate_text_messages() ->
+ Msgs =
+ msgs4() ++
+ msgs5(),
+ megaco_codec_test_lib:generate_text_messages(?V2, ?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg51a)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg51b)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg52)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg53)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg54a)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg58a)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg58b)).
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_message(msg61a)).
+profile_decode_compact_text_message(MsgTag) ->
+ Codec = megaco_compact_text_encoder,
+ Config = [],
+ profile_decode_text_message(Codec, Config, MsgTag).
+
+%% (catch megaco_codec_v2_test:profile_decode_pretty_text_message(msg51a)).
+%% (catch megaco_codec_v2_test:profile_decode_pretty_text_message(msg51b)).
+%% (catch megaco_codec_v2_test:profile_decode_pretty_text_message(msg52)).
+profile_decode_pretty_text_message(MsgTag) ->
+ Codec = megaco_pretty_text_encoder,
+ Config = [],
+ profile_decode_text_message(Codec, Config, MsgTag).
+
+profile_decode_text_message(Codec, Config, MsgTag) ->
+ Msgs = msgs4() ++ msgs5(),
+ case lists:keysearch(MsgTag, 1, Msgs) of
+ {value, Msg} ->
+ profile_decode_text_messages(Codec, Config, [Msg]);
+ false ->
+ {error, {no_such_message, MsgTag}}
+ end.
+
+
+%% (catch megaco_codec_v2_test:profile_decode_compact_text_messages()).
+profile_decode_compact_text_messages() ->
+ Config = [],
+ Slogan = decode_compact_v2,
+ profile_decode_compact_text_messages(Slogan, Config).
+
+%% (catch megaco_codec_v2_test:profile_decode_compact_flex_text_messages()).
+profile_decode_compact_flex_text_messages() ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = decode_compact_flex_v2,
+ Res = profile_decode_compact_text_messages(Slogan, [Config]),
+ flex_finish(Conf),
+ Res.
+
+profile_decode_compact_text_messages(Slogan, Config) ->
+ Codec = megaco_compact_text_encoder,
+ profile_decode_text_messages(Slogan, Codec, Config).
+
+%% (catch megaco_codec_v2_test:profile_decode_pretty_text_messages()).
+profile_decode_pretty_text_messages() ->
+ Config = [],
+ Slogan = decode_pretty_v2,
+ profile_decode_pretty_text_messages(Slogan, Config).
+
+%% (catch megaco_codec_v2_test:profile_decode_pretty_flex_text_messages()).
+profile_decode_pretty_flex_text_messages() ->
+ Conf = flex_init([]),
+ Config = flex_scanner_conf(Conf),
+ Slogan = decode_pretty_flex_v2,
+ Res = profile_decode_pretty_text_messages(Slogan, [Config]),
+ flex_finish(Conf),
+ Res.
+
+profile_decode_pretty_text_messages(Slogan, Config) ->
+ Codec = megaco_pretty_text_encoder,
+ profile_decode_text_messages(Slogan, Codec, Config).
+
+profile_decode_text_messages(Slogan, Codec, Config) ->
+ Msgs = msgs4() ++ msgs5(),
+ profile_decode_text_messages(Slogan, Codec, Config, Msgs).
+
+profile_decode_text_messages(Slogan, Codec, Config, Msgs0) ->
+ Msgs = [Msg || {_, Msg, _, _} <- Msgs0],
+ EncodeRes = encode_text_messages(Codec, Config, Msgs, []),
+ Bins = [Bin || {ok, Bin} <- EncodeRes],
+ Fun = fun() ->
+ decode_text_messages(Codec, Config, Bins, [])
+ end,
+ %% Make a dry run, just to make sure all modules are loaded:
+ io:format("make a dry run..~n", []),
+ (catch Fun()),
+ io:format("make the run..~n", []),
+ megaco_profile:profile(Slogan, Fun).
+
+%% (catch megaco_codec_v2_test:profile_encode_compact_text_messages()).
+profile_encode_compact_text_messages() ->
+ Codec = megaco_compact_text_encoder,
+ Config = [],
+ Slogan = encode_compact_v2,
+ profile_encode_text_messages(Slogan, Codec, Config).
+
+%% (catch megaco_codec_v2_test:profile_encode_pretty_text_messages()).
+profile_encode_pretty_text_messages() ->
+ Codec = megaco_pretty_text_encoder,
+ Config = [],
+ Slogan = encode_pretty_v2,
+ profile_encode_text_messages(Slogan, Codec, Config).
+
+profile_encode_text_messages(Slogan, Codec, Config) ->
+ Msgs = msgs4() ++ msgs5(),
+ profile_encode_text_messages(Slogan, Codec, Config, Msgs).
+
+profile_encode_text_messages(Slogan, Codec, Config, Msgs0) ->
+ Msgs = [Msg || {_, Msg, _, _} <- Msgs0],
+ Fun = fun() ->
+ encode_text_messages(Codec, Config, Msgs, [])
+ end,
+ %% Make a dry run, just to make sure all modules are loaded:
+ io:format("make a dry run...~n", []),
+ (catch Fun()),
+ io:format("make the run...~n", []),
+ megaco_profile:profile(Slogan, Fun).
+
+encode_text_messages(_Codec, _Config, [], Acc) ->
+ Acc;
+encode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
+ Res = Codec:encode_message(Config, ?VERSION, Msg),
+ encode_text_messages(Codec, Config, Msgs, [Res | Acc]).
+
+decode_text_messages(_Codec, _Config, [], Acc) ->
+ Acc;
+decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
+ Res = Codec:decode_message(Config, dynamic, Msg),
+ decode_text_messages(Codec, Config, Msgs, [Res | Acc]).
+
+
+%% ----
+
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ pretty_tickets,
+ flex_compact_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4299_msg2,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5290_msg01,
+ compact_otp5290_msg02,
+ compact_otp5793_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03,
+ compact_otp7138_msg01,
+ compact_otp7138_msg02,
+ compact_otp7457_msg01,
+ compact_otp7457_msg02,
+ compact_otp7457_msg03,
+ compact_otp7534_msg01,
+ compact_otp7576_msg01,
+ compact_otp7671_msg01
+ ].
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7138_msg01,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7457_msg01,
+ flex_compact_otp7457_msg02,
+ flex_compact_otp7457_msg03,
+ flex_compact_otp7534_msg01,
+ flex_compact_otp7573_msg01,
+ flex_compact_otp7576_msg01
+ ].
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7249_msg01,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05
+ ].
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4() ++ msgs5(),
+ %% Msgs = msgs5(),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4(),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [Conf], Msgs).
+
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_pretty_text_encoder, false, [Conf], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("flex_pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("flex_pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1(), [Conf]).
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(error, pretty_otp5085_msg2(), [Conf]).
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3(), [Conf]).
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4(), [Conf]).
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5(), [Conf]).
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6(), [Conf]).
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7(), [Conf]).
+
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg1(), [Conf]).
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5600(ok, pretty_otp5600_msg2(), [Conf]).
+
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5601(ok, pretty_otp5601_msg1(), [Conf]).
+
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ pretty_otp5793(ok, pretty_otp5793_msg1(), [Conf]).
+
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf) ->
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []);
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg2() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg3() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg4() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a}
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg5() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg6() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg7() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v}
+ }
+ }
+ }
+ }
+ }".
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4(),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4(),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,3}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({2,3,4}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,31}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({10,21,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({99,23,11}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers7(suite) ->
+ [];
+flex_compact_dm_timers7(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers7 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers8(suite) ->
+ [];
+flex_compact_dm_timers8(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("01", "09", "01", "02"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false, [Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers8 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,9,1,2}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s", [T, S, L])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(T, S, L, Z) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s,Z:~s", [T, S, L,Z])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(TMRs) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [TMRs]),
+ lists:flatten(M).
+
+
+verify_dm_timers(TMRs, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ {error, Reason} ->
+ exit({invalid_timer, {TMRs, Reason}});
+ TMRs ->
+ ok;
+ TMRs1 ->
+ exit({invalid_timer_values, {TMRs, TMRs1}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts])
+ when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = asn1_NOVALUE} ->
+ {ok, {T, S, L}};
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = Z} ->
+ {ok, {T, S, L, Z}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs4(),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs4(),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs4(),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs4(),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs4(),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, [], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4(),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+% put(severity,trc),
+% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+% erase(severity),
+% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+% put(severity,trc),
+% put(dbg,true),
+ ok = compact_otp4011(M).
+
+
+compact_otp4011(M) ->
+ d("compact_otp4011 -> entry with"
+ "~n M: '~s'", [M]),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ d("compact_otp4011 -> expected error result (so far)", []),
+ case lists:keysearch(reason,1,Error) of
+ {value, {reason,Reason}} ->
+ d("compact_otp4011 -> expected error: "
+ "~n Reason: ~p", [Reason]),
+ case Reason of
+ {0, megaco_text_parser_v2,
+ {do_merge_control_streamParms, [A,B]}}
+ when is_list(A) andalso is_record(B, 'LocalControlDescriptor') ->
+ case lists:keysearch(mode,1,A) of
+ {value, {mode, Mode}}
+ when B#'LocalControlDescriptor'.streamMode /= asn1_NOVALUE ->
+ d("compact_otp4011 -> "
+ "expected error [~w]",[Mode]),
+ ok;
+ Other ->
+ exit({unexpected_mode_reason, {A,B,Other}})
+ end;
+ Other ->
+ exit({unexpected_reason, Other})
+ end;
+
+ false ->
+ d("compact_otp4011 -> OUPS, wrong kind of error", []),
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ d("compact_otp4011 -> unexpected decode result: ~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/2 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _} ->
+ exit({decoded_erroneous_message,M});
+ {error, Reason} when is_list(Reason) ->
+ {value, {reason, no_version_found, _}} =
+ lists:keysearch(reason, 1, Reason),
+ {value, {token, [{'SafeChars',_,"megcao/2"}|_]}} =
+ lists:keysearch(token, 1, Reason),
+ ok;
+ Else ->
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, M} ->
+ exit({decoded_erroneous_message,M});
+ {error, Error} when is_list(Error) -> % Expected result
+ t("compact_otp4085_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{999999, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> THE ACTUAL ERROR: "
+ "~n LINE NUMBER: 999999"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Module, Crap]),
+ %% ok;
+ exit({decode_failed_999999, Module, Crap});
+ {value, {reason,{Line, Module, Crap}}} ->
+ t("compact_otp4085_msg1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap: ~p", [Line, Module, Crap]),
+ ok;
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M1 = compact_otp4085_erroneous_msg() ++ "}",
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, M2} ->
+ l("compact_otp4085_msg1 -> successfull decode"
+ "~n M2: ~p", [M2]),
+ ok;
+ Else ->
+ e("compact_otp4085_msg1 -> decode error"
+ "~n Else: ~p", [Else]),
+ exit({unexpected_decode_result,Else})
+ end.
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4280_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _Msg} ->
+ ok;
+ {error, Error} when is_list(Error) ->
+ t("compact_otp4280_msg1 -> decode failed", []),
+ case lists:keysearch(reason, 1, Error) of
+ {value, {reason,{Line, Module, Reason} = R}} ->
+ t("compact_otp4280_msg1 -> "
+ "~n Line: ~w"
+ "~n Module: ~w"
+ "~n Reason: ~w", [Line, Module, Reason]),
+ exit({decode_failed, R});
+ false ->
+ exit({unexpected_result, Error})
+ end;
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4299_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+%% Same message, but this time decoded using the flex scanner
+compact_otp4299_msg2(suite) ->
+ [];
+compact_otp4299_msg2(Config) when is_list(Config) ->
+ d("compact_otp4299_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+
+ {Pid, Conf} = compact_otp4299_msg2_init(),
+
+ Bin = list_to_binary(compact_otp4299_msg()),
+ Res = decode_message(megaco_compact_text_encoder, false, [Conf], Bin),
+ compact_otp4299_msg2_finish(Pid),
+
+ case Res of
+ {ok, _Msg} ->
+ ok;
+
+ {error, Reason} ->
+ exit({decode_error, Reason});
+
+ Else ->
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+compact_otp4299_msg2_init() ->
+ Flag = process_flag(trap_exit, true),
+ Res = (catch start_flex_scanner()),
+ process_flag(trap_exit, Flag),
+ case Res of
+ {error, Reason} ->
+ skip(Reason);
+ {ok, FlexConfig} ->
+ FlexConfig
+ end.
+
+compact_otp4299_msg2_finish(Pid) ->
+ stop_flex_scanner(Pid).
+
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/"
+ ?VERSION_STR
+ " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Bin = list_to_binary(compact_otp4359_msg()),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, #'MegacoMessage'{mess = Mess}} ->
+ {transactions, Trans} = Mess#'Message'.messageBody,
+ case Trans of
+ [{transactionRequest,#'TransactionRequest'{transactionId = asn1_NOVALUE}}] ->
+ ok;
+ _ ->
+ exit({unexpected_transactions, Trans})
+ end;
+ Else ->
+ t("compact_otp4359_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg0(), true).
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg1(), false).
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg2(), false).
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg3(), true).
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg4(), true).
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg5(), true).
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg6(), true).
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg7(), true).
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ % put(dbg,true),
+ compact_otp4920_msg_1(compact_otp4920_msg8(), false).
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg9(), false).
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg10(), false).
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg11(), false).
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_1(compact_otp4920_msg12(), true).
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg20(), bad_mid_duplicate_padding).
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg21(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg22(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg23(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg24(), bad_mid_ip6addr_length).
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp4920_msg_2(compact_otp4920_msg25(), bad_mid_ip6addr_length).
+
+compact_otp4920_msg_1(M1, CheckEqual) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin1) of
+ {ok, Msg} ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, [], Msg) of
+ {ok, Bin1} ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when is_binary(Bin2) andalso (CheckEqual =:= true) ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, M1, M2});
+ {ok, _} ->
+ io:format(", encoded:", []),
+ ok;
+ Else ->
+ io:format(", encode failed:", []),
+ exit({unexpected_encode_result, Else})
+ end;
+ Else ->
+ io:format("decode failed:", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp4920_msg_2(M1, ExpectedReason) ->
+ Bin = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg} ->
+ io:format("unexpected successfull decode", []),
+ exit({unexpected_encode_ok, Msg});
+ {error, [{reason, {__Line, _Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ {error, [{reason, {_Mod, Reason}}|_]} ->
+ case element(1, Reason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ exit({unexpected_decode_error_reason,
+ ExpectedReason, Reason})
+ end;
+ Else ->
+ io:format("unexpected decode result", []),
+ exit({unexpected_decode_result, Else})
+
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg01(), error, ignore).
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_1(compact_otp5186_msg02(), ok, ok).
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok).
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok).
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok).
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok).
+
+compact_otp5186_msg_1(M1, DecodeExpect, EncodeExpect) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin1) of
+ {ok, Msg} when DecodeExpect == ok ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, [], Msg) of
+ {ok, Bin1} when EncodeExpect == ok ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when EncodeExpect == ok ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, Msg, M1, M2});
+ {ok, Bin3} when EncodeExpect == error ->
+ M3 = binary_to_list(Bin3),
+ io:format(", unexpected encode:", []),
+ exit({unexpected_encode_success, Msg, M1, M3});
+ _Else when EncodeExpect == error ->
+ io:format(", encode failed ", []),
+ ok
+ end;
+ {ok, Msg} when DecodeExpect == error ->
+ io:format(" decoded", []),
+ exit({unexpected_decode_success, Msg});
+ _Else when DecodeExpect == error ->
+ io:format(" decode failed ", []),
+ ok;
+ Else when DecodeExpect == ok ->
+ io:format(" decode failed ", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp5186_msg_2(Msg1, EncodeExpect, DecodeExpect) ->
+ case encode_message(megaco_compact_text_encoder, [], Msg1) of
+ {ok, Bin} when EncodeExpect == ok ->
+ io:format(" encoded", []),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg1} when DecodeExpect == ok ->
+ io:format(", decoded - equal:", []),
+ ok;
+ {ok, Msg2} when DecodeExpect == ok ->
+ M = binary_to_list(Bin),
+ case (catch compact_otp5186_check_megamsg(Msg1, Msg2)) of
+ ok ->
+ io:format(", decoded - not equal - ok:", []),
+ ok;
+ {'EXIT', Reason} ->
+ io:format(", decoded - not equal:", []),
+ exit({messages_not_equal, M, Reason, Msg1, Msg2})
+ end;
+ {ok, Msg3} when DecodeExpect == error ->
+ M = binary_to_list(Bin),
+ io:format(", decoded:", []),
+ exit({unexpected_decode_success, M, Msg1, Msg3});
+ Else when DecodeExpect == ok ->
+ M = binary_to_list(Bin),
+ io:format(", decode failed ", []),
+ exit({unexpected_decode_success, Msg1, M, Else});
+ _Else when DecodeExpect == error ->
+ io:format(", decode failed ", []),
+ ok
+ end;
+ {ok, Bin} when EncodeExpect == error ->
+ M = binary_to_list(Bin),
+ io:format(" encoded", []),
+ exit({unexpected_encode_success, Msg1, M});
+ _Else when EncodeExpect == error ->
+ io:format(" encode failed ", []),
+ ok;
+ Else when EncodeExpect == ok ->
+ io:format(" encode failed ", []),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/2 <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/2 <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',2,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',2,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+%% --
+
+compact_otp5186_check_megamsg(M1, M1) ->
+ ok;
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH,
+ mess = M1},
+ #'MegacoMessage'{authHeader = AH,
+ mess = M2}) ->
+ compact_otp5186_check_mess(M1, M2);
+compact_otp5186_check_megamsg(#'MegacoMessage'{authHeader = AH1},
+ #'MegacoMessage'{authHeader = AH2}) ->
+ exit({not_equal, authHeader, AH1, AH2}).
+
+compact_otp5186_check_mess(M, M) ->
+ ok;
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId,
+ messageBody = B1},
+ #'Message'{version = V,
+ mId = MId,
+ messageBody = B2}) ->
+ compact_otp5186_check_body(B1, B2);
+compact_otp5186_check_mess(#'Message'{version = V,
+ mId = MId1},
+ #'Message'{version = V,
+ mId = MId2}) ->
+ exit({not_equal, mId, MId1, MId2});
+compact_otp5186_check_mess(#'Message'{version = V1,
+ mId = MId},
+ #'Message'{version = V2,
+ mId = MId}) ->
+ exit({not_equal, version, V1, V2}).
+
+compact_otp5186_check_body(B, B) ->
+ ok;
+compact_otp5186_check_body({transactions, T1}, {transactions, T2}) ->
+ compact_otp5186_check_trans(T1, T2);
+compact_otp5186_check_body({messageError, E1}, {messageError, E2}) ->
+ compact_otp5186_check_merr(E1, E2);
+compact_otp5186_check_body(B1, B2) ->
+ exit({not_equal, messageBody, B1, B2}).
+
+compact_otp5186_check_trans([], []) ->
+ ok;
+compact_otp5186_check_trans([], T2) ->
+ exit({not_equal, transactions, [], T2});
+compact_otp5186_check_trans(T1, []) ->
+ exit({not_equal, transactions, T1, []});
+compact_otp5186_check_trans([Tran1|Trans1], [Tran2|Trans2]) ->
+ compact_otp5186_check_trans(Trans1, Trans2),
+ compact_otp5186_check_transaction(Tran1, Tran2).
+
+compact_otp5186_check_merr(ME, ME) ->
+ ok;
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC,
+ errorText = ET1},
+ #'ErrorDescriptor'{errorCode = EC,
+ errorText = ET2}) ->
+ exit({not_equal, errorText, ET1, ET2});
+compact_otp5186_check_merr(#'ErrorDescriptor'{errorCode = EC1,
+ errorText = ET},
+ #'ErrorDescriptor'{errorCode = EC2,
+ errorText = ET}) ->
+ exit({not_equal, errorCode, EC1, EC2}).
+
+compact_otp5186_check_transaction(T, T) ->
+ ok;
+compact_otp5186_check_transaction({transactionReply, TR1},
+ {transactionReply, TR2}) ->
+ compact_otp5186_check_transRep(TR1, TR2);
+compact_otp5186_check_transaction(T1, T2) ->
+ exit({unexpected_transactions, T1, T2}).
+
+compact_otp5186_check_transRep(T, T) ->
+ ok;
+compact_otp5186_check_transRep(#'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TId,
+ immAckRequired = IAR,
+ transactionResult = TR2}) ->
+ compact_otp5186_check_transRes(TR1, TR2);
+compact_otp5186_check_transRep(T1, T2) ->
+ exit({unexpected_transaction_reply, T1, T2}).
+
+compact_otp5186_check_transRes(TR, TR) ->
+ ok;
+compact_otp5186_check_transRes({actionReplies, AR1},
+ {actionReplies, AR2}) ->
+ compact_otp5186_check_actReps(AR1, AR2);
+compact_otp5186_check_transRes(TR1, TR2) ->
+ exit({unexpected_transaction_result, TR1, TR2}).
+
+compact_otp5186_check_actReps([], []) ->
+ ok;
+compact_otp5186_check_actReps(AR1, []) ->
+ exit({not_equal, actionReplies, AR1, []});
+compact_otp5186_check_actReps([], AR2) ->
+ exit({not_equal, actionReplies, [], AR2});
+compact_otp5186_check_actReps([AR1|ARs1], [AR2|ARs2]) ->
+ compact_otp5186_check_actRep(AR1, AR2),
+ compact_otp5186_check_actReps(ARs1, ARs2).
+
+compact_otp5186_check_actRep(AR, AR) ->
+ ok;
+compact_otp5186_check_actRep(#'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = ID,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep2}) ->
+ compact_otp5186_check_cmdReps(CmdRep1, CmdRep2);
+compact_otp5186_check_actRep(AR1, AR2) ->
+ exit({unexpected_actionReply, AR1, AR2}).
+
+compact_otp5186_check_cmdReps([], []) ->
+ ok;
+compact_otp5186_check_cmdReps(CR1, []) ->
+ exit({not_equal, commandReplies, CR1, []});
+compact_otp5186_check_cmdReps([], CR2) ->
+ exit({not_equal, commandReplies, [], CR2});
+compact_otp5186_check_cmdReps([CR1|CRs1], [CR2|CRs2]) ->
+ compact_otp5186_check_cmdRep(CR1, CR2),
+ compact_otp5186_check_cmdReps(CRs1, CRs2).
+
+compact_otp5186_check_cmdRep(CR, CR) ->
+ ok;
+compact_otp5186_check_cmdRep({auditValueReply, AVR1},
+ {auditValueReply, AVR2}) ->
+ compact_otp5186_check_auditReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep({addReply, AVR1},
+ {addReply, AVR2}) ->
+ compact_otp5186_check_ammsReply(AVR1, AVR2);
+compact_otp5186_check_cmdRep(CR1, CR2) ->
+ exit({unexpected_commandReply, CR1, CR2}).
+
+compact_otp5186_check_auditReply(AR, AR) ->
+ ok;
+compact_otp5186_check_auditReply({auditResult, AR1},
+ {auditResult, AR2}) ->
+ compact_otp5186_check_auditRes(AR1, AR2);
+compact_otp5186_check_auditReply(AR1, AR2) ->
+ exit({unexpected_auditReply, AR1, AR2}).
+
+compact_otp5186_check_ammsReply(AR, AR) ->
+ ok;
+compact_otp5186_check_ammsReply(#'AmmsReply'{terminationID = ID,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = ID,
+ terminationAudit = TA2}) ->
+ %% This is just to simplify the test
+ F = fun(asn1_NOVALUE) -> [];
+ (E) -> E
+ end,
+ compact_otp5186_check_termAudit(F(TA1), F(TA2));
+compact_otp5186_check_ammsReply(AR1, AR2) ->
+ exit({unexpected_ammsReply, AR1, AR2}).
+
+compact_otp5186_check_auditRes(AR, AR) ->
+ ok;
+compact_otp5186_check_auditRes(#'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = ID,
+ terminationAuditResult = TAR2}) ->
+ compact_otp5186_check_termAuditRes(TAR1, TAR2);
+compact_otp5186_check_auditRes(AR1, AR2) ->
+ exit({unexpected_auditResult, AR1, AR2}).
+
+compact_otp5186_check_termAuditRes([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAuditRes(TAR1, []);
+compact_otp5186_check_termAuditRes(TAR1, []) ->
+ exit({not_equal, termAuditRes, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAuditRes([], [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAuditRes([], TAR2);
+compact_otp5186_check_termAuditRes([], TAR2) ->
+ exit({not_equal, termAuditRes, [], TAR2});
+compact_otp5186_check_termAuditRes([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAuditRes(TAR1, TAR2).
+
+compact_otp5186_check_termAudit([], []) ->
+ ok;
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR1], []) ->
+ compact_otp5186_check_termAudit(TAR1, []);
+compact_otp5186_check_termAudit(TAR1, []) ->
+ exit({not_equal, termAudit, TAR1, []});
+%% An empty empty descriptor is removed
+compact_otp5186_check_termAudit([],
+ [{emptyDescriptors,
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE}}|TAR2]) ->
+ compact_otp5186_check_termAudit([], TAR2);
+compact_otp5186_check_termAudit([], TAR2) ->
+ exit({not_equal, termAudit, [], TAR2});
+compact_otp5186_check_termAudit([ARP1|TAR1], [ARP2|TAR2]) ->
+ compact_otp5186_check_auditRetParm(ARP1, ARP2),
+ compact_otp5186_check_termAudit(TAR1, TAR2).
+
+compact_otp5186_check_auditRetParm(ARP, ARP) ->
+ ok;
+compact_otp5186_check_auditRetParm({emptyDescriptors, AD1},
+ {emptyDescriptors, AD2}) ->
+ compact_otp5186_check_auditDesc(AD1, AD2);
+compact_otp5186_check_auditRetParm(ARP1, ARP2) ->
+ exit({unexpected_auditRetParm, ARP1, ARP2}).
+
+compact_otp5186_check_auditDesc(AD, AD) ->
+ ok;
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = L1,
+ auditPropertyToken = asn1_NOVALUE},
+ #'AuditDescriptor'{auditToken = L2,
+ auditPropertyToken = asn1_NOVALUE}) ->
+ compact_otp5186_check_auditDesc_auditItems(L1, L2);
+compact_otp5186_check_auditDesc(#'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = APT2}) ->
+ compact_otp5186_check_auditDesc_apt(APT1, APT2);
+compact_otp5186_check_auditDesc(AD1, AD2) ->
+ exit({unexpected_auditDesc, AD1, AD2}).
+
+compact_otp5186_check_auditDesc_auditItems([], []) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItems(AI1, []) ->
+ exit({not_equal, auditItems, AI1, []});
+compact_otp5186_check_auditDesc_auditItems([], AI2) ->
+ exit({not_equal, auditItems, [], AI2});
+compact_otp5186_check_auditDesc_auditItems([AI1|AIs1], [AI2|AIs2]) ->
+ compact_otp5186_check_auditDesc_auditItem(AI1, AI2),
+ compact_otp5186_check_auditDesc_auditItems(AIs1, AIs2).
+
+compact_otp5186_check_auditDesc_auditItem(AI, AI) ->
+ ok;
+compact_otp5186_check_auditDesc_auditItem(AI1, AI2) ->
+ exit({not_equal, auditItem, AI1, AI2}).
+
+compact_otp5186_check_auditDesc_apt(APT, APT) ->
+ ok;
+compact_otp5186_check_auditDesc_apt(APT1, APT2) ->
+ exit({not_equal, auditPropertyToken, APT1, APT2}).
+
+
+
+%% --------------------------------------------------------------
+
+compact_otp5290_msg01(suite) ->
+ [];
+compact_otp5290_msg01(Config) when is_list(Config) ->
+ d("compact_otp5290_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5290_msg_1(compact_otp5290_msg01(), ok, ok).
+
+compact_otp5290_msg02(suite) ->
+ [];
+compact_otp5290_msg02(Config) when is_list(Config) ->
+ d("compact_otp5290_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5290_msg_1(compact_otp5290_msg02(), error, ignore).
+
+compact_otp5290_msg_1(M1, DecodeExpect, EncodeExpect) ->
+ Bin1 = list_to_binary(M1),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin1) of
+ {ok, Msg} when DecodeExpect == ok ->
+ io:format(" decoded", []),
+ case encode_message(megaco_compact_text_encoder, [], Msg) of
+ {ok, Bin1} when EncodeExpect == ok ->
+ io:format(", encoded - equal:", []),
+ ok;
+ {ok, Bin2} when EncodeExpect == ok ->
+ M2 = binary_to_list(Bin2),
+ io:format(", encoded - not equal:", []),
+ exit({messages_not_equal, Msg, M1, M2});
+ {ok, Bin3} when EncodeExpect == error ->
+ M3 = binary_to_list(Bin3),
+ io:format(", unexpected encode:", []),
+ exit({unexpected_encode_success, Msg, M3});
+ _ when EncodeExpect == error ->
+ io:format(", encode failed ", []),
+ ok
+ end;
+ {ok, Msg} when DecodeExpect == error ->
+ io:format(" decoded", []),
+ exit({unexpected_decode_success, Msg});
+ _Else when DecodeExpect == error ->
+ io:format(" decode failed ", []),
+ ok;
+ Else when DecodeExpect == ok ->
+ io:format(" decode failed ", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+compact_otp5290_msg01() ->
+ "!/" ?VERSION_STR " <ml>\nT=12345678{C=*{CA{TP,PR}}}".
+
+compact_otp5290_msg02() ->
+ "!/" ?VERSION_STR " <ml>\nT=12345678{C=*{CA{TP,PR,TP}}}".
+
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5793(ok, pretty_otp5793_msg1()).
+
+compact_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_compact_text_encoder, Msg, []).
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg01()).
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg02()).
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ compact_otp5993(ok, compact_otp5993_msg03()).
+
+compact_otp5993(Expected, Msg) ->
+ expect_codec(Expected, megaco_compact_text_encoder, Msg, []).
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ ok.
+
+compact_otp6017(BadCID) ->
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, [], Bin) of
+ {ok, Msg} ->
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ exit({unexpected_reason, ActualReason});
+ false ->
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ exit({unexpected_decode_result, Crap})
+ end.
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "MEGACO/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% --------------------------------------------------------------
+
+compact_otp7138_msg01(suite) ->
+ [];
+compact_otp7138_msg01(Config) when is_list(Config) ->
+%% put(dbg, true),
+%% put(severity, trc),
+ d("compact_otp7138_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7138_msg01(),
+ EC = [],
+ ok = compact_otp7138(EC, Msg),
+ ok.
+
+compact_otp7138_msg02(suite) ->
+ [];
+compact_otp7138_msg02(Config) when is_list(Config) ->
+%% put(dbg, true),
+%% put(severity, trc),
+ d("compact_otp7138_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7138_msg02(),
+ EC = [],
+ ok = compact_otp7138(EC, Msg),
+ ok.
+
+compact_otp7138_msg01() ->
+ <<"!/2 <gw>\nT=1111{C=1{N=mgw2dev1/1{OE=16777985{ctyp/dtone{dtt=CT}}}}}">>.
+
+compact_otp7138_msg02() ->
+ <<"!/2 <gw>\nT=1111{C=1{N=mgw2dev1/1{OE=16777985{ctyp/dtone{dtt=\"CT\"}}}}}">>.
+
+compact_otp7138(EC, BinMsg) ->
+ d("compact_otp7138 -> "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ Codec = megaco_compact_text_encoder,
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, Msg} ->
+ case encode_message(Codec, EC, Msg) of
+ {ok, BinMsg} ->
+ d("compact_otp7138 -> encode successfull: "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ ok;
+ {ok, BinMsg2} ->
+ d("compact_otp7138 -> encode successfull but result differ: "
+ "~n ~p", [binary_to_list(BinMsg2)]),
+ ok;
+ {error, Reason} ->
+ e("encode failed: ~p", [Reason]),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ e("decode failed: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+
+compact_otp7457_msg01(suite) ->
+ [];
+compact_otp7457_msg01(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("compact_otp7457_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7457_msg01(),
+ EC = [],
+ ok = compact_otp7457(EC, Msg),
+ ok.
+
+compact_otp7457_msg02(suite) ->
+ [];
+compact_otp7457_msg02(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("compact_otp7457_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7457_msg02(),
+ EC = [],
+ ok = compact_otp7457(EC, Msg),
+ ok.
+
+compact_otp7457_msg03(suite) ->
+ [];
+compact_otp7457_msg03(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("compact_otp7457_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7457_msg03(),
+ EC = [],
+ ok = compact_otp7457(EC, Msg),
+ ok.
+
+compact_otp7457_msg01() ->
+ <<"!/2 <mg1>\nT=15{C=-{SC=tdm12/1/1/*{SV{MT=RS,RE=900}}}}\n">>.
+
+compact_otp7457_msg02() ->
+ <<"!/2 <mg1>\nT=15{C=-{O-SC=tdm12/1/1/*{SV{MT=RS,RE=900}}}}\n">>.
+
+compact_otp7457_msg03() ->
+ <<"!/2 <mg1>\nT=15{C=-{W-SC=tdm12/1/1/*{SV{MT=RS,RE=900}}}}\n">>.
+
+compact_otp7457(EC, BinMsg) ->
+ d("compact_otp7457 -> "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ Codec = megaco_compact_text_encoder,
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, Msg} ->
+ case encode_message(Codec, EC, Msg) of
+ {ok, BinMsg} ->
+ d("compact_otp7457 -> encode successfull: "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ ok;
+ {ok, BinMsg2} ->
+ d("compact_otp7457 -> "
+ "encode successfull but result differ: "
+ "~n ~p", [binary_to_list(BinMsg2)]),
+ ok;
+ {error, Reason} ->
+ e("encode failed: ~p", [Reason]),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ e("decode failed: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+compact_otp7534_msg01(suite) ->
+ [];
+compact_otp7534_msg01(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("compact_otp7534_msg01 -> entry", []),
+ Msg = otp7534_msg01(),
+ compact_otp7534([], Msg).
+
+
+compact_otp7576_msg01(suite) ->
+ [];
+compact_otp7576_msg01(Config) when is_list(Config) ->
+%% put(dbg, true),
+%% put(severity, trc),
+ d("compact_otp7576_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp7576_msg01(),
+ EC = [],
+ ok = compact_otp7576(EC, Msg),
+ ok.
+
+compact_otp7576_msg01() ->
+ M = "!/"
+ ?VERSION_STR
+ "[130.100.144.37]:2944\nT=10032{C=${tp{*,*,is,st=1},pr=6,a=rtp/2/${m{st=1{o{mo=so,rv=ON},l{
+v=0
+c=IN IP4 $
+m=audio $ RTP/AVP 0
+b=AS:64
+a=rtpmap:0 PCMU/8000
+}}},e=1{G/CAUSE}},a=rtp/2/${m{st=1{o{mo=rc,rv=ON},l{
+v=0
+c=IN IP4 $
+m=audio $ RTP/AVP 0
+b=AS:64
+a=rtpmap:0 PCMU/8000
+},r{
+v=0
+c=IN IP4 130.100.126.77
+m=audio 8014 RTP/AVP 0
+b=AS:64
+a=rtpmap:0 PCMU/8000
+}}},e=1{G/CAUSE}}}}",
+ list_to_binary(M).
+
+compact_otp7576(EC, BinMsg) ->
+ d("compact_otp7576 -> "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ Codec = megaco_compact_text_encoder,
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, Msg} ->
+ case encode_message(Codec, EC, Msg) of
+ {ok, BinMsg} ->
+ d("compact_otp7138 -> encode successfull: "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ ok;
+ {ok, BinMsg2} ->
+ d("compact_otp7138 -> encode successfull but result differ: "
+ "~n ~p", [binary_to_list(BinMsg2)]),
+ case decode_message(Codec, false, EC, BinMsg2) of
+ {ok, Msg} ->
+ d("compact_otp7138 -> "
+ "extra verification decode ok", []),
+ ok;
+ {ok, Msg2} ->
+ e("verification decode generated other message: "
+ "~n Msg: ~p"
+ "~n Msg2: ~p", [Msg, Msg2]),
+ {error, {verification_decode, Msg, Msg2}}
+ end;
+ {error, Reason} ->
+ e("encode failed: ~p", [Reason]),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ e("decode failed: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+
+%% --------------------------------------------------------------
+%%
+
+compact_otp7671_msg01(suite) ->
+ [];
+compact_otp7671_msg01(Config) when is_list(Config) ->
+ put(severity, trc),
+ put(dbg, true),
+ d("compact_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp7671( compact_otp7671_msg01(), [] ),
+ erase(dbg),
+ erase(severity),
+ ok.
+
+compact_otp7671(Msg, Conf) ->
+ compact_otp7671(Msg, Conf, ok).
+
+compact_otp7671(Msg, Conf, ExpectedEncode) ->
+ compact_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+compact_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_compact_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+%% "!/" ?VERSION_STR " <ml>\nT=172047781{C=-{MF=root{DM=DmName}}}",
+compact_otp7671_msg01() ->
+ pretty_otp7671_msg01().
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+flex_compact_otp7138_msg01(suite) ->
+ [];
+flex_compact_otp7138_msg01(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp7138_msg01 -> entry", []),
+ Msg = compact_otp7138_msg01(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7138([Conf], Msg).
+
+flex_compact_otp7138_msg02(suite) ->
+ [];
+flex_compact_otp7138_msg02(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp7138_msg02 -> entry", []),
+ Msg = compact_otp7138_msg02(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7138([Conf], Msg).
+
+
+flex_compact_otp7431_msg01(suite) ->
+ [];
+flex_compact_otp7431_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+flex_compact_otp7457_msg01(suite) ->
+ [];
+flex_compact_otp7457_msg01(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("flex_compact_otp7457_msg01 -> entry", []),
+ Msg = compact_otp7457_msg01(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7457([Conf], Msg).
+
+flex_compact_otp7457_msg02(suite) ->
+ [];
+flex_compact_otp7457_msg02(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("flex_compact_otp7457_msg02 -> entry", []),
+ Msg = compact_otp7457_msg02(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7457([Conf], Msg).
+
+flex_compact_otp7457_msg03(suite) ->
+ [];
+flex_compact_otp7457_msg03(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("flex_compact_otp7457_msg03 -> entry", []),
+ Msg = compact_otp7457_msg03(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7457([Conf], Msg).
+
+flex_compact_otp7534_msg01(suite) ->
+ [];
+flex_compact_otp7534_msg01(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("flex_compact_otp7534_msg01 -> entry", []),
+ Msg = otp7534_msg01(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7534([Conf], Msg).
+
+otp7534_msg01() ->
+ <<"!/2 bgwch3_1\nP=62916991{C=-{AV=root{M{TS{ipra/ar=[interconnect,interconnect1,internal],SI=IV}},PG{root-2,ocp-1,it-1,nt-1,rtp-1,gm-1,ds-1,tman-1,xnq-1}}}}">>.
+
+compact_otp7534(EC, BinMsg) ->
+ Codec = megaco_compact_text_encoder,
+ otp7534(Codec, EC, BinMsg).
+
+otp7534(Codec, EC, BinMsg) ->
+ d("otp7534 -> "
+ "~n Codec: ~p"
+ "~n ~p", [Codec, binary_to_list(BinMsg)]),
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, Msg} ->
+ case encode_message(Codec, EC, Msg) of
+ {ok, BinMsg} ->
+ d("otp7457 -> encode successfull: "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ ok;
+ {ok, BinMsg2} ->
+ d("otp7457 -> "
+ "encode successfull but result differ: "
+ "~n ~p", [binary_to_list(BinMsg2)]),
+ ok;
+ {error, Reason} ->
+ e("encode failed: ~p", [Reason]),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ e("decode failed: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+
+flex_compact_otp7573_msg01(suite) ->
+ [];
+flex_compact_otp7573_msg01(Config) when is_list(Config) ->
+ put(dbg, true),
+ put(severity, trc),
+ d("flex_compact_otp7573_msg01 -> entry", []),
+ Msg = otp7573_msg01(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7573([Conf], Msg).
+
+otp7573_msg01() ->
+ <<"!/2 <aa>\nP=37775561{C=-{AV=root{M{TS{root/maxnumberofcontexts=16000,root/maxterminationspercontext=2,root/normalmgexecutiontime=3000,root/normalmgcexecutiontime=3000,root/mgprovisionalresponsetimervalue=2000,root/mgcprovisionalresponsetimervalue=2000,root/mgcoriginatedpendinglimit=5,root/mgoriginatedpendinglimit=5,ipra/ar=[\"\"],SI=IV}},PG{root-2,ocp-1,it-1,nt-1,rtp-1,gm-1,ds-1,tman-1,xnq-1,ipra-1}}}}">>.
+
+compact_otp7573(EC, BinMsg) ->
+ Codec = megaco_compact_text_encoder,
+ otp7573(Codec, EC, BinMsg).
+
+otp7573(Codec, EC, BinMsg) ->
+ d("otp7573 -> "
+ "~n Codec: ~p"
+ "~n ~p", [Codec, binary_to_list(BinMsg)]),
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, Msg} ->
+ case encode_message(Codec, EC, Msg) of
+ {ok, BinMsg} ->
+ d("otp7573 -> encode successfull: "
+ "~n ~p", [binary_to_list(BinMsg)]),
+ ok;
+ {ok, BinMsg2} ->
+ d("otp7573 -> "
+ "encode successfull but result differ: "
+ "~n ~p", [binary_to_list(BinMsg2)]),
+ ok;
+ {error, Reason} ->
+ e("encode failed: ~p", [Reason]),
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ e("decode failed: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+
+flex_compact_otp7576_msg01(suite) ->
+ [];
+flex_compact_otp7576_msg01(Config) when is_list(Config) ->
+%% put(dbg, true),
+%% put(severity, trc),
+ d("flex_compact_otp7576_msg01 -> entry", []),
+ Msg = compact_otp7576_msg01(),
+ Conf = flex_scanner_conf(Config),
+ compact_otp7576([Conf], Msg).
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], BinMsg),
+ ok = chk_MegacoMessage(Msg0, Msg1);
+ Else ->
+ t("pretty_otp4632_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg2(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, BinMsg} when is_binary(BinMsg) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], BinMsg),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder,
+ false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ Msg0 = Msg1,
+ ok;
+ Else ->
+ t("pretty_otp4632_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4632_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4632_msg4_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4632_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4_chk([], []) ->
+ exit(messages_not_eq);
+pretty_otp4632_msg4_chk([], Rest1) ->
+ exit({messages_not_eq1, Rest1});
+pretty_otp4632_msg4_chk(Rest0, []) ->
+ exit({messages_not_eq0, Rest0});
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest0],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1]) ->
+ ok;
+pretty_otp4632_msg4_chk([_|Rest0], [_|Rest1]) ->
+ pretty_otp4632_msg4_chk(Rest0,Rest1).
+
+
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg0) of
+ {ok, Bin} when is_binary(Bin) ->
+ {ok, Msg1} = decode_message(megaco_pretty_text_encoder, false,
+ [], Bin),
+ ok = chk_MegacoMessage(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4710_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ {ok, Bin1} = encode_message(megaco_pretty_text_encoder, [], Msg),
+ Msg1 = binary_to_list(Bin1),
+ %% io:format("Msg1:~n~s~n", [Msg1]),
+ pretty_otp4710_msg2_chk(Msg0,Msg1);
+ Else ->
+ t("pretty_otp4710_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(Msg,Msg) ->
+ ok;
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ io:format("pretty_otp4945_msg1 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeMethod]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {missing_required_serviceChangeParm, [serviceChangeReason, serviceChangeMethod]} ->
+ ok;
+ {missing_required_serviceChangeParm, [serviceChangeMethod, serviceChangeReason]} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg4(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4945_msg4 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg5(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_serviceChangeParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg5 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4945_msg6(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_serviceChangeParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4945_msg6 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4945_msg6 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {ok, _} ->
+ ok;
+ Else ->
+ t("pretty_otp4949_msg1 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg2(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {at_most_once_servChgReplyParm, {profile, _Val1, _Val2}} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg2 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg2 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp4949_msg3(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {not_both_address_mgcid_servChgReplyParm, _Val1, _Val2} ->
+ ok;
+ Else ->
+ io:format("pretty_otp4949_msg3 -> "
+ "~n Else: ~w"
+ "~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ t("pretty_otp4949_msg3 -> "
+ "~n Else: ~w", [Else]),
+ exit({unexpected_decode_result, Else})
+ end.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg0 = pretty_otp5042_msg1(),
+ Bin0 = list_to_binary(Msg0),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin0) of
+ {error, [{reason, Reason}|_]} ->
+ case Reason of
+ {_, _Mod, {bad_timeStamp, TimeStamp}} ->
+ exit({bad_timeStamp, TimeStamp});
+ _ ->
+ io:format("pretty_otp5042_msg1 -> "
+ "~n Reason: ~w"
+ "~n", [Reason]),
+ exit({unexpected_decode_result, Reason})
+ end;
+ {ok, M} ->
+ t("pretty_otp5042_msg1 -> successfull decode:"
+ "~n~p", [M]),
+ ok
+ end.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = pretty_otp5068_msg1(),
+ case encode_message(megaco_pretty_text_encoder, [], Msg) of
+ {error, Reason} ->
+% io:format("pretty_otp5068_msg1 -> "
+% "~n Reason: ~w"
+% "~n", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} ->
+% io:format("pretty_otp5068_msg1 -> successfull encode:"
+% "~n~s~n", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, [], Bin) of
+ {ok, _} ->
+% io:format("pretty_otp5068_msg1 -> ok~n", []),
+ ok;
+ Else ->
+% io:format("pretty_otp5068_msg1 -> ~n~p~n", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ 2,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE}}]}}}]}]}}}]}}}.
+
+
+
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg1()).
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(error, pretty_otp5085_msg2()).
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg3()).
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg4()).
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg5()).
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg6()).
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ pretty_otp5085(ok, pretty_otp5085_msg7()).
+
+pretty_otp5085(Expected, Msg) ->
+ pretty_otp5085(Expected, Msg, []).
+
+pretty_otp5085(Expected, Msg, Conf) ->
+ t("pretty_otp5085 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5085 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5085 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5085 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5085 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5085 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5085 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5085 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg1()).
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5600(ok, pretty_otp5600_msg2()).
+
+pretty_otp5600(Expected, Msg) ->
+ pretty_otp5600(Expected, Msg, []).
+
+pretty_otp5600(Expected, Msg, Conf) ->
+ t("pretty_otp5600 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5600 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5600 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5600 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5600 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5600 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5600 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5600 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5601(ok, pretty_otp5601_msg1()).
+
+pretty_otp5601(Expected, Msg) ->
+ pretty_otp5601(Expected, Msg, []).
+
+pretty_otp5601(Expected, Msg, Conf) ->
+ t("pretty_otp5601 -> entry with"
+ "~n Expected: ~p"
+ "~n Msg: ~p", [Expected, Msg]),
+ case (catch encode_message(megaco_pretty_text_encoder, Conf, Msg)) of
+ {error, Reason} when Expected == error ->
+ d("pretty_otp5601 -> encode failed as expected"
+ "~n Reason: ~w", [Reason]),
+ ok;
+ {error, Reason} ->
+ e("pretty_otp5601 -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expected == error ->
+ e("pretty_otp5601 -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("pretty_otp5601 -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case decode_message(megaco_pretty_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("pretty_otp5601 -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("pretty_otp5601 -> successfull decode"
+ " - but not equal", []),
+ exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("pretty_otp5601 -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end
+ end.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+%% put(severity,trc),
+%% put(dbg,true),
+ pretty_otp5793(ok, pretty_otp5793_msg1()).
+
+pretty_otp5793(Expected, Msg) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, []).
+
+pretty_otp5793(Expected, Msg, Conf) ->
+ expect_codec(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',2,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]}]}}]}]}}}]}}}.
+
+
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% put(severity,trc),
+ %% put(dbg,true),
+ pretty_otp5882().
+
+pretty_otp5882() ->
+ otp5882(megaco_pretty_text_encoder, []).
+
+otp5882(Codec, Conf) ->
+ Msg = pretty_otp5882_msg01(),
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, {message_encode_failed, {error, {ActualReason, _}}, _}} ->
+ case ActualReason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ exit({unexpected_error_actual_reason, ActualReason})
+ end;
+ {error, Reason} ->
+ exit({unexpected_error_reason, Reason});
+ {ok, Bin} ->
+ exit({unexpected_encode_sucess, binary_to_list(Bin)})
+ end.
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = ?MSG_LIB:cre_StreamParms(LCD),
+ StreamDesc = ?MSG_LIB:cre_StreamDescriptor(1, Parms),
+ MediaDesc = ?MSG_LIB:cre_MediaDescriptor([StreamDesc]),
+ AmmReq = ?MSG_LIB:cre_AmmRequest([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ Cmd = ?MSG_LIB:cre_Command(modReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ CID = ?MSG_LIB:cre_ContextID(5882),
+ ActReq = ?MSG_LIB:cre_ActionRequest(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = ?MSG_LIB:cre_TransactionId(7302),
+ TransReq = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TransReq),
+ Mid = ?MG1_MID,
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ %% erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp6490( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490(Msg, Conf) ->
+ pretty_otp6490(Msg, Conf, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode) ->
+ pretty_otp6490(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp6490(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp6490(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+otp6490(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode == error ->
+ ok;
+ {error, Reason} when ExpectedEncode == ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode == error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode == ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode == ok ->
+ ok;
+ {ok, Msg} when ExpectedDecode == error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode == ok ->
+ exit({unexpected_decode_result, Msg, Msg2});
+ {ok, Msg2} when ExpectedDecode == error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode == error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp7249_msg01(suite) ->
+ [];
+pretty_otp7249_msg01(doc) ->
+ "Ticket OTP-7249 has really nothing to to with just version 2 "
+ "although the test message is version 2. Instead the decode "
+ "is actually done by the mini decoder, which is where the bug "
+ "manifests itself. The bug is in effect located in the (plain) "
+ "text scanner. ";
+pretty_otp7249_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp7249_msg01 -> entry", []),
+ ok = pretty_otp7249( pretty_otp7249_msg01() ),
+ %% erase(dbg),
+ %% erase(severity),
+ ok.
+
+
+pretty_otp7249_msg01() ->
+ "MEGACO/2 <AGW95_DCT_2_DPNSS>\r\nTransaction = 500017 { \r\nContext = - { ServiceChange = ROOT { Services { \r\nMethod = Disconnected, Reason = 900, 20070116T15233997 } \r\n } } } \r\n".
+
+pretty_otp7249(EncodedMsg) ->
+ Codec = megaco_pretty_text_encoder,
+ Conf = [],
+ Bin = list_to_binary(EncodedMsg),
+ case decode_mini_message(Codec, Conf, Bin) of
+ {ok, Msg} when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("Msg: ~n~p"
+ %% "~n", [Msg]),
+ ok;
+ {error, Reason} ->
+ exit({unexpected_decode_failure, EncodedMsg, Reason})
+ end.
+
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check)
+ when is_function(Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ["root"]}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_DigitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_DigitMapDesc(),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[],
+ asn1_NOVALUE}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+expect_codec(Expect, Codec, Msg, Conf) ->
+ t("expect_codec -> entry with"
+ "~n Expect: ~p"
+ "~n Msg: ~p", [Expect, Msg]),
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when Expect == error ->
+ d("expect_codec -> encode failed as expected"
+ "~n _Reason: ~w", [_Reason]),
+ ok;
+ {error, Reason} ->
+ e("expect_codec -> encode failed unexpectedly: "
+ "~n Reason: ~w", [Reason]),
+ exit({unexpected_encode_result, Reason});
+ {ok, Bin} when Expect == error ->
+ e("expect_codec -> encode succeded unexpectedly: "
+ "~n ~w", [binary_to_list(Bin)]),
+ exit({unexpected_encode_result, binary_to_list(Bin)});
+ {ok, Bin} ->
+ d("expect_codec -> successfull encode as expected:"
+ "~n~s", [binary_to_list(Bin)]),
+ case (catch decode_message(Codec, false, Conf, Bin)) of
+ {ok, Msg} ->
+ d("expect_codec -> successfull decode~n", []),
+ ok;
+ {ok, Msg2} ->
+ e("expect_codec -> successfull decode"
+ " - but not equal", []),
+ chk_MegacoMessage(Msg, Msg2);
+ %% exit({unexpected_decode_result, Msg, Msg2});
+ Else ->
+ e("expect_codec -> decode failed:~n~p", [Else]),
+ exit({unexpected_decode_result, Else})
+ end;
+ Else ->
+ e("expect_codec -> encode failed:~n~p", [Else]),
+ exit({unexpected_encode_result, Else})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ Msgs = msgs1() ++ msgs2() ++ msgs3() ++ msgs4(),
+ [M || {_, M, _, _} <- Msgs].
+
+msgs1() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+
+msgs2() ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, [], M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+msgs4() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg51a, msg51a(), Plain, [{dbg, false}]},
+ {msg51b, msg51b(), Plain, [{dbg, false}]},
+ {msg51c, msg51c(), Plain, [{dbg, false}]},
+ {msg51d, msg51d(), Plain, [{dbg, false}]},
+ {msg51e, msg51e(), Plain, [{dbg, false}]},
+ {msg51f, msg51f(), Plain, [{dbg, false}]},
+ {msg51g, msg51g(), Plain, [{dbg, false}]},
+ {msg51h, msg51h(), Plain, [{dbg, false}]},
+ {msg51i, msg51i(), Plain, [{dbg, false}]},
+ {msg52, msg52(), Plain, [{dbg, false}]},
+ {msg53, msg53(), Plain, [{dbg, false}]},
+ {msg54a, msg54a(), Plain, [{dbg, false}]},
+ {msg54b, msg54b(), Plain, [{dbg, false}]},
+ {msg54c, msg54c(), Plain, [{dbg, false}]},
+ {msg55, msg55(), Plain, [{dbg, false}]},
+ {msg56, msg56(), Plain, [{dbg, false}]},
+ {msg57, msg57(), Plain, [{dbg, false}]},
+ {msg58a, msg58a(), Plain, [{dbg, false}]},
+ {msg58b, msg58b(), Plain, [{dbg, false}]}
+ ].
+
+
+msgs5() ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ PlainEDFail =
+ fun(Codec, DD, Ver, EC, M) ->
+ Res =
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M),
+ case Res of
+ {error, {message_encode_failed, Reason, _M}} ->
+ case Reason of
+ {error, {{deprecated, _}, _}} ->
+ ok;
+ _ ->
+ Res
+ end;
+ _ ->
+ Res
+ end
+ end,
+
+ PlainDE =
+ fun(Codec, _DD, Ver, EC, B) ->
+ Res =
+ megaco_codec_test_lib:decode_message(Codec, false, Ver,
+ EC, B),
+ case Res of
+ {ok, M} ->
+ #'MegacoMessage'{mess = Mess} = M,
+ #'Message'{messageBody = {transactions, TRs}} = Mess,
+ [{transactionRequest, TR}] = TRs,
+ #'TransactionRequest'{actions = Actions} = TR,
+ [Action] = Actions,
+ #'ActionRequest'{commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {addReq,AmmReq} = Cmd,
+ #'AmmRequest'{descriptors = []} = AmmReq,
+ ok;
+ _ ->
+ Res
+ end
+ end,
+
+ [
+ {msg61a, msg61a(), Plain, [{dbg, false}]},
+ {msg61b, msg61b(), Plain, [{dbg, false}]},
+ {msg61c, msg61c(), Plain, [{dbg, false}]},
+ {msg62a, msg62a(), PlainEDFail, [{dbg, false}]},
+ {msg62b, msg62b(), PlainDE, [{dbg, false}]}
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = ?MSG_LIB:cre_ActionRequest(CtxId,CmdReqs),
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ megaco_trans_req(TransInfo, [Trans|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(Version, Mid, Body),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(?VERSION, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Auth, Mess).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) ->
+ Action = cre_ActRep(ContextId, CmdReply),
+ Actions = [Action],
+ TR = cre_TransRep(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_MegacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_TransAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ReqEvent = cre_ReqedEv("al/of"),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ EventParm = cre_EvParm("strict",["exact"]),
+ ReqEvent = cre_ReqedEv("al/of", [EventParm]),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChResParm(Address,Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_EvParm("strict",["state"]),
+ On = cre_ReqedEv("al/on", [Strict]),
+ Name = "dialplan00",
+ Action = cre_ReqedActs(Name),
+ Ce = cre_ReqedEv("dd/ce", Action),
+ EventsDesc = cre_EvsDesc(2223,[On, Ce]),
+ Signal = cre_Sig("cg/rt"),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22010001"),
+ Parm = cre_EvParm("ds",["916135551212"]),
+ Event = cre_ObsEv("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_ObsEvsDesc(2223,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(recvOnly,[Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 $ "),
+ M2 = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_StreamParms(LCD, LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Signal = cre_Sig("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD2 = cre_LocalControlDesc(sendRecv, [Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ LD2 = cre_LocalRemoteDesc([[V, C, M, A]]),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_LocalRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_StreamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ %% Cmd 1)
+ Signal = cre_Sig("cg/rt"),
+ AmmReq1 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_CmdReq({modReq, AmmReq1}),
+
+ %% Cmd 2)
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_StreamParms(LCD),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+
+ %% Cmd 3)
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms3 = cre_StreamParmsR(RD),
+ StreamDesc3 = cre_StreamDesc(2,Parms3),
+ MediaDesc3 = cre_MediaDesc(StreamDesc3),
+ AmmReq3 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_CmdReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22020002"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(1234,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_ReqedEv("al/on"),
+ EventsDesc = cre_EvsDesc(1235,[On]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_AuditDesc(Tokens),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(sendRecv,[Jit]),
+ LDV = cre_PropParm("v", "0"),
+ LDC = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_PropParm("a", "ptime:30"),
+ LD = cre_LocalRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_PropParm("v", "0"),
+ RDC = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_PropParm("a", "ptime:30"),
+ RD = cre_LocalRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_StreamParms(LCD,LD,RD),
+ StreamDesc = cre_StreamDesc(1,StreamParms),
+ Media = cre_MediaDesc(StreamDesc),
+ PackagesItem = cre_PkgsItem("nt",1),
+ PackagesItem2 = cre_PkgsItem("rtp",1),
+ Stat = cre_StatsParm("rtp/ps","1200"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_AuditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_CmdReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_NotifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_CmdReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_AuditDesc([statsToken]),
+ SubReq = cre_SubReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_SubReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_CmdReq({subtractReq, SubReq}),
+ CmdReq2 = cre_CmdReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_StatsParm("nt/os","45123"),
+ Stat12 = cre_StatsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_AmmsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_StatsParm("rtp/ps","1245"),
+ Stat22 = cre_StatsParm("nt/os", "62345"),
+ Stat23 = cre_StatsParm("rtp/pr", "780"),
+ Stat24 = cre_StatsParm("nt/or", "45123"),
+ Stat25 = cre_StatsParm("rtp/pl", "10"),
+ Stat26 = cre_StatsParm("rtp/jit", "27"),
+ Stat27 = cre_StatsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ Auth = cre_AuthHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+msg50(Mid, APT) ->
+ AD = cre_AuditDesc(asn1_NOVALUE, APT),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AD),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%% IndAudMediaDescriptor:
+msg51(Mid, IATSDorStream) ->
+ IAMD = cre_IndAudMediaDesc(IATSDorStream),
+ IAP = cre_IndAudParam(IAMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg51a() ->
+ msg51a(?MG2_MID).
+msg51a(Mid) ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51b() ->
+ msg51b(?MG2_MID).
+msg51b(Mid) ->
+ PP = cre_IndAudPropertyParm("nt/jit"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51c() ->
+ msg51c(?MG2_MID).
+msg51c(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, 'NULL'),
+ msg51(Mid, IATSD).
+
+msg51d() ->
+ msg51d(?MG2_MID).
+msg51d(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg51(Mid, IATSD).
+
+msg51e() ->
+ msg51e(?MG2_MID).
+msg51e(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc('NULL', asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51f() ->
+ msg51f(?MG2_MID).
+msg51f(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL',
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51g() ->
+ msg51g(?MG2_MID).
+msg51g(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ 'NULL', asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51h() ->
+ msg51h(?MG2_MID).
+msg51h(Mid) ->
+ Name = "nt/jit",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, [IAPP]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+msg51i() ->
+ msg51i(?MG2_MID).
+msg51i(Mid) ->
+ Name = "nt/jit",
+ Name2 = "tdmc/ec",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ IALCD = cre_IndAudLocalControlDesc('NULL', 'NULL', 'NULL',
+ [IAPP, IAPP2]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+%% IndAudEventsDescriptor:
+msg52() ->
+ msg52(?MG2_MID).
+msg52(Mid) ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ IAP = cre_IndAudParam(IAED),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudEventBufferDescriptor:
+msg53() ->
+ msg53(?MG2_MID).
+msg53(Mid) ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ IAP = cre_IndAudParam(IAEBD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudSignalsDescriptor:
+msg54(Mid, Sig) ->
+ IASD = cre_IndAudSigsDesc(Sig),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg54a() ->
+ msg54a(?MG2_MID).
+msg54a(Mid) ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54b() ->
+ msg54b(?MG2_MID).
+msg54b(Mid) ->
+ SN = "dg/d0",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54c() ->
+ msg54c(?MG2_MID).
+msg54c(Mid) ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg54(Mid, SSL).
+
+%% IndAudDigitMapDescriptor:
+msg55() ->
+ msg55(?MG2_MID).
+msg55(Mid) ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ IAP = cre_IndAudParam(IADMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudStatisticsDescriptor:
+msg56() ->
+ msg56(?MG2_MID).
+msg56(Mid) ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudPackagesDescriptor:
+msg57() ->
+ msg57(?MG2_MID).
+msg57(Mid) ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ IAP = cre_IndAudParam(IAPD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% Sum it up:
+msg58_iaMediaDesc_iap(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ cre_IndAudParam(IAMD).
+
+msg58_iaMediaDesc_iap_a() ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaMediaDesc_iap_b() ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaEvsDesc_iap() ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ cre_IndAudParam(IAED).
+
+msg58_iaEvBufDesc_iap() ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ cre_IndAudParam(IAEBD).
+
+msg58_iaSigsDesc_iap(S) ->
+ IASD = cre_IndAudSigsDesc(S),
+ cre_IndAudParam(IASD).
+
+msg58_iaSigsDesc_iap_a() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg58_iaSigsDesc_iap(Sig).
+
+msg58_iaSigsDesc_iap_b() ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg58_iaSigsDesc_iap(SSL).
+
+msg58_iaDigMapDesc_iap() ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ cre_IndAudParam(IADMD).
+
+msg58_iaStatsDesc_iap() ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ cre_IndAudParam(IASD).
+
+msg58_iaPacksDesc_iap() ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ cre_IndAudParam(IAPD).
+
+msg58a() ->
+ msg58a(?MG2_MID).
+msg58a(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_a(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_a(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+msg58b() ->
+ msg58b(?MG2_MID).
+msg58b(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_b(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_b(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Tests some of the changes in the v2 corr 1 (EmergencyOff and ModemDesc)
+
+%% Emergency On/Off (optional) tests
+msg61(EM) ->
+ TS = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TS),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ Cmd = ?MSG_LIB:cre_Command(notifyReq, NotReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CtxReq = ?MSG_LIB:cre_ContextRequest(15, EM),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CtxReq, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+msg61a() ->
+ msg61(false).
+
+msg61b() ->
+ msg61(true).
+
+msg61c() ->
+ msg61(asn1_NOVALUE).
+
+
+msg62a() ->
+ MT = ?MSG_LIB:cre_ModemType(v18),
+ PP = cre_PropParm("c", "IN IP4 $ "),
+ MD = ?MSG_LIB:cre_ModemDescriptor([MT], [PP]),
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(MD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AmmReq = ?MSG_LIB:cre_AmmRequest(TermIDs, [AmmDesc]),
+ Cmd = ?MSG_LIB:cre_Command(addReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ ActReq = ?MSG_LIB:cre_ActionRequest(2, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+msg62b() ->
+ MP =
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555
+Transaction = 9898 {
+ Context = 2 {
+ Add = 11111111/00000000/00000000 {
+ Modem[V18] {
+ tdmc/gain=2
+ }
+ }
+ }
+}",
+% MC =
+% "!/" ?VERSION_STR " [124.124.124.222]:55555\nT=9898{C=2{A=11111111/00000000/00000000{MD[V18]{tdmc/gain=2}}}}",
+ list_to_binary(MP).
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 2),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+skip(Reason) ->
+ megaco_codec_test_lib:skip(Reason).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_mini_message(Codec, Conf, Bin) ->
+ Codec:decode_mini_message(Conf, dynamic, Bin).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M1, M2) ->
+ ?MSG_LIB:chk_MegacoMessage(M1, M2).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_MegacoMessage(V, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(V, Mid, Body),
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_AuthHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_AuthHeader(SecParmIdx, SeqNum, AD).
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_AuthHeader(Idx, Num, D) ->
+ ?MSG_LIB:cre_AuthenticationHeader(Idx, Num, D).
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_TransRep(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions).
+
+cre_TransAck(First, Last) ->
+ ?MSG_LIB:cre_TransactionAck(First, Last).
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_ActRep(CtxId, CmdReply) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, CmdReply).
+
+cre_CtxID(Id) ->
+ ?MSG_LIB:cre_ContextID(Id).
+
+%% Ind Aud related:
+
+cre_IndAudParam(IAP) ->
+ ?MSG_LIB:cre_IndAuditParameter(IAP).
+
+cre_IndAudMediaDesc(D) ->
+ ?MSG_LIB:cre_IndAudMediaDescriptor(D).
+
+cre_IndAudStreamDesc(SID, SP) ->
+ ?MSG_LIB:cre_IndAudStreamDescriptor(SID, SP).
+
+cre_IndAudStreamParms(LCD) ->
+ ?MSG_LIB:cre_IndAudStreamParms(LCD).
+
+cre_IndAudLocalControlDesc(SM, RV, RG, PP) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(SM, RV, RG, PP).
+
+cre_IndAudPropertyParm(Name) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name).
+
+cre_IndAudTermStateDesc(PP) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP).
+
+cre_IndAudTermStateDesc(PP, EBC, SS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS).
+
+cre_IndAudEvsDesc(RID, PN)
+ when is_integer(RID) ->
+ ?MSG_LIB:cre_IndAudEventsDescriptor(RID, PN).
+
+cre_IndAudEvBufDesc(EN, SID) ->
+ ?MSG_LIB:cre_IndAudEventBufferDescriptor(EN, SID).
+
+cre_IndAudSigsDesc(D) ->
+ ?MSG_LIB:cre_IndAudSignalsDescriptor(D).
+
+cre_IndAudSig(SN) ->
+ ?MSG_LIB:cre_IndAudSignal(SN).
+
+cre_IndAudSeqSigList(ID, SL) ->
+ ?MSG_LIB:cre_IndAudSeqSigList(ID, SL).
+
+cre_IndAudDigitMapDesc(DMN) ->
+ ?MSG_LIB:cre_IndAudDigitMapDescriptor(DMN).
+
+cre_IndAudStatsDesc(SN) ->
+ ?MSG_LIB:cre_IndAudStatisticsDescriptor(SN).
+
+cre_IndAudPkgsDesc(PN, PV) ->
+ ?MSG_LIB:cre_IndAudPackagesDescriptor(PN, PV).
+
+%% Parameter related
+cre_PropParm(Name, Val) ->
+ ?MSG_LIB:cre_PropertyParm(Name, [Val]).
+
+
+%% Statistics related
+cre_StatsParm(Name, Val) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name, [Val]).
+
+
+% Event related
+cre_EvParm(Name, Val) ->
+ ?MSG_LIB:cre_EventParameter(Name, Val).
+
+cre_ObsEv(Name, Not) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Not).
+cre_ObsEv(Name, Not, Par) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Par, Not).
+
+cre_ReqedEv(Name) ->
+ ?MSG_LIB:cre_RequestedEvent(Name).
+cre_ReqedEv(Name, Action) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, Action).
+
+
+cre_ObsEvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_ObservedEventsDescriptor(Id, EvList).
+
+cre_EvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_EventsDescriptor(Id, EvList).
+
+
+%% Service change related
+cre_SvcChParm(M, A, R, P) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, P, R).
+
+cre_SvcChResParm(A, P) ->
+ ?MSG_LIB:cre_ServiceChangeResParm(A, P).
+
+cre_SvcChReq(Tids, P) ->
+ ?MSG_LIB:cre_ServiceChangeRequest(Tids, P).
+
+cre_SvcChProf(Name, Ver) ->
+ ?MSG_LIB:cre_ServiceChangeProfile(Name, Ver).
+
+cre_SvcChRep(Tids, Res) ->
+ ?MSG_LIB:cre_ServiceChangeReply(Tids, Res).
+
+
+%% Stream related
+cre_StreamParms(Lcd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd).
+cre_StreamParms(Lcd, Ld) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld).
+cre_StreamParms(Lcd, Ld, Rd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld, Rd).
+cre_StreamParmsL(Ld) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, Ld, asn1_NOVALUE).
+cre_StreamParmsR(Rd) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, asn1_NOVALUE, Rd).
+
+cre_StreamDesc(Id, P) ->
+ ?MSG_LIB:cre_StreamDescriptor(Id, P).
+
+
+%% "Local" related
+cre_LocalControlDesc(Mode) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode).
+cre_LocalControlDesc(Mode, Parms) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode, Parms).
+
+cre_LocalRemoteDesc(Grps) ->
+ ?MSG_LIB:cre_LocalRemoteDescriptor(Grps).
+
+
+%% DigitMap related
+cre_DigitMapDesc() ->
+ ?MSG_LIB:cre_DigitMapDescriptor().
+cre_DigitMapDesc(NameOrVal) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(NameOrVal).
+cre_DigitMapDesc(Name, Val) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(Name, Val).
+
+cre_DigitMapValue(Body) ->
+ ?MSG_LIB:cre_DigitMapValue(Body).
+
+cre_DigitMapValue(Body, Start, Short, Long) ->
+ ?MSG_LIB:cre_DigitMapValue(Start, Short, Long, Body).
+
+%% Media related
+cre_MediaDesc(SD) when is_record(SD, 'StreamDescriptor') ->
+ cre_MediaDesc([SD]);
+cre_MediaDesc(SDs) ->
+ ?MSG_LIB:cre_MediaDescriptor(SDs).
+
+
+%% Notify related
+cre_NotifyReq(Tids, EvsDesc) ->
+ ?MSG_LIB:cre_NotifyRequest(Tids, EvsDesc).
+
+cre_NotifyRep(Tids) ->
+ ?MSG_LIB:cre_NotifyReply(Tids).
+
+
+%% Subtract related
+cre_SubReq(Tids, Desc) ->
+ ?MSG_LIB:cre_SubtractRequest(Tids, Desc).
+
+
+%% Audit related
+cre_AuditDesc(Tokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens).
+
+cre_AuditDesc(Tokens, PropertTokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens, PropertTokens).
+
+cre_AuditReq(Tid, Desc) ->
+ ?MSG_LIB:cre_AuditRequest(Tid, Desc).
+
+cre_AuditRes(Tid, Res) ->
+ ?MSG_LIB:cre_AuditResult(Tid, Res).
+
+
+%% AMM/AMMS related
+cre_AmmReq(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmRequest(Tids, Descs).
+
+cre_AmmsReply(Tids) ->
+ ?MSG_LIB:cre_AmmsReply(Tids).
+cre_AmmsReply(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmsReply(Tids, Descs).
+
+
+%% Command related
+%% cre_command(Tag, Req) ->
+%% ?MSG_LIB:cre_Command(Tag, Req).
+
+cre_CmdReq(Cmd) ->
+ ?MSG_LIB:cre_CommandRequest(Cmd).
+
+
+%% Actions related
+cre_ReqedActs(DmName) ->
+ EDM = ?MSG_LIB:cre_EventDM(DmName),
+ ?MSG_LIB:cre_RequestedActions(EDM).
+
+
+%% Signal related
+cre_Sig(Name) ->
+ ?MSG_LIB:cre_Signal(Name).
+
+
+%% Others
+cre_TimeNot(D,T) ->
+ ?MSG_LIB:cre_TimeNotation(D, T).
+
+cre_PkgsItem(Name, Ver) ->
+ ?MSG_LIB:cre_PackagesItem(Name, Ver).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+start_flex_scanner() ->
+ megaco_codec_flex_lib:start().
+
+stop_flex_scanner(Pid) ->
+ megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+l(F,A) ->
+ p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s: " ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "T";
+image_of(dbg) ->
+ "D";
+image_of(log) ->
+ "L";
+image_of(err) ->
+ "E";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
+
diff --git a/lib/megaco/test/megaco_codec_v3_test.erl b/lib/megaco/test/megaco_codec_v3_test.erl
new file mode 100644
index 0000000000..f49c3a677a
--- /dev/null
+++ b/lib/megaco/test/megaco_codec_v3_test.erl
@@ -0,0 +1,8479 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test encoding/decoding (codec) module of Megaco/H.248
+%%----------------------------------------------------------------------
+
+-module(megaco_codec_v3_test).
+
+%% ----
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include("megaco_test_lib.hrl").
+
+%% ----
+
+-export([msgs/0]).
+-export([rfc3525_msgs_display/0, rfc3525_msgs_test/0]).
+
+-export([t/0, t/1]).
+
+-export([all/1,
+
+ text/1,
+
+ pretty/1,
+ pretty_test_msgs/1,
+
+ compact/1,
+ compact_test_msgs/1,
+
+ flex_pretty/1,
+ flex_pretty_init/1,
+ flex_pretty_finish/1,
+ flex_pretty_test_msgs/1,
+
+ flex_compact/1,
+ flex_compact_init/1,
+ flex_compact_finish/1,
+ flex_compact_test_msgs/1,
+
+ flex_compact_dm_timers1/1,
+ flex_compact_dm_timers2/1,
+ flex_compact_dm_timers3/1,
+ flex_compact_dm_timers4/1,
+ flex_compact_dm_timers5/1,
+ flex_compact_dm_timers6/1,
+ flex_compact_dm_timers7/1,
+ flex_compact_dm_timers8/1,
+
+ binary/1,
+
+ bin/1,
+ bin_test_msgs/1,
+
+ ber/1,
+ ber_test_msgs/1,
+
+ ber_bin/1,
+ ber_bin_test_msgs/1,
+
+ per/1,
+ per_test_msgs/1,
+
+ per_bin/1,
+ per_bin_test_msgs/1,
+
+ erl_dist/1,
+ erl_dist_m/1,
+ erl_dist_m_test_msgs/1,
+
+ tickets/0,
+ tickets/1,
+
+ compact_tickets/1,
+ compact_otp4011_msg1/1,
+ compact_otp4011_msg2/1,
+ compact_otp4011_msg3/1,
+ compact_otp4013_msg1/1,
+ compact_otp4085_msg1/1,
+ compact_otp4085_msg2/1,
+ compact_otp4280_msg1/1,
+ compact_otp4299_msg1/1,
+ compact_otp4359_msg1/1,
+ compact_otp4920_msg0/1,
+ compact_otp4920_msg1/1,
+ compact_otp4920_msg2/1,
+ compact_otp4920_msg3/1,
+ compact_otp4920_msg4/1,
+ compact_otp4920_msg5/1,
+ compact_otp4920_msg6/1,
+ compact_otp4920_msg7/1,
+ compact_otp4920_msg8/1,
+ compact_otp4920_msg9/1,
+ compact_otp4920_msg10/1,
+ compact_otp4920_msg11/1,
+ compact_otp4920_msg12/1,
+ compact_otp4920_msg20/1,
+ compact_otp4920_msg21/1,
+ compact_otp4920_msg22/1,
+ compact_otp4920_msg23/1,
+ compact_otp4920_msg24/1,
+ compact_otp4920_msg25/1,
+ compact_otp5186_msg01/1,
+ compact_otp5186_msg02/1,
+ compact_otp5186_msg03/1,
+ compact_otp5186_msg04/1,
+ compact_otp5186_msg05/1,
+ compact_otp5186_msg06/1,
+ compact_otp5793_msg01/1,
+ compact_otp5836_msg01/1,
+ compact_otp5993_msg01/1,
+ compact_otp5993_msg02/1,
+ compact_otp5993_msg03/1,
+ compact_otp6017_msg01/1,
+ compact_otp6017_msg02/1,
+ compact_otp6017_msg03/1,
+
+ flex_compact_tickets/1,
+ flex_compact_otp4299_msg1/1,
+ flex_compact_otp7431_msg01/1,
+ flex_compact_otp7431_msg02/1,
+ flex_compact_otp7431_msg03/1,
+ flex_compact_otp7431_msg04/1,
+ flex_compact_otp7431_msg05/1,
+ flex_compact_otp7431_msg06/1,
+ flex_compact_otp7431_msg07/1,
+
+
+ pretty_tickets/1,
+ pretty_otp4632_msg1/1,
+ pretty_otp4632_msg2/1,
+ pretty_otp4632_msg3/1,
+ pretty_otp4632_msg4/1,
+ pretty_otp4710_msg1/1,
+ pretty_otp4710_msg2/1,
+ pretty_otp4945_msg1/1,
+ pretty_otp4945_msg2/1,
+ pretty_otp4945_msg3/1,
+ pretty_otp4945_msg4/1,
+ pretty_otp4945_msg5/1,
+ pretty_otp4945_msg6/1,
+ pretty_otp4949_msg1/1,
+ pretty_otp4949_msg2/1,
+ pretty_otp4949_msg3/1,
+ pretty_otp5042_msg1/1,
+ pretty_otp5068_msg1/1,
+ pretty_otp5085_msg1/1,
+ pretty_otp5085_msg2/1,
+ pretty_otp5085_msg3/1,
+ pretty_otp5085_msg4/1,
+ pretty_otp5085_msg5/1,
+ pretty_otp5085_msg6/1,
+ pretty_otp5085_msg7/1,
+ pretty_otp5085_msg8/1,
+ pretty_otp5600_msg1/1,
+ pretty_otp5600_msg2/1,
+ pretty_otp5601_msg1/1,
+ pretty_otp5793_msg01/1,
+ pretty_otp5803_msg01/1,
+ pretty_otp5803_msg02/1,
+ pretty_otp5805_msg01/1,
+ pretty_otp5836_msg01/1,
+ pretty_otp5882_msg01/1,
+ pretty_otp6490_msg01/1,
+ pretty_otp6490_msg02/1,
+ pretty_otp6490_msg03/1,
+ pretty_otp6490_msg04/1,
+ pretty_otp6490_msg05/1,
+ pretty_otp6490_msg06/1,
+ pretty_otp7671_msg01/1,
+ pretty_otp7671_msg02/1,
+ pretty_otp7671_msg03/1,
+ pretty_otp7671_msg04/1,
+ pretty_otp7671_msg05/1,
+ pretty_otp8114_msg01/1,
+
+ flex_pretty_tickets/1,
+ flex_pretty_otp5042_msg1/1,
+ flex_pretty_otp5085_msg1/1,
+ flex_pretty_otp5085_msg2/1,
+ flex_pretty_otp5085_msg3/1,
+ flex_pretty_otp5085_msg4/1,
+ flex_pretty_otp5085_msg5/1,
+ flex_pretty_otp5085_msg6/1,
+ flex_pretty_otp5085_msg7/1,
+ flex_pretty_otp5085_msg8/1,
+ flex_pretty_otp5600_msg1/1,
+ flex_pretty_otp5600_msg2/1,
+ flex_pretty_otp5601_msg1/1,
+ flex_pretty_otp5793_msg01/1,
+ flex_pretty_otp5803_msg01/1,
+ flex_pretty_otp5803_msg02/1,
+ flex_pretty_otp5805_msg01/1,
+ flex_pretty_otp5836_msg01/1,
+ flex_pretty_otp7431_msg01/1,
+ flex_pretty_otp7431_msg02/1,
+ flex_pretty_otp7431_msg03/1,
+ flex_pretty_otp7431_msg04/1,
+ flex_pretty_otp7431_msg05/1,
+ flex_pretty_otp7431_msg06/1,
+ flex_pretty_otp7431_msg07/1,
+
+ init_per_testcase/2, fin_per_testcase/2]).
+
+-export([display_text_messages/0, generate_text_messages/0]).
+
+
+%% ----
+
+-define(V3, v3).
+-define(EC_V3, {version3,?V3}).
+-define(EC, [?EC_V3]).
+
+-define(VERSION, 3).
+-define(VERSION_STR, "3").
+-define(MSG_LIB, megaco_test_msg_v3_lib).
+-define(DEFAULT_PORT, 55555).
+-define(MG1_MID_NO_PORT, {ip4Address,
+ #'IP4Address'{address = [124, 124, 124, 222]}}).
+-define(MG1_MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG2_MID, {ip4Address, #'IP4Address'{address = [125, 125, 125, 111],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MG3_MID, {ip4Address, #'IP4Address'{address = [125, 124, 123, 122],
+ portNumber = ?DEFAULT_PORT}}).
+-define(MGC_MID, {ip4Address, #'IP4Address'{address = [123, 123, 123, 4],
+ portNumber = ?DEFAULT_PORT}}).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+
+%% ----
+
+display_text_messages() ->
+ Msgs =
+ msgs7(text) ++
+ msgs8(text),
+ megaco_codec_test_lib:display_text_messages(?VERSION, ?EC, Msgs).
+
+
+generate_text_messages() ->
+ Msgs =
+ msgs7(text) ++
+ msgs8(text),
+ megaco_codec_test_lib:generate_text_messages(?V3, ?VERSION, ?EC, Msgs).
+
+
+%% ----
+
+
+expand(RootCase) ->
+ expand([RootCase], []).
+
+expand([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+expand([Case|Cases], Acc) ->
+ case (catch apply(?MODULE,Case,[suite])) of
+ [] ->
+ expand(Cases, [Case|Acc]);
+ C when is_list(C) ->
+ expand(Cases, [expand(C, [])|Acc]);
+ _ ->
+ expand(Cases, [Case|Acc])
+ end.
+
+
+%% ----
+
+tickets() ->
+ Flag = process_flag(trap_exit, true),
+ Cases = expand(tickets),
+ Fun = fun(Case) ->
+ C = init_per_testcase(Case, [{tc_timeout,
+ timer:minutes(10)}]),
+ io:format("Eval ~w~n", [Case]),
+ Result =
+ case (catch apply(?MODULE, Case, [C])) of
+ {'EXIT', Reason} ->
+ io:format("~n~p exited:~n ~p~n",
+ [Case, Reason]),
+ {error, {Case, Reason}};
+ Res ->
+ Res
+ end,
+ fin_per_testcase(Case, C),
+ Result
+ end,
+ process_flag(trap_exit, Flag),
+ lists:map(Fun, Cases).
+
+
+%% ----
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+init_per_testcase(Case, Config) ->
+ %% CaseString = io_lib:format("~p", [Case]),
+ C =
+ case lists:suffix("time_test", atom_to_list(Case)) of
+ true ->
+ [{tc_timeout, timer:minutes(10)}|Config];
+ false ->
+ put(verbosity,trc),
+ Config
+ end,
+ megaco_test_lib:init_per_testcase(Case, C).
+
+fin_per_testcase(Case, Config) ->
+ erase(verbosity),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ text,
+ binary,
+ erl_dist,
+ tickets
+ ].
+
+text(suite) ->
+ [
+ pretty,
+ flex_pretty,
+ compact,
+ flex_compact
+ ].
+
+binary(suite) ->
+ [
+ bin,
+ ber,
+ ber_bin,
+ per,
+ per_bin
+ ].
+
+erl_dist(suite) ->
+ [
+ erl_dist_m
+ ].
+
+pretty(suite) ->
+ [
+ pretty_test_msgs
+ ].
+
+
+compact(suite) ->
+ [
+ compact_test_msgs
+ ].
+
+
+flex_pretty(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_cases(), flex_pretty_finish}}.
+
+flex_pretty_cases() ->
+ [
+ flex_pretty_test_msgs
+ ].
+
+flex_compact(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_cases(), flex_compact_finish}}.
+
+flex_compact_cases() ->
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
+
+bin(suite) ->
+ [
+ bin_test_msgs
+ ].
+
+
+ber(suite) ->
+ [
+ ber_test_msgs
+ ].
+
+
+ber_bin(suite) ->
+ [
+ ber_bin_test_msgs
+ ].
+
+
+per(suite) ->
+ [
+ per_test_msgs
+ ].
+
+
+%% Support for per_bin was added to ASN.1 as of version
+%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
+%% releases are identical (as far as I know).
+%%
+per_bin(suite) ->
+ [
+ per_bin_test_msgs
+ ].
+
+
+erl_dist_m(suite) ->
+ [
+ erl_dist_m_test_msgs
+ ].
+
+tickets(suite) ->
+ [
+ compact_tickets,
+ flex_compact_tickets,
+ pretty_tickets,
+ flex_pretty_tickets
+ ].
+
+
+compact_tickets(suite) ->
+ [
+ compact_otp4011_msg1,
+ compact_otp4011_msg2,
+ compact_otp4011_msg3,
+ compact_otp4013_msg1,
+ compact_otp4085_msg1,
+ compact_otp4085_msg2,
+ compact_otp4280_msg1,
+ compact_otp4299_msg1,
+ compact_otp4359_msg1,
+ compact_otp4920_msg0,
+ compact_otp4920_msg1,
+ compact_otp4920_msg2,
+ compact_otp4920_msg3,
+ compact_otp4920_msg4,
+ compact_otp4920_msg5,
+ compact_otp4920_msg6,
+ compact_otp4920_msg7,
+ compact_otp4920_msg8,
+ compact_otp4920_msg9,
+ compact_otp4920_msg10,
+ compact_otp4920_msg11,
+ compact_otp4920_msg12,
+ compact_otp4920_msg20,
+ compact_otp4920_msg21,
+ compact_otp4920_msg22,
+ compact_otp4920_msg23,
+ compact_otp4920_msg24,
+ compact_otp4920_msg25,
+ compact_otp5186_msg01,
+ compact_otp5186_msg02,
+ compact_otp5186_msg03,
+ compact_otp5186_msg04,
+ compact_otp5186_msg05,
+ compact_otp5186_msg06,
+ compact_otp5793_msg01,
+ compact_otp5836_msg01,
+ compact_otp5993_msg01,
+ compact_otp5993_msg02,
+ compact_otp5993_msg03,
+ compact_otp6017_msg01,
+ compact_otp6017_msg02,
+ compact_otp6017_msg03
+ ].
+
+
+flex_compact_tickets(suite) ->
+ {req, [],
+ {conf, flex_compact_init, flex_compact_tickets_cases(),
+ flex_compact_finish}}.
+
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
+
+
+pretty_tickets(suite) ->
+ [
+ pretty_otp4632_msg1,
+ pretty_otp4632_msg2,
+ pretty_otp4632_msg3,
+ pretty_otp4632_msg4,
+ pretty_otp4710_msg1,
+ pretty_otp4710_msg2,
+ pretty_otp4945_msg1,
+ pretty_otp4945_msg2,
+ pretty_otp4945_msg3,
+ pretty_otp4945_msg4,
+ pretty_otp4945_msg5,
+ pretty_otp4945_msg6,
+ pretty_otp4949_msg1,
+ pretty_otp4949_msg2,
+ pretty_otp4949_msg3,
+ pretty_otp5042_msg1,
+ pretty_otp5068_msg1,
+ pretty_otp5085_msg1,
+ pretty_otp5085_msg2,
+ pretty_otp5085_msg3,
+ pretty_otp5085_msg4,
+ pretty_otp5085_msg5,
+ pretty_otp5085_msg6,
+ pretty_otp5085_msg7,
+ pretty_otp5085_msg8,
+ pretty_otp5600_msg1,
+ pretty_otp5600_msg2,
+ pretty_otp5601_msg1,
+ pretty_otp5793_msg01,
+ pretty_otp5803_msg01,
+ pretty_otp5803_msg02,
+ pretty_otp5805_msg01,
+ pretty_otp5836_msg01,
+ pretty_otp5882_msg01,
+ pretty_otp6490_msg01,
+ pretty_otp6490_msg02,
+ pretty_otp6490_msg03,
+ pretty_otp6490_msg04,
+ pretty_otp6490_msg05,
+ pretty_otp6490_msg06,
+ pretty_otp7671_msg01,
+ pretty_otp7671_msg02,
+ pretty_otp7671_msg03,
+ pretty_otp7671_msg04,
+ pretty_otp7671_msg05,
+ pretty_otp8114_msg01
+ ].
+
+
+flex_pretty_tickets(suite) ->
+ {req, [],
+ {conf, flex_pretty_init, flex_pretty_tickets_cases(),
+ flex_pretty_finish}}.
+
+flex_pretty_tickets_cases() ->
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pretty_test_msgs(suite) ->
+ [];
+pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text) ++
+ msgs8(text),
+ %% Msgs = msgs1a(text),
+ %% Msgs = msgs1b(text),
+ %% Msgs = msgs35525(text),
+ %% Msgs = msgs5(text),
+ %% Msgs = msgs6(text),
+ %% Msgs = msgs7(text),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_pretty_init(Config) ->
+ flex_init(Config).
+
+flex_pretty_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_pretty_test_msgs(suite) ->
+ [];
+flex_pretty_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text) ++
+ msgs8(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = false,
+ test_msgs(megaco_pretty_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compact_test_msgs(suite) ->
+ [];
+compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text) ++
+ msgs8(text),
+ %% Msgs = msgs7(text),
+ DynamicDecode = false,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_compact_init(Config) ->
+ flex_init(Config).
+
+flex_compact_finish(Config) ->
+ flex_finish(Config).
+
+
+flex_compact_test_msgs(suite) ->
+ [];
+flex_compact_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(text) ++
+ msgs1b(text) ++
+ msgs3525(text) ++
+ msgs5(text) ++
+ msgs6(text) ++
+ msgs7(text) ++
+ msgs8(text),
+ Conf = flex_scanner_conf(Config),
+ DynamicDecode = true,
+ test_msgs(megaco_compact_text_encoder, DynamicDecode, [?EC_V3,Conf], Msgs).
+
+
+flex_compact_dm_timers1(suite) ->
+ [];
+flex_compact_dm_timers1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "2", "3"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers1 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,3}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers2(suite) ->
+ [];
+flex_compact_dm_timers2(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("02", "03", "04"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers2 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({2,3,4}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers3(suite) ->
+ [];
+flex_compact_dm_timers3(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("1", "02", "31"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers3 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,2,31}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers4(suite) ->
+ [];
+flex_compact_dm_timers4(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("10", "21", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers4 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({10,21,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers5(suite) ->
+ [];
+flex_compact_dm_timers5(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("99", "23", "11"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers5 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({99,23,11}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers6(suite) ->
+ [];
+flex_compact_dm_timers6(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers6 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers7(suite) ->
+ [];
+flex_compact_dm_timers7(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("77", "09", "1", "99"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers7 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({77,9,1,99}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+flex_compact_dm_timers8(suite) ->
+ [];
+flex_compact_dm_timers8(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ M = build_dm_timers_message("01", "09", "01", "02"),
+ B = list_to_binary(M),
+ Conf = flex_scanner_conf(Config),
+ case decode_message(megaco_compact_text_encoder, false,
+ [?EC_V3,Conf], B) of
+ {ok, M1} when is_record(M1,'MegacoMessage') ->
+ t("flex_compact_dm_timers8 -> "
+ "~n M: ~s"
+ "~n M1: ~p", [M, M1]),
+ verify_dm_timers({1,9,1,2}, M1);
+ Else ->
+ exit({decode_failed, M, Else})
+ end.
+
+
+build_dm_timers_message(T, S, L) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s", [T, S, L])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(T, S, L, Z) ->
+ TMRs = lists:flatten(io_lib:format("T:~s,S:~s,L:~s,Z:~s", [T, S, L,Z])),
+ build_dm_timers_message(TMRs).
+
+build_dm_timers_message(TMRs) ->
+ M = io_lib:format("!/" ?VERSION_STR " [123.123.123.4]:55555\nT=10001{C=-{MF=11111111/00000000/00000000{E=2223{al/on,dd/ce{DM=dialplan00}},SG{cg/rt},DM=dialplan00{~s,(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)}}}}", [TMRs]),
+ lists:flatten(M).
+
+
+verify_dm_timers(TMRs, #'MegacoMessage'{mess = Mess}) ->
+ #'Message'{messageBody = Body} = Mess,
+ case get_dm_timers(Body) of
+ TMRs ->
+ ok;
+ {error, Reason} ->
+ exit({invalid_timer, {TMRs, Reason}});
+ TMRs1 ->
+ exit({invalid_timer_values, {TMRs, TMRs1}})
+ end.
+
+get_dm_timers({transactions, T}) when is_list(T) ->
+ get_dm_timers1(T);
+get_dm_timers(Other) ->
+ {error, {invalid_transactions, Other}}.
+
+get_dm_timers1([{transactionRequest,T}|Ts])
+ when is_record(T,'TransactionRequest') ->
+ case get_dm_timers2(T) of
+ {ok, Timers} ->
+ Timers;
+ _ ->
+ get_dm_timers1(Ts)
+ end;
+get_dm_timers1([_|Ts]) ->
+ get_dm_timers1(Ts);
+get_dm_timers1([]) ->
+ {error, {no_timers, 'TransactionRequest'}}.
+
+
+get_dm_timers2(#'TransactionRequest'{actions = Actions}) when is_list(Actions) ->
+ get_dm_timers3(Actions).
+
+
+get_dm_timers3([#'ActionRequest'{commandRequests = Cmds}|Ars]) when is_list(Cmds) ->
+ case get_dm_timers4(Cmds) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers3(Ars)
+ end;
+get_dm_timers3([_|Ars]) ->
+ get_dm_timers3(Ars);
+get_dm_timers3([]) ->
+ {error, {no_timers, 'ActionRequest'}}.
+
+get_dm_timers4([#'CommandRequest'{command = Cmd}|Cmds]) ->
+ case get_dm_timers5(Cmd) of
+ {ok, Timers} ->
+ {ok, Timers};
+ _ ->
+ get_dm_timers4(Cmds)
+ end;
+get_dm_timers4([_|Cmds]) ->
+ get_dm_timers4(Cmds);
+get_dm_timers4([]) ->
+ {error, {no_timers, 'CommandRequest'}}.
+
+
+get_dm_timers5({modReq, #'AmmRequest'{descriptors = Descriptors}}) ->
+ get_dm_timers6(Descriptors);
+get_dm_timers5(R) ->
+ {error, {no_modReq, R}}.
+
+
+get_dm_timers6([{digitMapDescriptor, #'DigitMapDescriptor'{digitMapValue = Val}}|_]) ->
+ case Val of
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = asn1_NOVALUE} ->
+ {ok, {T, S, L}};
+ #'DigitMapValue'{startTimer = T,
+ shortTimer = S,
+ longTimer = L,
+ durationTimer = Z} ->
+ {ok, {T, S, L, Z}};
+ _ ->
+ {error, no_value_in_dm}
+ end;
+get_dm_timers6([_|Descs]) ->
+ get_dm_timers6(Descs);
+get_dm_timers6([]) ->
+ {error, {no_timers, descriptors}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bin_test_msgs(suite) ->
+ [];
+bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary) ++
+ msgs8(binary),
+ %% Msgs = msgs6(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_binary_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_test_msgs(suite) ->
+ [];
+ber_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary) ++
+ msgs8(binary),
+ %% Msgs = msgs7(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_ber_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ber_bin_test_msgs(suite) ->
+ [];
+ber_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary) ++
+ msgs8(binary),
+ DynamicDecode = true,
+ test_msgs(megaco_ber_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_test_msgs(suite) ->
+ [];
+per_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary) ++
+ msgs8(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+per_bin_test_msgs(suite) ->
+ [];
+per_bin_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(binary) ++
+ msgs5(binary) ++
+ msgs6(binary) ++
+ msgs7(binary) ++
+ msgs8(binary),
+ DynamicDecode = false,
+ test_msgs(megaco_per_bin_encoder, DynamicDecode, ?EC, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+erl_dist_m_test_msgs(suite) ->
+ [];
+erl_dist_m_test_msgs(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Msgs =
+ msgs1a(erlang) ++
+ msgs1b(erlang) ++
+ msgs3525(erlang) ++
+ msgs5(erlang) ++
+ msgs6(erlang) ++
+ msgs7(erlang) ++
+ msgs8(erlang),
+ DynamicDecode = false,
+ Conf = [megaco_compressed],
+ test_msgs(megaco_erl_dist_encoder, DynamicDecode, Conf, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+%% Ticket test cases:
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg1(suite) ->
+ [];
+compact_otp4011_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+compact_otp4011_msg2(suite) ->
+ [];
+compact_otp4011_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SO,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SR}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% --------------------------------------------------------------
+%% Observe that this decode SHALL fail
+%%
+
+compact_otp4011_msg3(suite) ->
+ [];
+compact_otp4011_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4011_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "!/" ?VERSION_STR " ML T=233350{C=${A=stedevice/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=OFF,MO=SO}}}}}",
+ ok = compact_otp4011(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4011(Msg) ->
+ compact_otp4011(Msg, ?EC).
+
+compact_otp4011(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4011_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4011_chk1(R1) ->
+ case lists:keysearch(reason, 1, R1) of
+ {value, {reason, R2}} ->
+ compact_otp4011_chk2(R2);
+ false ->
+ {error, {unexpected_result, R1}}
+ end.
+
+compact_otp4011_chk2({0, ParserMod, {ParserFunc, [A, B]}})
+ when (ParserMod =:= megaco_text_parser_v3) andalso
+ (ParserFunc =:= do_merge_control_streamParms) andalso
+ is_list(A) andalso
+ is_record(B, 'LocalControlDescriptor') ->
+ SM = B#'LocalControlDescriptor'.streamMode,
+ case lists:keysearch(mode, 1, A) of
+ {value, {mode, _Mode}} when SM /= asn1_NOVALUE ->
+ ok;
+ {value, {mode, _Mode}} ->
+ {error, {unexpected_streamMode_reason, {A, B}}};
+ false ->
+ {error, {unexpected_mode_reason, {A, B}}}
+ end;
+compact_otp4011_chk2(Bad) ->
+ {error, {unexpected_reason, Bad}}.
+
+
+%% --------------------------------------------------------------
+%% Note that this decode SHALL fail, because of the misspelled
+%% MEGCAO instead of the correct MEGACO.
+compact_otp4013_msg1(suite) ->
+ [];
+compact_otp4013_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4013_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = "MEGCAO/3 MG1 T=12345678{C=-{SC=root{SV{MT=RS,RE=901}}}}",
+ ok = compact_otp4013(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4013(Msg) ->
+ compact_otp4013(Msg, ?EC).
+
+compact_otp4013(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4013_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4013_chk1(Reason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, no_version_found, _}} ->
+ case lists:keysearch(token, 1, Reason) of
+ {value, {token, [{'SafeChars',_,"megcao/3"}|_]}} ->
+ ok;
+ {value, {token, Tokens}} ->
+ {error, {unexpected_tokens, Tokens}};
+ false ->
+ {error, {tokens_not_found, Reason}}
+ end;
+ {value, {reason, BadReason, _}} ->
+ {error, {unexpected_reason, BadReason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4085_msg1(suite) ->
+ [];
+compact_otp4085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg(),
+ ok = compact_otp4085_1(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4085_1(Msg) ->
+ compact_otp4085_1(Msg, ?EC).
+
+compact_otp4085_1(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4085_1_chk1(Reason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4085_1_chk1(Reason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {Line, Module, Crap}}} when is_integer(Line) and
+ is_atom(Module) ->
+ Crap2 =
+ case (catch lists:flatten(Crap)) of
+ L when is_list(L) ->
+ L;
+ _ ->
+ Crap
+ end,
+ t("compact_otp4085_1_chk1 -> Expected: "
+ "~n Line: ~p"
+ "~n Module: ~p"
+ "~n Crap2: ~p", [Line, Module, Crap2]),
+ ok;
+ {value, BadReason} ->
+ e("compact_otp4085_1_chk1 -> error: "
+ "~n BadReason: ~p", [BadReason]),
+ {error, {unexpected_reason, Reason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+
+%% --------------------------------------------------------------
+%% This test case is just to show that the message used in
+%% compact_otp4085_msg1 is actually ok when you add '}' at the end.
+compact_otp4085_msg2(suite) ->
+ [];
+compact_otp4085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4085_erroneous_msg() ++ "}",
+ ok = compact_otp4085_2(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4085_2(Msg) ->
+ compact_otp4085_2(Msg, ?EC).
+
+compact_otp4085_2(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+
+%% This message lack the ending parentesis (}).
+compact_otp4085_erroneous_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " ML T=11223342{C=${A=${M{O{MO=SR,RV=OFF,RG=OFF},L{v=0,"
+ "c=ATM NSAP $ ,"
+ "a=eecid:$ ,"
+ "m=audio - AAL1/ATMF -,"
+ "}}},A=stee1181/01{M{O{MO=SR,RV=OFF,RG=OFF,tdmc/ec=off}}}}",
+ M.
+
+%% --------------------------------------------------------------
+%%
+%%
+compact_otp4280_msg1(suite) ->
+ [];
+compact_otp4280_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4280_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ M = compact_otp4280_msg(),
+ ok = compact_otp4280(M),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4280(Msg) ->
+ compact_otp4280(Msg, ?EC).
+
+compact_otp4280(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4280_msg() ->
+ M = "!/"
+ ?VERSION_STR
+ " mgw1 P=71853646{C=-{AV=root{M{TS{root/maxnumberofcontexts=49500,"
+ "root/maxterminationspercontext=2,root/normalmgexecutiontime=200,"
+ "root/normalmgcexecutiontime=150,"
+ "root/provisionalresponsetimervalue=2000,BF=OFF,SI=IV}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%% This ticket is about comments in a message
+%%
+compact_otp4299_msg1(suite) ->
+ [];
+compact_otp4299_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4299_msg(),
+ ok = compact_otp4299(Msg),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4299(Msg) ->
+ compact_otp4299(Msg, ?EC).
+
+compact_otp4299(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ ok;
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4299_msg() ->
+ M = ";KALLE\n"
+ "!/"
+ ?VERSION_STR
+ " mg58_1 P=005197711{; YET ANOTHER COMMENT\n"
+ "C=035146207{A=mg58_1_1_4_1_23/19; BEFORE COMMA\n"
+ ",; AFTER COMMA\n"
+ "A=eph58_1/0xA4023371{M{L{\n"
+ "v=0\n"
+ "c=ATM NSAP 39.0102.0304.0506.0708.090a.0b58.0100.0000.0000.00\n"
+ "m=audio - AAL1/ATMF -\n"
+ "a=eecid:A4023371\n"
+ "}}; HOBBE\n}; KALLE \"HOBBE \n}}"
+ ";KALLE\n\n",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+
+compact_otp4359_msg1(suite) ->
+ [];
+compact_otp4359_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4359_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4359_msg(),
+ ok = compact_otp4359(Msg),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4359_msg() ->
+ M = "!/" ?VERSION_STR " ml2 T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4359(Msg) ->
+ compact_otp4359(Msg, ?EC).
+
+compact_otp4359(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M) when is_record(M, 'MegacoMessage') ->
+ compact_otp4359_chk(M);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+compact_otp4359_chk(#'MegacoMessage'{mess = Mess}) ->
+ case Mess#'Message'.messageBody of
+ {transactions, Trans} ->
+ case Trans of
+ [{transactionRequest, TR}] ->
+ case TR of
+ #'TransactionRequest'{transactionId = asn1_NOVALUE} ->
+ ok;
+ _ ->
+ {error, {unexpected_trans_req, TR}}
+ end;
+ _ ->
+ {error, {unexpected_trans, Trans}}
+ end;
+ Body ->
+ {error, {unexpected_messageBody, Body}}
+ end.
+
+
+%% --------------------------------------------------------------
+%%
+compact_otp4920_msg0(suite) ->
+ [];
+compact_otp4920_msg0(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg0 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg0() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg1(suite) ->
+ [];
+compact_otp4920_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg2(suite) ->
+ [];
+compact_otp4920_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg3(suite) ->
+ [];
+compact_otp4920_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg4(suite) ->
+ [];
+compact_otp4920_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg5(suite) ->
+ [];
+compact_otp4920_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg5() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg6(suite) ->
+ [];
+compact_otp4920_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg6() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg7(suite) ->
+ [];
+compact_otp4920_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg7() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg8(suite) ->
+ [];
+compact_otp4920_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg8() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg9(suite) ->
+ [];
+compact_otp4920_msg9(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg9 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg9() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg10(suite) ->
+ [];
+compact_otp4920_msg10(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg10 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg10() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg11(suite) ->
+ [];
+compact_otp4920_msg11(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg11 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg11() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp4920_msg12(suite) ->
+ [];
+compact_otp4920_msg12(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg12 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp4920_msg12() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Duplicate padding
+compact_otp4920_msg20(suite) ->
+ [];
+compact_otp4920_msg20(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg20 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg20(), bad_mid_duplicate_padding),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg21(suite) ->
+ [];
+compact_otp4920_msg21(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg21 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg21(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg22(suite) ->
+ [];
+compact_otp4920_msg22(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg22 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg22(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg23(suite) ->
+ [];
+compact_otp4920_msg23(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg23 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg23(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg24(suite) ->
+ [];
+compact_otp4920_msg24(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg24 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg24(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% Length
+compact_otp4920_msg25(suite) ->
+ [];
+compact_otp4920_msg25(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp4920_msg25 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp4920(compact_otp4920_msg25(), bad_mid_ip6addr_length),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+compact_otp4920(Msg, ExpectedReason) ->
+ compact_otp4920(Msg, ?EC, ExpectedReason).
+
+compact_otp4920(Msg, Conf, ExpectedReason) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(Reason) when is_list(Reason) ->
+ compact_otp4920_chk(Reason, ExpectedReason);
+ (Crap) ->
+ {error, {unexpected_decode_result, Crap}}
+ end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+compact_otp4920_chk(Reason, ExpectedReason) ->
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {__Line, _Mod, ActualReason}}} ->
+ case element(1, ActualReason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ {error, {unexpected_decode_reason,
+ {ActualReason, ExpectedReason}}}
+ end;
+ {value, {reason, {_Mod, ActualReason}}} ->
+ case element(1, ActualReason) of
+ ExpectedReason ->
+ ok;
+ _ ->
+ {error, {unexpected_decode_reason,
+ {ActualReason, ExpectedReason}}}
+ end;
+ {value, UnknownReason} ->
+ {error, {unexpected_decode_reason, UnknownReason}};
+ false ->
+ {error, {reason_not_found, Reason}}
+ end.
+
+compact_otp4920_msg0() ->
+ M = "!/" ?VERSION_STR " [192.168.30.1]\nT=100{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg1() ->
+ M = "!/" ?VERSION_STR " [2031:0000:130F:0000:0000:09C0:876A:130B]\nT=101{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg2() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:876A:130B]\nT=102{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg3() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:876A:130B]\nT=103{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg4() ->
+ M = "!/" ?VERSION_STR " [::1]\nT=104{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg5() ->
+ M = "!/" ?VERSION_STR " [::]\nT=105{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg6() ->
+ M = "!/" ?VERSION_STR " [1::]\nT=106{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg7() ->
+ M = "!/" ?VERSION_STR " [FEDC:1::]\nT=107{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg8() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F:0:0:9C0:135.106.19.11]\nT=108{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg9() ->
+ M = "!/" ?VERSION_STR " [2031:0:130F::9C0:135.106.19.11]\nT=109{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg10() ->
+ M = "!/" ?VERSION_STR " [::FFFF:192.168.30.1]\nT=110{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg11() ->
+ M = "!/" ?VERSION_STR " [::192.168.30.1]\nT=111{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+compact_otp4920_msg12() ->
+ M = "!/" ?VERSION_STR " [::C0A8:1E01]\nT=112{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: only one :: allowed
+compact_otp4920_msg20() ->
+ M = "!/" ?VERSION_STR " [2031::130F::9C0]\nT=120{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg21() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:0000:0000:09C0:876A:130B]\nT=121{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg22() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0:130F:0:0:9C0:135.106.19.11]\nT=122{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg23() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354::09C0:876A:130B]\nT=123{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg24() ->
+ M = "!/" ?VERSION_STR " [::2031:FFEE:0000:130F:2132:4354:09C0:876A:130B]\nT=124{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+%% Illegal: length
+compact_otp4920_msg25() ->
+ M = "!/" ?VERSION_STR " [2031:FFEE:0000:130F:2132:4354:09C0:876A:130B::]\nT=125{C=${A=${M{O{MO=SR,RG=OFF,RV=OFF}}}}}",
+ M.
+
+
+%% --------------------------------------------------------------
+%%
+
+compact_otp5186_msg01(suite) ->
+ [];
+compact_otp5186_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_error( compact_otp5186_msg01() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg02(suite) ->
+ [];
+compact_otp5186_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_decode_encode_ok( compact_otp5186_msg02() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg03(suite) ->
+ [];
+compact_otp5186_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg03(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg03() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg04(suite) ->
+ [];
+compact_otp5186_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg04(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg04() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg05(suite) ->
+ [];
+compact_otp5186_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg05(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg05() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5186_msg06(suite) ->
+ [];
+compact_otp5186_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5186_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ %% ok = compact_otp5186_msg_2(compact_otp5186_msg06(), ok, ok),
+ ok = ticket_compact_encode_decode_ok( compact_otp5186_msg06() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+%% --
+
+compact_otp5186_msg01() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001{}}}".
+
+compact_otp5186_msg02() ->
+ "!/" ?VERSION_STR " <mg5>\nP=67111298{C=2699{AV=mg5_ipeph/0x0f0001}}".
+
+compact_otp5186_msg03() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg04() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]},
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg05() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+compact_otp5186_msg06() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,{domainName,{'DomainName',"mg5",asn1_NOVALUE}},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',67111298,asn1_NOVALUE,
+ {actionReplies,[
+ {'ActionReply',2699,asn1_NOVALUE,asn1_NOVALUE,
+ [
+ {addReply,
+ {'AmmsReply',
+ [
+ {megaco_term_id,false,["mg5_ipeph","0x0f0001"]}
+ ],
+ [
+ {emptyDescriptors,
+ {'AuditDescriptor',asn1_NOVALUE,asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5793_msg01(suite) ->
+ [];
+compact_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok(pretty_otp5793_msg1()),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5836_msg01(suite) ->
+ [];
+compact_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok(compact_otp5836_msg1()),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+compact_otp5836_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"bs_sbg_4/34"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 12,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 4294967295,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {error, {'ErrorDescriptor', 431, asn1_NOVALUE}}}
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+
+compact_otp5993_msg01(suite) ->
+ [];
+compact_otp5993_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg01() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg01() ->
+ MT = h221,
+ T = #megaco_term_id{id = ?A4444},
+ TL = [T],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+
+compact_otp5993_msg02(suite) ->
+ [];
+compact_otp5993_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg02() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg02() ->
+ MT = h223,
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TL = [T1, T2],
+ MD = #'MuxDescriptor'{muxType = MT,
+ termList = TL},
+ compact_otp5993_msg(MD).
+
+
+compact_otp5993_msg03(suite) ->
+ [];
+compact_otp5993_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp5993_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_compact_encode_decode_ok( compact_otp5993_msg03() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp5993_msg03() ->
+ T1 = #megaco_term_id{id = ?A4445},
+ T2 = #megaco_term_id{id = ?A5556},
+ TIDs = [T1, T2],
+ AudRep = {contextAuditResult, TIDs},
+ CmdRep = {auditValueReply, AudRep},
+ ActRep = #'ActionReply'{contextId = 5993,
+ commandReply = [CmdRep]},
+ TransRes = {actionReplies, [ActRep]},
+ TransRep = #'TransactionReply'{transactionId = 3995,
+ transactionResult = TransRes},
+ Trans = {transactionReply, TransRep},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+compact_otp5993_msg(MD) when is_record(MD, 'MuxDescriptor') ->
+ AmmDesc = {muxDescriptor, MD},
+ AmmReq = #'AmmRequest'{terminationID = [hd(MD#'MuxDescriptor'.termList)],
+ descriptors = [AmmDesc]},
+ Cmd = {addReq, AmmReq},
+ CmdReq = #'CommandRequest'{command = Cmd},
+ ActReq = #'ActionRequest'{contextId = 5993,
+ commandRequests = [CmdReq]},
+ TransReq = #'TransactionRequest'{transactionId = 3995,
+ actions = [ActReq]},
+ Trans = {transactionRequest, TransReq},
+ Body = {transactions, [Trans]},
+ Msg = #'Message'{version = ?VERSION,
+ mId = ?MG1_MID,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Msg}.
+
+
+%% --------------------------------------------------------------
+
+compact_otp6017_msg01(suite) ->
+ [];
+compact_otp6017_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp6017_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(0),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp6017_msg02(suite) ->
+ [];
+compact_otp6017_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp6017_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFE),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp6017_msg03(suite) ->
+ [];
+compact_otp6017_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("compact_otp6017_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = compact_otp6017(16#FFFFFFFF),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+compact_otp6017(BadCID) ->
+ d("compact_otp6017 -> entry with"
+ "~n BadCID: ~p", [BadCID]),
+ Conf = ?EC,
+ M = compact_otp6017_msg(BadCID),
+ Bin = list_to_binary(M),
+ case decode_message(megaco_compact_text_encoder, false, Conf, Bin) of
+ {ok, Msg} ->
+ d("compact_otp6017 -> Msg: ~n~p", [Msg]),
+ exit({unexpected_decode_success, {Msg, M}});
+ {error, Reason} when is_list(Reason) -> % Expected result
+ case lists:keysearch(reason, 1, Reason) of
+ {value, {reason, {_Line, _Mod, {bad_ContextID, BadCID}}}} ->
+ io:format(" ~w", [BadCID]),
+ ok;
+ {value, {reason, ActualReason}} ->
+ d("compact_otp6017 -> wrong reason: ~n~p", [ActualReason]),
+ exit({unexpected_reason, ActualReason});
+ false ->
+ d("compact_otp6017 -> no reason: ~n~p", [Reason]),
+ exit({reason_not_found, Reason})
+ end;
+ Crap ->
+ d("compact_otp6017 -> unexpected decode result: ~n~p", [Crap]),
+ exit({unexpected_decode_result, Crap})
+ end.
+
+compact_otp6017_msg(CID) when is_integer(CID) ->
+ "!/" ?VERSION_STR " MG1 T=12345678{C=" ++
+ integer_to_list(CID) ++
+ "{SC=root{SV{MT=RS,RE=901}}}}".
+
+
+%% ==============================================================
+%%
+%% F l e x C o m p a c t T e s t c a s e s
+%%
+
+flex_compact_otp4299_msg1(suite) ->
+ [];
+flex_compact_otp4299_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp4299_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Msg = compact_otp4299_msg(),
+ Conf = flex_scanner_conf(Config),
+ ok = compact_otp4299(Msg, [?EC_V3,Conf]),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+flex_compact_otp7431_msg01(suite) ->
+ [];
+flex_compact_otp7431_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg01 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(ok, flex_compact_otp7431_msg1(), [Conf]).
+
+flex_compact_otp7431_msg02(suite) ->
+ [];
+flex_compact_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg02 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg2(), [Conf]).
+
+flex_compact_otp7431_msg03(suite) ->
+ [];
+flex_compact_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg03 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg3(), [Conf]).
+
+flex_compact_otp7431_msg04(suite) ->
+ [];
+flex_compact_otp7431_msg04(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg04 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg4(), [Conf]).
+
+flex_compact_otp7431_msg05(suite) ->
+ [];
+flex_compact_otp7431_msg05(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg05 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg5(), [Conf]).
+
+flex_compact_otp7431_msg06(suite) ->
+ [];
+flex_compact_otp7431_msg06(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg06 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg6(), [Conf]).
+
+flex_compact_otp7431_msg07(suite) ->
+ [];
+flex_compact_otp7431_msg07(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_comppact_otp7431_msg07 -> entry", []),
+ Conf = flex_scanner_conf(Config),
+ flex_compact_otp7431(error, flex_compact_otp7431_msg7(), [Conf]).
+
+
+flex_compact_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_compact_text_encoder, Msg, Conf).
+
+flex_compact_otp7431_msg1() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+}}}}}}".
+
+flex_compact_otp7431_msg2() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a= }
+}}}}}".
+
+
+flex_compact_otp7431_msg3() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a }
+}}}}}".
+
+
+flex_compact_otp7431_msg4() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a}
+}}}}}".
+
+
+flex_compact_otp7431_msg5() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v= }
+}}}}}".
+
+
+flex_compact_otp7431_msg6() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v }
+}}}}}".
+
+flex_compact_otp7431_msg7() ->
+ "!/1 [124.124.124.222]:55555
+P=10003{C=2000{A=a4444,A=a4445{M{ST=1{L{
+v}
+}}}}}".
+
+
+%% ==============================================================
+%%
+%% P r e t t y T e s t c a s e s
+%%
+
+pretty_otp4632_msg1(suite) ->
+ [];
+pretty_otp4632_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4632_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg1() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+
+pretty_otp4632_msg2(suite) ->
+ [];
+pretty_otp4632_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4632_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg2() ->
+ msg4(?MG1_MID_NO_PORT, "901").
+
+
+pretty_otp4632_msg3(suite) ->
+ [];
+pretty_otp4632_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp4632_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4632_msg3() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901\"\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+
+pretty_otp4632_msg4(suite) ->
+ [];
+pretty_otp4632_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4632_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(B2, B1) -> pretty_otp4632_msg4_chk(B1, B2) end,
+ ok = ticket_pretty_decode_encode_only(pretty_otp4632_msg4(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+pretty_otp4632_msg4() ->
+ M = "MEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = 901\n\t\t\t}\n\t\t}\n\t}\n}",
+ M.
+
+pretty_otp4632_msg4_chk(B1, B2) when is_binary(B1) and is_binary(B2) ->
+ S1 = binary_to_list(B1),
+ S2 = binary_to_list(B2),
+ %% io:format("~n"
+ %% "S1: ~s~n"
+ %% "S2: ~s~n", [S1, S2]),
+ pretty_otp4632_msg4_chk(S1, S2);
+
+pretty_otp4632_msg4_chk([], []) ->
+ messages_not_eq;
+pretty_otp4632_msg4_chk([], Rest2) ->
+ {messages_not_eq2, Rest2};
+pretty_otp4632_msg4_chk(Rest1, []) ->
+ {messages_not_eq1, Rest1};
+pretty_otp4632_msg4_chk([$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$",$9,$0,$1,$"|_Rest1],
+ [$R,$e,$a,$s,$o,$n,$ ,$=,$ ,$9,$0,$1|_Rest2]) ->
+ ok;
+pretty_otp4632_msg4_chk([_H1|Rest1], [_H2|Rest2]) ->
+ pretty_otp4632_msg4_chk(Rest1, Rest2).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4710_msg1(suite) ->
+ [];
+pretty_otp4710_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4710_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp4710_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4710_msg1() ->
+ msg40().
+
+
+pretty_otp4710_msg2(suite) ->
+ [];
+pretty_otp4710_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4710_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(B1, B2) -> pretty_otp4710_msg2_chk(B1, B2) end,
+ ok = ticket_pretty_decode_encode_only(pretty_otp4710_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4710_msg2() ->
+ "Authentication = 0xEFCDAB89:0x12345678:0x1234567889ABCDEF76543210\nMEGACO/" ?VERSION_STR " [124.124.124.222]\nTransaction = 9998 {\n\tContext = - {\n\t\tServiceChange = root {\n\t\t\tServices {\n\t\t\t\tMethod = Restart,\n\t\t\t\tServiceChangeAddress = 55555,\n\t\t\t\tProfile = resgw/1,\n\t\t\t\tReason = \"901 mg col boot\"\n\t\t\t}\n\t\t}\n\t}\n}".
+
+pretty_otp4710_msg2_chk(B1, B2) when is_binary(B1) and is_binary(B2) ->
+ S1 = binary_to_list(B1),
+ S2 = binary_to_list(B2),
+ pretty_otp4710_msg2_chk(S1, S2);
+
+pretty_otp4710_msg2_chk(Msg, Msg) ->
+ ok;
+
+pretty_otp4710_msg2_chk(
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg0],
+ [$A,$u,$t,$h,$e,$n,$t,$i,$c,$a,$t,$i,$o,$n,$=,$ |Msg1]) ->
+ {AH0, Rest0} = pretty_otp4710_msg2_chk_ah(Msg0, []),
+ {AH1, Rest1} = pretty_otp4710_msg2_chk_ah(Msg1, []),
+ case AH0 == AH1 of
+ true ->
+ exit({message_not_equal, Rest0, Rest1});
+ false ->
+ exit({auth_header_not_equal, AH0, AH1})
+ end.
+
+pretty_otp4710_msg2_chk_ah([], _Acc) ->
+ exit(no_auth_header_found);
+pretty_otp4710_msg2_chk_ah([$M,$E,$G,$A,$C,$O,$/,_|Rest], Acc) ->
+ {lists:reverse(Acc), Rest};
+pretty_otp4710_msg2_chk_ah([C|R], Acc) ->
+ pretty_otp4710_msg2_chk_ah(R, [C|Acc]).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4945_msg1(suite) ->
+ [];
+pretty_otp4945_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg1_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg1(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg1_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeReason],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg2(suite) ->
+ [];
+pretty_otp4945_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg2_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg2_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeMethod],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg3(suite) ->
+ [];
+pretty_otp4945_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg3_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg3(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg3_chk(R) when is_list(R) ->
+ ExpMissing = [serviceChangeReason, serviceChangeMethod],
+ Check = fun(Reason) ->
+ pretty_otp4945_chk(Reason, ExpMissing)
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg4(suite) ->
+ [];
+pretty_otp4945_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp4945_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4945_msg5(suite) ->
+ [];
+pretty_otp4945_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg5_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg5(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg5() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg5_chk(R) when is_list(R) ->
+ Check = fun({at_most_once_serviceChangeParm, {profile, _, _}}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_msg6(suite) ->
+ [];
+pretty_otp4945_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4945_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4945_msg6_chk(R) end,
+ ok = ticket_pretty_decode_error(pretty_otp4945_msg6(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4945_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4945_msg6_chk(R) when is_list(R) ->
+ Check = fun({not_both_address_mgcid_serviceChangeParm, _, _}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4945_chk({missing_required_serviceChangeParm, Missing},
+ ExpMissing) when is_list(Missing) ->
+ case ExpMissing -- Missing of
+ [] ->
+ ok;
+ Diff ->
+ {error, {unexpected_missing_serviceChangeParm, Diff}}
+ end;
+pretty_otp4945_chk(Reason, _ExpMissing) ->
+ {error, {unexpected_reason, Reason}}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp4949_msg1(suite) ->
+ [];
+pretty_otp4949_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp4949_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+pretty_otp4949_msg2(suite) ->
+ [];
+pretty_otp4949_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4949_msg2_chk(R) end,
+ ok = ticket_pretty_decode_error( pretty_otp4949_msg2(), Check),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg2() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Profile = ResGW/1,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/2
+ }
+ }
+ }
+}".
+
+pretty_otp4949_msg2_chk(R) when is_list(R) ->
+ Check = fun({at_most_once_servChgReplyParm, {profile, _, _}}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+pretty_otp4949_msg3(suite) ->
+ [];
+pretty_otp4949_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp4949_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp4949_msg3_chk(R) end,
+ ok = ticket_pretty_decode_error( pretty_otp4949_msg3(), Check ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp4949_msg3() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ MgcIdToTry = kalle,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+pretty_otp4949_msg3_chk(R) when is_list(R) ->
+ Check = fun({not_both_address_mgcid_servChgReplyParm, _, _}) ->
+ ok;
+ (Reason) ->
+ {error, {unexpected_reason, Reason}}
+ end,
+ ticket_check_decode_only_error_reason(R, Check).
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5042_msg1(suite) ->
+ [];
+pretty_otp5042_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp5042_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5042_msg1() ->
+"MEGACO/" ?VERSION_STR " <CATAPULT>:2944
+Transaction = 102 {
+Context = 5 { Notify = MUX/1 { ObservedEvents = 1 {
+h245bh/h245msgin { Stream = 1
+, h245enc =
+0270020600088175000653401004100403E802E00180018001780680000034301160000700088175010101007A0100020001800001320000C0000219D005027F0070500100040100021080000319D005027F00504001008000041C001250000700088175010000400280010003000880000518AA027F400006850130008011020100000001030002000300040005000006
+ } }
+ } } }".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5068_msg1(suite) ->
+ [];
+pretty_otp5068_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5068_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_only( pretty_otp5068_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5068_msg1() ->
+{'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,[109,103,51,51]},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 190,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply', %% Comments: Detta upprepas m�nga g�nger
+ 0,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {auditResult,
+ {'AuditResult',
+ {megaco_term_id,false,
+ [[99,101,100,101,118,49,47,52,47,49,47,49],[51,49]]},
+ [{mediaDescriptor,
+ {'MediaDescriptor',
+ {'TerminationStateDescriptor',
+ [],
+ asn1_NOVALUE,
+ inSvc},
+ asn1_NOVALUE}
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+}.
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5085_msg1(suite) ->
+ [];
+pretty_otp5085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg1() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg2(suite) ->
+ [];
+pretty_otp5085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg2() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg3(suite) ->
+ [];
+pretty_otp5085_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg3() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg3() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 3},
+ []
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg4(suite) ->
+ [];
+pretty_otp5085_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg4() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg4() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg5(suite) ->
+ [];
+pretty_otp5085_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg5() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg5() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"mg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ asn1_NOVALUE,
+ #'ContextRequest'{priority = 5},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg6(suite) ->
+ [];
+pretty_otp5085_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg6() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg6() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 6},
+ [{addReply, cre_AmmsReply([#megaco_term_id{id = ?A4444}])},
+ {notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg7(suite) ->
+ [];
+pretty_otp5085_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg7() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg7() ->
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 7},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+pretty_otp5085_msg8(suite) ->
+ [];
+pretty_otp5085_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg8() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5085_msg8() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ {'MegacoMessage',
+ asn1_NOVALUE,
+ {'Message',
+ ?VERSION,
+ {deviceName,"msg36"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 230,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 400,
+ {'ErrorDescriptor',504,asn1_NOVALUE},
+ #'ContextRequest'{priority = 8,
+ emergency = true,
+ topologyReq =
+ [#'TopologyRequest'{terminationFrom = From1,
+ terminationTo = To1,
+ topologyDirection = bothway},
+ #'TopologyRequest'{terminationFrom = From2,
+ terminationTo = To2,
+ topologyDirection = oneway}
+ ],
+ iepscallind = true,
+ contextProp = [cre_PropParm("tdmc/gain", "2")]},
+ [{notifyReply, cre_NotifyRep([#megaco_term_id{id = ?A5555}])}]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5600_msg1(suite) ->
+ [];
+pretty_otp5600_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5600_msg1() ->
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ RA = #'RequestedActions'{ secondEvent = SED,
+ signalsDescriptor = [ SIG ] },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+pretty_otp5600_msg2(suite) ->
+ [];
+pretty_otp5600_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5600_msg2() ->
+ SIG = { signal, #'Signal'{ signalName = "cg/dt",
+ sigParList = [] } },
+
+ SRA = #'SecondRequestedActions'{ signalsDescriptor = [ SIG ] },
+
+ SRE = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5601_msg1(suite) ->
+ [];
+pretty_otp5601_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5601_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5601_msg1() ->
+ SRE1 = #'SecondRequestedEvent'{ pkgdName = "al/on",
+ evParList = [] },
+
+ SRA = #'SecondRequestedActions'{ eventDM = { digitMapName, "dialllan0" }},
+
+ SRE2 = #'SecondRequestedEvent'{ pkgdName = "dd/ce",
+ eventAction = SRA,
+ evParList = [] },
+
+ SED = #'SecondEventsDescriptor'{ requestID = 2,
+ eventList = [ SRE1, SRE2 ] },
+
+ RA = #'RequestedActions'{ secondEvent = SED },
+
+ RE = #'RequestedEvent'{ pkgdName = "al/of",
+ eventAction = RA,
+ evParList = [] },
+
+ EV = #'EventsDescriptor'{ requestID = 1, eventList = [ RE ] },
+
+ TermID = {megaco_term_id, true, [[$*]] },
+
+ AMMR = #'AmmRequest'{ terminationID = [ TermID ],
+ descriptors = [ { eventsDescriptor, EV } ] },
+
+ CR = #'CommandRequest'{command = {modReq, AMMR}},
+
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ ARs = [AR],
+ TR = #'TransactionRequest'{transactionId = 5600, actions = ARs},
+ TRs = [{transactionRequest, TR}],
+ Mess = #'Message'{version = ?VERSION,
+ mId = ?MGC_MID,
+ messageBody = {transactions, TRs}},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5793_msg01(suite) ->
+ [];
+pretty_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5793_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5793_msg1() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',3,
+ {deviceName,"bs_sbg_4/99"},
+ {transactions,
+ [{transactionReply,
+ {'TransactionReply',
+ 370,
+ asn1_NOVALUE,
+ {actionReplies,
+ [{'ActionReply',
+ 3,
+ asn1_NOVALUE,
+ asn1_NOVALUE,
+ [{auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "1",
+ "18"]}]}},
+ {auditValueReply,
+ {contextAuditResult,
+ [{megaco_term_id,
+ false,
+ ["ip",
+ "104",
+ "2",
+ "19"]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },asn1_NOVALUE,asn1_NOVALUE
+ }
+ }
+ ]
+ }
+ }
+ }.
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5803_msg01(suite) ->
+ [];
+pretty_otp5803_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5803_msg1() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ },
+ Stream=2{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+pretty_otp5803_msg02(suite) ->
+ [];
+pretty_otp5803_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg2() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5803_msg2() ->
+"MEGACO/" ?VERSION_STR " [134.138.234.29]Transaction=384{
+ Context=27{
+ Modify=ip/104/1/76{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ },
+ Audit{
+ Media{
+ Stream=1{
+ Statistics{*/*}
+ }
+ }
+ }
+ },
+ Modify=ip/104/2/77{
+ Media{
+ Stream=1{
+ Local{},
+ Remote{}
+ },
+ Stream=2{
+ Local{},
+ Remote{}
+ }
+ }
+ }
+ }
+}".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5805_msg01(suite) ->
+ [];
+pretty_otp5805_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_error( pretty_otp5805_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5805_msg1() ->
+"MEGACO/4 [134.138.234.29]
+Transaction=1{
+ Context=*{
+ AuditValue=ip/0/*{
+ Audit{}
+ }
+ }
+}".
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5836_msg01(suite) ->
+ [];
+pretty_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( compact_otp5836_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp5882_msg01(suite) ->
+ [];
+pretty_otp5882_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("pretty_otp5882_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Check = fun(R) -> pretty_otp5882_msg01_chk(R) end,
+ ok = ticket_pretty_encode_error( pretty_otp5882_msg01(), Check ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp5882_msg01_chk({message_encode_failed, {error, {Reason, _}}, _}) ->
+ case Reason of
+ {invalid_LocalControlDescriptor, empty} ->
+ ok;
+ _ ->
+ {error, {unexpected_error_actual_reason, Reason}}
+ end;
+pretty_otp5882_msg01_chk(Reason) ->
+ {error, {unexpected_reason, Reason}}.
+
+
+pretty_otp5882_msg01() ->
+ LCD = #'LocalControlDescriptor'{}, % Create illegal LCD
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% --------------------------------------------------------------
+%%
+pretty_otp6490_msg01(suite) ->
+ [];
+pretty_otp6490_msg01(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg01(), [] ),
+ %% erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp6490_msg02(suite) ->
+ [];
+pretty_otp6490_msg02(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg02(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg03(suite) ->
+ [];
+pretty_otp6490_msg03(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg03(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg04(suite) ->
+ [];
+pretty_otp6490_msg04(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg04(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg05(suite) ->
+ [];
+pretty_otp6490_msg05(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg05 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg05(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg06(suite) ->
+ [];
+pretty_otp6490_msg06(Config) when is_list(Config) ->
+ %% put(severity, trc),
+ %% put(dbg, true),
+ d("pretty_otp6490_msg06 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp6490_msg06(), [] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+pretty_otp6490_msg(EBD) ->
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(EBD),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}], [AmmDesc]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ CID = cre_CtxID(64901),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(64902),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+pretty_otp6490_msg01() ->
+ EvSpecs = [], % This will result in an error
+ EBD = EvSpecs, % This is because the lib checks that the size is valid
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg02() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg03() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar1,EvPar2,EvPar3]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg04() ->
+ EvPar1 = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ EvPar2 = ?MSG_LIB:cre_EventParameter("kalle", ["anka"]),
+ EvPar3 = ?MSG_LIB:cre_EventParameter("flippa", ["ur"]),
+ PkgdName1 = ?MSG_LIB:cre_PkgdName("foo", "a"),
+ EvName1 = ?MSG_LIB:cre_EventName(PkgdName1),
+ EvSpec1 = ?MSG_LIB:cre_EventSpec(EvName1, [EvPar1,EvPar2,EvPar3]),
+ EvPar4 = ?MSG_LIB:cre_EventParameter("hej", ["hopp"]),
+ PkgdName2 = ?MSG_LIB:cre_PkgdName("bar", "b"),
+ EvName2 = ?MSG_LIB:cre_EventName(PkgdName2),
+ EvSpec2 = ?MSG_LIB:cre_EventSpec(EvName2, [EvPar4]),
+ EvSpecs = [EvSpec1,EvSpec2],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg05() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName("foo", root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+pretty_otp6490_msg06() ->
+ EvPar = ?MSG_LIB:cre_EventParameter("sune", ["mangs"]),
+ PkgdName = ?MSG_LIB:cre_PkgdName(root, root),
+ EvName = ?MSG_LIB:cre_EventName(PkgdName),
+ EvSpec = ?MSG_LIB:cre_EventSpec(EvName, [EvPar]),
+ EvSpecs = [EvSpec],
+ EBD = ?MSG_LIB:cre_EventBufferDescriptor(EvSpecs),
+ pretty_otp6490_msg(EBD).
+
+
+%% --------------------------------------------------------------
+%%
+
+pretty_otp7671_msg01(suite) ->
+ [];
+pretty_otp7671_msg01(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg01 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg01(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg02(suite) ->
+ [];
+pretty_otp7671_msg02(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg02 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg02(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg03(suite) ->
+ [];
+pretty_otp7671_msg03(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg03 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg03(), [] ),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg04(suite) ->
+ [];
+pretty_otp7671_msg04(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg04 -> entry", []),
+ %% ?ACQUIRE_NODES(1, Config),
+ ok = pretty_otp7671( pretty_otp7671_msg04(), [] , error, ignore),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671_msg05(suite) ->
+ [];
+pretty_otp7671_msg05(Config) when is_list(Config) ->
+%% put(severity, trc),
+%% put(dbg, true),
+ d("pretty_otp7671_msg05 -> entry", []),
+ Check = fun(M1, M2) -> cmp_otp7671_msg05(M1, M2) end,
+ ok = pretty_otp7671( pretty_otp7671_msg05(), [] , ok, ok, Check),
+%% erase(dbg),
+%% erase(severity),
+ ok.
+
+pretty_otp7671(Msg, Conf) ->
+ pretty_otp7671(Msg, Conf, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode) ->
+ pretty_otp7671(Msg, Conf, ExpectedEncode, ok).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode).
+
+pretty_otp7671(Msg, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ otp7671(Msg, megaco_pretty_text_encoder, Conf,
+ ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode) ->
+ Check = fun(M1, M2) ->
+ exit({unexpected_decode_result, M1, M2})
+ end,
+ otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check).
+
+otp7671(Msg, Codec, Conf, ExpectedEncode, ExpectedDecode, Check) ->
+ case (catch encode_message(Codec, Conf, Msg)) of
+ {error, _Reason} when ExpectedEncode =:= error ->
+ ok;
+ {error, Reason} when ExpectedEncode =:= ok ->
+ exit({unexpected_encode_failure, Reason});
+ {ok, Bin} when ExpectedEncode =:= error ->
+ exit({unexpected_encode_success, Msg, binary_to_list(Bin)});
+ {ok, Bin} when ExpectedEncode =:= ok ->
+ case decode_message(Codec, false, Conf, Bin) of
+ {ok, Msg} when ExpectedDecode =:= ok ->
+ ok;
+ {ok, Msg2} when ExpectedDecode =:= ok ->
+ Check(Msg, Msg2);
+ {ok, Msg} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg});
+ {ok, Msg2} when ExpectedDecode =:= error ->
+ exit({unexpected_decode_success, Msg, Msg2});
+ {error, _Reason} when ExpectedDecode =:= error ->
+ ok;
+ {error, Reason} when ExpectedDecode == ok ->
+ exit({unexpected_decode_failure, Msg, Reason})
+ end
+ end.
+
+
+pretty_otp7671_msg(DigitMapDesc) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{digitMapDescriptor, DigitMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MGC_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+pretty_otp7671_msg01() ->
+ Name = "dialplan01",
+ DigitMapDesc = cre_DigitMapDesc(Name),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg02() ->
+ Name = "dialplan02",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Name, Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg03() ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ DigitMapDesc = cre_DigitMapDesc(Value),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg04() ->
+ DigitMapDesc = cre_DigitMapDesc(),
+ pretty_otp7671_msg(DigitMapDesc).
+
+pretty_otp7671_msg05() ->
+ {'MegacoMessage',asn1_NOVALUE,
+ {'Message',?VERSION,
+ {domainName,{'DomainName',"tgc",asn1_NOVALUE}},
+ {transactions,
+ [{transactionRequest,
+ {'TransactionRequest',12582952,
+ [{'ActionRequest',0,asn1_NOVALUE,asn1_NOVALUE,
+ [{'CommandRequest',
+ {modReq,
+ {'AmmRequest',
+ [{megaco_term_id,false,["root"]}],
+ [{digitMapDescriptor,
+ {'DigitMapDescriptor',"dialplan1",
+ {'DigitMapValue',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,[],
+ asn1_NOVALUE}}}]}},
+ asn1_NOVALUE,asn1_NOVALUE}]}]}}]}}}.
+
+cmp_otp7671_msg05(#'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M1},
+ #'MegacoMessage'{authHeader = asn1_NOVALUE,
+ mess = M2}) ->
+ #'Message'{messageBody = Body1} = M1,
+ #'Message'{messageBody = Body2} = M2,
+ {transactions, Trans1} = Body1,
+ {transactions, Trans2} = Body2,
+ [{transactionRequest, TR1}] = Trans1,
+ [{transactionRequest, TR2}] = Trans2,
+ #'TransactionRequest'{actions = Acts1} = TR1,
+ #'TransactionRequest'{actions = Acts2} = TR2,
+ [#'ActionRequest'{commandRequests = CR1}] = Acts1,
+ [#'ActionRequest'{commandRequests = CR2}] = Acts2,
+ [#'CommandRequest'{command = Cmd1}] = CR1,
+ [#'CommandRequest'{command = Cmd2}] = CR2,
+ {modReq, #'AmmRequest'{descriptors = Descs1}} = Cmd1,
+ {modReq, #'AmmRequest'{descriptors = Descs2}} = Cmd2,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value1}}] = Descs1,
+ [{digitMapDescriptor,
+ #'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Value2}}] = Descs2,
+ #'DigitMapValue'{startTimer = asn1_NOVALUE,
+ shortTimer = asn1_NOVALUE,
+ longTimer = asn1_NOVALUE,
+ digitMapBody = [],
+ durationTimer = asn1_NOVALUE} = Value1,
+ asn1_NOVALUE = Value2,
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+
+
+pretty_otp8114_msg01(suite) ->
+ [];
+pretty_otp8114_msg01(Config) when is_list(Config) ->
+ put(severity, trc),
+ put(dbg, true),
+ d("pretty_otp8114_msg01 -> entry", []),
+ ok = otp8114( pretty_otp8114_msg01(), megaco_pretty_text_encoder, ?EC),
+ erase(dbg),
+ erase(severity),
+ ok.
+
+pretty_otp8114_msg01() ->
+ "MEGACO/" ?VERSION_STR " [10.10.10.10]:1234\nTransaction = 1 {\n\tContext =\n1 {\n\t\tModify = ip/1/1/1 {\n\t\t\tMedia {\n\t\t\t\tStream = 1\n{\n\t\t\t\t\t\tLocalControl {\n\t\t\t\t\t\tMode =\nSendReceive\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tEvents = 1\n{\n\t\t\t\tadid/ipstop\n{\n\t\t\t\t\tdt=30,\n\t\t\t\t\tdir=\"BOTH\"\n\t\t\t\t},\n\t\t\t\tg/cause\n\n\t\t\t}\n\t\t}\n\t}\n}".
+
+
+otp8114(InitialMessage, Codec, Conf) ->
+ Decode = fun(M) -> Codec:decode_message(Conf, M) end,
+ Encode = fun(B) -> Codec:encode_message(Conf, B) end,
+ InitialData = InitialMessage,
+ Instructions =
+ [
+ %% List to binary
+ megaco_codec_test_lib:expect_instruction(
+ "Convert (initial) message to a binary",
+ fun(Msg) when is_list(Msg) ->
+ %% io:format("~s~n", [Msg]),
+ {ok, list_to_binary(Msg)};
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ {ok, Bin};
+ (Bad, _Msg) ->
+ {error, {failed_to_binary, Bad}}
+ end),
+
+ %% Initial decode
+ megaco_codec_test_lib:expect_instruction(
+ "Decode (initial) message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {initial_decode_failed, Bad}}
+ end),
+
+ %% Encode
+ megaco_codec_test_lib:expect_instruction(
+ "Encode message",
+ fun(Msg) when is_record(Msg, 'MegacoMessage') ->
+ (catch Encode(Msg));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Bin}, _Msg) when is_binary(Bin) ->
+ %% io:format("~s~n", [binary_to_list(Bin)]),
+ {ok, Bin};
+ (Bad, _) ->
+ {error, {encode_failed, Bad}}
+ end),
+
+ %% Decode
+ megaco_codec_test_lib:expect_instruction(
+ "(final) Decode message",
+ fun(Bin) when is_binary(Bin) ->
+ (catch Decode(Bin));
+ (Bad) ->
+ {error, {invalid_data, Bad}}
+ end,
+ fun({ok, Msg}, _Bin) when is_record(Msg, 'MegacoMessage') ->
+ %% io:format("~p~n", [Msg]),
+ {ok, Msg};
+ (Bad, _) ->
+ {error, {decode_failed, Bad}}
+ end)
+ ],
+ megaco_codec_test_lib:expect_exec(Instructions, InitialData).
+
+
+%% ==============================================================
+%%
+%% F l e x P r e t t y T e s t c a s e s
+%%
+
+flex_pretty_otp5042_msg1(suite) ->
+ [];
+flex_pretty_otp5042_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5042_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ ok = ticket_pretty_decode_only( pretty_otp5042_msg1() ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5085_msg1(suite) ->
+ [];
+flex_pretty_otp5085_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg2(suite) ->
+ [];
+flex_pretty_otp5085_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg3(suite) ->
+ [];
+flex_pretty_otp5085_msg3(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg3 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg4(suite) ->
+ [];
+flex_pretty_otp5085_msg4(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg4 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg5(suite) ->
+ [];
+flex_pretty_otp5085_msg5(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg5 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg6(suite) ->
+ [];
+flex_pretty_otp5085_msg6(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg6 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg7(suite) ->
+ [];
+flex_pretty_otp5085_msg7(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg7 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5085_msg8(suite) ->
+ [];
+flex_pretty_otp5085_msg8(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5085_msg8 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5085_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5600_msg1(suite) ->
+ [];
+flex_pretty_otp5600_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5600_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5600_msg2(suite) ->
+ [];
+flex_pretty_otp5600_msg2(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5600_msg2 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5600_msg2(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5601_msg1(suite) ->
+ [];
+flex_pretty_otp5601_msg1(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5601_msg1 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5601_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5793_msg01(suite) ->
+ [];
+flex_pretty_otp5793_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5793_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( pretty_otp5793_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5803_msg01(suite) ->
+ [];
+flex_pretty_otp5803_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5803_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+flex_pretty_otp5803_msg02(suite) ->
+ [];
+flex_pretty_otp5803_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5803_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_encode_ok( pretty_otp5803_msg2(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5805_msg01(suite) ->
+ [];
+flex_pretty_otp5805_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5805_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_decode_error( pretty_otp5805_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+%% --------------------------------------------------------------
+%%
+flex_pretty_otp5836_msg01(suite) ->
+ [];
+flex_pretty_otp5836_msg01(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp5836_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ ok = ticket_pretty_encode_decode_ok( compact_otp5836_msg1(), [Conf] ),
+ %% erase(severity),
+ %% erase(dbg),
+ ok.
+
+
+flex_pretty_otp7431_msg01(suite) ->
+ [];
+flex_pretty_otp7431_msg01(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg01 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(ok, flex_pretty_otp7431_msg1(), [Conf]).
+
+flex_pretty_otp7431_msg02(suite) ->
+ [];
+flex_pretty_otp7431_msg02(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg02 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg2(), [Conf]).
+
+flex_pretty_otp7431_msg03(suite) ->
+ [];
+flex_pretty_otp7431_msg03(Config) when is_list(Config) ->
+ %% put(severity,trc),
+ %% put(dbg,true),
+ d("flex_pretty_otp7431_msg03 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg3(), [Conf]).
+
+flex_pretty_otp7431_msg04(suite) ->
+ [];
+flex_pretty_otp7431_msg04(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg04 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg4(), [Conf]).
+
+flex_pretty_otp7431_msg05(suite) ->
+ [];
+flex_pretty_otp7431_msg05(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg05 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg5(), [Conf]).
+
+flex_pretty_otp7431_msg06(suite) ->
+ [];
+flex_pretty_otp7431_msg06(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg06 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg6(), [Conf]).
+
+flex_pretty_otp7431_msg07(suite) ->
+ [];
+flex_pretty_otp7431_msg07(Config) when is_list(Config) ->
+ d("flex_pretty_otp7431_msg07 -> entry", []),
+ ?ACQUIRE_NODES(1, Config),
+ Conf = flex_scanner_conf(Config),
+ flex_pretty_otp7431(error, flex_pretty_otp7431_msg7(), [Conf]).
+
+flex_pretty_otp7431(Expected, Msg, Conf) ->
+ otp7431(Expected, megaco_pretty_text_encoder, Msg, Conf).
+
+otp7431(Expected, Codec, Msg0, Conf0) ->
+ Bin0 = list_to_binary(Msg0),
+ Conf = [?EC_V3|Conf0],
+ case decode_message(Codec, false, Conf, Bin0) of
+ {ok, _Msg1} when Expected =:= ok ->
+ io:format(" decoded", []);
+ {error, {bad_property_parm, Reason}} when (Expected =:= error) andalso
+ is_list(Reason) ->
+ io:format("expected result: ~s", [Reason]),
+ ok;
+ Else ->
+ io:format("unexpected result", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+flex_pretty_otp7431_msg1() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg2() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg3() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg4() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0
+ o=- 2890844526 2890842807 IN IP4 124.124.124.222
+ s=-
+ t= 0 0
+ c=IN IP4 124.124.124.222
+ m=audio 2222 RTP/AVP 4
+ a=ptime:30
+ a}
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg5() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v= }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg6() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v }
+ }
+ }
+ }
+ }
+ }".
+
+flex_pretty_otp7431_msg7() ->
+ "MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+ v}
+ }
+ }
+ }
+ }
+ }".
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msgs() ->
+ [M || {_, M, _, _} <- msgs(text)].
+
+msgs(Encoding) ->
+ msgs1a(Encoding) ++
+ msgs1b(Encoding) ++
+ msgs3525(Encoding) ++
+ msgs5(Encoding) ++
+ msgs6(Encoding) ++
+ msgs7(Encoding) ++
+ msgs8(Encoding).
+
+msgs1a(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg01a, msg1a(), Plain, [{dbg,false}]},
+ {msg01b, msg1b(), Plain, [{dbg,false}]},
+ {msg02, msg2(), Plain, [{dbg,false}]},
+ {msg03, msg3(), Plain, [{dbg,false}]},
+ {msg04, msg4(), Plain, [{dbg,false}]},
+ {msg05, msg5(), Plain, [{dbg,false}]},
+ {msg06a, msg6a(), Plain, [{dbg,false}]},
+ {msg06b, msg6b(), Plain, [{dbg,false}]},
+ {msg07, msg7(), Plain, [{dbg,false}]},
+ {msg08a, msg8a(), Plain, [{dbg,false}]},
+ {msg08b, msg8b(), Plain, [{dbg,false}]},
+ {msg09, msg9(), Plain, [{dbg,false}]},
+ {msg10, msg10(), Plain, [{dbg,false}]},
+ {msg11, msg11(), Plain, [{dbg,false}]},
+ {msg12, msg12(), Plain, [{dbg,false}]},
+ {msg13, msg13(), Plain, [{dbg,false}]},
+ {msg14, msg14(), Plain, [{dbg,false}]},
+ {msg15, msg15(), Plain, [{dbg,false}]},
+ {msg16, msg16(), Plain, [{dbg,false}]},
+ {msg17, msg17(), Plain, [{dbg,false}]},
+ {msg18, msg18(), Plain, [{dbg,false}]},
+ {msg19, msg19(), Plain, [{dbg,false}]},
+ {msg20, msg20(), Plain, [{dbg,false}]},
+ {msg21, msg21(), Plain, [{dbg,false}]},
+ {msg22a, msg22a(), Plain, [{dbg,false}]},
+ {msg22b, msg22b(), Plain, [{dbg,false}]},
+ {msg22c, msg22c(), Plain, [{dbg,false}]},
+ {msg22d, msg22d(), Plain, [{dbg,false}]},
+ {msg22e, msg22e(), Plain, [{dbg,false}]},
+ {msg22f, msg22f(), Plain, [{dbg,false}]},
+ {msg23a, msg23a(), Plain, [{dbg,false}]},
+ {msg23b, msg23b(), Plain, [{dbg,false}]},
+ {msg23c, msg23c(), Plain, [{dbg,false}]},
+ {msg23d, msg23d(), Plain, [{dbg,false}]},
+ {msg24, msg24(), Plain, [{dbg,false}]},
+ {msg25, msg25(), Plain, [{dbg,false}]},
+ {msg30a, msg30a(), Plain, [{dbg,false}]},
+ {msg30b, msg30b(), Plain, [{dbg,false}]},
+ {msg30c, msg30c(), Plain, [{dbg,false}]},
+ {msg30d, msg30d(), Plain, [{dbg,false}]}
+ ].
+
+
+msgs1b(_) ->
+ TransFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:trans_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionsFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:actions_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ ActionFirst =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:action_first_encode_decode(Codec, DD,
+ Ver, EC, M)
+ end,
+ [
+ {msg01a_tf, msg1a(), TransFirst, [{dbg,false}]},
+ {msg02_tf, msg2(), TransFirst, [{dbg,false}]},
+ {msg10_tf, msg10(), TransFirst, [{dbg,false}]},
+ {msg11_tf, msg11(), TransFirst, [{dbg,false}]},
+ {msg23d_tf, msg23d(), TransFirst, [{dbg,false}]},
+ {msg30b_tf, msg30b(), TransFirst, [{dbg,false}]},
+ {msg30c_tf, msg30c(), TransFirst, [{dbg,false}]},
+ {msg01a_asf, msg1a(), ActionsFirst, [{dbg,false}]},
+ {msg02_asf, msg2(), ActionsFirst, [{dbg,false}]},
+ {msg10_asf, msg10(), ActionsFirst, [{dbg,false}]},
+ {msg23d_asf, msg23d(), ActionsFirst, [{dbg,false}]},
+ {msg01a_af, msg1a(), ActionFirst, [{dbg,false}]},
+ {msg02_af, msg2(), ActionFirst, [{dbg,false}]},
+ {msg10_af, msg10(), ActionFirst, [{dbg,false}]},
+ {msg23d_af, msg23d(), ActionFirst, [{dbg,false}]}
+ ].
+
+
+msgs3525(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [{msgs3_name(Name), rfc3525_decode(M), Plain, [{dbg, false}]} ||
+ {Name, M} <- rfc3525_msgs()].
+
+msgs3_name(N) ->
+ list_to_atom("rfc3525_" ++ atom_to_list(N)).
+
+rfc3525_decode(M) when is_list(M) ->
+ rfc3525_decode(list_to_binary(M));
+rfc3525_decode(M) when is_binary(M) ->
+ case (catch decode_message(megaco_pretty_text_encoder, false, ?EC, M)) of
+ {ok, Msg} ->
+ Msg;
+ Error ->
+ {error, {rfc3525_decode_error, Error}}
+ end.
+
+
+msgs5(_) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+ [
+ {msg51a, msg51a(), Plain, [{dbg, false}]},
+ {msg51b, msg51b(), Plain, [{dbg, false}]},
+ {msg51c, msg51c(), Plain, [{dbg, false}]},
+ {msg51d, msg51d(), Plain, [{dbg, false}]},
+ {msg51e, msg51e(), Plain, [{dbg, false}]},
+ {msg51f, msg51f(), Plain, [{dbg, false}]},
+ {msg51g, msg51g(), Plain, [{dbg, false}]},
+ {msg51h, msg51h(), Plain, [{dbg, false}]},
+ {msg51i, msg51i(), Plain, [{dbg, false}]},
+ {msg52, msg52(), Plain, [{dbg, false}]},
+ {msg53, msg53(), Plain, [{dbg, false}]},
+ {msg54a, msg54a(), Plain, [{dbg, false}]},
+ {msg54b, msg54b(), Plain, [{dbg, false}]},
+ {msg54c, msg54c(), Plain, [{dbg, false}]},
+ {msg55, msg55(), Plain, [{dbg, false}]},
+ {msg56, msg56(), Plain, [{dbg, false}]},
+ {msg57, msg57(), Plain, [{dbg, false}]},
+ {msg58a, msg58a(), Plain, [{dbg, false}]},
+ {msg58b, msg58b(), Plain, [{dbg, false}]}
+ ].
+
+
+msgs6(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ PlainEDFail =
+ fun(Codec, DD, Ver, EC, M) ->
+ Res =
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M),
+ case Res of
+ {error, {message_encode_failed, Reason, _M}} ->
+ case Reason of
+ {error, {{deprecated, _}, _}} ->
+ ok;
+ _ ->
+ Res
+ end;
+ _ ->
+ Res
+ end
+ end,
+
+ PlainDE =
+ fun(Codec, _DD, Ver, EC, B) ->
+ Res =
+ megaco_codec_test_lib:decode_message(Codec, false, Ver,
+ EC, B),
+ case Res of
+ {ok, M} ->
+ #'MegacoMessage'{mess = Mess} = M,
+ #'Message'{messageBody = {transactions, TRs}} = Mess,
+ [{transactionRequest, TR}] = TRs,
+ #'TransactionRequest'{actions = Actions} = TR,
+ [Action] = Actions,
+ #'ActionRequest'{commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {addReq,AmmReq} = Cmd,
+ #'AmmRequest'{descriptors = []} = AmmReq,
+ ok;
+ _ ->
+ Res
+ end
+ end,
+
+ Msgs =
+ [
+ {msg61a, msg61a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61b, msg61b(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg61c, msg61c(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg62a, msg62a(), PlainEDFail, [{dbg,false}],[text,binary,erlang]},
+ {msg62b, msg62b(), PlainDE, [{dbg,false}],[text]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+msgs7(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ Msgs =
+ [
+ {msg71a, msg71a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b01, msg71b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b02, msg71b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b03, msg71b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b04, msg71b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b05, msg71b05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b06, msg71b06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b07, msg71b07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b08, msg71b08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b09, msg71b09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b10, msg71b10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b11, msg71b11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b12, msg71b12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b13, msg71b13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b14, msg71b14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b15, msg71b15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b16, msg71b16(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b17, msg71b17(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b18, msg71b18(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b19, msg71b19(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b20, msg71b20(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b21, msg71b21(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71b22, msg71b22(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c01, msg71c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c02, msg71c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c03, msg71c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c04, msg71c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c05, msg71c05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c06, msg71c06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c07, msg71c07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c08, msg71c08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c09, msg71c09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c10, msg71c10(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c11, msg71c11(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c12, msg71c12(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c13, msg71c13(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c14, msg71c14(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71c15, msg71c15(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d01, msg71d01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d02, msg71d02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d03, msg71d03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg71d04, msg71d04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a01, msg72a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a02, msg72a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72a03, msg72a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b01, msg72b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b02, msg72b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b03, msg72b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72b04, msg72b04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c01, msg72c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c02, msg72c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c03, msg72c03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg72c04, msg72c04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73a, msg73a(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b01, msg73b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73b02, msg73b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c01, msg73c01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg73c02, msg73c02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a01, msg74a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a02, msg74a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a03, msg74a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a04, msg74a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a05, msg74a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg74a06, msg74a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a01, msg75a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg75a02, msg75a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76a01, msg76a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76a02, msg76a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg76b01, msg76b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ %% {msg76b02, msg76b02(), Plain, [{dbg,true}],[text,binary,erlang]},
+ {msg77a01, msg77a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a01, msg78a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a02, msg78a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a03, msg78a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a04, msg78a04(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a05, msg78a05(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a06, msg78a06(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a07, msg78a07(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a08, msg78a08(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg78a09, msg78a09(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg79a01, msg79a01(), Plain, [{dbg,false}],[text,binary,erlang]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+msgs8(Encoding) ->
+ Plain =
+ fun(Codec, DD, Ver, EC, M) ->
+ megaco_codec_test_lib:plain_encode_decode(Codec, DD, Ver,
+ EC, M)
+ end,
+
+ Msgs =
+ [
+ {msg80a01, msg80a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg80a02, msg80a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg80a03, msg80a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg80b01, msg80b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg80b02, msg80b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg80b03, msg80b03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81a01, msg81a01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81a02, msg81a02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81a03, msg81a03(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81b01, msg81b01(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81b02, msg81b02(), Plain, [{dbg,false}],[text,binary,erlang]},
+ {msg81b03, msg81b03(), Plain, [{dbg,false}],[text,binary,erlang]}
+ ],
+ [{N,M,F,C}||{N,M,F,C,E} <- Msgs,lists:member(Encoding,E)].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+msg_actions([], Actions) ->
+ lists:reverse(Actions);
+msg_actions([{CtxId, CmdReqs}|ActionInfo], Actions) ->
+ Action = ?MSG_LIB:cre_ActionRequest(CtxId,CmdReqs),
+ msg_actions(ActionInfo, [Action|Actions]).
+
+megaco_trans_req([], Transactions) ->
+ {transactions, lists:reverse(Transactions)};
+megaco_trans_req([{TransId, ActionInfo}|TransInfo], Transactions) ->
+ Actions = msg_actions(ActionInfo, []),
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ megaco_trans_req(TransInfo, [Trans|Transactions]).
+
+megaco_message(Version, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(Version, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+msg_request(Mid, TransInfo) ->
+ TransReq = megaco_trans_req(TransInfo, []),
+ megaco_message(?VERSION, Mid, TransReq).
+
+msg_request(Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_request(Auth, Mid, TransId, ContextId, CmdReq) ->
+ Action = ?MSG_LIB:cre_ActionRequest(ContextId, CmdReq),
+ Actions = [Action],
+ TR = ?MSG_LIB:cre_TransactionRequest(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Auth, Mess).
+
+msg_reply(Mid, TransId, Actions) ->
+ TR = cre_TransRep(TransId, Actions),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg_reply(Mid, TransId, ContextId, CmdReply) ->
+ Action = cre_ActRep(ContextId, CmdReply),
+ Actions = [Action],
+ msg_reply(Mid, TransId, Actions).
+
+msg_ack(Mid, [Range|_] = Ranges) when is_tuple(Range) ->
+ msg_ack(Mid, [Ranges]);
+
+msg_ack(Mid, Ranges) ->
+ %% TRAs = make_tras(Ranges, []),
+ TRAs = make_tras(Ranges),
+ Req = {transactions, TRAs},
+ cre_MegacoMessage(?VERSION, Mid, Req).
+
+make_tras(TRARanges) ->
+ F = fun(R) -> {transactionResponseAck, make_tra(R)} end,
+ lists:map(F, TRARanges).
+
+make_tra(Ranges) ->
+ F = fun({F,L}) -> cre_TransAck(F,L) end,
+ lists:map(F, Ranges).
+
+
+%% -------------------------------------------------------------------------
+
+
+msg1(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ReqEvent = cre_ReqEv("al/of"),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ Msg = msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]),
+ Msg.
+
+msg1a() ->
+ msg1a(?MGC_MID).
+msg1a(Mid) ->
+ msg1(Mid, ?A4444).
+
+msg1b() ->
+ msg1b(?MGC_MID).
+msg1b(Mid) ->
+ msg1(Mid, ?A4445).
+
+
+%% --------------------------
+
+
+msg2() ->
+ msg2(?MGC_MID).
+msg2(Mid) ->
+ msg2(Mid, ?A4444).
+msg2(Mid, Tid) ->
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv,[Gain, Ec]),
+ V = cre_PropParm("v", "0"),
+ %% C = cre_PropParm("c", "IN IP4 $ "),
+ C = cre_PropParm("c", [$I,$N,$ ,$I,$P,$4,$ ,$$,$ ]),
+ M = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ A = cre_PropParm("a", "fmtp:PCMU VAD=X-NNVAD"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A]]),
+ Parms = cre_StreamParms(LCD,LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ EventParm = cre_EvParm("strict",["exact"]),
+ ReqEvent = cre_ReqEv("al/of", [EventParm]),
+ EventsDesc = cre_EvsDesc(2222,[ReqEvent]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = Tid}],
+ [{mediaDescriptor, MediaDesc},
+ {eventsDescriptor, EventsDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 9999, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg3() ->
+ msg3(?MG1_MID).
+msg3(Mid) ->
+ TimeStamp = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10000, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg4() ->
+ msg4(?MG1_MID_NO_PORT, "901 mg col boot").
+msg4(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ msg_request(Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg5() ->
+ msg5(?MGC_MID).
+msg5(Mid) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChResParm(Address,Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms,Parm}),
+ msg_reply(Mid, 9998, ?megaco_null_context_id,
+ [{serviceChangeReply, Reply}]).
+
+
+%% --------------------------
+
+msg6(Mid, Tid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = Tid}]),
+ msg_reply(Mid, 9999, ?megaco_null_context_id, [{modReply, Reply}]).
+
+msg6a() ->
+ msg6a(?MG1_MID).
+msg6a(Mid) ->
+ msg6(Mid, ?A4444).
+
+msg6b() ->
+ msg6b(?MG2_MID).
+msg6b(Mid) ->
+ msg6(Mid, ?A5555).
+
+
+%% --------------------------
+
+msg7() ->
+ msg7(?MGC_MID).
+msg7(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A4444}]),
+ msg_reply(Mid, 10000, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg8(Mid, DigitMapValue) ->
+ Strict = cre_EvParm("strict",["state"]),
+ On = cre_ReqEv("al/on", [Strict]),
+ Name = "dialplan00",
+ EDM = cre_EvDM(Name),
+ Action = cre_ReqActs(EDM),
+ Ce = cre_ReqEv("dd/ce", Action),
+ EventsDesc = cre_EvsDesc(2223, [On, Ce]),
+ Signal = cre_Sig("cg/rt"),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg8a() ->
+ msg8a(?MGC_MID).
+msg8a(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body),
+ msg8(Mid, Value).
+
+msg8b() ->
+ msg8b(?MGC_MID).
+msg8b(Mid) ->
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ Value = cre_DigitMapValue(Body, 1, 23, 99),
+ msg8(Mid, Value).
+
+
+%% --------------------------
+
+msg9() ->
+ msg9(?MG1_MID).
+msg9(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22010001"),
+ Parm = cre_EvParm("ds",["916135551212"]),
+ Event = cre_ObsEv("dd/ce",TimeStamp,[Parm]),
+ Desc = cre_ObsEvsDesc(2223,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}], Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 10002, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg10() ->
+ msg10(?MGC_MID).
+msg10(Mid) ->
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],[]),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(recvOnly,[Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 $ "),
+ M2 = cre_PropParm("m", "audio $ RTP/AVP 0"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A], [V2, C2, M2]]),
+ Parms = cre_StreamParms(LCD, LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 10003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+msg11() ->
+ msg11(?MG1_MID).
+msg11(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 10003, 2000, [{addReply, Reply}, {addReply, Reply2}]).
+
+
+%% --------------------------
+
+msg12() ->
+ msg12(?MGC_MID).
+msg12(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Signal = cre_Sig("al/ri"),
+ Descs = [{mediaDescriptor, MediaDesc},
+ {signalsDescriptor, [{signal, Signal}]}],
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}], Descs),
+ CmdReq = cre_CmdReq({addReq, AmmReq}),
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD2 = cre_LocalControlDesc(sendRecv, [Jit]),
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 $ "),
+ M = cre_PropParm("m", "audio $ RTP/AVP 4"),
+ A = cre_PropParm("a", "ptime:30"),
+ LD2 = cre_LocalRemoteDesc([[V, C, M, A]]),
+ V2 = cre_PropParm("v", "0"),
+ C2 = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M2 = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RD2 = cre_LocalRemoteDesc([[V2, C2, M2]]),
+ Parms2 = cre_StreamParms(LCD2,LD2,RD2),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ ChooseTid = #megaco_term_id{contains_wildcards = true,
+ id = [[?megaco_choose]]},
+ AmmReq2 = cre_AmmReq([ChooseTid],[{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({addReq, AmmReq2}),
+ msg_request(Mid, 50003, ?megaco_choose_context_id, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg13() ->
+ msg13(?MG2_MID).
+msg13(Mid) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{mediaDescriptor, MediaDesc}]),
+ msg_reply(Mid, 50003, 5000, [{addReply, Reply}]).
+
+
+%% --------------------------
+
+msg14() ->
+ msg14(?MGC_MID).
+msg14(Mid) ->
+ Signal = cre_Sig("cg/rt"),
+ AmmReq1 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, [{signal, Signal}]}]),
+ CmdReq1 = cre_CmdReq({modReq, AmmReq1}),
+
+ Gain = cre_PropParm("tdmc/gain", "2"),
+ Ec = cre_PropParm("tdmc/ec", "g165"),
+ LCD = cre_LocalControlDesc(sendRecv, [Gain, Ec]),
+ Parms2 = cre_StreamParms(LCD),
+ StreamDesc2 = cre_StreamDesc(1,Parms2),
+ MediaDesc2 = cre_MediaDesc(StreamDesc2),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc2}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ M = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ RD = cre_LocalRemoteDesc([[V, C, M]]),
+ Parms3 = cre_StreamParmsR(RD),
+ StreamDesc3 = cre_StreamDesc(2,Parms3),
+ MediaDesc3 = cre_MediaDesc(StreamDesc3),
+ AmmReq3 = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc3}]),
+ CmdReq3 = cre_CmdReq({modReq, AmmReq3}),
+ msg_request(Mid, 10005, 2000, [CmdReq1, CmdReq2, CmdReq3]).
+
+
+%% --------------------------
+
+msg15() ->
+ msg15(?MG1_MID).
+msg15(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 10005, 2000, [{modReply, Reply}, {modReply, Reply2}]).
+
+
+%% --------------------------
+
+msg16() ->
+ msg16(?MG2_MID).
+msg16(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","22020002"),
+ Event = cre_ObsEv("al/of",TimeStamp),
+ Desc = cre_ObsEvsDesc(1234,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50005, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg17() ->
+ msg17(?MGC_MID).
+msg17(Mid) ->
+ Reply = cre_NotifyRep([#megaco_term_id{id = ?A5555}]),
+ msg_reply(Mid, 50005, ?megaco_null_context_id, [{notifyReply, Reply}]).
+
+
+%% --------------------------
+
+msg18() ->
+ msg18(?MGC_MID).
+msg18(Mid) ->
+ On = cre_ReqEv("al/on"),
+ EventsDesc = cre_EvsDesc(1235,[On]),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A5555}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, []}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(Mid, 50006, 5000, [CmdReq]).
+
+
+%% --------------------------
+
+msg19() ->
+ msg19(?MG2_MID).
+msg19(Mid) ->
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4445}]),
+ msg_reply(Mid, 50006, 5000, [{modReply, Reply}]).
+
+
+%% --------------------------
+
+msg20() ->
+ msg20(?MGC_MID).
+msg20(Mid) ->
+ LCD = cre_LocalControlDesc(sendRecv),
+ Parms = cre_StreamParms(LCD),
+ StreamDesc = cre_StreamDesc(1,Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ AmmReq2 = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{signalsDescriptor, []}]),
+ CmdReq2 = cre_CmdReq({modReq, AmmReq2}),
+ msg_request(Mid, 10006, 2000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg21() ->
+ msg21(?MGC_MID).
+msg21(Mid) ->
+ Tokens = [mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, packagesToken],
+ AuditDesc = cre_AuditDesc(Tokens),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AuditDesc),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+
+%% --------------------------
+
+msg22a() ->
+ msg22(1).
+
+msg22b() ->
+ msg22(10).
+
+msg22c() ->
+ msg22(25).
+
+msg22d() ->
+ msg22(50).
+
+msg22e() ->
+ msg22(75).
+
+msg22f() ->
+ msg22(100).
+
+msg22(N) ->
+ msg22(?MG2_MID, N).
+msg22(Mid, N) ->
+ Jit = cre_PropParm("nt/jit", "40"),
+ LCD = cre_LocalControlDesc(sendRecv,[Jit]),
+ LDV = cre_PropParm("v", "0"),
+ LDC = cre_PropParm("c", "IN IP4 125.125.125.111"),
+ LDM = cre_PropParm("m", "audio 1111 RTP/AVP 4"),
+ LDA = cre_PropParm("a", "ptime:30"),
+ LD = cre_LocalRemoteDesc([[LDV, LDC, LDM, LDA]]),
+ RDV = cre_PropParm("v", "0"),
+ RDC = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ RDM = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ RDA = cre_PropParm("a", "ptime:30"),
+ RD = cre_LocalRemoteDesc([[RDV, RDC, RDM, RDA]]),
+ StreamParms = cre_StreamParms(LCD,LD,RD),
+ StreamDesc = cre_StreamDesc(1,StreamParms),
+ Media = cre_MediaDesc(StreamDesc),
+ PackagesItem = cre_PkgsItem("nt",1),
+ PackagesItem2 = cre_PkgsItem("rtp",1),
+ Stat = cre_StatsParm("rtp/ps","1200"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Statistics = [Stat, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ Audits = [{mediaDescriptor, Media},
+ {packagesDescriptor, [PackagesItem, PackagesItem2]},
+ {statisticsDescriptor, Statistics}],
+ Reply = {auditResult,
+ cre_AuditRes(#megaco_term_id{id = ?A5556},Audits)},
+ msg_reply(Mid, 50007, ?megaco_null_context_id,
+ lists:duplicate(N,{auditValueReply, Reply})).
+%% msg_reply(Mid, 50007, ?megaco_null_context_id,
+%% lists.duplicate([{auditValueReply, Reply}]).
+
+
+%% --------------------------
+
+msg23a() ->
+ msg23a(?MG2_MID).
+msg23a(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq = cre_CmdReq({notifyReq, NotifyReq}),
+ msg_request(Mid, 50008, 5000, [CmdReq]).
+
+
+msg23b() ->
+ msg23b(?MG2_MID).
+msg23b(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo}],
+ msg_request(Mid, TransInfo).
+
+
+msg23c() ->
+ msg23c(?MG2_MID).
+msg23c(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ ActionInfo1 = [{5000, [CmdReq1]}],
+ ActionInfo2 = [{5001, [CmdReq2]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+msg23d() ->
+ msg23d(?MG2_MID).
+msg23d(Mid) ->
+ TimeStamp = cre_TimeNot("19990729","24020002"),
+ Event = cre_ObsEv("al/on",TimeStamp),
+ Desc = cre_ObsEvsDesc(1235,[Event]),
+ NotifyReq1 = cre_NotifyReq([#megaco_term_id{id = ?A5555}],Desc),
+ CmdReq1 = cre_CmdReq({notifyReq, NotifyReq1}),
+ NotifyReq2 = cre_NotifyReq([#megaco_term_id{id = ?A5556}],Desc),
+ CmdReq2 = cre_CmdReq({notifyReq, NotifyReq2}),
+ NotifyReq3 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq3 = cre_CmdReq({notifyReq, NotifyReq3}),
+ NotifyReq4 = cre_NotifyReq([#megaco_term_id{id = ?A4445}],Desc),
+ CmdReq4 = cre_CmdReq({notifyReq, NotifyReq4}),
+ ActionInfo1 = [{5000, [CmdReq1]}, {5001, [CmdReq2]}],
+ ActionInfo2 = [{5003, [CmdReq3]}, {5004, [CmdReq4]}],
+ TransInfo = [{50008, ActionInfo1}, {50009, ActionInfo2}],
+ msg_request(Mid, TransInfo).
+
+
+%% --------------------------
+
+msg24() ->
+ msg24(?MGC_MID).
+msg24(Mid) ->
+ AuditDesc = cre_AuditDesc([statsToken]),
+ SubReq = cre_SubReq([#megaco_term_id{id = ?A5555}], AuditDesc),
+ SubReq2 = cre_SubReq([#megaco_term_id{id = ?A5556}], AuditDesc),
+ CmdReq = cre_CmdReq({subtractReq, SubReq}),
+ CmdReq2 = cre_CmdReq({subtractReq, SubReq2}),
+ msg_request(Mid, 50009, 5000, [CmdReq, CmdReq2]).
+
+
+%% --------------------------
+
+msg25() ->
+ msg25(?MG2_MID).
+msg25(Mid) ->
+ Stat11 = cre_StatsParm("nt/os","45123"),
+ Stat12 = cre_StatsParm("nt/dur", "40"),
+ Stats1 = [Stat11, Stat12],
+ Reply1 = cre_AmmsReply([#megaco_term_id{id = ?A5555}],
+ [{statisticsDescriptor, Stats1}]),
+ Stat21 = cre_StatsParm("rtp/ps","1245"),
+ Stat22 = cre_StatsParm("nt/os", "62345"),
+ Stat23 = cre_StatsParm("rtp/pr", "780"),
+ Stat24 = cre_StatsParm("nt/or", "45123"),
+ Stat25 = cre_StatsParm("rtp/pl", "10"),
+ Stat26 = cre_StatsParm("rtp/jit", "27"),
+ Stat27 = cre_StatsParm("rtp/delay","48"),
+ Stats2 = [Stat21, Stat22, Stat23, Stat24, Stat25, Stat26, Stat27],
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A5556}],
+ [{statisticsDescriptor, Stats2}]),
+ msg_reply(Mid, 50009, 5000,
+ [{subtractReply, Reply1}, {subtractReply, Reply2}]).
+
+
+msg30a() ->
+ msg_ack(?MG2_MID, [{9,9}]).
+
+msg30b() ->
+ msg_ack(?MG2_MID, [{9,13}]).
+
+msg30c() ->
+ msg_ack(?MG2_MID,
+ [{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90},
+ {101,105},{109,119},{121,130},{140,160},{170,175},{180,189},
+ {201,205},{209,219},{221,230},{240,260},{270,275},{280,289},
+ {301,305},{309,319},{321,330},{340,360},{370,375},{380,389},
+ {401,405},{409,419},{421,430},{440,460},{470,475},{480,489},
+ {501,505},{509,519},{521,530},{540,560},{570,575},{580,589}
+ ]).
+
+%% Don't think this will be used by the megaco stack, but since it
+%% seem's to be a valid construction...
+msg30d() ->
+ msg_ack(?MG2_MID,
+ [[{9,13}, {15,15}, {33,40}, {50,60}, {70,80}, {85,90}],
+ [{101,105},{109,119},{121,130},{140,160},{170,175},{180,189}],
+ [{201,205},{209,219},{221,230},{240,260},{270,275},{280,289}],
+ [{301,305},{309,319},{321,330},{340,360},{370,375},{380,389}],
+ [{401,405},{409,419},{421,430},{440,460},{470,475},{480,489}],
+ [{501,505},{509,519},{521,530},{540,560},{570,575},{580,589}]
+ ]).
+
+
+
+msg40() ->
+ msg40(?MG1_MID_NO_PORT, "901 mg col boot").
+msg40(Mid, Reason) when is_list(Reason) ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(restart,Address,[Reason],Profile),
+ Req = cre_SvcChReq([?megaco_root_termination_id],Parm),
+ CmdReq = cre_CmdReq({serviceChangeReq, Req}),
+ Auth = cre_AuthHeader(),
+ msg_request(Auth, Mid, 9998, ?megaco_null_context_id, [CmdReq]).
+
+
+msg50(Mid, APT) ->
+ AD = cre_AuditDesc(asn1_NOVALUE, APT),
+ Req = cre_AuditReq(#megaco_term_id{id = ?A5556},AD),
+ CmdReq = cre_CmdReq({auditValueRequest, Req}),
+ msg_request(Mid, 50007, ?megaco_null_context_id, [CmdReq]).
+
+%% IndAudMediaDescriptor:
+msg51(Mid, IATSDorStream) ->
+ IAMD = cre_IndAudMediaDesc(IATSDorStream),
+ IAP = cre_IndAudParam(IAMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg51a() ->
+ msg51a(?MG2_MID).
+msg51a(Mid) ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51b() ->
+ msg51b(?MG2_MID).
+msg51b(Mid) ->
+ PP = cre_IndAudPropertyParm("nt/jit"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg51(Mid, IATSD).
+
+msg51c() ->
+ msg51c(?MG2_MID).
+msg51c(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, 'NULL'),
+ msg51(Mid, IATSD).
+
+msg51d() ->
+ msg51d(?MG2_MID).
+msg51d(Mid) ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg51(Mid, IATSD).
+
+msg51e() ->
+ msg51e(?MG2_MID).
+msg51e(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc('NULL', asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51f() ->
+ msg51f(?MG2_MID).
+msg51f(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL',
+ asn1_NOVALUE, asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51g() ->
+ msg51g(?MG2_MID).
+msg51g(Mid) ->
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ 'NULL', asn1_NOVALUE),
+ IASP = cre_IndAudStreamParms(IALCD),
+ msg51(Mid, IASP).
+
+msg51h() ->
+ msg51h(?MG2_MID).
+msg51h(Mid) ->
+ Name = "nt/jit",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, [IAPP]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+msg51i() ->
+ msg51i(?MG2_MID).
+msg51i(Mid) ->
+ Name = "nt/jit",
+ Name2 = "tdmc/ec",
+ IAPP = cre_IndAudPropertyParm(Name),
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ IALCD = cre_IndAudLocalControlDesc('NULL', 'NULL', 'NULL',
+ [IAPP, IAPP2]),
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ msg51(Mid, [IASD]).
+
+
+%% IndAudEventsDescriptor:
+msg52() ->
+ msg52(?MG2_MID).
+msg52(Mid) ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ IAP = cre_IndAudParam(IAED),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudEventBufferDescriptor:
+msg53() ->
+ msg53(?MG2_MID).
+msg53(Mid) ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ IAP = cre_IndAudParam(IAEBD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudSignalsDescriptor:
+msg54(Mid, Sig) ->
+ IASD = cre_IndAudSigsDesc(Sig),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+msg54a() ->
+ msg54a(?MG2_MID).
+msg54a(Mid) ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54b() ->
+ msg54b(?MG2_MID).
+msg54b(Mid) ->
+ SN = "dg/d0",
+ Sig = cre_IndAudSig(SN),
+ msg54(Mid, Sig).
+
+msg54c() ->
+ msg54c(?MG2_MID).
+msg54c(Mid) ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg54(Mid, SSL).
+
+%% IndAudDigitMapDescriptor:
+msg55() ->
+ msg55(?MG2_MID).
+msg55(Mid) ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ IAP = cre_IndAudParam(IADMD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudStatisticsDescriptor:
+msg56() ->
+ msg56(?MG2_MID).
+msg56(Mid) ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ IAP = cre_IndAudParam(IASD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% IndAudPackagesDescriptor:
+msg57() ->
+ msg57(?MG2_MID).
+msg57(Mid) ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ IAP = cre_IndAudParam(IAPD),
+ APT = [IAP],
+ msg50(Mid, APT).
+
+%% Sum it up:
+msg58_iaMediaDesc_iap(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ cre_IndAudParam(IAMD).
+
+msg58_iaMediaDesc_iap_a() ->
+ PP = cre_IndAudPropertyParm("tdmc/gain"),
+ PPs = [PP],
+ IATSD = cre_IndAudTermStateDesc(PPs),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaMediaDesc_iap_b() ->
+ IATSD = cre_IndAudTermStateDesc([], 'NULL', asn1_NOVALUE),
+ msg58_iaMediaDesc_iap(IATSD).
+
+msg58_iaEvsDesc_iap() ->
+ RequestID = 1235,
+ PkgdName = "tonedet/std",
+ IAED = cre_IndAudEvsDesc(RequestID, PkgdName),
+ cre_IndAudParam(IAED).
+
+msg58_iaEvBufDesc_iap() ->
+ EN = "tonedet/std",
+ SID = 1,
+ IAEBD = cre_IndAudEvBufDesc(EN, SID),
+ cre_IndAudParam(IAEBD).
+
+msg58_iaSigsDesc_iap(S) ->
+ IASD = cre_IndAudSigsDesc(S),
+ cre_IndAudParam(IASD).
+
+msg58_iaSigsDesc_iap_a() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN),
+ msg58_iaSigsDesc_iap(Sig).
+
+msg58_iaSigsDesc_iap_b() ->
+ SN = "ct/ct",
+ Sig = cre_IndAudSig(SN),
+ ID = 4321,
+ SSL = cre_IndAudSeqSigList(ID, Sig),
+ msg58_iaSigsDesc_iap(SSL).
+
+msg58_iaDigMapDesc_iap() ->
+ DMN = "dialplan00",
+ IADMD = cre_IndAudDigitMapDesc(DMN),
+ cre_IndAudParam(IADMD).
+
+msg58_iaStatsDesc_iap() ->
+ SN = "nt/dur",
+ IASD = cre_IndAudStatsDesc(SN),
+ cre_IndAudParam(IASD).
+
+msg58_iaPacksDesc_iap() ->
+ PN = "al",
+ PV = 1,
+ IAPD = cre_IndAudPkgsDesc(PN, PV),
+ cre_IndAudParam(IAPD).
+
+msg58a() ->
+ msg58a(?MG2_MID).
+msg58a(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_a(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_a(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+msg58b() ->
+ msg58b(?MG2_MID).
+msg58b(Mid) ->
+ IAMD = msg58_iaMediaDesc_iap_b(),
+ IAED = msg58_iaEvsDesc_iap(),
+ IAEBD = msg58_iaEvBufDesc_iap(),
+ IASiD = msg58_iaSigsDesc_iap_b(),
+ IADMD = msg58_iaDigMapDesc_iap(),
+ IAStD = msg58_iaStatsDesc_iap(),
+ IAPD = msg58_iaPacksDesc_iap(),
+ APT = [IAMD, IAED, IAEBD, IASiD, IADMD, IAStD, IAPD],
+ msg50(Mid, APT).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Tests some of the changes in the v2 corr 1 (EmergencyOff and ModemDesc)
+
+%% Emergency On/Off (optional) tests
+msg61(EM) ->
+ TS = cre_TimeNot("19990729", "22000000"),
+ Event = cre_ObsEv("al/of",TS),
+ Desc = cre_ObsEvsDesc(2222,[Event]),
+ NotReq = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ Cmd = ?MSG_LIB:cre_Command(notifyReq, NotReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CtxReq = cre_CtxReq(15, EM),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CtxReq, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg61a() ->
+ msg61(false).
+
+msg61b() ->
+ msg61(true).
+
+msg61c() ->
+ msg61(asn1_NOVALUE).
+
+
+msg62a() ->
+ MT = ?MSG_LIB:cre_ModemType(v18),
+ PP = cre_PropParm("c", "IN IP4 $ "),
+ MD = ?MSG_LIB:cre_ModemDescriptor([MT], [PP]),
+ AmmDesc = ?MSG_LIB:cre_AmmDescriptor(MD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AmmReq = ?MSG_LIB:cre_AmmRequest(TermIDs, [AmmDesc]),
+ Cmd = ?MSG_LIB:cre_Command(addReq, AmmReq),
+ CmdReq = ?MSG_LIB:cre_CommandRequest(Cmd),
+ ActReq = ?MSG_LIB:cre_ActionRequest(2, [CmdReq]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg62b() ->
+ MP =
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555
+Transaction = 9898 {
+ Context = 2 {
+ Add = 11111111/00000000/00000000 {
+ Modem[V18] {
+ tdmc/gain=2
+ }
+ }
+ }
+}",
+% MC =
+% "!/" ?VERSION_STR " [124.124.124.222]:55555\nT=9898{C=2{A=11111111/00000000/00000000{MD[V18]{tdmc/gain=2}}}}",
+ list_to_binary(MP).
+
+%% ActionRequest with various combinations of ContextRequest and
+%% ContextAttrAuditRequest
+msg71(CR, CAAR) ->
+ TS1 = cre_TimeNot("19990729", "22000000"),
+ TS2 = cre_TimeNot("19990729", "22000111"),
+ Event1 = cre_ObsEv("al/of",TS1),
+ Event2 = cre_ObsEv("al/on",TS2),
+ Desc1 = cre_ObsEvsDesc(2222,[Event1]),
+ Desc2 = cre_ObsEvsDesc(2222,[Event2]),
+ NR1 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc1),
+ NR2 = cre_NotifyReq([#megaco_term_id{id = ?A4444}],Desc2),
+ Cmd1 = ?MSG_LIB:cre_Command(notifyReq, NR1),
+ Cmd2 = ?MSG_LIB:cre_Command(notifyReq, NR2),
+ CR1 = cre_CmdReq(Cmd1),
+ CR2 = cre_CmdReq(Cmd2),
+ ActReq = ?MSG_LIB:cre_ActionRequest(1, CR, CAAR, [CR1, CR2]),
+ Acts = [ActReq],
+ TR = ?MSG_LIB:cre_TransactionRequest(9898, Acts),
+ Trans = ?MSG_LIB:cre_Transaction(TR),
+ Mess = ?MSG_LIB:cre_Message(?VERSION, ?MG1_MID, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg71a() ->
+ CR = cre_CtxReq(),
+ CAAR = cre_CtxAttrAuditReq(),
+ msg71(CR, CAAR).
+
+msg71b(CR) ->
+ CAAR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71b01() ->
+ CR = cre_CtxReq(15),
+ msg71b(CR).
+
+msg71b02() ->
+ CR = cre_CtxReq(true),
+ msg71b(CR).
+
+msg71b03() ->
+ CR = cre_CtxReq(false),
+ msg71b(CR).
+
+msg71b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(Top),
+ msg71b(CR).
+
+msg71b05() ->
+ CR = cre_CtxReq(15, true),
+ msg71b(CR).
+
+msg71b06() ->
+ CR = cre_CtxReq(15, false),
+ msg71b(CR).
+
+msg71b07() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, Top),
+ msg71b(CR).
+
+msg71b08() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top),
+ msg71b(CR).
+
+msg71b09() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b10() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = onewayboth,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b11() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = onewayexternal,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg71b(CR).
+
+msg71b12() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, true),
+ msg71b(CR).
+
+msg71b13() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg71b(CR).
+
+msg71b14() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b15() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, greaterThan),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b16() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","10"], range, true),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b17() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("nt/jit", ["40","50","50"], sublist, true),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg71b(CR).
+
+msg71b18() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+ msg71b(CR).
+
+msg71b19() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg71b(CR).
+
+msg71b20() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+ msg71b(CR).
+
+msg71b21() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, CIDs),
+ msg71b(CR).
+
+msg71b22() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, Props, CIDs),
+ msg71b(CR).
+
+msg71c(CAAR) ->
+ CR = asn1_NOVALUE,
+ msg71(CR, CAAR).
+
+msg71c01() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c02() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c03() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c04() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c05() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, asn1_NOVALUE, 'NULL'),
+ msg71c(CAAR).
+
+msg71c06() ->
+ CAAR = cre_CtxAttrAuditReq(asn1_NOVALUE, 'NULL', asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c07() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c08() ->
+ CAAR = cre_CtxAttrAuditReq('NULL', asn1_NOVALUE, 'NULL', 'NULL'),
+ msg71c(CAAR).
+
+msg71c09() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA),
+ msg71c(CAAR).
+
+msg71c10() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA, SPrio),
+ msg71c(CAAR).
+
+msg71c11() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, asn1_NOVALUE, asn1_NOVALUE),
+ msg71c(CAAR).
+
+msg71c12() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = false,
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps),
+ msg71c(CAAR).
+
+msg71c13() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = false,
+ SIeps = true,
+ SLog = cre_SelectLogic(andAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71c(CAAR).
+
+msg71c14() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = true,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71c(CAAR).
+
+msg71c15() ->
+ Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, CPA,
+ SPrio, SLog),
+ msg71c(CAAR).
+
+msg71d01() ->
+ CR = cre_CtxReq(15, true),
+ CAAR = cre_CtxAttrAuditReq('NULL', 'NULL', 'NULL'),
+ msg71(CR, CAAR).
+
+msg71d02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg71d03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA),
+
+ msg71(CR, CAAR).
+
+msg71d04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2"], relation, unequalTo),
+ Props = [PP],
+ CID1 = cre_CtxID(10191),
+ CID2 = cre_CtxID(10192),
+ CIDs = [CID1, CID2],
+ CR = cre_CtxReq(15, true, Top, false, Props, CIDs),
+
+ CAAR_Top = 'NULL',
+ Em = 'NULL',
+ Prio = 'NULL',
+ Ieps = 'NULL',
+ IAPP1 = cre_IndAudPropertyParm("tdmc/gain"),
+ IAPP2 = cre_IndAudPropertyParm("nt/jit"),
+ CPA = [IAPP1, IAPP2],
+ SPrio = 10,
+ SEm = true,
+ SIeps = true,
+ SLog = cre_SelectLogic(orAUDITSelect),
+ CAAR = cre_CtxAttrAuditReq(CAAR_Top, Em, Prio, Ieps, CPA,
+ SPrio, SEm, SIeps, SLog),
+ msg71(CR, CAAR).
+
+msg72(ED, CR) ->
+ V = cre_PropParm("v", "0"),
+ C = cre_PropParm("c", "IN IP4 124.124.124.222"),
+ M = cre_PropParm("m", "audio 2222 RTP/AVP 4"),
+ A = cre_PropParm("a", "a=ptime:30"),
+ A2 = cre_PropParm("a", "recvonly"),
+ LD = cre_LocalRemoteDesc([[V, C, M, A, A2]]),
+ Parms = cre_StreamParmsL(LD),
+ StreamDesc = cre_StreamDesc(1, Parms),
+ MediaDesc = cre_MediaDesc(StreamDesc),
+ Reply = cre_AmmsReply([#megaco_term_id{id = ?A4444}]),
+ Reply2 = cre_AmmsReply([#megaco_term_id{id = ?A4445}],
+ [{mediaDescriptor, MediaDesc}]),
+ CmdRep = [{addReply, Reply}, {addReply, Reply2}],
+ Action = cre_ActRep(2000, ED, CR, CmdRep),
+ msg_reply(?MGC_MID, 10003, [Action]).
+
+msg72a(CR) ->
+ ED = asn1_NOVALUE,
+ msg72(ED, CR).
+
+msg72a01() ->
+ CR = cre_CtxReq(false),
+ msg72a(CR).
+
+msg72a02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(Top),
+ msg72a(CR).
+
+msg72a03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = bothway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, Top),
+ msg72a(CR).
+
+msg72b(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC),
+ msg72(ED, CR).
+
+msg72b01() ->
+ CR = cre_CtxReq(15, false),
+ msg72b(CR).
+
+msg72b02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = isolate,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, false, Top),
+ msg72b(CR).
+
+msg72b03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, true),
+ msg72b(CR).
+
+msg72b04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = bothway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ CR = cre_CtxReq(15, true, Top, false),
+ msg72b(CR).
+
+msg72c(CR) ->
+ EC = ?MSG_LIB:cre_ErrorCode(?megaco_not_ready),
+ ET = ?MSG_LIB:cre_ErrorText("Just another error string"),
+ ED = ?MSG_LIB:cre_ErrorDescriptor(EC, ET),
+ msg72(ED, CR).
+
+msg72c01() ->
+ CR = cre_CtxReq(15),
+ msg72c(CR).
+
+msg72c02() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = oneway,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", "2"),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, Props),
+ msg72c(CR).
+
+msg72c03() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, true, Props),
+ msg72c(CR).
+
+msg72c04() ->
+ From1 = #megaco_term_id{id = ["11111111", "00000000", "00000000"]},
+ To1 = #megaco_term_id{id = ["11111111", "00000000", "00001111"]},
+ Dir1 = oneway,
+ Top1 = cre_TopologyRequest(From1, To1, Dir1),
+ From2 = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ To2 = #megaco_term_id{id = ["11111111", "00001111", "00001111"]},
+ Dir2 = isolate,
+ Top2 = cre_TopologyRequest(From2, To2, Dir2),
+ Top = [Top1, Top2],
+ PP = cre_PropParm("tdmc/gain", ["2","4","8"], sublist, false),
+ Props = [PP],
+ CR = cre_CtxReq(15, true, Top, false, Props),
+ msg72c(CR).
+
+
+msg73() ->
+ Stat1 = cre_StatsParm("rtp/ps"),
+ Stat2 = cre_StatsParm("nt/os","62300"),
+ Stat3 = cre_StatsParm("rtp/pr","700"),
+ Stat4 = cre_StatsParm("nt/or","45100"),
+ Stat5 = cre_StatsParm("rtp/pl","0.2"),
+ Stat6 = cre_StatsParm("rtp/jit","20"),
+ Stat7 = cre_StatsParm("rtp/delay","40"),
+ Stats = [Stat1, Stat2, Stat3, Stat4, Stat5, Stat6, Stat7],
+ cre_StatsDesc(Stats).
+
+%% StatisticsDescriptor in AmmDescriptor
+msg73a() ->
+ StatDesc = msg73(),
+ AmmDesc = cre_AmmDesc(StatDesc),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmReq = cre_AmmReq(TermIDs, [AmmDesc]),
+ Cmd = cre_Cmd(addReq, AmmReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7301),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7302),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+%% StatisticsDescriptor in IndAudStreamParms
+msg73b1() ->
+ IASD = cre_IndAudStatsDesc("nt/dur"),
+ cre_IndAudStreamParms(IASD).
+
+msg73b2(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc([IAP]),
+ TermID = #megaco_term_id{id = ["11111111", "00001111", "00000000"]},
+ AudReq = cre_AuditReq(TermID, AD),
+ Cmd = cre_Cmd(auditValueRequest, AudReq),
+ CmdReq = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7311),
+ ActReq = cre_ActReq(CID, [CmdReq]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7312),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73b01() ->
+ IASP = msg73b1(),
+ IAMD = cre_IndAudMediaDesc(IASP),
+ msg73b2(IAMD).
+
+msg73b02() ->
+ IASP = msg73b1(),
+ SID = cre_StreamID(303),
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg73b2(IAMD).
+
+%% StatisticsDescriptor in StreamParms
+msg73c1() ->
+ StatDesc = msg73(),
+ SP = cre_StreamParms(StatDesc),
+ SID = cre_StreamID(505),
+ cre_StreamDesc(SID, SP).
+
+msg73c2(MD) ->
+ ARP = cre_AuditRetParam(MD),
+ TA = cre_TermAudit([ARP]),
+ TermIDs = [#megaco_term_id{id = ["11111111", "00001111", "00000000"]}],
+ AmmsRep = cre_AmmsReply(TermIDs, TA),
+ CmdRep = cre_CmdRep(moveReply, AmmsRep),
+ CID = cre_CtxID(606),
+ ActRep = cre_ActRep(CID, [CmdRep]),
+ TransId = cre_TransId(8899),
+ TransRep = cre_TransRep(TransId, [ActRep]),
+ Trans = cre_Trans(TransRep),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg73c01() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc(SD),
+ msg73c2(MD).
+
+msg73c02() ->
+ SD = msg73c1(),
+ MD = cre_MediaDesc([SD]),
+ msg73c2(MD).
+
+
+%% New Signal (direction and requestID); msg74
+msg74a1(D) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, asn1_NOVALUE).
+
+msg74a2(D, RID) ->
+ Dir = cre_SigDir(D),
+ cre_Sig("cg/rt", Dir, RID).
+
+msg74a3(D, RID) ->
+ Name = "al/ri",
+ SID = cre_StreamID(7401),
+ ST = cre_SigType(brief),
+ Dur = 7499,
+ NC = cre_NotifCompl([onTimeOut,otherReason]),
+ KA = cre_BOOLEAN(true),
+ SPL = [],
+ Dir = cre_SigDir(D),
+ cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+msg74a4(Sig) ->
+ SR = cre_SigReq(Sig),
+ SD = cre_SigsDesc([SR]),
+ AD = cre_AmmDesc(SD),
+ TermIDs = [#megaco_term_id{id = ?A4444}],
+ AR = cre_AmmReq(TermIDs, [AD]),
+ Cmd = cre_Cmd(modReq, AR),
+ cre_CmdReq(Cmd).
+
+msg74a01() ->
+ Sig = msg74a1(internal),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7411),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7421),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a02() ->
+ Sig = msg74a1(both),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7412),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7422),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a03() ->
+ RID = cre_ReqID(7433),
+ Sig = msg74a2(external, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7413),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7423),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a04() ->
+ RID = cre_ReqID(7434),
+ Sig = msg74a2(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7414),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7424),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a05() ->
+ RID = cre_ReqID(7435),
+ Sig = msg74a3(both, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7415),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7425),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg74a06() ->
+ RID = cre_ReqID(7436),
+ Sig = msg74a3(internal, RID),
+ CR = msg74a4(Sig),
+ CID = cre_CtxID(7416),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7426),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+
+
+%% New ServiceChangeParm (serviceChangeIncompleteFlag); msg75
+msg75a(IncFlag) ->
+ Method = cre_SvcChMethod(restart),
+ Address = cre_SvcChAddr(portNumber, ?DEFAULT_PORT),
+ Reason = "901 mg col boot",
+ Profile = cre_SvcChProf("resgw",1),
+ Parm = cre_SvcChParm(Method, Address, [Reason], Profile, IncFlag),
+ TermIDs = [?megaco_root_termination_id],
+ Req = cre_SvcChReq(TermIDs, Parm),
+ Cmd = cre_Cmd(serviceChangeReq, Req),
+ CR = cre_CmdReq(Cmd),
+ CID = cre_CtxID(7501),
+ ActReq = cre_ActReq(CID, [CR]),
+ Actions = [ActReq],
+ TransId = cre_TransId(7502),
+ TransReq = cre_TransReq(TransId, Actions),
+ Trans = cre_Trans(TransReq),
+ Mid = ?MG1_MID,
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg75a01() ->
+ msg75a(asn1_NOVALUE).
+
+msg75a02() ->
+ msg75a('NULL').
+
+
+msg76(IAMD) ->
+ IAP = cre_IndAudParam(IAMD),
+ AD = cre_AuditDesc(asn1_NOVALUE, [IAP]),
+ AR = cre_AuditReq(#megaco_term_id{id = ?A5556}, AD),
+ CR = cre_CmdReq({auditValueRequest, AR}),
+ msg_request(?MG2_MID, 50076, ?megaco_null_context_id, [CR]).
+
+%% IndAudLocalControlDescriptor and IndAudPropertyParm
+msg76a(IALCD) when is_record(IALCD, 'IndAudLocalControlDescriptor') ->
+ IASP = cre_IndAudStreamParms(IALCD),
+ SID = 123,
+ IASD = cre_IndAudStreamDesc(SID, IASP),
+ IAMD = cre_IndAudMediaDesc([IASD]),
+ msg76(IAMD).
+
+msg76a01() ->
+ Name1 = "nt/jit",
+ IAPP1 = cre_IndAudPropertyParm(Name1),
+ Name2 = "tdmc/ec",
+ IAPP2 = cre_IndAudPropertyParm(Name2),
+ SMS = cre_StreamMode(recvOnly),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL', 'NULL',
+ [IAPP1, IAPP2], SMS),
+ msg76a(IALCD).
+
+msg76a02() ->
+ Name1 = "tdmc/gain",
+ PP1 = cre_PropParm("tdmc/gain", "2"),
+ IAPP1 = cre_IndAudPropertyParm(Name1, PP1),
+ Name2 = "tdmc/gain",
+ PP2 = cre_PropParm("tdmc/gain", "3"),
+ IAPP2 = cre_IndAudPropertyParm(Name2, PP2),
+ SMS = cre_StreamMode(recvOnly),
+ IALCD = cre_IndAudLocalControlDesc(asn1_NOVALUE, 'NULL', 'NULL',
+ [IAPP1, IAPP2], SMS),
+ msg76a(IALCD).
+
+%% IndAudTerminationStateDescription + ServiceState
+msg76b(IATSD) ->
+ IAMD = cre_IndAudMediaDesc(IATSD),
+ msg76(IAMD).
+
+msg76b01() ->
+ SSS = cre_ServiceState(outOfSvc),
+ IATSD = cre_IndAudTermStateDesc([], asn1_NOVALUE, asn1_NOVALUE, SSS),
+ msg76b(IATSD).
+
+%% msg76b02() ->
+%% PP = cre_PropParm("tdmc/gain", "2"),
+%% IAPP = cre_IndAudPropertyParm("nt/jit", PP),
+%% IAPPs = [IAPP],
+%% SSS = cre_ServiceState(outOfSvc),
+%% IATSD = cre_IndAudTermStateDesc(IAPPs, 'NULL', asn1_NOVALUE, SSS),
+%% msg76b(IATSD).
+
+msg77a01() ->
+ SN = "tonegen/pt",
+ Sig = cre_IndAudSig(SN, 7701),
+ msg54(?MG2_MID, Sig).
+
+
+msg78a(Events) ->
+ EventsDesc = cre_EvsDesc(2223, Events),
+ Signal = cre_Sig("cg/rt"),
+ Name = "dialplan00",
+ Body = "(0s| 00s|[1-7]xlxx|8lxxxxxxx|#xxxxxxx|*xx|9l1xxxxxxxxxx|9l011x.s)",
+ DigitMapValue = cre_DigitMapValue(Body),
+ DigMapDesc = cre_DigitMapDesc(Name, DigitMapValue),
+ AmmReq = cre_AmmReq([#megaco_term_id{id = ?A4444}],
+ [{eventsDescriptor, EventsDesc},
+ {signalsDescriptor, [{signal, Signal}]},
+ {digitMapDescriptor, DigMapDesc}]),
+ CmdReq = cre_CmdReq({modReq, AmmReq}),
+ msg_request(?MG2_MID, 10001, ?megaco_null_context_id, [CmdReq]).
+
+msg78a01() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict", ["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7801,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ NB2 = cre_NotifBehav(notifyImmediate, 'NULL'),
+ RED2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, RED2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a02() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7802,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ NB2 = cre_NotifBehav(neverNotify, 'NULL'),
+ RED2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, RED2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a03() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7803,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ RED2 = cre_RegEmbedDesc(),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a04() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7814, [SRE2]),
+ RED2 = cre_RegEmbedDesc(SED2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7824, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a05() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ SID2 = 7805,
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SD2 = cre_SigsDesc(),
+ RED2 = cre_RegEmbedDesc(SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, SID2, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a06() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7816, [SRE2]),
+ Sig2 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR2 = cre_SigReq(Sig2),
+ SRs2 = [SR2],
+ SD2 = cre_SigsDesc(SRs2),
+ RED2 = cre_RegEmbedDesc(SED2, SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = asn1_NOVALUE,
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7826, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a07() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+ SRE2 = cre_SecReqEv("al/on"),
+ SED2 = cre_SecEvsDesc(7817, [SRE2]),
+ Sig2 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR2 = cre_SigReq(Sig2),
+ SRs2 = [SR2],
+ SD2 = cre_SigsDesc(SRs2),
+ RED2 = cre_RegEmbedDesc(SED2, SD2),
+ NB2 = cre_NotifBehav(notifyRegulated, RED2),
+ REvD2 = 'NULL',
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB2, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7827, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a08() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+
+ Sig21 = cre_Sig("al/ri", both, asn1_NOVALUE),
+ SR21 = cre_SigReq(Sig21),
+ SRs21 = [SR21],
+ SD21 = cre_SigsDesc(SRs21),
+ RED21 = cre_RegEmbedDesc(SD21),
+ NB21 = cre_NotifBehav(notifyRegulated, RED21),
+ SRA2 = cre_SecReqActs(KA2, EDM2, asn1_NOVALUE, NB21, 'NULL'),
+ SRE2 = cre_SecReqEv("al/of", 7816, SRA2),
+ SED2 = cre_SecEvsDesc(7826, [SRE2]),
+
+ Sig22 = cre_Sig("cg/rt", external, asn1_NOVALUE),
+ SR22 = cre_SigReq(Sig22),
+ SRs22 = [SR22],
+ SD22 = cre_SigsDesc(SRs22),
+ RED22 = cre_RegEmbedDesc(SED2, SD22),
+ NB22 = cre_NotifBehav(notifyRegulated, RED22),
+ REvD2 = 'NULL',
+
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB22, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7836, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+msg78a09() ->
+ Name1 = "al/on",
+ Strict = cre_EvParm("strict",["state"]),
+ EPL1 = [Strict],
+ RE1 = cre_ReqEv(Name1, EPL1),
+
+ Name2 = "al/on",
+ KA2 = true,
+ EDM2 = cre_EvDM("dialplan00"),
+
+ SID21 = cre_StreamID(7819),
+ ST21 = cre_SigType(timeOut),
+ Dur21 = 7898,
+ NC21 = cre_NotifCompl([onTimeOut, onInterruptByEvent, otherReason]),
+ KA21 = cre_BOOLEAN(false),
+ SPL21 = [],
+ Dir21 = cre_SigDir(both),
+ RID21 = cre_ReqID(7829),
+
+ Sig21 = cre_Sig("cg/rt", SID21, ST21, Dur21, NC21, KA21, SPL21, Dir21,
+ RID21, 7839),
+ SR21 = cre_SigReq(Sig21),
+ SRs21 = [SR21],
+ SD21 = cre_SigsDesc(SRs21),
+ RED21 = cre_RegEmbedDesc(SD21),
+ NB21 = cre_NotifBehav(notifyRegulated, RED21),
+
+ SRA2 = cre_SecReqActs(KA2, EDM2, asn1_NOVALUE, NB21, 'NULL'),
+ SRE2 = cre_SecReqEv("al/of", 7849, SRA2),
+ SED2 = cre_SecEvsDesc(7859, [SRE2]),
+
+ SID22 = cre_StreamID(7869),
+ ST22 = cre_SigType(brief),
+ Dur22 = 17809,
+ NC22 = cre_NotifCompl([onTimeOut, otherReason]),
+ KA22 = cre_BOOLEAN(true),
+ SPL22 = [],
+ Dir22 = cre_SigDir(external),
+ RID22 = cre_ReqID(7879),
+
+ Sig22 = cre_Sig("cg/rt", SID22, ST22, Dur22, NC22, KA22, SPL22, Dir22,
+ RID22, 7889),
+ SR22 = cre_SigReq(Sig22),
+ SRs22 = [SR22],
+ SD22 = cre_SigsDesc(SRs22),
+ RED22 = cre_RegEmbedDesc(SED2, SD22),
+
+ NB22 = cre_NotifBehav(notifyRegulated, RED22),
+ REvD2 = 'NULL',
+
+ RA2 = cre_ReqActs(KA2, EDM2, asn1_NOVALUE, asn1_NOVALUE, NB22, REvD2),
+ EPL2 = EPL1,
+ RE2 = cre_ReqEv(Name2, 7899, RA2, EPL2),
+ msg78a([RE1, RE2]).
+
+
+msg79a01() ->
+ TID1 = #megaco_term_id{id = ?A4444},
+ TID2 = #megaco_term_id{id = ?A4445},
+ TID3 = #megaco_term_id{id = ?A5555},
+ TIDs = cre_TermIDList([TID1, TID2, TID3]),
+ ErC = cre_ErrCode(?megaco_not_ready),
+ ErD = cre_ErrDesc(ErC),
+ ARP1 = cre_AuditRetParam(ErD),
+ RE = cre_ReqEv("al/of"),
+ EvD = cre_EvsDesc(7911,[RE]),
+ ARP2 = cre_AuditRetParam(EvD),
+ Tks = [mediaToken, digitMapToken, statsToken, packagesToken],
+ AD = cre_AuditDesc(Tks),
+ ARP3 = cre_AuditRetParam(AD),
+ TAR = cre_TermAudit([ARP1, ARP2, ARP3]),
+ TLAR = cre_TermListAuditRes(TIDs, TAR),
+ AudR = cre_AuditRep(TLAR),
+ CR = cre_CmdRep(auditValueReply, AudR),
+ ActR = cre_ActRep(7921, [CR]),
+ Acts = [ActR],
+ msg_reply(?MG2_MID, 7931, Acts).
+
+
+%% --
+
+msg80() ->
+ Address = {portNumber, ?DEFAULT_PORT},
+ Profile = cre_SvcChProf("resgw", 1),
+ Parm = cre_SvcChResParm(Address, Profile),
+ Reply = cre_SvcChRep([?megaco_root_termination_id],
+ {serviceChangeResParms, Parm}),
+ CmdRep = cre_CmdRep(serviceChangeReply, Reply),
+ cre_ActRep(80, [CmdRep]).
+
+msg80a(Mid, SN) ->
+ TransId = 8000,
+ ActRep = msg80(),
+ TransRep = cre_TransRep(TransId, [ActRep], SN),
+ Trans = cre_Trans(TransRep),
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg80a01() ->
+ msg80a(?MG1_MID, 1).
+
+msg80a02() ->
+ msg80a(?MG2_MID, 1000).
+
+msg80a03() ->
+ msg80a(?MG3_MID, 65535).
+
+msg80b(Mid, SN) ->
+ TransId = 8989,
+ ActRep = msg80(),
+ TransRep = cre_TransRep(TransId, [ActRep], SN, 'NULL'),
+ Trans = cre_Trans(TransRep),
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg80b01() ->
+ msg80b(?MG1_MID, 1).
+
+msg80b02() ->
+ msg80b(?MG2_MID, 1000).
+
+msg80b03() ->
+ msg80b(?MG3_MID, 65535).
+
+msg81a(Mid, SN) ->
+ TransId = 8101,
+ SegReply = cre_SegRep(TransId, SN),
+ Trans = cre_Trans(SegReply),
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg81a01() ->
+ msg81a(?MG1_MID, 1).
+
+msg81a02() ->
+ msg81a(?MG2_MID, 1000).
+
+msg81a03() ->
+ msg81a(?MG3_MID, 65535).
+
+msg81b(Mid, SN) ->
+ TransId = 8102,
+ SegReply = cre_SegRep(TransId, SN, 'NULL'),
+ Trans = cre_Trans(SegReply),
+ Mess = cre_Msg(Mid, [Trans]),
+ cre_MegacoMessage(Mess).
+
+msg81b01() ->
+ msg81b(?MG1_MID, 1).
+
+msg81b02() ->
+ msg81b(?MG2_MID, 1000).
+
+msg81b03() ->
+ msg81b(?MG3_MID, 65535).
+
+
+%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+%% Pretty RFC 3525 messages:
+
+%% Added Reason
+rfc3525_msg1() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222] Transaction = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ Method = Restart,
+ Reason = 901,
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+rfc3525_msg2() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 9998 {
+ Context = - {
+ ServiceChange = ROOT {
+ Services {
+ ServiceChangeAddress = 55555,
+ Profile = ResGW/1
+ }
+ }
+ }
+}".
+
+
+%% Removed "," after LocalControl ending "}"
+rfc3525_msg3() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 9999 {
+ Context = - {
+ Modify = A4444 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ tdmc/gain=2, ; in dB,
+ tdmc/ec=on
+ }
+ }
+ },
+ Events = 2222 {
+ al/of {strict=state}
+ }
+ }
+ }
+}".
+
+%% Removed the outermost "{}" pair (before the Reply token)
+rfc3525_msg4() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 9999 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg6() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10000 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2222 {
+ 19990729T22000000:al/of{init=false}
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg7() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10000 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+rfc3525_msg8() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10001 {
+ Context = - {
+ Modify = A4444 {
+ Events = 2223 {
+ al/on {strict=state},
+ dd/ce {DigitMap=Dialplan0}
+ },
+ Signals {cg/dt},
+ DigitMap = Dialplan0 {
+ (0| 00|[1-7]xxx|8xxxxxxx|fxxxxxxx|exx|91xxxxxxxxxx|9011x.)
+ }
+ }
+ }
+}".
+
+rfc3525_msg9() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10001 {
+ Context = - {
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg10() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Transaction = 10002 {
+ Context = - {
+ Notify = A4444 {
+ ObservedEvents =2223 {
+ 19990729T22010001:dd/ce {
+ ds=\"916135551212\",
+ Meth=UM
+ }
+ }
+ }
+ }
+}".
+
+
+rfc3525_msg11() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 10002 {
+ Context = - {
+ Notify = A4444
+ }
+}".
+
+%% Added ?
+rfc3525_msg12() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10003 {
+ Context = $ {
+ Add = A4444,
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = ReceiveOnly,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30 v=0 c=IN IP4 $ m=audio $ RTP/AVP 0
+ }
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg13() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10003 {
+ Context = 2000 {
+ Add = A4444,
+ Add = A4445 {
+ Media {
+ Stream = 1 {
+ Local {
+v=0
+o=- 2890844526 2890842807 IN IP4 124.124.124.222
+s=-
+t= 0 0
+c=IN IP4 124.124.124.222
+m=audio 2222 RTP/AVP 4
+a=ptime:30
+a=recvonly
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%%
+%% Added ?
+rfc3525_msg14() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50003 {
+ Context = $ {
+ Add = A5555 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ },
+ Events = 1234 {
+ al/of {strict=state}
+ },
+ Signals {al/ri}
+ },
+ Add = $ {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40 ; in ms
+ },
+ Local {
+ v=0 c=IN IP4 $ m=audio $ RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ } ; RTP profile for G.723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg15() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50003 {
+ Context = 5000 {
+ Add = A5555,
+ Add = A5556 {
+ Media {
+ Stream = 1 {
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg16a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10005 {
+ Context = 2000 {
+ Modify = A4444 {
+ Signals {cg/rt}
+ },
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ Remote {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4
+ } ; RTP profile for G723.1 is 4
+ }
+ }
+ }
+ }
+}".
+
+rfc3525_msg16b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10005 {
+ Context = 2000 {
+ Modify = A4444,
+ Modify = A4445
+ }
+}".
+
+rfc3525_msg17a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50005 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents = 1234 {
+ 19990729T22020002:al/of{init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg17b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50005 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg17c() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50006 {
+ Context = 5000 {
+ Modify = A5555 {
+ Events = 1235 {
+ al/on{strict=state}
+ },
+ Signals ; to turn off ringing
+ }
+ }
+}".
+
+rfc3525_msg17d() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50006 {
+ Context = 5000 {
+ Modify = A4445
+ }
+}".
+
+%% Removed "{ }" after Signals
+rfc3525_msg18a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 10006 {
+ Context = 2000 {
+ Modify = A4445 {
+ Media {
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive
+ }
+ }
+ }
+ },
+ Modify = A4444 {
+ Signals
+ }
+ }
+}".
+
+rfc3525_msg18b() ->
+"MEGACO/" ?VERSION_STR " [124.124.124.222]:55555 Reply = 10006 {
+ Context = 2000 {
+ Modify = A4445,
+ Modify = A4444
+ }
+}".
+
+rfc3525_msg19() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Audit {
+ Media, DigitMap, Events, Signals, Packages, Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg20() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50007 {
+ Context = - {
+ AuditValue = A5556 {
+ Media {
+ TerminationState {
+ ServiceStates = InService,
+ Buffer = OFF
+ },
+ Stream = 1 {
+ LocalControl {
+ Mode = SendReceive,
+ nt/jit=40
+ },
+ Local {
+ v=0 o=- 7736844526 7736842807 IN IP4 125.125.125.111 s=- t= 0 0 c=IN IP4 125.125.125.111 m=audio 1111 RTP/AVP 4 a=ptime:30
+ },
+ Remote {
+ v=0 o=- 2890844526 2890842807 IN IP4 124.124.124.222 s=- t= 0 0 c=IN IP4 124.124.124.222 m=audio 2222 RTP/AVP 4 a=ptime:30
+ }
+ }
+ },
+ Events,
+ Signals,
+ DigitMap,
+ Packages {nt-1, rtp-1},
+ Statistics {
+ rtp/ps=1200, ; packets sent
+ nt/os=62300, ; octets sent
+ rtp/pr=700, ; packets received
+ nt/or=45100, ; octets received
+ rtp/pl=0.2, ; % packet loss
+ rtp/jit=20,
+ rtp/delay=40 ; avg latency
+ }
+ }
+ }
+}".
+
+rfc3525_msg21a() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Transaction = 50008 {
+ Context = 5000 {
+ Notify = A5555 {
+ ObservedEvents =1235 {
+ 19990729T24020002:al/on {init=false}
+ }
+ }
+ }
+}".
+
+rfc3525_msg21b() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Reply = 50008 {
+ Context = - {
+ Notify = A5555
+ }
+}".
+
+rfc3525_msg22a() ->
+"MEGACO/" ?VERSION_STR " [123.123.123.4]:55555 Transaction = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Audit {
+ Statistics
+ }
+ },
+ Subtract = A5556 {
+ Audit {
+ Statistics
+ }
+ }
+ }
+}".
+
+%% Added ?
+rfc3525_msg22b() ->
+"MEGACO/" ?VERSION_STR " [125.125.125.111]:55555 Reply = 50009 {
+ Context = 5000 {
+ Subtract = A5555 {
+ Statistics {
+ nt/os=45123, ; Octets Sent
+ nt/dur=40 ; in seconds
+ }
+ },
+ Subtract = A5556 {
+ Statistics {
+ rtp/ps=1245, ; packets sent
+ nt/os=62345, ; octets sent
+ rtp/pr=780, ; packets received
+ nt/or=45123, ; octets received
+ rtp/pl=10, ; % packets lost
+ rtp/jit=27,
+ rtp/delay=48 ; average latency
+ }
+ }
+ }
+}".
+
+rfc3525_msgs() ->
+ [
+ {msg1, rfc3525_msg1()},
+ {msg2, rfc3525_msg2()},
+ {msg3, rfc3525_msg3()},
+ {msg4, rfc3525_msg4()},
+ {msg6, rfc3525_msg6()},
+ {msg7, rfc3525_msg7()},
+ {msg8, rfc3525_msg8()},
+ {msg9, rfc3525_msg9()},
+ {msg10, rfc3525_msg10()},
+ {msg11, rfc3525_msg11()},
+ {msg12, rfc3525_msg12()},
+ {msg13, rfc3525_msg13()},
+ {msg14, rfc3525_msg14()},
+ {msg15, rfc3525_msg15()},
+ {msg16a, rfc3525_msg16a()},
+ {msg16b, rfc3525_msg16b()},
+ {msg17a, rfc3525_msg17a()},
+ {msg17b, rfc3525_msg17b()},
+ {msg17c, rfc3525_msg17c()},
+ {msg17d, rfc3525_msg17d()},
+ {msg18a, rfc3525_msg18a()},
+ {msg18b, rfc3525_msg18b()},
+ {msg19, rfc3525_msg19()},
+ {msg20, rfc3525_msg20()},
+ {msg21a, rfc3525_msg21a()},
+ {msg21b, rfc3525_msg21b()},
+ {msg22a, rfc3525_msg22a()},
+ {msg22b, rfc3525_msg22b()}
+ ].
+
+rfc3525_msgs_display() ->
+ Msgs = rfc3525_msgs(),
+ Fun = fun({Name, Msg}) ->
+ io:format("~w: ~n~s~n~n", [Name, Msg])
+ end,
+ lists:foreach(Fun, Msgs).
+
+rfc3525_msgs_test() ->
+ put(dbg,true),
+ Res = rfc3525_msgs_test(megaco_pretty_text_encoder, [], 2),
+ erase(dbg),
+ io:format("~w~n", [Res]).
+
+rfc3525_msgs_test(Codec, Config, Ver) ->
+ io:format("-----------------------------------------"
+ "~ntesting with"
+ "~n Codec: ~w"
+ "~n Config: ~w"
+ "~n Version: ~w"
+ "~n", [Codec, Config, Ver]),
+ Msgs = rfc3525_msgs(),
+ Test = fun({N,M1}) ->
+ %% io:format("testing ~w: ", [N]),
+ io:format("~n*** testing ~w *** ~n~s~n", [N,M1]),
+ Bin1 = erlang:list_to_binary(M1),
+ case (catch Codec:decode_message(Config, Ver, Bin1)) of
+ {ok, M2} ->
+ %% io:format("d", []),
+ io:format("decoded:~n~p~n", [M2]),
+ case (catch Codec:encode_message(Config, Ver, M2)) of
+ {ok, Bin2} when is_binary(Bin2) ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [erlang:binary_to_list(Bin2)]),
+ {N,ok};
+ {ok, M3} ->
+ %% io:format("e~n", []),
+ io:format("encode: ~n~s~n", [M3]),
+ {N,ok};
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,encode_error}
+ end;
+ E ->
+ io:format("~n~p~n", [E]),
+ {N,decode_error}
+ end
+ end,
+ [Test(M) || M <- Msgs].
+
+%% --------------------------
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% skip(Reason) ->
+%% megaco_codec_test_lib:skip(Reason).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ticket_compact_encode_decode_ok(Msg) ->
+ ticket_compact_encode_decode_ok(Msg, []).
+
+ticket_compact_encode_decode_ok(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_encode_decode_ok(Msg, Codec, Conf).
+
+ticket_pretty_encode_decode_ok(Msg) ->
+ ticket_pretty_encode_decode_ok(Msg, []).
+
+ticket_pretty_encode_decode_ok(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_ok(Msg, Codec, Conf).
+
+ticket_encode_decode_ok(Msg, Codec, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Check = fun(M1, M2) -> chk_MegacoMessage(M1, M2) end,
+ megaco_codec_test_lib:expect_encode_decode(Msg, Encode, Decode, Check).
+
+%% --
+
+%% ticket_compact_encode_error(Msg) ->
+%% ticket_compact_encode_error(Msg, []).
+
+%% ticket_compact_encode_error(Msg, Conf) ->
+%% Codec = megaco_compact_text_encoder,
+%% ticket_encode_error(Msg, Codec, Conf).
+
+%% ticket_pretty_encode_error(Msg) ->
+%% ticket_pretty_encode_error(Msg, []).
+
+ticket_pretty_encode_error(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_error(Msg, Codec, Conf);
+ticket_pretty_encode_error(Msg, Check) when is_function(Check) ->
+ ticket_pretty_encode_error(Msg, [], Check).
+
+ticket_pretty_encode_error(Msg, Conf, Check) when is_function(Check) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_error(Msg, Codec, Conf, Check).
+
+ticket_encode_error(Msg, Codec, Conf) when is_list(Conf) ->
+ Check = fun(_) -> ok end, % Only called when encode failes
+ ticket_encode_error(Msg, Codec, Conf, Check).
+
+ticket_encode_error(Msg, Codec, Conf0, Check) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ megaco_codec_test_lib:expect_encode(Msg, Encode, Check).
+
+%% --
+
+ticket_compact_decode_encode_ok(Msg) ->
+ ticket_compact_decode_encode_ok(Msg, []).
+
+ticket_compact_decode_encode_ok(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_decode_encode_ok(Msg, Codec, Conf).
+
+ticket_pretty_decode_encode_ok(Msg) ->
+ ticket_pretty_decode_encode_ok(Msg, []).
+
+ticket_pretty_decode_encode_ok(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_encode_ok(Msg, Codec, Conf).
+
+ticket_decode_encode_ok(Msg, Codec, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Check = fun(M1, M2) -> chk_MegacoMessage(M1, M2) end,
+ megaco_codec_test_lib:expect_decode_encode(Msg, Decode, Encode, Check).
+
+%% --
+
+ticket_pretty_decode_encode_only(Msg, Check) ->
+ ticket_pretty_decode_encode_only(Msg, Check, []).
+
+ticket_pretty_decode_encode_only(Msg, Check, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_encode_only(Msg, Codec, Check, Conf).
+
+ticket_decode_encode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ megaco_codec_test_lib:expect_decode_encode_only(Msg, Decode, Encode,
+ Check).
+
+%% --
+
+ticket_pretty_encode_decode_only(Msg) ->
+ ticket_pretty_encode_decode_only(Msg, []).
+
+ticket_pretty_encode_decode_only(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_only(Msg, Codec, Conf);
+ticket_pretty_encode_decode_only(Msg, Check) when is_function(Check) ->
+ ticket_pretty_encode_decode_only(Msg, Check, []).
+
+ticket_pretty_encode_decode_only(Msg, Check, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_encode_decode_only(Msg, Codec, Check, Conf).
+
+ticket_encode_decode_only(Msg, Codec, Conf) ->
+ Check = fun(_) -> ok end,
+ ticket_encode_decode_only(Msg, Codec, Check, Conf).
+
+ticket_encode_decode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Encode = fun(M) -> encode_message(Codec, Conf, M) end,
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_encode_decode_only(Msg, Encode, Decode,
+ Check).
+
+%% --
+
+ticket_pretty_decode_only(Msg) ->
+ ticket_pretty_decode_only(Msg, []).
+
+ticket_pretty_decode_only(Msg, Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_only(Msg, Codec, Conf).
+
+ticket_decode_only(Msg, Codec, Conf) ->
+ Check = fun(_) -> ok end,
+ ticket_decode_only(Msg, Codec, Check, Conf).
+
+ticket_decode_only(Msg, Codec, Check, Conf0) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_decode_only(Msg, Decode, Check).
+
+ticket_check_decode_only_error_reason(R, Check)
+ when is_list(R) and is_function(Check) ->
+ case lists:keysearch(reason, 1, R) of
+ {value, {reason, Reason}} ->
+ Check(Reason);
+ false ->
+ {error, {reason_not_found, R}}
+ end.
+
+
+%% --
+
+ticket_compact_decode_error(Msg) ->
+ ticket_compact_decode_error(Msg, []).
+
+ticket_compact_decode_error(Msg, Conf) ->
+ Codec = megaco_compact_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf).
+
+ticket_pretty_decode_error(Msg) ->
+ ticket_pretty_decode_error(Msg, []).
+
+ticket_pretty_decode_error(Msg, Conf) when is_list(Conf) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf);
+ticket_pretty_decode_error(Msg, Check) when is_function(Check) ->
+ ticket_pretty_decode_error(Msg, [], Check).
+
+ticket_pretty_decode_error(Msg, Conf, Check) ->
+ Codec = megaco_pretty_text_encoder,
+ ticket_decode_error(Msg, Codec, Conf, Check).
+
+ticket_decode_error(Msg, Codec, Conf) ->
+ Check = fun(X) ->
+ d("decode error reason: ~n~p~n", [X]),
+ ok
+ end, % Only called when decode failes
+ ticket_decode_error(Msg, Codec, Conf, Check).
+
+ticket_decode_error(Msg, Codec, Conf0, Check) ->
+ Conf = [?EC_V3|Conf0],
+ Decode = fun(B) -> decode_message(Codec, false, Conf, B) end,
+ megaco_codec_test_lib:expect_decode(Msg, Decode, Check).
+
+%% --
+
+%% ticket_expect_exec(Instructions, Msg) ->
+%% megaco_codec_test_lib:expect_exec(Instructions, Msg).
+
+%% ticket_expect_instruction(Desc, Cmd, Verify) ->
+%% megaco_codec_test_lib:expect_instruction(Desc, Cmd, Verify).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% pretty_decode_message(DynamicDecode, Conf, Bin) ->
+%% decode_message(megaco_pretty_text_encoder, DynamicDecode, Conf, Bin).
+
+%% compact_decode_message(DynamicDecode, Conf, Bin) ->
+%% decode_message(megaco_compact_text_encoder, DynamicDecode, Conf, Bin).
+
+decode_message(Codec, DynamicDecode, Conf, Bin) ->
+ megaco_codec_test_lib:decode_message(Codec, DynamicDecode, ?VERSION,
+ Conf, Bin).
+
+%% pretty_encode_message(Conf, Msg) ->
+%% encode_message(megaco_pretty_text_encoder, Conf, Msg).
+
+%% compact_encode_message(Conf, Msg) ->
+%% encode_message(megaco_compact_text_encoder, Conf, Msg).
+
+encode_message(Codec, Conf, Msg) ->
+ megaco_codec_test_lib:encode_message(Codec, ?VERSION, Conf, Msg).
+
+test_msgs(Codec, DynamicDecode, Conf, Msgs) ->
+ megaco_codec_test_lib:test_msgs(Codec, DynamicDecode, ?VERSION, Conf,
+ fun chk_MegacoMessage/2, Msgs).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+chk_MegacoMessage(M1, M2) ->
+ ?MSG_LIB:chk_MegacoMessage(M1, M2).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Mess).
+
+cre_MegacoMessage(Auth, Mess) ->
+ ?MSG_LIB:cre_MegacoMessage(Auth, Mess).
+
+cre_MegacoMessage(V, Mid, Body) ->
+ Mess = ?MSG_LIB:cre_Message(V, Mid, Body),
+ cre_MegacoMessage(Mess).
+
+cre_AuthHeader() ->
+ SecParmIdx = [239, 205, 171, 137],
+ SeqNum = [18, 52, 86, 120],
+ AD = [18, 52, 86, 120, 137, 171, 205, 239, 118, 84, 50, 16],
+ cre_AuthHeader(SecParmIdx, SeqNum, AD).
+
+cre_AuthHeader(Idx, Num, D) ->
+ ?MSG_LIB:cre_AuthenticationHeader(Idx, Num, D).
+
+cre_Msg(Mid, Body) ->
+ cre_Msg(?VERSION, Mid, Body).
+
+cre_Msg(V, Mid, Body) ->
+ ?MSG_LIB:cre_Message(V, Mid, Body).
+
+cre_TransId(TransId) ->
+ ?MSG_LIB:cre_TransactionId(TransId).
+
+cre_Trans(Trans) ->
+ ?MSG_LIB:cre_Transaction(Trans).
+
+cre_TransReq(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionRequest(TransId, Actions).
+
+cre_TransRep(TransId, Actions) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions).
+
+cre_TransRep(TransId, Actions, SN) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions, SN).
+
+cre_TransRep(TransId, Actions, SN, SC) ->
+ ?MSG_LIB:cre_TransactionReply(TransId, Actions, SN, SC).
+
+cre_SegRep(TransId, SN) ->
+ ?MSG_LIB:cre_SegmentReply(TransId, SN).
+
+cre_SegRep(TransId, SN, SC) ->
+ ?MSG_LIB:cre_SegmentReply(TransId, SN, SC).
+
+cre_TransAck(First, Last) ->
+ ?MSG_LIB:cre_TransactionAck(First, Last).
+
+cre_ActReq(CtxId, CmdReqs) ->
+ ?MSG_LIB:cre_ActionRequest(CtxId, CmdReqs).
+
+cre_ActRep(CtxId, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, CmdReps).
+
+cre_ActRep(CtxId, ED, CR, CmdReps) ->
+ ?MSG_LIB:cre_ActionReply(CtxId, ED, CR, CmdReps).
+
+cre_CtxReq() ->
+ ?MSG_LIB:cre_ContextRequest().
+
+cre_CtxReq(A) ->
+ ?MSG_LIB:cre_ContextRequest(A).
+
+cre_CtxReq(A, B) ->
+ ?MSG_LIB:cre_ContextRequest(A, B).
+
+cre_CtxReq(A, B, C) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C).
+
+cre_CtxReq(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D).
+
+cre_CtxReq(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextRequest(A, B, C, D, E).
+
+cre_CtxReq(Prio, Em, Top, Ieps, CtxProp, CtxList) ->
+ ?MSG_LIB:cre_ContextRequest(Prio, Em, Top, Ieps, CtxProp, CtxList).
+
+cre_CtxAttrAuditReq() ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest().
+
+% cre_CtxAttrAuditReq(A) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A).
+
+% cre_CtxAttrAuditReq(A, B) ->
+% ?MSG_LIB:cre_ContextAttrAuditRequest(A, B).
+
+cre_CtxAttrAuditReq(A, B, C) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C).
+
+cre_CtxAttrAuditReq(A, B, C, D) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D).
+
+cre_CtxAttrAuditReq(A, B, C, D, E) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SPrio).
+
+cre_CtxAttrAuditReq(A, B, C, D, E, F, G) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(A, B, C, D, E, F, G).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio, SEm, SIeps) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SPrio, SEm, SIeps).
+
+cre_CtxAttrAuditReq(Top, Em, Prio, Ieps, Ctx, SPrio, SEm, SIeps, SLog) ->
+ ?MSG_LIB:cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SPrio, SEm, SIeps, SLog).
+
+cre_TopologyRequest(From, To, Dir) ->
+ ?MSG_LIB:cre_TopologyRequest(From, To, Dir).
+
+%% Ind Aud related:
+
+cre_IndAudParam(IAP) ->
+ ?MSG_LIB:cre_IndAuditParameter(IAP).
+
+cre_IndAudMediaDesc(D) ->
+ ?MSG_LIB:cre_IndAudMediaDescriptor(D).
+
+cre_IndAudStreamDesc(SID, SP) ->
+ ?MSG_LIB:cre_IndAudStreamDescriptor(SID, SP).
+
+cre_IndAudStreamParms(LCD) ->
+ ?MSG_LIB:cre_IndAudStreamParms(LCD).
+
+cre_IndAudLocalControlDesc(A, B, C, D) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(A, B, C, D).
+
+cre_IndAudLocalControlDesc(SM, RV, RG, PP, SMS) ->
+ ?MSG_LIB:cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS).
+
+cre_IndAudPropertyParm(Name) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name).
+
+cre_IndAudPropertyParm(Name, PP) ->
+ ?MSG_LIB:cre_IndAudPropertyParm(Name, PP).
+
+cre_IndAudTermStateDesc(PP) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP).
+
+cre_IndAudTermStateDesc(PP, EBC, SS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS).
+
+cre_IndAudTermStateDesc(PP, EBC, SS, SSS) ->
+ ?MSG_LIB:cre_IndAudTerminationStateDescriptor(PP, EBC, SS, SSS).
+
+cre_IndAudEvsDesc(RID, PN)
+ when is_integer(RID) ->
+ ?MSG_LIB:cre_IndAudEventsDescriptor(RID, PN).
+
+cre_IndAudEvBufDesc(EN, SID) ->
+ ?MSG_LIB:cre_IndAudEventBufferDescriptor(EN, SID).
+
+cre_IndAudSigsDesc(D) ->
+ ?MSG_LIB:cre_IndAudSignalsDescriptor(D).
+
+cre_IndAudSig(SN) ->
+ ?MSG_LIB:cre_IndAudSignal(SN).
+
+cre_IndAudSig(SN, SigRID) ->
+ ?MSG_LIB:cre_IndAudSignal(SN, SigRID).
+
+cre_IndAudSeqSigList(ID, SL) ->
+ ?MSG_LIB:cre_IndAudSeqSigList(ID, SL).
+
+cre_IndAudDigitMapDesc(DMN) ->
+ ?MSG_LIB:cre_IndAudDigitMapDescriptor(DMN).
+
+cre_IndAudStatsDesc(SN) ->
+ ?MSG_LIB:cre_IndAudStatisticsDescriptor(SN).
+
+cre_IndAudPkgsDesc(PN, PV) ->
+ ?MSG_LIB:cre_IndAudPackagesDescriptor(PN, PV).
+
+%% Parameter related
+cre_PropParm(Name, Val) ->
+ ?MSG_LIB:cre_PropertyParm(Name, [Val]).
+
+cre_PropParm(Name, Vals, Tag, EI) ->
+ ?MSG_LIB:cre_PropertyParm(Name, Vals, Tag, EI).
+
+
+%% Statistics related
+cre_StatsDesc(SPs) ->
+ ?MSG_LIB:cre_StatisticsDescriptor(SPs).
+
+cre_StatsParm(Name) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name).
+
+cre_StatsParm(Name, Val) ->
+ ?MSG_LIB:cre_StatisticsParameter(Name, [Val]).
+
+
+% Event related
+cre_EvParm(Name, Val) ->
+ ?MSG_LIB:cre_EventParameter(Name, Val).
+
+cre_ObsEv(Name, Not) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Not).
+cre_ObsEv(Name, Not, Par) ->
+ ?MSG_LIB:cre_ObservedEvent(Name, Par, Not).
+
+cre_ReqEv(Name) ->
+ ?MSG_LIB:cre_RequestedEvent(Name).
+cre_ReqEv(Name, EPL) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, EPL).
+cre_ReqEv(Name, SID, RA, EPL) ->
+ ?MSG_LIB:cre_RequestedEvent(Name, SID, RA, EPL).
+
+
+cre_ObsEvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_ObservedEventsDescriptor(Id, EvList).
+
+cre_EvsDesc(Id, EvList) ->
+ ?MSG_LIB:cre_EventsDescriptor(Id, EvList).
+
+
+%% Service change related
+cre_SvcChParm(M, A, R, P) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, P, R).
+
+cre_SvcChParm(M, A, R, P, IF) ->
+ ?MSG_LIB:cre_ServiceChangeParm(M, A, asn1_NOVALUE, P, R, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, IF).
+
+cre_SvcChResParm(A, P) ->
+ ?MSG_LIB:cre_ServiceChangeResParm(A, P).
+
+cre_SvcChReq(Tids, P) ->
+ ?MSG_LIB:cre_ServiceChangeRequest(Tids, P).
+
+cre_SvcChProf(Name, Ver) ->
+ ?MSG_LIB:cre_ServiceChangeProfile(Name, Ver).
+
+cre_SvcChAddr(Tag, Val) ->
+ ?MSG_LIB:cre_ServiceChangeAddress(Tag, Val).
+
+cre_SvcChMethod(M) ->
+ ?MSG_LIB:cre_ServiceChangeMethod(M).
+
+cre_SvcChRep(Tids, Res) ->
+ ?MSG_LIB:cre_ServiceChangeReply(Tids, Res).
+
+
+%% Stream related
+cre_StreamID(Id) ->
+ ?MSG_LIB:cre_StreamID(Id).
+
+cre_StreamParms(Lcd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd).
+cre_StreamParms(Lcd, Ld) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld).
+cre_StreamParms(Lcd, Ld, Rd) ->
+ ?MSG_LIB:cre_StreamParms(Lcd, Ld, Rd).
+cre_StreamParmsL(Ld) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, Ld, asn1_NOVALUE).
+cre_StreamParmsR(Rd) ->
+ ?MSG_LIB:cre_StreamParms(asn1_NOVALUE, asn1_NOVALUE, Rd).
+
+cre_StreamDesc(Id, P) ->
+ ?MSG_LIB:cre_StreamDescriptor(Id, P).
+
+
+%% "Local" related
+cre_LocalControlDesc(Mode) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode).
+cre_LocalControlDesc(Mode, Parms) ->
+ ?MSG_LIB:cre_LocalControlDescriptor(Mode, Parms).
+
+cre_LocalRemoteDesc(Grps) ->
+ ?MSG_LIB:cre_LocalRemoteDescriptor(Grps).
+
+
+%% DigitMap related
+cre_DigitMapDesc() ->
+ ?MSG_LIB:cre_DigitMapDescriptor().
+cre_DigitMapDesc(NameOrVal) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(NameOrVal).
+cre_DigitMapDesc(Name, Val) ->
+ ?MSG_LIB:cre_DigitMapDescriptor(Name, Val).
+
+cre_DigitMapValue(Body) ->
+ ?MSG_LIB:cre_DigitMapValue(Body).
+
+cre_DigitMapValue(Body, Start, Short, Long) ->
+ ?MSG_LIB:cre_DigitMapValue(Start, Short, Long, Body).
+
+%% Media related
+cre_MediaDesc(SD) when is_record(SD, 'StreamDescriptor') ->
+ cre_MediaDesc([SD]);
+cre_MediaDesc(SDs) ->
+ ?MSG_LIB:cre_MediaDescriptor(SDs).
+
+
+%% Notify related
+cre_NotifyReq(Tids, EvsDesc) ->
+ ?MSG_LIB:cre_NotifyRequest(Tids, EvsDesc).
+
+cre_NotifyRep(Tids) ->
+ ?MSG_LIB:cre_NotifyReply(Tids).
+
+
+%% Subtract related
+cre_SubReq(Tids, Desc) ->
+ ?MSG_LIB:cre_SubtractRequest(Tids, Desc).
+
+
+%% Audit related
+cre_AuditDesc(Tokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens).
+
+cre_AuditDesc(Tokens, PropertTokens) ->
+ ?MSG_LIB:cre_AuditDescriptor(Tokens, PropertTokens).
+
+cre_AuditReq(Tid, Desc) ->
+ ?MSG_LIB:cre_AuditRequest(Tid, Desc).
+
+cre_AuditRep(AR) ->
+ ?MSG_LIB:cre_AuditReply(AR).
+
+cre_AuditRes(Tid, Res) ->
+ ?MSG_LIB:cre_AuditResult(Tid, Res).
+
+cre_TermAudit(ARP) ->
+ ?MSG_LIB:cre_TerminationAudit(ARP).
+
+cre_AuditRetParam(D) ->
+ ?MSG_LIB:cre_AuditReturnParameter(D).
+
+cre_TermListAuditRes(TIDs, TA) ->
+ ?MSG_LIB:cre_TermListAuditResult(TIDs, TA).
+
+%% AMM/AMMS related
+cre_AmmDesc(D) ->
+ ?MSG_LIB:cre_AmmDescriptor(D).
+
+cre_AmmReq(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmRequest(Tids, Descs).
+
+cre_AmmsReply(Tids) ->
+ ?MSG_LIB:cre_AmmsReply(Tids).
+cre_AmmsReply(Tids, Descs) ->
+ ?MSG_LIB:cre_AmmsReply(Tids, Descs).
+
+
+%% Command related
+cre_Cmd(Tag, Req) ->
+ ?MSG_LIB:cre_Command(Tag, Req).
+
+cre_CmdReq(Cmd) ->
+ ?MSG_LIB:cre_CommandRequest(Cmd).
+
+cre_CmdRep(Tag, Rep) ->
+ ?MSG_LIB:cre_CommandReply(Tag, Rep).
+
+
+%% Actions related
+cre_ReqActs(A) ->
+ ?MSG_LIB:cre_RequestedActions(A).
+
+cre_ReqActs(KA, EDM, SE, SD, NB, RED) ->
+ ?MSG_LIB:cre_RequestedActions(KA, EDM, SE, SD, NB, RED).
+
+%% cre_SecReqActs() ->
+%% ?MSG_LIB:cre_SecondRequestedActions().
+
+%% cre_SecReqActs(A) ->
+%% ?MSG_LIB:cre_SecondRequestedActions(A).
+
+cre_SecReqActs(KA, EDM, SD, NB, RED) ->
+ ?MSG_LIB:cre_SecondRequestedActions(KA, EDM, SD, NB, RED).
+
+cre_EvDM(Name) when is_list(Name) ->
+ ?MSG_LIB:cre_EventDM(Name).
+
+cre_RegEmbedDesc() ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor().
+
+cre_RegEmbedDesc(D) ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor(D).
+
+cre_RegEmbedDesc(SED, SD) ->
+ ?MSG_LIB:cre_RegulatedEmbeddedDescriptor(SED, SD).
+
+%% cre_SecEvsDesc(REDs) ->
+%% ?MSG_LIB:cre_SecondEventsDescriptor(REDs).
+
+cre_SecEvsDesc(RID, REDs) ->
+ ?MSG_LIB:cre_SecondEventsDescriptor(RID, REDs).
+
+cre_SecReqEv(N) ->
+ cre_SecReqEv(N, []).
+
+cre_SecReqEv(N, EPL) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(N, EPL).
+
+cre_SecReqEv(N, SID, EA) when is_list(N) and
+ is_integer(SID) and
+ is_record(EA, 'SecondRequestedActions') ->
+ cre_SecReqEv(N, SID, EA, []);
+cre_SecReqEv(A, B, C) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(A, B, C).
+
+cre_SecReqEv(N, SID, EA, EPL) ->
+ ?MSG_LIB:cre_SecondRequestedEvent(N, SID, EA, EPL).
+
+%% Signal related
+cre_SigsDesc() ->
+ cre_SigsDesc([]).
+
+cre_SigsDesc(SRs) ->
+ ?MSG_LIB:cre_SignalsDescriptor(SRs).
+
+cre_SigDir(D) ->
+ ?MSG_LIB:cre_SignalDirection(D).
+
+cre_Sig(Name) ->
+ cre_Sig(Name, []).
+
+cre_Sig(Name, SPL) ->
+ ?MSG_LIB:cre_Signal(Name, SPL).
+
+cre_Sig(Name, Dir, RID) ->
+ cre_Sig(Name, [], Dir, RID).
+
+cre_Sig(Name, SPL, Dir, RID) ->
+ cre_Sig(Name, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID).
+
+cre_Sig(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD) ->
+ ?MSG_LIB:cre_Signal(Name, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD).
+
+cre_SigReq(S) ->
+ ?MSG_LIB:cre_SignalRequest(S).
+
+cre_NotifBehav(Tag, Val) ->
+ ?MSG_LIB:cre_NotifyBehaviour(Tag, Val).
+
+cre_NotifCompl(NC) ->
+ ?MSG_LIB:cre_NotifyCompletion(NC).
+
+cre_SigType(ST) ->
+ ?MSG_LIB:cre_SignalType(ST).
+
+
+%% Others
+cre_ErrCode(EC) ->
+ ?MSG_LIB:cre_ErrorCode(EC).
+
+cre_ErrDesc(EC) ->
+ ?MSG_LIB:cre_ErrorDescriptor(EC).
+
+cre_TermIDList(TIDs) ->
+ ?MSG_LIB:cre_TerminationIDList(TIDs).
+
+cre_ServiceState(SS) ->
+ ?MSG_LIB:cre_ServiceState(SS).
+
+cre_StreamMode(SS) ->
+ ?MSG_LIB:cre_StreamMode(SS).
+
+cre_SelectLogic(Tag) ->
+ ?MSG_LIB:cre_SelectLogic(Tag).
+
+cre_CtxID(CID) ->
+ ?MSG_LIB:cre_ContextID(CID).
+
+cre_ReqID(RID) ->
+ ?MSG_LIB:cre_RequestID(RID).
+
+cre_TimeNot(D,T) ->
+ ?MSG_LIB:cre_TimeNotation(D, T).
+
+cre_PkgsItem(Name, Ver) ->
+ ?MSG_LIB:cre_PackagesItem(Name, Ver).
+
+cre_BOOLEAN(B) ->
+ ?MSG_LIB:cre_BOOLEAN(B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+flex_init(Config) ->
+ megaco_codec_flex_lib:init(Config).
+
+flex_finish(Config) ->
+ megaco_codec_flex_lib:finish(Config).
+
+flex_scanner_conf(Config) ->
+ megaco_codec_flex_lib:scanner_conf(Config).
+
+%% start_flex_scanner() ->
+%% megaco_codec_flex_lib:start().
+
+%% stop_flex_scanner(Pid) ->
+%% megaco_codec_flex_lib:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t(F,A) ->
+ p(printable(get(severity),trc),trc,F,A).
+
+d(F,A) ->
+ p(printable(get(severity),dbg),dbg,F,A).
+
+%% l(F,A) ->
+%% p(printable(get(severity),log),log,F,A).
+
+e(F,A) ->
+ p(printable(get(severity),err),err,F,A).
+
+
+printable(trc,_) ->
+ true;
+printable(dbg,trc) ->
+ false;
+printable(dbg,_) ->
+ true;
+printable(log,log) ->
+ true;
+printable(log,err) ->
+ true;
+printable(err,err) ->
+ true;
+printable(_,_) ->
+ false.
+
+
+p(true,L,F,A) ->
+ io:format("~s:" ++ F ++ "~n", [image_of(L)|A]);
+p(_,_,_,_) ->
+ ok.
+
+image_of(trc) ->
+ "TRC";
+image_of(dbg) ->
+ "DBG";
+image_of(log) ->
+ "LOG";
+image_of(err) ->
+ "ERR";
+image_of(L) ->
+ io_lib:format("~p",[L]).
+
diff --git a/lib/megaco/test/megaco_config_test.erl b/lib/megaco/test/megaco_config_test.erl
new file mode 100644
index 0000000000..453c1b8964
--- /dev/null
+++ b/lib/megaco/test/megaco_config_test.erl
@@ -0,0 +1,1110 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test application config
+%%----------------------------------------------------------------------
+
+-module(megaco_config_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/src/app/megaco_internal.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+min(M) -> timer:minutes(M).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(3)}|C]).
+
+do_init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+-record(command, {id, desc, cmd, verify}).
+
+-define(TEST_VERBOSITY, debug).
+-define(NUM_CNT_PROCS, 100).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(suite) ->
+ [
+ config,
+ transaction_id_counter,
+ tickets
+ ].
+
+transaction_id_counter(suite) ->
+ [
+ transaction_id_counter_mg,
+ transaction_id_counter_mgc
+ ].
+
+tickets(suite) ->
+ [
+ otp_7216,
+ otp_8167,
+ otp_8183
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Config test case
+
+config(suite) ->
+ [];
+config(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Mid = fake_mid,
+
+ %% Nice values
+ Int = 3,
+ IT = #megaco_incr_timer{max_retries = Int},
+
+ %% Evil values
+ NonInt = non_int,
+ IT2 = #megaco_incr_timer{wait_for = NonInt},
+ IT3 = #megaco_incr_timer{factor = NonInt},
+ IT4 = #megaco_incr_timer{max_retries = NonInt},
+ IT5 = #megaco_incr_timer{max_retries = non_infinity},
+
+ %% Command range values
+ Initial = 100,
+ Verify = 200,
+ Nice = 300,
+ Evil = 400,
+ End = 500,
+
+ Commands =
+ [
+ %% Initial commands
+ initial_command( Initial + 0,
+ "enable trace",
+ fun() -> megaco:enable_trace(100, io) end, ok),
+ initial_command( Initial + 1,
+ "start",
+ fun() -> megaco:start() end, ok),
+ initial_command( Initial + 2,
+ "Verify no active requests",
+ fun() -> megaco:system_info(n_active_requests) end,
+ 0),
+ initial_command( Initial + 3,
+ "Verify no active replies",
+ fun() -> megaco:system_info(n_active_replies) end,
+ 0),
+ initial_command( Initial + 4,
+ "Verify no active connections",
+ fun() ->
+ megaco:system_info(n_active_connections)
+ end,
+ 0),
+ initial_command( Initial + 5,
+ "Verify no connections",
+ fun() -> megaco:system_info(connections) end, []),
+ initial_command( Initial + 6,
+ "Verify no users",
+ fun() -> megaco:system_info(users) end, []),
+ initial_command( Initial + 7,
+ "Start user",
+ fun() -> megaco:start_user(Mid, []) end, ok),
+
+
+ %% Verify user defaults
+ verify_user_default_command(Mid, Verify + 1, connections, []),
+ verify_user_default_command(Mid, Verify + 2, min_trans_id, 1),
+ verify_user_default_command(Mid, Verify + 3, max_trans_id, infinity),
+ verify_user_default_command(Mid, Verify + 4, request_timer,
+ #megaco_incr_timer{}),
+ verify_user_default_command(Mid, Verify + 5, long_request_timer, timer:seconds(60)),
+ verify_user_default_command(Mid, Verify + 6, auto_ack, false),
+ verify_user_default_command(Mid, Verify + 7, pending_timer, 30000),
+ verify_user_default_command(Mid, Verify + 8, reply_timer, 30000),
+ verify_user_default_command(Mid, Verify + 9, send_mod, megaco_tcp),
+ verify_user_default_command(Mid, Verify + 10, encoding_mod,
+ megaco_pretty_text_encoder),
+ verify_user_default_command(Mid, Verify + 11, encoding_config, []),
+ verify_user_default_command(Mid, Verify + 12, protocol_version, 1),
+ verify_user_default_command(Mid, Verify + 13, reply_data, undefined),
+ verify_user_default_command(Mid, Verify + 14, receive_handle,
+ fun(H) when is_record(H, megaco_receive_handle) -> {ok, H};
+ (R) -> {error, R}
+ end),
+
+
+ %% Nice update
+ nice_user_update_command(Mid, Nice + 1, min_trans_id, Int),
+ nice_user_update_command(Mid, Nice + 2, max_trans_id, Int),
+ nice_user_update_command(Mid, Nice + 3, max_trans_id, infinity),
+ nice_user_update_command(Mid, Nice + 4, request_timer, Int),
+ nice_user_update_command(Mid, Nice + 5, request_timer, infinity),
+ nice_user_update_command(Mid, Nice + 6, request_timer, IT),
+ nice_user_update_command(Mid, Nice + 7, long_request_timer, Int),
+ nice_user_update_command(Mid, Nice + 8, long_request_timer, infinity),
+ nice_user_update_command(Mid, Nice + 9, long_request_timer, IT),
+ nice_user_update_command(Mid, Nice + 10, auto_ack, true),
+ nice_user_update_command(Mid, Nice + 11, auto_ack, false),
+ nice_user_update_command(Mid, Nice + 12, pending_timer, Int),
+ nice_user_update_command(Mid, Nice + 13, pending_timer, infinity),
+ nice_user_update_command(Mid, Nice + 14, pending_timer, IT),
+ nice_user_update_command(Mid, Nice + 15, reply_timer, Int),
+ nice_user_update_command(Mid, Nice + 16, reply_timer, infinity),
+ nice_user_update_command(Mid, Nice + 17, reply_timer, IT),
+ nice_user_update_command(Mid, Nice + 18, send_mod, an_atom),
+ nice_user_update_command(Mid, Nice + 19, encoding_mod, an_atom),
+ nice_user_update_command(Mid, Nice + 20, encoding_config, []),
+ nice_user_update_command(Mid, Nice + 21, protocol_version, Int),
+ nice_user_update_command(Mid, Nice + 23, reply_data, IT),
+ nice_user_update_command(Mid, Nice + 23, resend_indication, true),
+ nice_user_update_command(Mid, Nice + 24, resend_indication, false),
+ nice_user_update_command(Mid, Nice + 25, resend_indication, flag),
+
+
+ %% Evil update
+ evil_user_update_command(Mid, Evil + 1, min_trans_id, NonInt),
+ evil_user_update_command(Mid, Evil + 2, max_trans_id, NonInt),
+ evil_user_update_command(Mid, Evil + 3, max_trans_id, non_infinity),
+ evil_user_update_command(Mid, Evil + 4, request_timer, NonInt),
+ evil_user_update_command(Mid, Evil + 5, request_timer, non_infinity),
+ evil_user_update_command(Mid, Evil + 6, request_timer, IT2),
+ evil_user_update_command(Mid, Evil + 7, request_timer, IT3),
+ evil_user_update_command(Mid, Evil + 8, request_timer, IT4),
+ evil_user_update_command(Mid, Evil + 9, request_timer, IT5),
+ evil_user_update_command(Mid, Evil + 10, long_request_timer, NonInt),
+ evil_user_update_command(Mid, Evil + 11, long_request_timer, non_infinity),
+ evil_user_update_command(Mid, Evil + 12, long_request_timer, IT2),
+ evil_user_update_command(Mid, Evil + 13, long_request_timer, IT3),
+ evil_user_update_command(Mid, Evil + 14, long_request_timer, IT4),
+ evil_user_update_command(Mid, Evil + 15, long_request_timer, IT5),
+ evil_user_update_command(Mid, Evil + 16, auto_ack, non_bool),
+ evil_user_update_command(Mid, Evil + 17, pending_timer, NonInt),
+ evil_user_update_command(Mid, Evil + 18, pending_timer, non_infinity),
+ evil_user_update_command(Mid, Evil + 19, pending_timer, IT2),
+ evil_user_update_command(Mid, Evil + 20, pending_timer, IT3),
+ evil_user_update_command(Mid, Evil + 21, pending_timer, IT4),
+ evil_user_update_command(Mid, Evil + 22, pending_timer, IT5),
+ evil_user_update_command(Mid, Evil + 23, reply_timer, NonInt),
+ evil_user_update_command(Mid, Evil + 24, reply_timer, non_infinity),
+ evil_user_update_command(Mid, Evil + 25, reply_timer, IT2),
+ evil_user_update_command(Mid, Evil + 26, reply_timer, IT3),
+ evil_user_update_command(Mid, Evil + 27, reply_timer, IT4),
+ evil_user_update_command(Mid, Evil + 28, reply_timer, IT5),
+ evil_user_update_command(Mid, Evil + 29, send_mod, {non_atom}),
+ evil_user_update_command(Mid, Evil + 30, encoding_mod, {non_atom}),
+ evil_user_update_command(Mid, Evil + 31, encoding_config, non_list),
+ evil_user_update_command(Mid, Evil + 32, protocol_version, NonInt),
+ evil_user_update_command(Mid, Evil + 33, resend_indication, flagg),
+
+
+ exit_command(End + 1,
+ "Verify non-existing system info",
+ fun() -> megaco:system_info(non_exist) end),
+ exit_command(End + 2,
+ "Verify non-existing user user info",
+ fun() -> megaco:user_info(non_exist, trans_id) end),
+ exit_command(End + 3, "Verify non-existing user info",
+ fun() -> megaco:user_info(Mid, non_exist) end),
+
+ error_command(End + 4,
+ "Try updating user info for non-existing user",
+ fun() ->
+ megaco:update_user_info(non_exist, trans_id, 1)
+ end,
+ no_such_user, 2),
+ error_command(End + 11,
+ "Try updating non-existing user info",
+ fun() ->
+ megaco:update_user_info(Mid, trans_id, 4711)
+ end,
+ bad_user_val, 4),
+ error_command(End + 12,
+ "Try start already started user",
+ fun() ->
+ megaco:start_user(Mid, [])
+ end,
+ user_already_exists, 2),
+
+ command(End + 13, "Verify started users",
+ fun() -> megaco:system_info(users) end, [Mid]),
+ command(End + 14, "Stop user", fun() -> megaco:stop_user(Mid) end, ok),
+ command(End + 15, "Verify started users",
+ fun() -> megaco:system_info(users) end, []),
+ error_command(End + 16, "Try stop not started user",
+ fun() -> megaco:stop_user(Mid) end, no_such_user, 2),
+ error_command(End + 17, "Try start megaco (it's already started)",
+ fun() -> megaco:start() end, already_started, 2),
+ command(End + 18, "Stop megaco", fun() -> megaco:stop() end, ok),
+ error_command(End + 19, "Try stop megaco (it's not running)",
+ fun() -> megaco:stop() end, not_started, 2)
+ ],
+
+
+ exec(Commands).
+
+
+
+exec([]) ->
+ ok;
+exec([#command{id = No,
+ desc = Desc,
+ cmd = Cmd,
+ verify = Verify}|Commands]) ->
+ io:format("Executing command ~2w: ~s: ", [No, Desc]),
+ case (catch Verify((catch Cmd()))) of
+ {ok, OK} ->
+ io:format("ok => ~p~n", [OK]),
+ exec(Commands);
+ {error, Reason} ->
+ io:format("error => ~p~n", [Reason]),
+ {error, {bad_result, No, Reason}};
+ Error ->
+ io:format("exit => ~p~n", [Error]),
+ {error, {unexpected_result, No, Error}}
+ end.
+
+initial_command(No, Desc0, Cmd, VerifyVal) when is_function(Cmd) ->
+ Desc = lists:flatten(io_lib:format("Initial - ~s", [Desc0])),
+ command(No, Desc, Cmd, VerifyVal).
+
+verify_user_default_command(Mid, No, Key, Verify) ->
+ Desc = lists:flatten(io_lib:format("Defaults - Verify ~w", [Key])),
+ Cmd = fun() -> megaco:user_info(Mid, Key) end,
+ command(No, Desc, Cmd, Verify).
+
+nice_user_update_command(Mid, No, Key, Val) ->
+ Desc = lists:flatten(io_lib:format("Nice - Update ~w", [Key])),
+ Cmd = fun() -> megaco:update_user_info(Mid, Key, Val) end,
+ Verify = fun(ok) ->
+ case (catch megaco:user_info(Mid, Key)) of
+ {'EXIT', R} ->
+ {error, {value_retreival_failed, R}};
+ Val ->
+ {ok, Val};
+ Invalid ->
+ {error, {value_update_failed, Val, Invalid}}
+ end;
+ (R) ->
+ {error, R}
+ end,
+ command(No, Desc, Cmd, Verify).
+
+
+evil_user_update_command(Mid, No, Key, Val) ->
+ Desc = lists:flatten(io_lib:format("Evil: Update ~w", [Key])),
+ Cmd = fun() ->
+ case (catch megaco:user_info(Mid, Key)) of
+ {'EXIT', R} ->
+ {{error, {old_value_retreival_failed, R}},
+ ignore};
+ OldVal ->
+ {OldVal,
+ (catch megaco:update_user_info(Mid, Key, Val))}
+ end
+ end,
+ Verify = fun({{error, _} = Error, ignore}) ->
+ Error;
+ ({OldVal, {error, {bad_user_val, _, _, _}}}) ->
+ case (catch megaco:user_info(Mid, Key)) of
+ {'EXIT', R} ->
+ {error, {value_retreival_failed, R}};
+ OldVal ->
+ {ok, OldVal};
+ Invalid ->
+ {error, {value_update_failed, OldVal, Invalid}}
+ end;
+ (R) ->
+ {error, R}
+ end,
+ command(No, Desc, Cmd, Verify).
+
+exit_command(No, Desc, Cmd) when is_function(Cmd) ->
+ Verify = fun({'EXIT', _} = E) ->
+ {ok, E};
+ (R) ->
+ {error, R}
+ end,
+ command(No, Desc, Cmd, Verify).
+
+error_command(No, Desc, Cmd, MainReason, TS) when is_function(Cmd) ->
+ Verify = fun({error, Reason}) ->
+ io:format("verify -> Reason: ~n~p~n", [Reason]),
+ case Reason of
+ {MainReason, _} when TS == 2 ->
+ {ok, MainReason};
+ {MainReason, _, _, _} when TS == 4 ->
+ {ok, MainReason};
+ _ ->
+ {error, Reason}
+ end;
+ (R) ->
+ {error, R}
+ end,
+ command(No, Desc, Cmd, Verify).
+
+command(No, Desc, Cmd, Verify) when is_integer(No) and is_list(Desc) and
+ is_function(Cmd) and is_function(Verify) ->
+ #command{id = No,
+ desc = Desc,
+ cmd = Cmd,
+ verify = Verify};
+command(No, Desc, Cmd, VerifyVal) when is_integer(No) and is_list(Desc) and
+ is_function(Cmd) ->
+ Verify = fun(Val) ->
+ case Val of
+ VerifyVal ->
+ {ok, Val};
+ _ ->
+ {error, Val}
+ end
+ end,
+ #command{id = No,
+ desc = Desc,
+ cmd = Cmd,
+ verify = Verify}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+transaction_id_counter_mg(suite) ->
+ [];
+transaction_id_counter_mg(doc) ->
+ ["This test case is intended to test and verify the "
+ "transaction counter handling of the application "
+ "in with one connection (MG). "];
+transaction_id_counter_mg(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, transaction_id_counter_mg),
+
+ process_flag(trap_exit, true),
+
+ i("starting"),
+
+ {ok, _ConfigPid} = megaco_config:start_link(),
+
+ %% Basic user data
+ UserMid = {deviceName, "mg"},
+ UserConfig = [
+ {min_trans_id, 1}
+ ],
+
+ %% Basic connection data
+ RemoteMid = {deviceName, "mgc"},
+ RecvHandle = #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ SendHandle = dummy_send_handle,
+ ControlPid = self(),
+
+ %% Start user
+ i("start user"),
+ ok = megaco_config:start_user(UserMid, UserConfig),
+
+ %% Create connection
+ i("create connection"),
+ {ok, CD} =
+ megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
+
+ %% Set counter limits
+ i("set counter max limit"),
+ CH = CD#conn_data.conn_handle,
+ megaco_config:update_conn_info(CH, max_trans_id, 1000),
+
+ %% Create the counter worker procs
+ i("create counter working procs"),
+ Pids = create_counter_working_procs(CH, ?NUM_CNT_PROCS, []),
+
+ %% Start the counter worker procs
+ i("release the counter working procs"),
+ start_counter_working_procs(Pids),
+
+ %% Await the counter worker procs termination
+ i("await the counter working procs completion"),
+ await_completion_counter_working_procs(Pids),
+
+ %% Verify result
+ i("verify counter result"),
+ TransId = megaco_config:conn_info(CH, trans_id),
+ 1 = TransId,
+
+ %% Stop test
+ i("disconnect"),
+ {ok, _, _} = megaco_config:disconnect(CH),
+ i("stop user"),
+ ok = megaco_config:stop_user(UserMid),
+ i("stop megaco_config"),
+ ok = megaco_config:stop(),
+
+ i("done"),
+ ok.
+
+
+
+create_counter_working_procs(_CH, 0, Pids) ->
+ Pids;
+create_counter_working_procs(CH, N, Pids) ->
+ TC = get(tc),
+ Pid = erlang:spawn_link(fun() -> counter_init(CH, TC) end),
+ create_counter_working_procs(CH, N-1, [Pid | Pids]).
+
+counter_init(CH, TC) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, lists:flatten(io_lib:format("CNT-~p", [self()]))),
+ put(tc, TC),
+ UserMid = CH#megaco_conn_handle.local_mid,
+ Min = megaco_config:user_info(UserMid, min_trans_id),
+ Max = megaco_config:conn_info(CH, max_trans_id),
+ Num = Max - Min + 1,
+ receive
+ start ->
+ %% i("received start command (~p)", [Num]),
+ ok
+ end,
+ counter_loop(CH, Num).
+
+counter_loop(_CH, 0) ->
+ %% i("done"),
+ exit(normal);
+counter_loop(CH, Num) when (Num > 0) ->
+ megaco_config:incr_trans_id_counter(CH, 1),
+ counter_loop(CH, Num-1).
+
+start_counter_working_procs([]) ->
+ %% i("released"),
+ ok;
+start_counter_working_procs([Pid | Pids]) ->
+ Pid ! start,
+ start_counter_working_procs(Pids).
+
+await_completion_counter_working_procs([]) ->
+ ok;
+await_completion_counter_working_procs(Pids) ->
+ receive
+ {'EXIT', Pid, normal} ->
+ Pids2 = lists:delete(Pid, Pids),
+ await_completion_counter_working_procs(Pids2);
+ _Any ->
+ await_completion_counter_working_procs(Pids)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+transaction_id_counter_mgc(suite) ->
+ [];
+transaction_id_counter_mgc(doc) ->
+ ["This test case is intended to test and verify the "
+ "transaction counter handling of the application "
+ "in with several connections (MGC). "];
+transaction_id_counter_mgc(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, transaction_id_counter_mgc),
+ process_flag(trap_exit, true),
+
+ i("starting"),
+
+ {ok, _ConfigPid} = megaco_config:start_link(),
+
+ %% Basic user data
+ UserMid = {deviceName, "mgc"},
+ UserConfig = [
+ {min_trans_id, 1}
+ ],
+
+ %% Basic connection data
+ RemoteMids =
+ [
+ {deviceName, "mg01"},
+ {deviceName, "mg02"},
+ {deviceName, "mg03"},
+ {deviceName, "mg04"},
+ {deviceName, "mg05"},
+ {deviceName, "mg06"},
+ {deviceName, "mg07"},
+ {deviceName, "mg08"},
+ {deviceName, "mg09"},
+ {deviceName, "mg10"}
+ ],
+ RecvHandles =
+ [
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE},
+ #megaco_receive_handle{local_mid = UserMid,
+ encoding_mod = ?MODULE,
+ encoding_config = [],
+ send_mod = ?MODULE}
+ ],
+ SendHandle = dummy_send_handle,
+ ControlPid = self(),
+
+ %% Start user
+ i("start user"),
+ ok = megaco_config:start_user(UserMid, UserConfig),
+
+ %% Create connection
+ i("create connection(s)"),
+ CDs = create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid),
+
+ %% Set counter limits
+ i("set counter max limit(s)"),
+ set_counter_max_limits(CDs, 1000),
+
+ %% Create the counter worker procs
+ i("create counter working procs"),
+ Pids = create_counter_working_procs(CDs, ?NUM_CNT_PROCS),
+
+ %% Start the counter worker procs
+ i("release the counter working procs"),
+ start_counter_working_procs(Pids),
+
+ %% Await the counter worker procs termination
+ i("await the counter working procs completion"),
+ await_completion_counter_working_procs(Pids),
+
+ %% Verify result
+ i("verify counter result"),
+ verify_counter_results(CDs),
+
+ %% Stop test
+ i("disconnect"),
+ delete_connections(CDs),
+ i("stop user"),
+ ok = megaco_config:stop_user(UserMid),
+ i("stop megaco_config"),
+ ok = megaco_config:stop(),
+
+ i("done"),
+ ok.
+
+create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid) ->
+ create_connections(RecvHandles, RemoteMids, SendHandle, ControlPid, []).
+
+create_connections([], [], _SendHandle, _ControlPid, Acc) ->
+ lists:reverse(Acc);
+create_connections([RecvHandle | RecvHandles],
+ [RemoteMid | RemoteMids],
+ SendHandle, ControlPid, Acc) ->
+ {ok, CD} =
+ megaco_config:connect(RecvHandle, RemoteMid, SendHandle, ControlPid),
+ create_connections(RecvHandles, RemoteMids,
+ SendHandle, ControlPid, [CD | Acc]).
+
+
+set_counter_max_limits([], _MaxTransId) ->
+ ok;
+set_counter_max_limits([#conn_data{conn_handle = CH} | CDs], MaxTransId) ->
+ megaco_config:update_conn_info(CH, max_trans_id, MaxTransId),
+ set_counter_max_limits(CDs, MaxTransId).
+
+
+create_counter_working_procs(CDs, NumCntProcs) ->
+ lists:flatten(create_counter_working_procs2(CDs, NumCntProcs)).
+
+create_counter_working_procs2([], _NumCntProcs) ->
+ [];
+create_counter_working_procs2([#conn_data{conn_handle = CH} | CDs],
+ NumCntProcs) ->
+ [create_counter_working_procs(CH, NumCntProcs, []) |
+ create_counter_working_procs2(CDs, NumCntProcs)].
+
+
+verify_counter_results([]) ->
+ ok;
+verify_counter_results([#conn_data{conn_handle = CH} | CDs]) ->
+ TransId = megaco_config:conn_info(CH, trans_id),
+ if
+ (TransId =:= 1) ->
+ ok;
+ true ->
+ ?ERROR({trans_id_verification_failed, CH, TransId})
+ end,
+ verify_counter_results(CDs).
+
+
+delete_connections([]) ->
+ ok;
+delete_connections([#conn_data{conn_handle = CH} | CDs]) ->
+ {ok, _, _} = megaco_config:disconnect(CH),
+ delete_connections(CDs).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7216(suite) ->
+ [];
+otp_7216(Config) when is_list(Config) ->
+ put(tc, otp_7216),
+ p("start"),
+
+ p("start the megaco config process"),
+ megaco_config:start_link(),
+
+ LocalMid1 = {deviceName, "local-mid-1"},
+ %% LocalMid2 = {deviceName, "local-mid-2"},
+ RemoteMid1 = {deviceName, "remote-mid-1"},
+ %% RemoteMid2 = {deviceName, "remote-mid-2"},
+ RH = #megaco_receive_handle{local_mid = LocalMid1,
+ encoding_mod = dummy_codec_module,
+ encoding_config = [],
+ send_mod = dummy_transport_module},
+ MinTransId = 7216,
+ MaxTransId = MinTransId + 10,
+ User1Config = [{min_trans_id, MinTransId},
+ {max_trans_id, MaxTransId}],
+
+ VerifySerial =
+ fun(Actual, Expected) ->
+ if
+ Actual == Expected ->
+ ok;
+ true ->
+ throw({error, {invalid_counter_value, Actual}})
+ end
+ end,
+
+ p("start local user: ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1Config),
+
+ p("connect"),
+ {ok, CD} = megaco_config:connect(RH, RemoteMid1,
+ dummy_send_handle, self()),
+ p("connect ok: CD = ~n~p", [CD]),
+ CH = CD#conn_data.conn_handle,
+
+
+ p("*** make the first counter increment ***"),
+ {ok, CD01} = megaco_config:incr_trans_id_counter(CH, 1),
+ Serial01 = CD01#conn_data.serial,
+ p("serial: ~p", [Serial01]),
+ VerifySerial(Serial01, MinTransId),
+ p("counter increment 1 ok"),
+
+
+ p("*** make two more counter increments ***"),
+ {ok, _} = megaco_config:incr_trans_id_counter(CH, 1),
+ {ok, CD02} = megaco_config:incr_trans_id_counter(CH, 1),
+ Serial02 = CD02#conn_data.serial,
+ p("serial: ~p", [Serial02]),
+ VerifySerial(Serial02, MinTransId+2),
+ p("counter increment 2 ok"),
+
+
+ p("*** make a big counter increment ***"),
+ {ok, CD03} = megaco_config:incr_trans_id_counter(CH, 8),
+ Serial03 = CD03#conn_data.serial,
+ p("serial: ~p", [Serial03]),
+ VerifySerial(Serial03, MinTransId+2+8),
+ p("counter increment 3 ok"),
+
+
+ p("*** make a wrap-around counter increment ***"),
+ {ok, CD04} = megaco_config:incr_trans_id_counter(CH, 1),
+ Serial04 = CD04#conn_data.serial,
+ p("serial: ~p", [Serial04]),
+ VerifySerial(Serial04, MinTransId),
+ p("counter increment 4 ok"),
+
+
+ p("*** make a big counter increment ***"),
+ {ok, CD05} = megaco_config:incr_trans_id_counter(CH, 10),
+ Serial05 = CD05#conn_data.serial,
+ p("serial: ~p", [Serial05]),
+ VerifySerial(Serial05, MinTransId+10),
+ p("counter increment 5 ok"),
+
+
+ p("*** make a big wrap-around counter increment ***"),
+ {ok, CD06} = megaco_config:incr_trans_id_counter(CH, 3),
+ Serial06 = CD06#conn_data.serial,
+ p("serial: ~p", [Serial06]),
+ VerifySerial(Serial06, MinTransId+(3-1)),
+ p("counter increment 6 ok"),
+
+
+ p("*** make a big counter increment ***"),
+ {ok, CD07} = megaco_config:incr_trans_id_counter(CH, 7),
+ Serial07 = CD07#conn_data.serial,
+ p("serial: ~p", [Serial07]),
+ VerifySerial(Serial07, MinTransId+(3-1)+7),
+ p("counter increment 7 ok"),
+
+
+ p("*** make a big wrap-around counter increment ***"),
+ {ok, CD08} = megaco_config:incr_trans_id_counter(CH, 5),
+ Serial08 = CD08#conn_data.serial,
+ p("serial: ~p", [Serial08]),
+ VerifySerial(Serial08, MinTransId+(5-1-1)),
+ p("counter increment 8 ok"),
+
+
+ p("disconnect"),
+ {ok, CD, RCD} = megaco_config:disconnect(CH),
+ p("disconnect ok: RCD = ~n~p", [RCD]),
+
+ p("stop user"),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("stop megaco config process"),
+ megaco_config:stop(),
+
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_8167(suite) ->
+ [];
+otp_8167(Config) when is_list(Config) ->
+ put(tc, otp8167),
+ p("start"),
+
+ p("start the megaco config process"),
+ megaco_config:start_link(),
+
+ LocalMid1 = {deviceName, "local-mid-1"},
+ LocalMid2 = {deviceName, "local-mid-2"},
+ RemoteMid1 = {deviceName, "remote-mid-1"},
+ %% RemoteMid2 = {deviceName, "remote-mid-2"},
+ RH1 = #megaco_receive_handle{local_mid = LocalMid1,
+ encoding_mod = dummy_codec_module,
+ encoding_config = [],
+ send_mod = dummy_transport_module},
+%% RH2 = #megaco_receive_handle{local_mid = LocalMid2,
+%% encoding_mod = dummy_codec_module,
+%% encoding_config = [],
+%% send_mod = dummy_transport_module},
+
+ User1ConfigA = [{call_proxy_gc_timeout, 1}],
+ User1ConfigB = [{call_proxy_gc_timeout, 0}],
+ User2ConfigA = [{call_proxy_gc_timeout, -1}],
+ User2ConfigB = [{call_proxy_gc_timeout, infinity}],
+ User2ConfigC = [{call_proxy_gc_timeout, "1"}],
+ User2ConfigD = [{call_proxy_gc_timeout, 1.0}],
+
+ p("start local user (1A): ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1ConfigA),
+ p("stop local user (1A): ~p", [LocalMid1]),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("start local user (1B): ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1ConfigB),
+ p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
+ [LocalMid1, -1]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
+ megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, -1),
+ p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
+ [LocalMid1, infinity]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
+ megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, infinity),
+ p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
+ [LocalMid1, "1"]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
+ megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, "1"),
+ p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
+ [LocalMid1, 1.0]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
+ megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 1.0),
+ p("change value for item call_proxy_gc_timeout for local user: ~p", [LocalMid1]),
+ ok = megaco_config:update_user_info(LocalMid1, call_proxy_gc_timeout, 10101),
+
+ p("connect"),
+ {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
+ dummy_send_handle, self()),
+ p("connect ok: CD = ~n~p", [CD]),
+ CH = CD#conn_data.conn_handle,
+
+ p("get value for item call_proxy_gc_timeout for connection: ~p", [CH]),
+ 10101 = megaco_config:conn_info(CH, call_proxy_gc_timeout),
+
+ p("change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
+ [CH, 20202]),
+ ok = megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 20202),
+
+ p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
+ [CH, -1]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, -1}} =
+ megaco_config:update_conn_info(CH, call_proxy_gc_timeout, -1),
+
+ p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
+ [CH, infinity]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, infinity}} =
+ megaco_config:update_conn_info(CH, call_proxy_gc_timeout, infinity),
+
+ p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
+ [CH, "1"]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, "1"}} =
+ megaco_config:update_conn_info(CH, call_proxy_gc_timeout, "1"),
+
+ p("try (and fail) change value for item call_proxy_gc_timeout for connection: ~p -> ~p",
+ [CH, 1.0]),
+ {error, {bad_user_val, LocalMid1, call_proxy_gc_timeout, 1.0}} =
+ megaco_config:update_conn_info(CH, call_proxy_gc_timeout, 1.0),
+
+ p("disconnect: ~p", [CH]),
+ {ok, _, _} = megaco_config:disconnect(CH),
+
+ p("stop local user (1B): ~p", [LocalMid1]),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("try (and fail) start local user (2A): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, -1}} =
+ megaco_config:start_user(LocalMid2, User2ConfigA),
+
+ p("try (and fail) start local user (2B): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, infinity}} =
+ megaco_config:start_user(LocalMid2, User2ConfigB),
+
+ p("try (and fail) start local user (2C): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, "1"}} =
+ megaco_config:start_user(LocalMid2, User2ConfigC),
+
+ p("try (and fail) start local user (2D): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, call_proxy_gc_timeout, 1.0}} =
+ megaco_config:start_user(LocalMid2, User2ConfigD),
+
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_8183(suite) ->
+ [];
+otp_8183(Config) when is_list(Config) ->
+ put(tc, otp8183),
+ p("start"),
+
+ p("start the megaco config process"),
+ megaco_config:start_link(),
+
+ LocalMid1 = {deviceName, "local-mid-1"},
+ LocalMid2 = {deviceName, "local-mid-2"},
+ RemoteMid1 = {deviceName, "remote-mid-1"},
+%% RemoteMid2 = {deviceName, "remote-mid-2"},
+ RH1 = #megaco_receive_handle{local_mid = LocalMid1,
+ encoding_mod = dummy_codec_module,
+ encoding_config = [],
+ send_mod = dummy_transport_module},
+%% RH2 = #megaco_receive_handle{local_mid = LocalMid2,
+%% encoding_mod = dummy_codec_module,
+%% encoding_config = [],
+%% send_mod = dummy_transport_module},
+
+ OkValA = 100,
+ OkValB = 0,
+ OkValC = plain,
+ OkValD = 10101,
+ OkValE = 20202,
+ BadValA = -1,
+ BadValB = pain,
+ BadValC = "1",
+ BadValD = 1.0,
+ User1ConfigA = [{request_keep_alive_timeout, OkValA}],
+ User1ConfigB = [{request_keep_alive_timeout, OkValB}],
+ User1ConfigC = [{request_keep_alive_timeout, OkValC}],
+ User2ConfigA = [{request_keep_alive_timeout, BadValA}],
+ User2ConfigB = [{request_keep_alive_timeout, BadValB}],
+ User2ConfigC = [{request_keep_alive_timeout, BadValC}],
+ User2ConfigD = [{request_keep_alive_timeout, BadValD}],
+
+ p("start local user (1A): ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1ConfigA),
+ p("stop local user (1A): ~p", [LocalMid1]),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("start local user (1B): ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1ConfigB),
+ p("stop local user (1B): ~p", [LocalMid1]),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("start local user (1C): ~p", [LocalMid1]),
+ ok = megaco_config:start_user(LocalMid1, User1ConfigC),
+
+ p("try (and fail) change value for item call_proxy_gc_timeout for local user: ~p -> ~p",
+ [LocalMid1, BadValA]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
+ megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValA),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
+ [LocalMid1, BadValB]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
+ megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValB),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
+ [LocalMid1, BadValC]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
+ megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValC),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for local user: ~p -> ~p",
+ [LocalMid1, BadValD]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
+ megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, BadValD),
+
+ p("change value for item request_keep_alive_timeout for local user: ~p", [LocalMid1]),
+ ok = megaco_config:update_user_info(LocalMid1, request_keep_alive_timeout, OkValD),
+
+ p("connect"),
+ {ok, CD} = megaco_config:connect(RH1, RemoteMid1,
+ dummy_send_handle, self()),
+ p("connect ok: CD = ~n~p", [CD]),
+ CH = CD#conn_data.conn_handle,
+
+ p("get value for item request_keep_alive_timeout for connection: ~p", [CH]),
+ OkValD = megaco_config:conn_info(CH, request_keep_alive_timeout),
+
+ p("change value for item request_keep_alive_timeout for connection: ~p -> ~p",
+ [CH, OkValE]),
+ ok = megaco_config:update_conn_info(CH, request_keep_alive_timeout, OkValE),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
+ [CH, BadValA]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValA}} =
+ megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValA),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
+ [CH, BadValB]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValB}} =
+ megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValB),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
+ [CH, BadValC]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValC}} =
+ megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValC),
+
+ p("try (and fail) change value for item request_keep_alive_timeout for connection: ~p -> ~p",
+ [CH, BadValD]),
+ {error, {bad_user_val, LocalMid1, request_keep_alive_timeout, BadValD}} =
+ megaco_config:update_conn_info(CH, request_keep_alive_timeout, BadValD),
+
+ p("disconnect: ~p", [CH]),
+ {ok, _, _} = megaco_config:disconnect(CH),
+
+ p("stop local user (1B): ~p", [LocalMid1]),
+ ok = megaco_config:stop_user(LocalMid1),
+
+ p("try (and fail) start local user (2A): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValA}} =
+ megaco_config:start_user(LocalMid2, User2ConfigA),
+
+ p("try (and fail) start local user (2B): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValB}} =
+ megaco_config:start_user(LocalMid2, User2ConfigB),
+
+ p("try (and fail) start local user (2C): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValC}} =
+ megaco_config:start_user(LocalMid2, User2ConfigC),
+
+ p("try (and fail) start local user (2D): ~p", [LocalMid2]),
+ {error, {bad_user_val, LocalMid2, request_keep_alive_timeout, BadValD}} =
+ megaco_config:start_user(LocalMid2, User2ConfigD),
+
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ io:format("[~w] " ++ F ++ "~n", [get(tc)|A]).
+
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
diff --git a/lib/megaco/test/megaco_digit_map_test.erl b/lib/megaco/test/megaco_digit_map_test.erl
new file mode 100644
index 0000000000..22e115278f
--- /dev/null
+++ b/lib/megaco/test/megaco_digit_map_test.erl
@@ -0,0 +1,637 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_digit_map_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ tickets
+ ],
+ Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tickets(suite) ->
+ [
+ otp_5750,
+ otp_5799,
+ otp_5826,
+ otp_7449
+ ].
+
+
+otp_5750(suite) ->
+ [
+ otp_5750_01,
+ otp_5750_02
+ ].
+
+otp_5799(suite) ->
+ [
+ otp_5799_01
+ ].
+
+otp_5826(suite) ->
+ [
+ otp_5826_01,
+ otp_5826_02,
+ otp_5826_03
+ ].
+
+otp_7449(suite) ->
+ [
+ otp_7449_1,
+ otp_7449_2
+ ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5750_01(suite) ->
+ [];
+otp_5750_01(doc) ->
+ [];
+otp_5750_01(Config) when is_list(Config) ->
+ DM = "1 | 123",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, "1"))
+ end,
+ fun({ok, {full, "1"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+
+ {2,
+ fun() ->
+ (catch tde(DM, "123"))
+ end,
+ fun({ok, {unambiguous, "123"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+
+ {3,
+ fun() ->
+ (catch tde(DM, "124"))
+ end,
+ fun({error, _}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5750_02(suite) ->
+ [];
+otp_5750_02(doc) ->
+ [];
+otp_5750_02(Config) when is_list(Config) ->
+ DM = "xxx | xxL3 | xxS4",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch otp_5750_02_exec(500, DM, "113"))
+ end,
+ fun({ok, {unambiguous, "113"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+
+ {2,
+ fun() ->
+ (catch otp_5750_02_exec(500, DM, "114"))
+ end,
+ fun({ok, {unambiguous, "114"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+
+ {3,
+ fun() ->
+ (catch otp_5750_02_exec(5000, DM, "11ssss3"))
+ end,
+ fun({ok, {unambiguous, "113"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+
+ {4,
+ fun() ->
+ (catch otp_5750_02_exec(5000, DM, "11ssss4"))
+ end,
+ fun({ok, {unambiguous, "114"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+otp_5750_02_exec(To, DM, Evs) ->
+ Pid = self(),
+ Tester =
+ spawn(fun() ->
+ Res = tde(DM, Evs),
+ Pid ! {result, self(), Res}
+ end),
+ receive
+ {result, Tester, Res} ->
+ Res
+ after To ->
+ {error, timeout}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5799_01(suite) ->
+ [];
+otp_5799_01(doc) ->
+ [];
+otp_5799_01(Config) when is_list(Config) ->
+ DM = "234 | 23456",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, "2349"))
+ end,
+ fun({ok, {full, "234", $9}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5826_01(suite) ->
+ [];
+otp_5826_01(doc) ->
+ [];
+otp_5826_01(Config) when is_list(Config) ->
+ DM = "123Z56",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, [$1,$2,$3,{long, $5},$6]))
+ end,
+ fun({ok, {unambiguous, "123Z56"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {2,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},{long,$5},$6]))
+ end,
+ fun({ok, {unambiguous, "123Z56"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {3,
+ fun() ->
+ (catch tde(DM, [$1,$2,$3,{long,$5},{long,$6}]))
+ end,
+ fun({ok, {unambiguous, "123Z56"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {4,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},{long,$5},{long,$6}]))
+ end,
+ fun({ok, {unambiguous, "123Z56"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5826_02(suite) ->
+ [];
+otp_5826_02(doc) ->
+ [];
+otp_5826_02(Config) when is_list(Config) ->
+ DM = "12356",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, [$1,$2,$3,{long, $5},$6]))
+ end,
+ fun({ok, {unambiguous, "12356"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5826_03(suite) ->
+ [];
+otp_5826_03(doc) ->
+ [];
+otp_5826_03(Config) when is_list(Config) ->
+ DM = "12346 | 12Z346 | 12Z34Z7 | 1234Z8",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},$4,$6]))
+ end,
+ fun({ok, {unambiguous, "12Z346"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {2,
+ fun() ->
+ (catch tde(DM, [$1, {long, $2}, {long, $3},$4, $6]))
+ end,
+ fun({ok, {unambiguous, "12Z346"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {3,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},{long, $4},$6]))
+ end,
+ fun({ok, {unambiguous, "12Z346"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {4,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},$4,{long, $7}]))
+ end,
+ fun({ok, {unambiguous, "12Z34Z7"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {5,
+ fun() ->
+ (catch tde(DM, [$1,$2,{long, $3},$4,{long, $8}]))
+ end,
+ fun({error,
+ {unexpected_event, {long, $8}, _Collected, _Expected}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {6,
+ fun() ->
+ (catch tde(DM, [$1,$2,$3,$4,{long, $8}]))
+ end,
+ fun({ok, {unambiguous, "1234Z8"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7449_1(suite) ->
+ [];
+otp_7449_1(doc) ->
+ [];
+otp_7449_1(Config) when is_list(Config) ->
+ DM = "([0-9ef])",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, [$0]))
+ end,
+ fun({ok, {unambiguous, "0"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {2,
+ fun() ->
+ (catch tde(DM, [$1]))
+ end,
+ fun({ok, {unambiguous, "1"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {3,
+ fun() ->
+ (catch tde(DM, [$2]))
+ end,
+ fun({ok, {unambiguous, "2"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {4,
+ fun() ->
+ (catch tde(DM, [$3]))
+ end,
+ fun({ok, {unambiguous, "3"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {5,
+ fun() ->
+ (catch tde(DM, [$4]))
+ end,
+ fun({ok, {unambiguous, "4"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {6,
+ fun() ->
+ (catch tde(DM, [$5]))
+ end,
+ fun({ok, {unambiguous, "5"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {7,
+ fun() ->
+ (catch tde(DM, [$6]))
+ end,
+ fun({ok, {unambiguous, "6"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {8,
+ fun() ->
+ (catch tde(DM, [$7]))
+ end,
+ fun({ok, {unambiguous, "7"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {9,
+ fun() ->
+ (catch tde(DM, [$8]))
+ end,
+ fun({ok, {unambiguous, "8"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {10,
+ fun() ->
+ (catch tde(DM, [$9]))
+ end,
+ fun({ok, {unambiguous, "9"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {11,
+ fun() ->
+ (catch tde(DM, [$a]))
+ end,
+ fun({error, {unexpected_event, $a, _Collected, _Expected}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {12,
+ fun() ->
+ (catch tde(DM, [$e]))
+ end,
+ fun({ok, {unambiguous, "e"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {13,
+ fun() ->
+ (catch tde(DM, [$f]))
+ end,
+ fun({ok, {unambiguous, "f"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {14,
+ fun() ->
+ (catch tde(DM, [$a]))
+ end,
+ fun({error, {unexpected_event, $a,
+ [] = _Collected,
+ [{letter, [{range, $0, $9},
+ {single, $e},
+ {single, $f}]}] = _Expected}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7449_2(suite) ->
+ [];
+otp_7449_2(doc) ->
+ [];
+otp_7449_2(Config) when is_list(Config) ->
+ DM = "([0-9]ef)",
+
+ %% First case
+ Tests =
+ [
+ {1,
+ fun() ->
+ (catch tde(DM, [$0,$e,$f]))
+ end,
+ fun({ok, {unambiguous, "0ef"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {2,
+ fun() ->
+ (catch tde(DM, [$1,$e,$f]))
+ end,
+ fun({ok, {unambiguous, "1ef"}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {3,
+ fun() ->
+ (catch tde(DM, [$2]))
+ end,
+ fun({error, {unexpected_event,
+ inter_event_timeout, [$2] = _Collected,
+ [{single, $e}] = _Expecting}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {4,
+ fun() ->
+ (catch tde(DM, [$3,$f,$f]))
+ end,
+ fun({error, {unexpected_event, $f, [$3] = _Collected,
+ [{single, $e}] = _Expected}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end},
+ {5,
+ fun() ->
+ (catch tde(DM, [$a,$e,$f]))
+ end,
+ fun({error, {unexpected_event, $a,
+ [] = _Collected,
+ [{letter, [{range, $0, $9}]}] = _Expected}}) ->
+ ok;
+ (Else) ->
+ {error, {unexpected_digit_map_result, Else}}
+ end}
+ ],
+
+ dm_tests(Tests),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+dm_tests([]) ->
+ ok;
+dm_tests([{No, Exec, Ver}|Tests])
+ when is_integer(No) andalso is_function(Exec) andalso is_function(Ver) ->
+ case dm_test(Exec, Ver) of
+ ok ->
+ dm_tests(Tests);
+ {error, Reason} ->
+ ?ERROR({No, Reason});
+ Error ->
+ ?ERROR({No, Error})
+ end.
+
+dm_test(Exec, Verify) ->
+ (catch Verify(Exec())).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tde(DM, Evs) -> megaco:test_digit_event(DM, Evs).
+
diff --git a/lib/megaco/test/megaco_examples_test.erl b/lib/megaco/test/megaco_examples_test.erl
new file mode 100644
index 0000000000..ef15cb1bde
--- /dev/null
+++ b/lib/megaco/test/megaco_examples_test.erl
@@ -0,0 +1,174 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test application config
+%%----------------------------------------------------------------------
+
+-module(megaco_examples_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ put(dbg,true),
+ purge_examples(),
+ load_examples(),
+ megaco:enable_trace(max, io),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ purge_examples(),
+ erase(dbg),
+ megaco:disable_trace(),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+example_modules() ->
+ [megaco_simple_mg, megaco_simple_mgc].
+
+load_examples() ->
+ case code:lib_dir(megaco) of
+ {error, Reason} ->
+ {error, Reason};
+ Dir ->
+ [code:load_abs(filename:join([Dir, examples, simple, M])) || M <- example_modules()]
+ end.
+
+purge_examples() ->
+ case code:lib_dir(megaco) of
+ {error, Reason} ->
+ {error, Reason};
+ _Dir ->
+ [code:purge(M) || M <- example_modules()]
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+all(doc) ->
+ ["Run all examples mentioned in the documentation",
+ "Are really all examples covered?"];
+all(suite) ->
+ [
+ simple
+ ].
+
+simple(suite) ->
+ [];
+simple(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ d("simple -> proxy start",[]),
+ ProxyPid = megaco_test_lib:proxy_start({?MODULE, ?LINE}),
+
+ d("simple -> start megaco",[]),
+ ?VERIFY(ok, megaco:start()),
+
+ d("simple -> start mgc",[]),
+ ?APPLY(ProxyPid, fun() -> megaco_simple_mgc:start() end),
+ receive
+ {res, _, {ok, MgcAll}} when is_list(MgcAll) ->
+ MgcBad = [MgcRes || MgcRes <- MgcAll, element(1, MgcRes) /= ok],
+ ?VERIFY([], MgcBad),
+ %% MgcGood = MgcAll -- MgcBad,
+ %% MgcRecHandles = [MgcRH || {ok, _MgcPort, MgcRH} <- MgcGood],
+
+ d("simple -> start mg",[]),
+ ?APPLY(ProxyPid, fun() -> megaco_simple_mg:start() end),
+ receive
+ {res, _, MgList} when is_list(MgList) andalso (length(MgList) =:= 4) ->
+ d("simple -> received res: ~p",[MgList]),
+ Verify =
+ fun({_MgMid, {TransId, Res}}) when TransId =:= 1 ->
+ case Res of
+ {ok, [AR]} when is_record(AR, 'ActionReply') ->
+ case AR#'ActionReply'.commandReply of
+ [{serviceChangeReply, SCR}] ->
+ case SCR#'ServiceChangeReply'.serviceChangeResult of
+ {serviceChangeResParms, MgcMid} when MgcMid /= asn1_NOVALUE ->
+ ok;
+ Error ->
+ ?ERROR(Error)
+ end;
+ Error ->
+ ?ERROR(Error)
+ end;
+ Error ->
+ ?ERROR(Error)
+ end;
+ (Error) ->
+ ?ERROR(Error)
+ end,
+ lists:map(Verify, MgList);
+ Error ->
+ ?ERROR(Error)
+ end;
+ Error ->
+ ?ERROR(Error)
+ end,
+ d("simple -> verify info()",[]),
+ info(),
+ d("simple -> verify system_info(users)",[]),
+ users(),
+ d("simple -> stop mgc",[]),
+ ?VERIFY(5, length(megaco_simple_mgc:stop())),
+ d("simple -> verify system_info(users)",[]),
+ users(),
+ d("simple -> stop megaco",[]),
+ ?VERIFY(ok, megaco:stop()),
+ d("simple -> kill (exit) ProxyPid: ~p",[ProxyPid]),
+ exit(ProxyPid, shutdown), % Controlled kill of transport supervisors
+
+ ok.
+
+
+info() ->
+ case (catch megaco:info()) of
+ {'EXIT', _} = Error ->
+ ?ERROR(Error);
+ Info ->
+ ?LOG("Ok, ~p~n", [Info])
+ end.
+
+users() ->
+ case (catch megaco:system_info(users)) of
+ {'EXIT', _} = Error ->
+ ?ERROR(Error);
+ Users ->
+ ?LOG("Ok, ~p~n", [Users])
+ end.
+
+
+
+
+d(F,A) ->
+ d(get(dbg),F,A).
+
+d(true,F,A) ->
+ io:format("DBG: " ++ F ++ "~n",A);
+d(_, _F, _A) ->
+ ok.
diff --git a/lib/megaco/test/megaco_flex_test.erl b/lib/megaco/test/megaco_flex_test.erl
new file mode 100644
index 0000000000..3dbcf53e7a
--- /dev/null
+++ b/lib/megaco/test/megaco_flex_test.erl
@@ -0,0 +1,230 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test various aspects of the flex scanner handling
+%%
+%% Test: ts:run(megaco, megaco_flex_test, [batch]).
+%%
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_test).
+
+-include("megaco_test_lib.hrl").
+
+-export([
+ t/0, t/1,
+
+ init_per_testcase/2, fin_per_testcase/2,
+
+ all/1,
+ flex_init/1, flex_fin/1,
+
+ plain/1,
+ port_exit/1,
+ garbage_in/1
+
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ plain,
+ port_exit,
+ garbage_in
+ ],
+ {req, [], {conf, flex_init, Cases, flex_fin}}.
+
+flex_init(suite) ->
+ [];
+flex_init(doc) ->
+ [];
+flex_init(Config) when is_list(Config) ->
+ case megaco_flex_scanner:is_enabled() of
+ true ->
+ Config;
+ false ->
+ ?SKIP(flex_scanner_not_enabled)
+ end.
+
+flex_fin(suite) -> [];
+flex_fin(doc) -> [];
+flex_fin(Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+plain(suite) ->
+ [];
+plain(doc) ->
+ ["This is to simply test that it is possible to start and stop the "
+ "flex handler."];
+plain(Config) when is_list(Config) ->
+ put(tc, plain),
+ p("begin"),
+ process_flag(trap_exit, true),
+ p("start the flex handler"),
+ {ok, Pid, _PortInfo} = flex_scanner_handler_start(),
+ p("stop handler"),
+ flex_scanner_handler_stop(Pid),
+ p("end"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+port_exit(suite) ->
+ [];
+port_exit(doc) ->
+ ["Test that the handler detects and handles an exiting port."];
+port_exit(Config) when is_list(Config) ->
+ put(tc, port_exit),
+ p("begin"),
+ process_flag(trap_exit, true),
+
+ p("start the flex handler"),
+ {ok, Pid, {flex, PortOrPorts}} = flex_scanner_handler_start(),
+ Port = case PortOrPorts of
+ P when is_port(P) ->
+ P;
+ Ports when is_tuple(Ports) ->
+ %% It does not matter which of the ports we choose
+ element(1, PortOrPorts);
+ Ports when is_list(Ports) ->
+ %% It does not matter which of the ports we choose
+ hd(Ports)
+ end,
+
+ p("simulate crash"),
+ exit(Port, simulated_crash),
+
+ p("await handler exit"),
+ receive
+ {'EXIT', Pid, _} ->
+ p("end"),
+ ok
+ after 5000 ->
+ p("timeout - stop handler"),
+ flex_scanner_handler_stop(Pid),
+ p("end after timeout"),
+ {error, timeout}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+garbage_in(suite) ->
+ [];
+garbage_in(doc) ->
+ ["Send in various unexpected messages and requeststo the handler "
+ "to see that it does die on us. "];
+garbage_in(Config) when is_list(Config) ->
+ put(tc, garbage_in),
+ p("begin"),
+ process_flag(trap_exit, true),
+
+ p("start the flex handler"),
+ {ok, Pid, _PortInfo} = flex_scanner_handler_start(),
+
+ p("make an invalid call"),
+ {error, _} = gen_server:call(Pid, garbage_request),
+ p("make an invalid cast"),
+ gen_server:cast(Pid, garbage_msg),
+ p("send an unknown message"),
+ Pid ! garbage_info,
+
+ p("wait for any garbage response"),
+ receive
+ Any ->
+ p("end with unexpected message: ~p", [Any]),
+ {error, {unexpected_msg, Any}}
+ after 1000 ->
+ p("end with nothing received - stop handler"),
+ flex_scanner_handler_stop(Pid),
+ ok
+ end.
+
+
+
+%% ------- Misc functions --------
+
+flex_scanner_handler_start() ->
+ case megaco_flex_scanner_handler:start_link() of
+ {error, {failed_starting_scanner, {error, {load_driver, _}}}} ->
+ p("failed loading driver"),
+ ?SKIP(could_not_load_driver);
+ {error, {failed_starting_scanner, {load_driver, _}}} ->
+ p("failed loading driver"),
+ ?SKIP(could_not_load_driver);
+ {error, {failed_starting_scanner, {load_driver, _}, _}} ->
+ p("failed loading driver"),
+ ?SKIP(could_not_load_driver);
+ Else ->
+ p("driver load result: ~p", [Else]),
+ Else
+ end.
+
+flex_scanner_handler_stop(Pid) ->
+ megaco_flex_scanner_handler:stop(Pid).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ TC = get(tc),
+ io:format("*** [~s] ~p ~w ***"
+ "~n " ++ F ++ "~n",
+ [formated_timestamp(), self(), TC | A]).
+
+formated_timestamp() ->
+ format_timestamp(erlang:now()).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY, MM, DD} = Date,
+ {Hour, Min, Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
diff --git a/lib/megaco/test/megaco_load_test.erl b/lib/megaco/test/megaco_load_test.erl
new file mode 100644
index 0000000000..5a22b7b4ee
--- /dev/null
+++ b/lib/megaco/test/megaco_load_test.erl
@@ -0,0 +1,692 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_load_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, silence).
+-define(MG_VERBOSITY, silence).
+
+-define(SINGLE_USER_LOAD_NUM_REQUESTS, 1000).
+-define(MULTI_USER_LOAD_NUM_REQUESTS, 1000).
+
+-define(MGC_START(Pid, Mid, ET, Conf, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET,
+ [{megaco_trace, false}] ++ Conf, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_USER_INFO(Pid,Tag), megaco_test_mgc:user_info(Pid,Tag)).
+-define(MGC_CONN_INFO(Pid,Tag), megaco_test_mgc:conn_info(Pid,Tag)).
+-define(MGC_SET_VERBOSITY(Pid, V), megaco_test_mgc:verbosity(Pid, V)).
+
+-define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb),
+ megaco_test_mg:start(Pid, Mid, Enc, Transp,
+ [{megaco_trace, false},
+ {transport_opts, [{serialize, true}]}] ++ Conf,
+ Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_USER_INFO(Pid,Tag), megaco_test_mg:user_info(Pid,Tag)).
+-define(MG_CONN_INFO(Pid,Tag), megaco_test_mg:conn_info(Pid,Tag)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_MLOAD(Pid, NL, NR),
+ timer:tc(megaco_test_mg, apply_multi_load, [Pid, NL, NR])).
+-define(MG_LOAD(Pid, NL, NR), megaco_test_mg:apply_multi_load(Pid, NL, NR)).
+-define(MG_SET_VERBOSITY(Pid, V), megaco_test_mg:verbosity(Pid, V)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+min(M) -> timer:minutes(M).
+
+%% Test server callbacks
+init_per_testcase(single_user_light_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(2)}|C]);
+init_per_testcase(single_user_medium_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(5)}|C]);
+init_per_testcase(single_user_heavy_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(10)}|C]);
+init_per_testcase(single_user_extreme_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(20)}|C]);
+init_per_testcase(multi_user_light_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(2)}|C]);
+init_per_testcase(multi_user_medium_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(5)}|C]);
+init_per_testcase(multi_user_heavy_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(10)}|C]);
+init_per_testcase(multi_user_extreme_load = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ do_init_per_testcase(Case, [{tc_timeout, min(20)}|C]);
+init_per_testcase(Case, Config) ->
+ do_init_per_testcase(Case, Config).
+
+do_init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ single_user_light_load,
+ single_user_medium_load,
+ single_user_heavy_load,
+ single_user_extreme_load,
+ multi_user_light_load,
+ multi_user_medium_load,
+ multi_user_heavy_load,
+ multi_user_extreme_load
+ ],
+ Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_user_light_load(suite) ->
+ [];
+single_user_light_load(doc) ->
+ [];
+single_user_light_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, single_user_light_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( single_user_load(5) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_user_medium_load(suite) ->
+ [];
+single_user_medium_load(doc) ->
+ [];
+single_user_medium_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, single_user_medium_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( single_user_load(15) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_user_heavy_load(suite) ->
+ [];
+single_user_heavy_load(doc) ->
+ [];
+single_user_heavy_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, single_user_heavy_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( single_user_load(25) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_user_extreme_load(suite) ->
+ [];
+single_user_extreme_load(doc) ->
+ [];
+single_user_extreme_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, single_user_extreme_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( single_user_load(100) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_user_light_load(suite) ->
+ [];
+multi_user_light_load(doc) ->
+ [];
+multi_user_light_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, multi_user_light_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( multi_user_load(3,1) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_user_medium_load(suite) ->
+ [];
+multi_user_medium_load(doc) ->
+ [];
+multi_user_medium_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, multi_user_medium_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( multi_user_load(3,5) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_user_heavy_load(suite) ->
+ [];
+multi_user_heavy_load(doc) ->
+ [];
+multi_user_heavy_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, multi_user_heavy_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( multi_user_load(3,10) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_user_extreme_load(suite) ->
+ [];
+multi_user_extreme_load(doc) ->
+ [];
+multi_user_extreme_load(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, multi_user_extreme_load),
+ put(sname, "TEST"),
+ i("starting"),
+
+ load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( multi_user_load(3,15) )
+ end),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+populate([]) ->
+ ok;
+populate([{Key,Val}|Env]) ->
+ put(Key, Val),
+ populate(Env).
+
+load_controller(Config, Fun) when is_list(Config) and is_function(Fun) ->
+ process_flag(trap_exit, true),
+ {value, {tc_timeout, TcTimeout}} =
+ lists:keysearch(tc_timeout, 1, Config),
+ SkipTimeout = trunc(95*TcTimeout/100), % 95% of TcTimeout
+ Env = get(),
+ Loader = erlang:spawn_link(fun() -> Fun(Env) end),
+ receive
+ {'EXIT', Loader, normal} ->
+ d("load_controller -> "
+ "loader [~p] terminated with normal", [Loader]),
+ ok;
+ {'EXIT', Loader, ok} ->
+ d("load_controller -> "
+ "loader [~p] terminated with ok~n", [Loader]),
+ ok;
+ {'EXIT', Loader, Reason} ->
+ i("load_controller -> "
+ "loader [~p] terminated with"
+ "~n ~p", [Loader, Reason]),
+ erlang:error({unexpected_loader_result, Reason})
+ after SkipTimeout ->
+ i("load_controller -> "
+ "loader [~p] timeout", [Loader]),
+ exit(Loader, kill),
+ ?SKIP({timeout, SkipTimeout, TcTimeout})
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_user_load(NumLoaders) ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("Nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p", [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ MgcMid = {deviceName, "ctrl"},
+ ET = [{text, tcp, [{serialize, true}]}],
+ DSI = maybe_display_system_info(NumLoaders),
+ {ok, Mgc} = ?MGC_START(MgcNode, MgcMid, ET, DSI, ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, DSI, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ megaco_test_mg:update_conn_info(Mg,reply_timer,1000),
+ megaco_test_mgc:update_conn_info(Mgc,reply_timer,1000),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("apply the load"),
+ Res = ?MG_MLOAD(Mg, NumLoaders, ?SINGLE_USER_LOAD_NUM_REQUESTS),
+ case Res of
+ {Time, {ok, Ok, Err}} ->
+ Sec = Time / 1000000,
+ io:format("~nmultiple loaders result: ~n"
+ " Number of successfull: ~w~n"
+ " Number of failure: ~w~n"
+ " Time: ~w seconds~n"
+ " Calls / seconds ~w~n~n",
+ [Ok, Err, Sec, (NumLoaders * ?SINGLE_USER_LOAD_NUM_REQUESTS)/Sec]);
+ {Time, Error} ->
+ io:format("SUL: multiple loaders failed: ~p after ~w~n",
+ [Error, Time])
+ end,
+
+ i("flush the message queue: ~p", [megaco_test_lib:flush()]),
+
+ i("verbosity to trace"),
+ ?MGC_SET_VERBOSITY(Mgc, debug),
+ ?MG_SET_VERBOSITY(Mg, debug),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ i("flush the message queue: ~p", [megaco_test_lib:flush()]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("flush the message queue: ~p", [megaco_test_lib:flush()]),
+
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_user_load(NumUsers, NumLoaders)
+ when (is_integer(NumUsers) andalso (NumUsers > 1) andalso
+ is_integer(NumLoaders) andalso (NumLoaders >= 1)) ->
+ MgcNode = make_node_name(mgc),
+ MgNodes = make_node_names(mg, NumUsers),
+ d("Nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNodes: ~p", [MgcNode, MgNodes]),
+ ok = megaco_test_lib:start_nodes([MgcNode| MgNodes], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ MgcMid = {deviceName, "ctrl"},
+ ET = [{text, tcp, [{serialize, false}]}],
+ DSI = maybe_display_system_info(2 * NumUsers * NumLoaders),
+ {ok, Mgc} = ?MGC_START(MgcNode, MgcMid, ET, DSI, ?MGC_VERBOSITY),
+
+ megaco_test_mgc:update_user_info(Mgc,reply_timer,1000),
+ d("MGC user info: ~p", [?MGC_USER_INFO(Mgc, all)]),
+
+ MgUsers = make_mids(MgNodes),
+
+ d("start MGs, apply the load and stop MGs"),
+ ok = multi_load(MgUsers, DSI, NumLoaders, ?MULTI_USER_LOAD_NUM_REQUESTS),
+
+ i("flush the message queue: ~p", [megaco_test_lib:flush()]),
+
+ ?MGC_SET_VERBOSITY(Mgc, debug),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("flush the message queue: ~p", [megaco_test_lib:flush()]),
+
+ ok.
+
+
+multi_load(MGs, DSI, NumLoaders, NumReqs) ->
+ d("multi_load -> entry with"
+ "~n MGs: ~p"
+ "~n DSI: ~p"
+ "~n NumLoaders: ~p"
+ "~n NumReqs: ~p", [MGs, DSI, NumLoaders, NumReqs]),
+
+ Pids = multi_load_collector_start(MGs, DSI, NumLoaders, NumReqs, []),
+ case timer:tc(?MODULE, do_multi_load, [Pids, NumLoaders, NumReqs]) of
+ {Time, {ok, OKs, []}} ->
+ Sec = Time / 1000000,
+ multi_load_collector_calc(Sec, OKs);
+ {Time, Error} ->
+ Sec = Time/1000000,
+ io:format("~nmulti load failed after ~.1f:~n~p~n~n", [Sec,Error]),
+ {error, Error}
+ end.
+
+do_multi_load(Pids, _NumLoaders, _NumReqs) ->
+ Fun =
+ fun({P,_}) ->
+ d("apply multi load for ~p", [P]),
+ P ! {apply_multi_load, self()}
+ end,
+ lists:foreach(Fun, Pids),
+ await_multi_load_collectors(Pids, [], []).
+
+multi_load_collector_start([], _DSI, _NumLoaders, _NumReqs, Pids) ->
+ Pids;
+multi_load_collector_start([{Mid, Node}|MGs], DSI, NumLoaders, NumReqs, Pids) ->
+ Env = get(),
+ Pid = spawn_link(?MODULE, multi_load_collector,
+ [self(), Node, Mid, DSI, NumLoaders, NumReqs, Env]),
+ multi_load_collector_start(MGs, DSI, NumLoaders, NumReqs, [{Pid,Mid}|Pids]).
+
+get_env(Key, Env) ->
+ case lists:keysearch(Key, 1, Env) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ undefined
+ end.
+
+multi_load_collector(Parent, Node, Mid, DSI, NumLoaders, NumReqs, Env) ->
+ put(verbosity, get_env(verbosity, Env)),
+ put(tc, get_env(tc, Env)),
+ put(sname, get_env(sname, Env) ++ "-loader"),
+ case ?MG_START(Node, Mid, text, tcp, DSI, ?MG_VERBOSITY) of
+ {ok, Pid} ->
+ d("MG ~p user info: ~n~p", [Mid, ?MG_USER_INFO(Pid,all)]),
+ ServChRes = ?MG_SERV_CHANGE(Pid),
+ d("service change result: ~p", [ServChRes]),
+ megaco_test_mg:update_conn_info(Pid,reply_timer,1000),
+ d("MG ~p conn info: ~p", [Mid, ?MG_CONN_INFO(Pid,all)]),
+ multi_load_collector_loop(Parent, Pid, Mid, NumLoaders, NumReqs);
+ Else ->
+ Parent ! {load_start_failed, self(), Mid, Else}
+ end.
+
+multi_load_collector_loop(Parent, Pid, Mid, NumLoaders, NumReqs) ->
+ d("multi_load_collector_loop -> entry with"
+ "~n Parent: ~p"
+ "~n Pid: ~p"
+ "~n Mid: ~p"
+ "~n NumLoaders: ~p"
+ "~n NumReqs: ~p"
+ "~nwhen"
+ "~n self(): ~p"
+ "~n node(): ~p",
+ [Parent, Pid, Mid, NumLoaders, NumReqs, self(), node()]),
+ receive
+ {apply_multi_load, Parent} ->
+ Res = ?MG_LOAD(Pid, NumLoaders, NumReqs),
+ Parent ! {load_complete, self(), Mid, Res},
+ ?MG_SET_VERBOSITY(Pid, debug),
+ ?MG_STOP(Pid),
+ exit(normal)
+ end.
+
+
+await_multi_load_collectors([], Oks, Errs) ->
+ i("await_multi_load_collectors -> done"),
+ {ok, Oks, Errs};
+await_multi_load_collectors(Pids, Oks, Errs) ->
+ receive
+ {load_complete, Pid, Mg, {ok, Ok, Err}} ->
+ i("await_multi_load_collectors -> "
+ "received ok complete from "
+ "~n ~p [~p]", [Pid, Mg]),
+ Pids2 = lists:keydelete(Pid, 1, Pids),
+ Oks2 = [{Mg, Ok, Err}|Oks],
+ await_multi_load_collectors(Pids2, Oks2, Errs);
+ {load_complete, Pid, Mg, Error} ->
+ i("await_multi_load_collectors -> "
+ "received error complete from "
+ "~n ~p [~p]: "
+ "~n ~p", [Pid, Mg, Error]),
+ Pids2 = lists:keydelete(Pid, 1, Pids),
+ Errs2 = [{Mg, Error}|Errs],
+ await_multi_load_collectors(Pids2, Oks, Errs2);
+
+ {'EXIT', Pid, normal} ->
+ %% This is assumed to be one of the collectors
+ i("await_multi_load_collectors -> "
+ "received (normal) exit signal from ~p", [Pid]),
+ await_multi_load_collectors(Pids, Oks, Errs);
+
+ {'EXIT', Pid, Reason} ->
+ i("await_multi_load_collectors -> "
+ "received unexpected exit from ~p:"
+ "~n ~p", [Pid, Reason]),
+ case lists:keydelete(Pid, 1, Pids) of
+ Pids ->
+ %% Not one of my procs, or a proc I have already
+ %% received a complete from.
+ await_multi_load_collectors(Pids, Oks, Errs);
+ Pids2 ->
+ [{Pid,Mg}] = Pids -- Pids2,
+ Errs2 = [{Mg, {unexpected_exit, Reason}}|Errs],
+ await_multi_load_collectors(Pids, Oks, Errs2)
+ end;
+
+ Else ->
+ i("await_multi_load_collectors -> received unexpected message:"
+ "~n~p", [Else]),
+ await_multi_load_collectors(Pids, Oks, Errs)
+ after
+ 5000 ->
+ i("await_multi_load_collectors -> still awaiting reply from:"
+ "~n~p", [Pids]),
+ await_multi_load_collectors(Pids, Oks, Errs)
+ end.
+
+
+%% Note that this is an approximation...we run all the
+%% MGs in parrallel, so it should be "accurate"...
+multi_load_collector_calc(Sec, Oks) ->
+ Succs = lists:sum([Ok || {_, Ok, _} <- Oks]),
+ Fails = lists:sum([Err || {_, _, Err} <- Oks]),
+ io:format("~ntotal multiple loaders result: ~n"
+ " Number of successfull: ~w~n"
+ " Number of failure: ~w~n"
+ " Total Calls / seconds: ~.2f~n~n",
+ [Succs, Fails, Sec]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_node_names(Name, Num) ->
+ make_node_names(Name, Num, []).
+
+make_node_names(_, 0, Names) ->
+ Names;
+make_node_names(BaseName, N, Names) ->
+ Name = lists:flatten(io_lib:format("~p~w", [BaseName,N])),
+ make_node_names(BaseName, N-1, [make_node_name(Name)|Names]).
+
+make_node_name(Name) when is_atom(Name) ->
+ make_node_name(atom_to_list(Name));
+make_node_name(Name) when is_list(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([Name ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+make_mids(MgNodes) when is_list(MgNodes) andalso (length(MgNodes) > 0) ->
+ make_mids(MgNodes, []).
+
+make_mids([], Mids) ->
+ lists:reverse(Mids);
+make_mids([MgNode|MgNodes], Mids) ->
+ case string:tokens(atom_to_list(MgNode), [$@]) of
+ [Name, _] ->
+ Mid = {deviceName, Name},
+ make_mids(MgNodes, [{Mid, MgNode}|Mids]);
+ _Else ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+tim() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+sleep(X) -> receive after X -> ok end.
+
+error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+maybe_display_system_info(NumLoaders) when NumLoaders > 50 ->
+ [{display_system_info, timer:seconds(2)}];
+maybe_display_system_info(NumLoaders) when NumLoaders > 10 ->
+ [{display_system_info, timer:seconds(1)}];
+maybe_display_system_info(_) ->
+ [].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), now(), get(tc), "DBG", F, A).
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ 10 * random:uniform(50).
+
+apply_load_timer() ->
+ erlang:send_after(random(), self(), apply_load_timeout).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
diff --git a/lib/megaco/test/megaco_mess_otp8212_test.erl b/lib/megaco/test/megaco_mess_otp8212_test.erl
new file mode 100644
index 0000000000..109886ebc4
--- /dev/null
+++ b/lib/megaco/test/megaco_mess_otp8212_test.erl
@@ -0,0 +1,181 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: A fun implementation of user callbacks
+%%----------------------------------------------------------------------
+
+-module(megaco_mess_otp8212_test).
+
+-behaviour(megaco_user).
+
+%% Megaco user callback exports
+-export([
+ handle_connect/2, handle_connect/3,
+ handle_disconnect/3,
+ %% handle_syntax_error/3, handle_syntax_error/4,
+ %% handle_message_error/3, handle_message_error/4,
+ handle_trans_request/3, %% handle_trans_request/4,
+ %% handle_trans_long_request/3, handle_trans_long_request/4,
+ %% handle_trans_reply/4, handle_trans_reply/5,
+ %% handle_trans_ack/4, handle_trans_ack/5,
+ handle_unexpected_trans/3, handle_unexpected_trans/4 %% ,
+ %% handle_trans_request_abort/4, handle_trans_request_abort/5,
+ %% handle_segment_reply/5, handle_segment_reply/6
+ ]).
+
+%% Megaco encoder callback exports
+-export([
+ encode_message/3,
+ decode_message/3
+ ]).
+
+%% Megaco transport callback exports
+-export([
+ send_message/2
+ ]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+%%----------------------------------------------------------------------
+%% Megaco user callback
+%%----------------------------------------------------------------------
+
+%% -- handle_connect/2 --
+
+handle_connect(_, _) ->
+ %% i("handle_connect -> entry"),
+ ok.
+
+handle_connect(_, _, otp8212_extra) ->
+ %% i("handle_connect -> entry"),
+ ok;
+handle_connect(_, _, {otp8212_extra, _}) ->
+ %% i("handle_connect -> entry"),
+ ok.
+
+handle_disconnect(Conn, _, {user_disconnect, {otp8212_done, Pid}}) ->
+ %% i("handle_disconnect -> entry"),
+ Pid ! {disconnected, Conn},
+ ok.
+
+handle_trans_request(_, _, _) -> %% incoming SC
+ %% i("handle_trans_request -> entry"),
+ {discard_ack, ["sc reply"]}.
+
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans) ->
+%% i("handle_unexpected_trans -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n ProtocolVersion: ~p"
+%% "~n Trans: ~p", [ConnHandle, ProtocolVersion, Trans]),
+ ok.
+handle_unexpected_trans(_ConnHandle, _ProtocolVersion, _Trans, {otp8212_extra, Pid}) ->
+%% i("handle_unexpected_trans -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n ProtocolVersion: ~p"
+%% "~n Trans: ~p", [ConnHandle, ProtocolVersion, Trans]),
+ Pid ! {handle_unexpected_trans, otp8212_extra},
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Megaco encoder callback
+%%----------------------------------------------------------------------
+
+
+%% Should only be encoding MGC's outgoing request, which we expect
+%% has transaction id = 1.
+
+-define(REQUEST(Id, A),
+ #'MegacoMessage'
+ {mess
+ = #'Message'
+ {version = 1,
+ mId = {deviceName,"MGC"},
+ messageBody
+ = {transactions, [{transactionRequest,
+ #'TransactionRequest'{transactionId = Id,
+ actions = A}}]}}}).
+
+-define(REPLY(A),
+ #'MegacoMessage'
+ {mess
+ = #'Message'
+ {version = 1,
+ mId = {deviceName,"MGC"},
+ messageBody
+ = {transactions,
+ [{transactionReply,
+ #'TransactionReply'{transactionResult
+ = {actionReplies, [A]}}}]}}}).
+
+request() ->
+ list_to_binary("!/1 MGC T=1{C=-{SC=ROOT{SV{MT=RS,RE=\"901\"}}}}").
+
+sc_reply() ->
+ list_to_binary("!/1 MGC P=19731{C=-{SC=root}}").
+
+encode_message(_, _, ?REQUEST(1, "action request")) ->
+ %% i("encode_message -> entry with request"),
+ {ok, request()};
+
+encode_message(_, _, ?REPLY("sc reply")) ->
+ %% i("encode_message -> entry with reply"),
+ {ok, sc_reply()}.
+
+decode_message(_, V248, Bin) ->
+ %% i("decode_message -> entry"),
+ megaco_compact_text_encoder:decode_message([], V248, Bin).
+
+
+%%----------------------------------------------------------------------
+%% Megaco transport callback
+%%----------------------------------------------------------------------
+
+%% Outgoing SC reply.
+%% send_message(otp8212_scr, _) ->
+%% i("send_message(scr) -> entry"),
+%% ok;
+
+%% Outgoing request: fake reception of the the reply.
+send_message({RH, ControlPid, _, WrongMidStr}, _) ->
+ %% i("send_message -> entry"),
+ spawn(fun() -> receive_reply(200, RH, ControlPid, WrongMidStr) end),
+ ok.
+
+receive_reply(After, RH, ControlPid, WrongMidStr) ->
+ timer:sleep(After),
+ %% i("receive_reply -> issue reply"),
+ megaco:process_received_message(RH, ControlPid,
+ otp8212_sendhandle,
+ reply(WrongMidStr),
+ {otp8212_extra, ControlPid}).
+
+reply(WrongMidStr) -> %% note "wrong" mid.
+ list_to_binary("!/1 " ++ WrongMidStr ++ " P=1{C=-{SC=root}}").
+
+%% i(F) ->
+%% i(F, []).
+
+%% i(F, A) ->
+%% io:format(F ++ "~n", A).
diff --git a/lib/megaco/test/megaco_mess_test.erl b/lib/megaco/test/megaco_mess_test.erl
new file mode 100644
index 0000000000..368800fa54
--- /dev/null
+++ b/lib/megaco/test/megaco_mess_test.erl
@@ -0,0 +1,13733 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the implementation of the ITU-T protocol H.248
+%%----------------------------------------------------------------------
+%% Run the entire test suite with:
+%%
+%% megaco_test_lib:t(megaco_test).
+%% megaco_test_lib:t({megaco_test, all}).
+%%
+%% Or parts of it:
+%%
+%% megaco_test_lib:t({megaco_test, accept}).
+%%----------------------------------------------------------------------
+-module(megaco_mess_test).
+
+%% -compile(export_all).
+-export([
+ all/1,
+ init_per_testcase/2,
+ fin_per_testcase/2,
+
+ connect/1,
+
+ request_and_reply/1,
+ request_and_reply_plain/1,
+ request_and_no_reply/1,
+ request_and_reply_pending_ack_no_pending/1,
+ request_and_reply_pending_ack_one_pending/1,
+ single_trans_req_and_reply/1,
+ single_trans_req_and_reply_sendopts/1,
+ request_and_reply_and_ack/1,
+ request_and_reply_and_no_ack/1,
+ request_and_reply_and_late_ack/1,
+ trans_req_and_reply_and_req/1,
+
+ pending_ack/1,
+ pending_ack_plain/1,
+ request_and_pending_and_late_reply/1,
+
+ dist/1,
+
+ tickets/1,
+ otp_4359/1,
+ otp_4836/1,
+ otp_5805/1,
+ otp_5881/1,
+ otp_5887/1,
+ otp_6253/1,
+ otp_6275/1,
+ otp_6276/1,
+ otp_6442/1,
+ otp_6442_resend_request1/1,
+ otp_6442_resend_request2/1,
+ otp_6442_resend_reply1/1,
+ otp_6442_resend_reply2/1,
+ otp_6865/1,
+ otp_6865_request_and_reply_plain_extra1/1,
+ otp_6865_request_and_reply_plain_extra2/1,
+ otp_7189/1,
+ otp_7259/1,
+ otp_7713/1,
+ otp_8183/1,
+ otp_8183_request1/1,
+ otp_8212/1
+ ]).
+
+%% -behaviour(megaco_user).
+-export([
+ handle_connect/3,
+ handle_disconnect/4,
+ handle_syntax_error/4,
+ handle_message_error/4,
+ handle_trans_request/4,
+ handle_trans_long_request/4,
+ handle_trans_reply/5,
+ handle_trans_ack/5,
+ handle_unexpected_trans/4,
+ handle_trans_request_abort/5
+ ]).
+
+%% -behaviour(megaco_transport).
+-export([
+ send_message/2,
+ unblock/1
+ ]).
+
+-ifdef(megaco_hipe_special).
+-export([
+ %% Case: request_and_reply_pending_ack_no_pending
+ rarpanp_mgc_verify_handle_connect/1,
+ rarpanp_mgc_verify_service_change_req/2,
+ rarpanp_mgc_verify_notify_request/1,
+ rarpanp_mgc_verify_handle_disconnect/1,
+ rarpanp_mg_verify_service_change_rep_msg/1,
+ rarpanp_mg_verify_notify_rep_msg/3,
+
+ %% Case: request_and_reply_pending_ack_one_pending
+ rarpaop_mgc_verify_handle_connect/1,
+ rarpaop_mgc_verify_service_change_req/2,
+ rarpaop_mgc_verify_notify_request/1,
+ rarpaop_mgc_verify_reply_ack/1,
+ rarpaop_mgc_verify_handle_disconnect/1,
+ rarpaop_mg_verify_service_change_rep_msg/1,
+ rarpaop_mg_verify_pending_msg/2,
+ rarpaop_mg_verify_notify_rep_msg/3,
+
+ %% Case: single_trans_req_and_reply
+ strar_mgc_verify_handle_connect/1,
+ strar_mgc_verify_service_change_req/2,
+ strar_mgc_verify_notify_request/1,
+ strar_mgc_verify_handle_disconnect/1,
+ strar_mg_verify_handle_connect/1,
+ strar_mg_verify_service_change_reply/1,
+ strar_mg_verify_notify_reply/1,
+
+ %% Case: single_trans_req_and_reply_sendopts
+ straro_mgc_verify_handle_connect/1,
+ straro_mgc_verify_service_change_req/2,
+ straro_mgc_verify_notify_request/1,
+ straro_mgc_verify_handle_trans_ack/1,
+ straro_mg_verify_handle_connect/1,
+ straro_mg_verify_service_change_reply/1,
+ straro_mg_verify_handle_disconnect/1,
+
+ %% Case: request_and_reply_and_ack
+ raraa_mgc_verify_handle_connect/1,
+ raraa_mgc_verify_service_change_req/2,
+ raraa_mgc_verify_notify_req/1,
+ raraa_mgc_verify_handle_trans_ack/1,
+ raraa_mgc_verify_handle_disconnect/1,
+ raraa_mg_verify_service_change_rep_msg/1,
+ raraa_mg_verify_notify_rep_msg/5,
+
+ %% Case: request_and_reply_and_no_ack
+ rarana_mgc_verify_handle_connect/1,
+ rarana_mgc_verify_service_change_req/2,
+ rarana_mgc_verify_notify_req/1,
+ rarana_mgc_verify_handle_trans_ack/1,
+ rarana_mgc_verify_handle_disconnect/1,
+ rarana_mg_verify_service_change_rep_msg/1,
+ rarana_mg_verify_notify_rep_msg/5,
+
+ %% Case: request_and_reply_and_late_ack
+ rarala_mgc_verify_handle_connect/1,
+ rarala_mgc_verify_service_change_req/2,
+ rarala_mgc_verify_notify_req/1,
+ rarala_mgc_verify_handle_trans_ack/1,
+ rarala_mgc_verify_handle_disconnect/1,
+ rarala_mg_verify_service_change_rep_msg/1,
+ rarala_mg_verify_notify_rep_msg/5,
+
+ %% Case: trans_req_and_reply_and_req
+ trarar_mgc_verify_handle_connect/1,
+ trarar_mgc_verify_service_change_req/2,
+ trarar_mgc_verify_notify_req/2,
+ trarar_mgc_verify_handle_disconnect/1,
+ trarar_mg_verify_service_change_rep_msg/1,
+ trarar_mg_verify_notify_rep_msg/5,
+
+ %% Case: pending_ack_plain
+ pap_mgc_verify_handle_connect/1,
+ pap_mgc_verify_service_change_req/2,
+ pap_mgc_verify_notify_req/1,
+ pap_mgc_verify_notify_req_long/1,
+ pap_mgc_verify_handle_trans_ack/1,
+ pap_mgc_verify_handle_disconnect/1,
+ pap_mg_verify_service_change_rep_msg/1,
+ pap_mg_verify_pending_msg/2,
+ pap_mg_verify_notify_rep_msg/5,
+
+ %% Case: request_and_pending_and_late_reply
+ rapalr_mgc_verify_service_change_req_msg/1,
+ rapalr_mgc_verify_notify_req_msg/5,
+ rapalr_mgc_verify_trans_ack_msg/2,
+ rapalr_mg_verify_handle_connect/1,
+ rapalr_mg_verify_service_change_rep/1,
+ rapalr_mg_verify_notify_rep/1,
+
+ %% Case: otp_4836
+ otp_4836_mgc_verify_service_change_req_msg/1,
+ otp_4836_mgc_verify_notify_req_msg/1,
+
+ %% Case: otp_5805
+ otp_5805_mgc_verify_handle_connect/1,
+ otp_5805_mgc_verify_service_change_req/2,
+ otp_5805_mgc_verify_handle_syntax_error/1,
+ otp_5805_mgc_verify_handle_disconnect/1,
+ otp_5805_mg_verify_service_change_rep_msg/1,
+ otp_5805_mg_verify_error_descriptor_msg/1,
+
+ %% Case: otp_5881
+ otp_5881_mgc_verify_service_change_req_msg/1,
+ otp_5881_mgc_verify_notify_req_msg/1,
+
+ %% Case: otp_5887
+ otp_5887_mgc_verify_service_change_req_msg/1,
+ otp_5887_mgc_verify_notify_req_msg/1,
+
+ %% Case: otp_6275
+ otp_6275_mgc_verify_service_change_req_msg/1,
+ otp_6275_mgc_verify_notify_rep_msg/1,
+ otp_6275_mg_verify_handle_connect/1,
+ otp_6275_mg_verify_notify_req/1,
+ otp_6275_mg_verify_handle_trans_rep/1,
+
+ %% Case: otp_6442_resend_request1
+ otp_6442_resend_request1_mg_verify_handle_connect/1,
+ otp_6442_resend_request1_mg_verify_service_change_rep/1,
+ otp_6442_resend_request1_mg_verify_notify_rep/1,
+
+ %% Case: otp_6442_resend_request2
+ otp_6442_resend_request2_mg_verify_handle_connect/1,
+ otp_6442_resend_request2_mg_verify_service_change_rep/1,
+ otp_6442_resend_request2_mg_verify_notify_rep/1,
+
+ %% Case: otp_6442_resend_reply1
+ otp_6442_resend_reply1_mg_verify_handle_connect/1,
+ otp_6442_resend_reply1_mg_verify_service_change_rep/1,
+ otp_6442_resend_reply1_mg_verify_notify_req/2,
+ otp_6442_resend_reply1_mg_verify_ack/1,
+
+ %% Case: otp_6442_resend_reply2
+ otp_6442_resend_reply2_mg_verify_handle_connect/1,
+ otp_6442_resend_reply2_mg_verify_service_change_rep/1,
+ otp_6442_resend_reply2_mg_verify_notify_req/2,
+ otp_6442_resend_reply2_mg_verify_ack/1,
+
+ %% Case: otp_6865_request_and_reply_plain_extra2
+ otp6865e2_mgc_verify_handle_connect/1,
+ otp6865e2_mgc_verify_service_change_req/3,
+ otp6865e2_mgc_verify_notify_req/4,
+ otp6865e2_mgc_verify_reply_ack/2,
+ otp6865e2_mgc_verify_notify_reply/2,
+ otp6865e2_mgc_verify_handle_disconnect/1,
+ otp6865e2_mg_verify_service_change_rep_msg/1,
+ otp6865e2_mg_verify_notify_rep_msg/6,
+ otp6865e2_mg_verify_notify_req_msg/1,
+
+ %% Case: otp_7189
+ otp_7189_mgc_verify_handle_connect/1,
+ otp_7189_mgc_verify_service_change_req/2,
+ otp_7189_mgc_verify_handle_trans_reply_req/1,
+ otp_7189_mgc_verify_handle_disconnect/1,
+ otp_7189_mg_verify_service_change_rep_msg/1,
+ otp_7189_mg_verify_notify_req_msg/1,
+
+ %% Case: otp_6442_resend_request1
+ otp_8183_request1_mg_verify_handle_connect/1,
+ otp_8183_request1_mg_verify_service_change_rep/1,
+ otp_8183_request1_mg_verify_notify_rep/1,
+
+ %% Utility
+ encode_msg/3,
+ decode_msg/3
+ ]).
+-endif.
+
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include("megaco_test_lib.hrl").
+
+-define(VERSION, 1).
+
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
+
+-define(MGC_START(Pid, Mid, ET, Conf, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET, Conf, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_REQ_PEND(Pid,To), megaco_test_mgc:request_pending(Pid,To)).
+-define(MGC_REQ_HP(Pid,To), megaco_test_mgc:request_handle_pending(Pid,To)).
+-define(MGC_ACK_INFO(Pid), megaco_test_mgc:ack_info(Pid,self())).
+
+-define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb),
+ megaco_test_mg:start(Pid, Mid, Enc, Transp, Conf, Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
+-define(MG_AWAIT_NOTIF_REP(Pid), megaco_test_mg:await_notify_reply(Pid)).
+-define(MG_CONN_INFO(Pid,Tag), megaco_test_mg:conn_info(Pid,Tag)).
+-define(MG_USER_INFO(Pid,Tag), megaco_test_mg:user_info(Pid,Tag)).
+-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+
+-define(SEND(Expr),
+ ?VERIFY(ok, megaco_mess_user_test:apply_proxy(fun() -> Expr end))).
+
+-define(USER(Expected, Reply),
+ megaco_mess_user_test:reply(?MODULE,
+ ?LINE,
+ fun(Actual) ->
+ case ?VERIFY(Expected, Actual) of
+ Expected -> {ok, Reply};
+ UnExpected -> {error, {reply_verify,
+ ?MODULE,
+ ?LINE,
+ UnExpected}}
+ end
+ end)).
+
+%% t() -> megaco_test_lib:t(?MODULE).
+%% t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+min(M) -> timer:minutes(M).
+
+%% Test server callbacks
+% init_per_testcase(pending_ack = Case, Config) ->
+% put(dbg,true),
+% megaco_test_lib:init_per_testcase(Case, Config);
+init_per_testcase(otp_7189 = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ megaco_test_lib:init_per_testcase(Case, [{tc_timeout, min(2)} |C]);
+init_per_testcase(request_and_no_reply = Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ megaco_test_lib:init_per_testcase(Case, [{tc_timeout, min(2)} |C]);
+init_per_testcase(Case, Config) ->
+ C = lists:keydelete(tc_timeout, 1, Config),
+ megaco_test_lib:init_per_testcase(Case, [{tc_timeout, min(1)} |C]).
+
+% fin_per_testcase(pending_ack = Case, Config) ->
+% erase(dbg),
+% megaco_test_lib:fin_per_testcase(Case, Config);
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ [
+ connect,
+ request_and_reply,
+ pending_ack,
+ dist,
+
+ %% Tickets last
+ tickets
+ ].
+
+request_and_reply(suite) ->
+ [
+ request_and_reply_plain,
+ request_and_no_reply,
+ request_and_reply_pending_ack_no_pending,
+ request_and_reply_pending_ack_one_pending,
+ single_trans_req_and_reply,
+ single_trans_req_and_reply_sendopts,
+ request_and_reply_and_ack,
+ request_and_reply_and_no_ack,
+ request_and_reply_and_late_ack,
+ trans_req_and_reply_and_req
+ ].
+
+pending_ack(suite) ->
+ [
+ pending_ack_plain,
+ request_and_pending_and_late_reply
+ ].
+
+tickets(suite) ->
+ [
+ otp_4359,
+ otp_4836,
+ otp_5805,
+ otp_5881,
+ otp_5887,
+ otp_6253,
+ otp_6275,
+ otp_6276,
+ otp_6442,
+ otp_6865,
+ otp_7189,
+ otp_7259,
+ otp_7713,
+ otp_8183,
+ otp_8212
+ ].
+
+otp_6442(suite) ->
+ [
+ otp_6442_resend_request1,
+ otp_6442_resend_request2,
+ otp_6442_resend_reply1,
+ otp_6442_resend_reply2
+ ].
+
+otp_6865(suite) ->
+ [
+ otp_6865_request_and_reply_plain_extra1,
+ otp_6865_request_and_reply_plain_extra2
+ ].
+
+otp_8183(suite) ->
+ [
+ otp_8183_request1
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+connect(suite) ->
+ [];
+connect(doc) ->
+ [];
+connect(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+
+ ?VERIFY(ok, application:start(megaco)),
+ ?VERIFY(ok, megaco:start_user(MgMid, [{send_mod, bad_send_mod},
+ {request_timer, infinity},
+ {reply_timer, infinity}])),
+
+ MgRH = user_info(MgMid, receive_handle),
+ {ok, PrelCH} = ?VERIFY({ok, _}, megaco:connect(MgRH, PrelMid, sh, self())),
+
+ connections([PrelCH]),
+ ?VERIFY([PrelCH], megaco:user_info(MgMid, connections)),
+
+ ?VERIFY(bad_send_mod, megaco:user_info(MgMid, send_mod)),
+ ?VERIFY(bad_send_mod, megaco:conn_info(PrelCH, send_mod)),
+ SC = service_change_request(),
+ ?VERIFY({1, {error, {send_message_failed, {'EXIT',
+ {undef, [{bad_send_mod, send_message, [sh, _]} | _]}}}}},
+ megaco:call(PrelCH, [SC], [])),
+
+ ?VERIFY(ok, megaco:disconnect(PrelCH, shutdown)),
+
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_plain(suite) ->
+ [];
+request_and_reply_plain(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ d("request_and_reply_plain -> start proxy",[]),
+ megaco_mess_user_test:start_proxy(),
+
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+ MgcMid = ipv4_mid(),
+ UserMod = megaco_mess_user_test,
+ d("request_and_reply_plain -> start megaco app",[]),
+ ?VERIFY(ok, application:start(megaco)),
+ UserConfig = [{user_mod, UserMod}, {send_mod, UserMod},
+ {request_timer, infinity}, {reply_timer, infinity}],
+ d("request_and_reply_plain -> start (MG) user ~p",[MgMid]),
+ ?VERIFY(ok, megaco:start_user(MgMid, UserConfig)),
+
+ d("request_and_reply_plain -> start (MGC) user ~p",[MgcMid]),
+ ?VERIFY(ok, megaco:start_user(MgcMid, UserConfig)),
+
+ d("request_and_reply_plain -> get receive info for ~p",[MgMid]),
+ MgRH = user_info(MgMid, receive_handle),
+ d("request_and_reply_plain -> get receive info for ~p",[MgcMid]),
+ MgcRH = user_info(MgcMid, receive_handle),
+ d("request_and_reply_plain -> start transport",[]),
+ {ok, MgPid, MgSH} =
+ ?VERIFY({ok, _, _}, UserMod:start_transport(MgRH, MgcRH)),
+ PrelMgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = preliminary_mid},
+ MgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = MgcMid},
+ MgcCH = #megaco_conn_handle{local_mid = MgcMid,
+ remote_mid = MgMid},
+ d("request_and_reply_plain -> (MG) try connect to MGC",[]),
+ ?SEND(megaco:connect(MgRH, PrelMid, MgSH, MgPid)), % Mg prel
+ d("request_and_reply_plain -> (MGC) await connect from MG",[]),
+ ?USER({connect, PrelMgCH, _V, []}, ok),
+ ?RECEIVE([{res, _, {ok, PrelMgCH}}]),
+
+ d("request_and_reply_plain -> (MG) send service change request",[]),
+ Req = service_change_request(),
+ ?SEND(megaco:call(PrelMgCH, [Req], [])),
+
+ d("request_and_reply_plain -> (MGC) send service change reply",[]),
+ ?USER({connect, MgcCH, _V, []}, ok), % Mgc auto
+ Rep = service_change_reply(MgcMid),
+ ?USER({request, MgcCH, _V, [[Req]]}, {discard_ack, [Rep]}),
+ ?USER({connect, MgCH, _V, []}, ok), % Mg confirm
+ ?RECEIVE([{res, _, {1, {ok, [Rep]}}}]),
+
+ d("request_and_reply_plain -> get (system info) connections",[]),
+ connections([MgCH, MgcCH]),
+ d("request_and_reply_plain -> get (~p) connections",[MgMid]),
+ ?VERIFY([MgCH], megaco:user_info(MgMid, connections)),
+ d("request_and_reply_plain -> get (~p) connections",[MgcMid]),
+ ?VERIFY([MgcCH], megaco:user_info(MgcMid, connections)),
+
+ Reason = shutdown,
+ d("request_and_reply_plain -> (MG) disconnect",[]),
+ ?SEND(megaco:disconnect(MgCH, Reason)),
+ ?USER({disconnect, MgCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+
+ d("request_and_reply_plain -> (MGC) disconnect",[]),
+ ?SEND(megaco:disconnect(MgcCH, Reason)),
+ ?USER({disconnect, MgcCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgcMid)),
+
+ d("request_and_reply_plain -> stop megaco app",[]),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+ d("request_and_reply_plain -> done",[]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% OTP-4760
+request_and_no_reply(suite) ->
+ [];
+request_and_no_reply(doc) ->
+ [];
+request_and_no_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, request_and_no_reply),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Start the MGC
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ Mg1Mid = {deviceName, "mg1"},
+ Mg2Mid = {deviceName, "mg2"},
+ Mg3Mid = {deviceName, "mg3"},
+ Mg4Mid = {deviceName, "mg4"},
+ ReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 2
+ },
+ LongReqTmr = #megaco_incr_timer{wait_for = 10000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3
+ },
+ %% Start the MGs
+ PendingTmr = 10000,
+ ReplyTmr = 16000,
+ MgConfig = [{request_timer, ReqTmr},
+ {long_request_timer, LongReqTmr},
+ {pending_timer, PendingTmr},
+ {reply_timer, ReplyTmr}],
+ {ok, Mg1} = ?MG_START(Mg1Node, Mg1Mid, text, tcp, MgConfig, ?MG_VERBOSITY),
+ {ok, Mg2} = ?MG_START(Mg2Node, Mg2Mid, text, udp, MgConfig, ?MG_VERBOSITY),
+ {ok, Mg3} = ?MG_START(Mg3Node, Mg3Mid, binary, tcp, MgConfig, ?MG_VERBOSITY),
+ {ok, Mg4} = ?MG_START(Mg4Node, Mg4Mid, binary, udp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG1 user info: ~p", [?MG_USER_INFO(Mg1, all)]),
+ d("MG1 conn info: ~p", [?MG_CONN_INFO(Mg1, all)]),
+ d("MG2 user info: ~p", [?MG_USER_INFO(Mg2, all)]),
+ d("MG2 conn info: ~p", [?MG_CONN_INFO(Mg2, all)]),
+ d("MG3 user info: ~p", [?MG_USER_INFO(Mg3, all)]),
+ d("MG3 conn info: ~p", [?MG_CONN_INFO(Mg3, all)]),
+ d("MG4 user info: ~p", [?MG_USER_INFO(Mg4, all)]),
+ d("MG4 conn info: ~p", [?MG_CONN_INFO(Mg4, all)]),
+
+ i("[MG1] connect to the MGC (service change)"),
+ ServChRes1 = ?MG_SERV_CHANGE(Mg1),
+ d("service change result: ~p", [ServChRes1]),
+ d("MG1 user info: ~p", [?MG_USER_INFO(Mg1, all)]),
+ d("MG1 conn info: ~p", [?MG_CONN_INFO(Mg1, all)]),
+
+ i("[MG2] connect to the MGC (service change)"),
+ ServChRes2 = ?MG_SERV_CHANGE(Mg2),
+ d("service change result: ~p", [ServChRes2]),
+ d("MG2 user info: ~p", [?MG_USER_INFO(Mg2, all)]),
+ d("MG2 conn info: ~p", [?MG_CONN_INFO(Mg2, all)]),
+
+ i("[MG3] connect to the MGC (service change)"),
+ ServChRes3 = ?MG_SERV_CHANGE(Mg3),
+ d("service change result: ~p", [ServChRes3]),
+ d("MG3 user info: ~p", [?MG_USER_INFO(Mg3, all)]),
+ d("MG3 conn info: ~p", [?MG_CONN_INFO(Mg3, all)]),
+
+ i("[MG4] connect to the MGC (service change)"),
+ ServChRes4 = ?MG_SERV_CHANGE(Mg4),
+ d("service change result: ~p", [ServChRes4]),
+ d("MG4 user info: ~p", [?MG_USER_INFO(Mg4, all)]),
+ d("MG4 conn info: ~p", [?MG_CONN_INFO(Mg4, all)]),
+
+ d("tell the MGC to ignore requests"),
+ ?MGC_REQ_PEND(Mgc, infinity),
+
+ d("[MG1] send the notify"),
+ ?MG_NOTIF_REQ(Mg1),
+
+ d("[MG2] send the notify"),
+ ?MG_NOTIF_REQ(Mg2),
+
+ d("[MG3] send the notify"),
+ ?MG_NOTIF_REQ(Mg3),
+
+ d("[MG4] send the notify"),
+ ?MG_NOTIF_REQ(Mg4),
+
+ d("[MG1] await notify reply"),
+ {ok, {_Vsn1, {error, timeout}}} = ?MG_AWAIT_NOTIF_REP(Mg1),
+ d("[MG1] received expected reply"),
+
+ d("[MG2] await notify reply"),
+ {ok, {_Vsn2, {error, timeout}}} = ?MG_AWAIT_NOTIF_REP(Mg2),
+ d("[MG2] received expected reply"),
+
+ d("[MG3] await notify reply"),
+ {ok, {_Vsn3, {error, timeout}}} = ?MG_AWAIT_NOTIF_REP(Mg3),
+ d("[MG3] received expected reply"),
+
+ d("[MG4] await notify reply"),
+ {ok, {_Vsn4, {error, timeout}}} = ?MG_AWAIT_NOTIF_REP(Mg4),
+ d("[MG4] received expected reply"),
+
+ d("MG1 user info: ~p", [?MG_USER_INFO(Mg1, all)]),
+ d("MG1 conn info: ~p", [?MG_CONN_INFO(Mg1, all)]),
+ d("MG2 user info: ~p", [?MG_USER_INFO(Mg2, all)]),
+ d("MG2 conn info: ~p", [?MG_CONN_INFO(Mg2, all)]),
+ d("MG3 user info: ~p", [?MG_USER_INFO(Mg3, all)]),
+ d("MG3 conn info: ~p", [?MG_CONN_INFO(Mg3, all)]),
+ d("MG4 user info: ~p", [?MG_USER_INFO(Mg4, all)]),
+ d("MG4 conn info: ~p", [?MG_CONN_INFO(Mg4, all)]),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_pending_ack_no_pending(suite) ->
+ [];
+request_and_reply_pending_ack_no_pending(doc) ->
+ ["This test case tests that megaco correctly handles the return "
+ "value handle_pending_ack from handle_trans_request when NO "
+ "pending message has been sent"];
+request_and_reply_pending_ack_no_pending(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rar_panp),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rarpanp_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rarpanp_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarpanp_mgc_verify_handle_connect_fun(),
+ {?MODULE, rarpanp_mgc_verify_handle_connect, []}).
+-define(rarpanp_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, rarpanp_mgc_verify_service_change_req, [Mid]}).
+-define(rarpanp_mgc_verify_notify_req_fun(),
+ {?MODULE, rarpanp_mgc_verify_notify_request, []}).
+-define(rarpanp_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, rarpanp_mgc_verify_handle_disconnect, []}).
+-else.
+-define(rarpanp_mgc_verify_handle_connect_fun(),
+ fun rarpanp_mgc_verify_handle_connect/1).
+-define(rarpanp_mgc_verify_service_change_req_fun(Mid),
+ rarpanp_mgc_verify_service_change_req_fun(Mid)).
+-define(rarpanp_mgc_verify_notify_req_fun(),
+ rarpanp_mgc_verify_notify_request_fun()).
+-define(rarpanp_mgc_verify_handle_disconnect_fun(),
+ fun rarpanp_mgc_verify_handle_disconnect/1).
+-endif.
+
+rarpanp_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?rarpanp_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?rarpanp_mgc_verify_service_change_req_fun(Mid),
+ NrVerify = ?rarpanp_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?rarpanp_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun rarpanp_mgc_verify_handle_connect/1,
+%% ScrVerify = rarpanp_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify = rarpanp_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun rarpanp_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify},
+ {megaco_callback, nocall, 10000},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+rarpanp_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+rarpanp_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+rarpanp_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ rarpanp_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+rarpanp_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("rarpanp_mgc_verify_service_change_req -> entry with"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ (catch rarpanp_mgc_do_verify_service_change_req(AR, Mid));
+rarpanp_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarpanp_mgc_do_verify_service_change_req(AR, Mid) ->
+ io:format("rarpanp_mgc_do_verify_service_change_req -> entry with"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [rarpanp_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+rarpanp_mgc_verify_notify_request_fun() ->
+ fun(Req) ->
+ rarpanp_mgc_verify_notify_request(Req)
+ end.
+-endif.
+
+rarpanp_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch rarpanp_mgc_do_verify_notify_request(AR));
+rarpanp_mgc_verify_notify_request(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarpanp_mgc_do_verify_notify_request(AR) ->
+ io:format("rarpanp_mgc_do_verify_notify_request -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = notify_request_verified,
+ Replies = [rarpanp_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_pending_ack, AckData}, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+%% Disconnect verification
+rarpanp_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+rarpanp_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+rarpanp_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+rarpanp_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarpanp_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rarpanp_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rarpanp_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, rarpanp_mg_verify_service_change_rep_msg, []}).
+-define(rarpanp_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ {?MODULE, rarpanp_mg_verify_notify_rep_msg, [TransId, TermId]}).
+-else.
+-define(rarpanp_mg_decode_msg_fun(Mod, Conf),
+ rarpanp_mg_decode_msg_fun(Mod, Conf)).
+-define(rarpanp_mg_encode_msg_fun(Mod, Conf),
+ rarpanp_mg_encode_msg_fun(Mod, Conf)).
+-define(rarpanp_mg_verify_service_change_rep_msg_fun(),
+ rarpanp_mg_verify_service_change_rep_msg_fun()).
+-define(rarpanp_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ rarpanp_mg_verify_notify_rep_msg_fun(TransId, TermId)).
+-endif.
+
+rarpanp_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?rarpanp_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?rarpanp_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = rarpanp_mg_service_change_request_msg(Mid, 1, 0),
+ ScrVerifyFun = ?rarpanp_mg_verify_service_change_rep_msg_fun(),
+ TransId = 2,
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = rarpanp_mg_notify_request_msg(Mid, TransId, 1, TermId, 1),
+ NrVerifyFun = ?rarpanp_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify-reply", {NrVerifyFun, 10000}},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+rarpanp_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarpanp_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarpanp_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch rarpanp_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+rarpanp_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rarpanp_mg_verify_service_change_rep_msg -> entry with"
+ "~n Mess: ~p"
+ "~n", [Mess]),
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+rarpanp_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rarpanp_mg_verify_notify_rep_msg_fun(TransId, TermId) ->
+ fun(Msg) ->
+ (catch rarpanp_mg_verify_notify_rep_msg(Msg, TransId, TermId))
+ end.
+-endif.
+
+rarpanp_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TransId, TermId) ->
+ io:format("rarpanp_mg_verify_notify_rep_msg -> entry with"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Mess: ~p"
+ "~n", [TransId, TermId, Mess]),
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = asn1_NOVALUE, % No ack
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyRep} ->
+ NotifyRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ io:format("rarpanp_mg_verify_notify_rep_msg -> done when verifyed"
+ "~n", []),
+ {ok, M};
+ #'NotifyReply'{terminationID = A,
+ errorDescriptor = B} ->
+ throw({error, {invalid_notifyReply,
+ {A, TermId},
+ {B, asn1_NOVALUE}}});
+ _ ->
+ throw({error, {invalid_notifyReply, NR}})
+ end;
+rarpanp_mg_verify_notify_rep_msg(_TransId, _TermId, Crap) ->
+ {error, {invalid_message, Crap}}.
+
+rarpanp_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarpanp_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = rarpanp_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarpanp_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarpanp_mg_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = rarpanp_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_pending_ack_one_pending(suite) ->
+ [];
+request_and_reply_pending_ack_one_pending(doc) ->
+ ["This test case tests that megaco correctly handles the return "
+ "value handle_pending_ack from handle_trans_request when ONE "
+ "pending message has been sent"];
+request_and_reply_pending_ack_one_pending(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rar_paop),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator"),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ %% MgcEvSeq = rarpaop_mgc_event_sequence(text, tcp),
+ MgcEvSeq = rarpaop_mgc_event_sequence(binary, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ %% MgEvSeq = rarpaop_mg_event_sequence(text, tcp),
+ MgEvSeq = rarpaop_mg_event_sequence(binary, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarpaop_mgc_verify_handle_connect_fun(),
+ {?MODULE, rarpaop_mgc_verify_handle_connect, []}).
+-define(rarpaop_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, rarpaop_mgc_verify_service_change_req, [Mid]}).
+-define(rarpaop_mgc_verify_notify_req_fun(),
+ {?MODULE, rarpaop_mgc_verify_notify_request, []}).
+-define(rarpaop_mgc_verify_reply_ack_fun(),
+ {?MODULE, rarpaop_mgc_verify_reply_ack, []}).
+-define(rarpaop_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, rarpaop_mgc_verify_handle_disconnect, []}).
+-else.
+-define(rarpaop_mgc_verify_handle_connect_fun(),
+ fun rarpaop_mgc_verify_handle_connect/1).
+-define(rarpaop_mgc_verify_service_change_req_fun(Mid),
+ rarpaop_mgc_verify_service_change_req_fun(Mid)).
+-define(rarpaop_mgc_verify_notify_req_fun(),
+ rarpaop_mgc_verify_notify_request_fun()).
+-define(rarpaop_mgc_verify_reply_ack_fun(),
+ rarpaop_mgc_verify_reply_ack_fun()).
+-define(rarpaop_mgc_verify_handle_disconnect_fun(),
+ fun rarpaop_mgc_verify_handle_disconnect/1).
+-endif.
+
+rarpaop_mgc_event_sequence(text, tcp) ->
+ Port = 2944,
+ TranspMod = megaco_tcp,
+ EncMod = megaco_pretty_text_encoder,
+ EncConf = [],
+ rarpaop_mgc_event_sequence(Port, TranspMod, EncMod, EncConf);
+rarpaop_mgc_event_sequence(binary, tcp) ->
+ Port = 2945,
+ TranspMod = megaco_tcp,
+ EncMod = megaco_ber_bin_encoder,
+ EncConf = [],
+ rarpaop_mgc_event_sequence(Port, TranspMod, EncMod, EncConf).
+
+rarpaop_mgc_event_sequence(Port, TranspMod, EncMod, EncConf) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, Port},
+ {transport_module, TranspMod},
+ {encoding_module, EncMod},
+ {encoding_config, EncConf}
+ ],
+ ConnectVerify = ?rarpaop_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?rarpaop_mgc_verify_service_change_req_fun(Mid),
+ NrVerify = ?rarpaop_mgc_verify_notify_req_fun(),
+ AckVerify = ?rarpaop_mgc_verify_reply_ack_fun(),
+ DiscoVerify = ?rarpaop_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun rarpaop_mgc_verify_handle_connect/1,
+%% ScrVerify = rarpaop_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify = rarpaop_mgc_verify_notify_request_fun(),
+%% AckVerify = rarpaop_mgc_verify_reply_ack_fun(),
+%% DiscoVerify = fun rarpaop_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, nocall, 10000},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+rarpaop_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+rarpaop_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+rarpaop_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ rarpaop_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+rarpaop_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch rarpaop_do_verify_service_change_req(AR, Mid));
+rarpaop_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarpaop_do_verify_service_change_req(AR, Mid) ->
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [rarpaop_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+rarpaop_mgc_verify_notify_request_fun() ->
+ fun(Req) ->
+ rarpaop_mgc_verify_notify_request(Req)
+ end.
+-endif.
+
+rarpaop_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch rarpaop_mgc_do_verify_notify_request(AR));
+rarpaop_mgc_verify_notify_request(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarpaop_mgc_do_verify_notify_request(AR) ->
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = notify_request_verified,
+ Replies = [rarpaop_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_pending_ack, AckData}, Replies},
+ {ok, 5000, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+%% Ack verification
+-ifndef(megaco_hipe_special).
+rarpaop_mgc_verify_reply_ack_fun() ->
+ fun(M) ->
+ rarpaop_mgc_verify_reply_ack(M)
+ end.
+-endif.
+
+rarpaop_mgc_verify_reply_ack({handle_trans_ack, _, ?VERSION, ok, _}) ->
+ io:format("rarpaop_mgc_verify_reply_ack -> ok~n", []),
+ {ok, ok, ok};
+rarpaop_mgc_verify_reply_ack({handle_trans_ack, _, ?VERSION, AS, AD} = Crap) ->
+ io:format("rarpaop_mgc_verify_reply_ack -> incorrect ack-status:"
+ "~n AS: ~p"
+ "~n AD: ~p"
+ "~n", [AS, AD]),
+ ED = cre_ErrDesc({invalid_ack_status, {AS, AD}}),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply};
+rarpaop_mgc_verify_reply_ack(Crap) ->
+ io:format("rarpaop_mgc_verify_reply_ack -> invalid ack:"
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+
+%% Disconnect verification
+rarpaop_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+rarpaop_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+rarpaop_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+rarpaop_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarpaop_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rarpaop_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rarpaop_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, rarpaop_mg_verify_service_change_rep_msg, []}).
+-define(rarpaop_mg_verify_pending_msg_fun(TransId),
+ {?MODULE, rarpaop_mg_verify_pending_msg, [TransId]}).
+-define(rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ {?MODULE, rarpaop_mg_verify_notify_rep_msg, [TransId, TermId]}).
+-else.
+-define(rarpaop_mg_decode_msg_fun(Mod, Conf),
+ rarpaop_mg_decode_msg_fun(Mod, Conf)).
+-define(rarpaop_mg_encode_msg_fun(Mod, Conf),
+ rarpaop_mg_encode_msg_fun(Mod, Conf)).
+-define(rarpaop_mg_verify_service_change_rep_msg_fun(),
+ rarpaop_mg_verify_service_change_rep_msg_fun()).
+-define(rarpaop_mg_verify_pending_msg_fun(TransId),
+ rarpaop_mg_verify_pending_msg_fun(TransId)).
+-define(rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId)).
+-endif.
+
+rarpaop_mg_event_sequence(text, tcp) ->
+ Port = 2944,
+ EncMod = megaco_pretty_text_encoder,
+ EncConf = [],
+ rarpaop_mg_event_sequence(Port, EncMod, EncConf);
+rarpaop_mg_event_sequence(binary, tcp) ->
+ Port = 2945,
+ EncMod = megaco_ber_bin_encoder,
+ EncConf = [],
+ rarpaop_mg_event_sequence(Port, EncMod, EncConf).
+
+rarpaop_mg_event_sequence(Port, EncMod, EncConf) ->
+ DecodeFun = ?rarpaop_mg_decode_msg_fun(EncMod, EncConf),
+ EncodeFun = ?rarpaop_mg_encode_msg_fun(EncMod, EncConf),
+ Mid = {deviceName, "mg"},
+ TransId = 2,
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ ServiceChangeReq = rarpaop_mg_service_change_request_msg(Mid, 1, 0),
+ NotifyReq = rarpaop_mg_notify_request_msg(Mid, TransId, 1, TermId, 1),
+ Ack = rarpaop_mg_ack_msg(Mid, TransId),
+ ScrVerifyFun = ?rarpaop_mg_verify_service_change_rep_msg_fun(),
+ PendVerifyFun = ?rarpaop_mg_verify_pending_msg_fun(TransId),
+ NrVerifyFun = ?rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId),
+%% ScrVerifyFun = rarpaop_mg_verify_service_change_rep_msg_fun(),
+%% PendVerifyFun = rarpaop_mg_verify_pending_msg_fun(TransId),
+%% NrVerifyFun = rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, Port},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {sleep, 2000},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "pending", {PendVerifyFun, 5000}},
+ {expect_receive, "notify-reply", {NrVerifyFun, 5000}},
+ {send, "reply ack", Ack},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+rarpaop_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarpaop_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarpaop_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch rarpaop_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+rarpaop_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+rarpaop_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rarpaop_mg_verify_pending_msg_fun(TransId) ->
+ fun(Msg) ->
+ (catch rarpaop_mg_verify_pending_msg(Msg, TransId))
+ end.
+-endif.
+
+rarpaop_mg_verify_pending_msg(#'MegacoMessage'{mess = Mess} = M, TransId) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TP =
+ case Trans of
+ {transactionPending, TransPending} ->
+ TransPending;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case TP of
+ #'TransactionPending'{transactionId = TransId} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_transactionPending, TP}})
+ end;
+rarpaop_mg_verify_pending_msg(Crap, _TransId) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rarpaop_mg_verify_notify_rep_msg_fun(TransId, TermId) ->
+ fun(Msg) ->
+ (catch rarpaop_mg_verify_notify_rep_msg(Msg, TransId, TermId))
+ end.
+-endif.
+
+rarpaop_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TransId, TermId) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL', % Ack
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyRep} ->
+ NotifyRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ #'NotifyReply'{terminationID = A,
+ errorDescriptor = B} ->
+ throw({error, {invalid_notifyReply,
+ {A, TermId},
+ {B, asn1_NOVALUE}}});
+ _ ->
+ throw({error, {invalid_notifyReply, NR}})
+ end;
+rarpaop_mg_verify_notify_rep_msg(Crap, _TransId, _TermId) ->
+ {error, {invalid_message, Crap}}.
+
+rarpaop_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarpaop_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = rarpaop_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarpaop_mg_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarpaop_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarpaop_mg_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = rarpaop_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_trans_req_and_reply(suite) ->
+ [];
+single_trans_req_and_reply(doc) ->
+ ["Receive a (single) transaction request and then send a "
+ "reply (discard ack). "
+ "The MGC is a megaco instance (megaco event sequence) and the "
+ "MG is emulated (tcp event sequence)"];
+single_trans_req_and_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, strar),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = strar_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = strar_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId], 30000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(strar_mgc_verify_handle_connect_fun(),
+ {?MODULE, strar_mgc_verify_handle_connect, []}).
+-define(strar_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, strar_mgc_verify_service_change_req, [Mid]}).
+-define(strar_mgc_verify_notify_req_fun(),
+ {?MODULE, strar_mgc_verify_notify_request, []}).
+-define(strar_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, strar_mgc_verify_handle_disconnect, []}).
+-else.
+-define(strar_mgc_verify_handle_connect_fun(),
+ fun strar_mgc_verify_handle_connect/1).
+-define(strar_mgc_verify_service_change_req_fun(Mid),
+ strar_mgc_verify_service_change_req_fun(Mid)).
+-define(strar_mgc_verify_notify_req_fun(),
+ strar_mgc_verify_notify_request_fun()).
+-define(strar_mgc_verify_handle_disconnect_fun(),
+ fun strar_mgc_verify_handle_disconnect/1).
+-endif.
+
+strar_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ %% Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+%% ReqTmr = #megaco_incr_timer{wait_for = 500,
+%% factor = 1,
+%% max_retries = 1},
+ ConnectVerify = ?strar_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?strar_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?strar_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?strar_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun strar_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = strar_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = strar_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun strar_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+strar_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("strar_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+strar_mgc_verify_handle_connect(Else) ->
+ io:format("strar_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+strar_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ strar_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+strar_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch strar_mgc_do_verify_service_change_req(AR, Mid));
+strar_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+strar_mgc_do_verify_service_change_req(AR, Mid) ->
+ io:format("strar_mgc_verify_service_change_req -> entry with"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [strar_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+-ifndef(megaco_hipe_special).
+strar_mgc_verify_notify_request_fun() ->
+ fun(Req) ->
+ strar_mgc_verify_notify_request(Req)
+ end.
+-endif.
+
+strar_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch strar_mgc_do_verify_notify_request(AR));
+strar_mgc_verify_notify_request(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+strar_mgc_do_verify_notify_request(AR) ->
+ io:format("strar_mgc_do_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} when (CtxID == 1) or
+ (CtxID == 2) ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ Replies = [strar_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {discard_ack, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ {error, Err6, ErrReply6}
+ end.
+
+strar_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("strar_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+strar_mgc_verify_handle_disconnect(Else) ->
+ io:format("strar_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+strar_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+strar_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+%% strar_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+%% AR = strar_mgc_notify_reply_ar(Cid, TermId),
+%% TRes = cre_transResult([AR]),
+%% TR = cre_transReply(TransId, TRes),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(strar_mg_verify_handle_connect_fun(),
+ {?MODULE, strar_mg_verify_handle_connect, []}).
+-define(strar_mg_verify_service_change_reply_fun(),
+ {?MODULE, strar_mg_verify_service_change_reply, []}).
+-define(strar_mg_verify_notify_reply_fun(),
+ {?MODULE, strar_mg_verify_notify_reply, []}).
+-else.
+-define(strar_mg_verify_handle_connect_fun(),
+ strar_mg_verify_handle_connect_fun()).
+-define(strar_mg_verify_service_change_reply_fun(),
+ strar_mg_verify_service_change_reply_fun()).
+-define(strar_mg_verify_notify_reply_fun(),
+ strar_mg_verify_notify_reply_fun()).
+-endif.
+
+strar_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName, "mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [strar_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [strar_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?strar_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?strar_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?strar_mg_verify_notify_reply_fun(),
+%% ConnectVerify = strar_mg_verify_handle_connect_fun(),
+%% ServiceChangeReplyVerify = strar_mg_verify_service_change_reply_fun(),
+%% NotifyReplyVerify = fun strar_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+strar_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ strar_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+strar_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("strar_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+strar_mg_verify_handle_connect(Else) ->
+ io:format("strar_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+strar_mg_verify_service_change_reply_fun() ->
+ fun(Rep) ->
+ strar_mg_verify_service_change_reply(Rep)
+ end.
+-endif.
+
+strar_mg_verify_service_change_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch strar_mg_do_verify_service_change_reply(AR));
+strar_mg_verify_service_change_reply(Crap) ->
+ {error, Crap, ok}.
+
+strar_mg_do_verify_service_change_reply(AR) ->
+ io:format("strar_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+strar_mg_verify_notify_reply_fun() ->
+ fun(Rep) ->
+ strar_mg_verify_notify_reply(Rep)
+ end.
+-endif.
+
+strar_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("strar_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+strar_mg_verify_notify_reply(Else) ->
+ io:format("strar_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+strar_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+strar_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_trans_req_and_reply_sendopts(suite) ->
+ [];
+single_trans_req_and_reply_sendopts(doc) ->
+ ["Receive a (single) transaction request and then send a "
+ "reply with handle_ack and a reply_timer in sendoptions. "
+ "The MGC is a megaco instance (megaco event sequence) and the "
+ "MG is emulated (tcp event sequence)"];
+single_trans_req_and_reply_sendopts(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin, linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, straro),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = straro_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = straro_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId], 30000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(straro_mgc_verify_handle_connect_fun(),
+ {?MODULE, straro_mgc_verify_handle_connect, []}).
+-define(straro_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, straro_mgc_verify_service_change_req, [Mid]}).
+-define(straro_mgc_verify_notify_req_fun(),
+ {?MODULE, straro_mgc_verify_notify_request, []}).
+-define(straro_mgc_verify_handle_trans_ack_fun(),
+ {?MODULE, straro_mgc_verify_handle_trans_ack, []}).
+-else.
+-define(straro_mgc_verify_handle_connect_fun(),
+ fun straro_mgc_verify_handle_connect/1).
+-define(straro_mgc_verify_service_change_req_fun(Mid),
+ straro_mgc_verify_service_change_req_fun(Mid)).
+-define(straro_mgc_verify_notify_req_fun(),
+ straro_mgc_verify_notify_request_fun()).
+-define(straro_mgc_verify_handle_trans_ack_fun(),
+ straro_mgc_verify_handle_trans_ack_fun()).
+-endif.
+
+straro_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?straro_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?straro_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?straro_mgc_verify_notify_req_fun(),
+ TransAckVerify = ?straro_mgc_verify_handle_trans_ack_fun(),
+%% ConnectVerify = fun straro_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = straro_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = straro_mgc_verify_notify_request_fun(),
+%% TransAckVerify = straro_mgc_verify_handle_trans_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, TransAckVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+straro_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("straro_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+straro_mgc_verify_handle_connect(Else) ->
+ io:format("straro_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+straro_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ straro_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+straro_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch straro_mgc_do_verify_service_change_req(AR, Mid));
+straro_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+straro_mgc_do_verify_service_change_req(AR, Mid) ->
+ io:format("straro_mgc_do_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [straro_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+-ifndef(megaco_hipe_special).
+straro_mgc_verify_notify_request_fun() ->
+ fun(Req) ->
+ straro_mgc_verify_notify_request(Req)
+ end.
+-endif.
+
+straro_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch straro_mgc_do_verify_notify_request(AR));
+straro_mgc_verify_notify_request(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+straro_mgc_do_verify_notify_request(AR) ->
+ io:format("straro_mgc_do_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} when (CtxID == 1) or
+ (CtxID == 2) ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ Replies = [straro_mgc_notify_reply_ar(Cid, Tid)],
+ SendOpts = [{protocol_version, 99}],
+ Reply = {{handle_ack, get(tc)}, Replies, SendOpts},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ {error, Err6, ErrReply6}
+ end.
+
+-ifndef(megaco_hipe_special).
+straro_mgc_verify_handle_trans_ack_fun() ->
+ fun(Ack) ->
+ straro_mgc_verify_handle_trans_ack(Ack)
+ end.
+-endif.
+
+straro_mgc_verify_handle_trans_ack(
+ {handle_trans_ack, _CH, ?VERSION, AS, _AD}) ->
+ (catch straro_mgc_do_verify_handle_trans_ack(AS));
+straro_mgc_verify_handle_trans_ack(Crap) ->
+ io:format("straro_mgc_verify_handle_trans_ack -> entry with"
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+straro_mgc_do_verify_handle_trans_ack({error, {EM, EF, [EC, Version, Msg], Reason}}) ->
+ io:format("straro_mgc_do_handle_verify_handle_trans_ack -> entry with"
+ "~n EM: ~p"
+ "~n EF: ~p"
+ "~n EC: ~p"
+ "~n Version: ~p"
+ "~n Msg: ~p"
+ "~n Reason: ~p"
+ "~n", [EM, EF, EC, Version, Msg, Reason]),
+ case Reason of
+ {bad_version, 99} ->
+ {ok, Reason, ok};
+ _ ->
+ {error, {unexpected_reason, Reason}, ok}
+ end;
+straro_mgc_do_verify_handle_trans_ack(Else) ->
+ io:format("straro_mgc_verify_handle_trans_ack -> unknown"
+ "~n Else: ~p"
+ "~n", [Else]),
+ {error, Else, ok}.
+
+%% straro_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+%% io:format("straro_mgc_verify_handle_disconnect -> ok"
+%% "~n CH: ~p"
+%% "~n R: ~p"
+%% "~n", [CH, R]),
+%% {ok, CH, ok};
+%% straro_mgc_verify_handle_disconnect(Else) ->
+%% io:format("straro_mgc_verify_handle_disconnect -> unknown"
+%% "~n Else: ~p~n", [Else]),
+%% {error, Else, ok}.
+
+
+straro_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+straro_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+%% straro_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+%% AR = straro_mgc_notify_reply_ar(Cid, TermId),
+%% TRes = cre_transResult([AR]),
+%% TR = cre_transReply(TransId, TRes),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(straro_mg_verify_handle_connect_fun(),
+ {?MODULE, straro_mg_verify_handle_connect, []}).
+-define(straro_mg_verify_service_change_reply_fun(),
+ {?MODULE, straro_mg_verify_service_change_reply, []}).
+-define(straro_mg_verify_handle_disconnect_fun(),
+ {?MODULE, straro_mg_verify_handle_disconnect, []}).
+-else.
+-define(straro_mg_verify_handle_connect_fun(),
+ straro_mg_verify_handle_connect_fun()).
+-define(straro_mg_verify_service_change_reply_fun(),
+ straro_mg_verify_service_change_reply_fun()).
+-define(straro_mg_verify_handle_disconnect_fun(),
+ fun straro_mg_verify_handle_disconnect/1).
+-endif.
+
+straro_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName, "mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [straro_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [straro_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?straro_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?straro_mg_verify_service_change_reply_fun(),
+ DiscoVerify = ?straro_mg_verify_handle_disconnect_fun(),
+%% ConnectVerify = straro_mg_verify_handle_connect_fun(),
+%% DiscoVerify = fun straro_mg_verify_handle_disconnect/1,
+%% ServiceChangeReplyVerify = straro_mg_verify_service_change_reply_fun(),
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+straro_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ straro_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+straro_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("straro_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+straro_mg_verify_handle_connect(Else) ->
+ io:format("straro_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straro_mg_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("straro_mg_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+straro_mg_verify_handle_disconnect(Else) ->
+ io:format("straro_mg_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+straro_mg_verify_service_change_reply_fun() ->
+ fun(Rep) ->
+ straro_mg_verify_service_change_reply(Rep)
+ end.
+-endif.
+
+straro_mg_verify_service_change_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch straro_mg_do_verify_service_change_reply(AR));
+straro_mg_verify_service_change_reply(Crap) ->
+ {error, Crap, ok}.
+
+straro_mg_do_verify_service_change_reply(AR) ->
+ io:format("straro_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+%% -ifndef(megaco_hipe_special).
+%% straro_mg_verify_notify_reply_fun() ->
+%% fun(Rep) ->
+%% straro_mg_verify_notify_reply(Rep)
+%% end.
+%% -endif.
+
+%% straro_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+%% {ok, [AR]}, _}) ->
+%% io:format("straro_mg_verify_notify_reply -> ok"
+%% "~n AR: ~p~n", [AR]),
+%% {ok, AR, ok};
+%% straro_mg_verify_notify_reply(Else) ->
+%% io:format("straro_mg_verify_notify_reply -> unknown"
+%% "~n Else: ~p~n", [Else]),
+%% {error, Else, ok}.
+
+straro_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+straro_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_and_ack(suite) ->
+ [];
+request_and_reply_and_ack(doc) ->
+ ["This test case tests that megaco correctly handles three-way-handshake"];
+request_and_reply_and_ack(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, raraa),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = raraa_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = raraa_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(raraa_mgc_verify_handle_connect_fun(),
+ {?MODULE, raraa_mgc_verify_handle_connect, []}).
+-define(raraa_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, raraa_mgc_verify_service_change_req, [Mid]}).
+-define(raraa_mgc_verify_notify_req_fun(),
+ {?MODULE, raraa_mgc_verify_notify_req, []}).
+-define(raraa_mgc_verify_handle_trans_ack_fun(),
+ {?MODULE, raraa_mgc_verify_handle_trans_ack, []}).
+-define(raraa_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, raraa_mgc_verify_handle_disconnect, []}).
+-else.
+-define(raraa_mgc_verify_handle_connect_fun(),
+ fun raraa_mgc_verify_handle_connect/1).
+-define(raraa_mgc_verify_service_change_req_fun(Mid),
+ raraa_mgc_verify_service_change_req_fun(Mid)).
+-define(raraa_mgc_verify_notify_req_fun(),
+ raraa_mgc_verify_notify_req_fun()).
+-define(raraa_mgc_verify_handle_trans_ack_fun(),
+ raraa_mgc_verify_handle_trans_ack_fun()).
+-define(raraa_mgc_verify_handle_disconnect_fun(),
+ fun raraa_mgc_verify_handle_disconnect/1).
+-endif.
+
+raraa_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?raraa_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?raraa_mgc_verify_service_change_req_fun(Mid),
+ NrVerify = ?raraa_mgc_verify_notify_req_fun(),
+ AckVerify = ?raraa_mgc_verify_handle_trans_ack_fun(),
+ DiscoVerify = ?raraa_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun raraa_mgc_verify_handle_connect/1,
+%% ScrVerify = raraa_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify = raraa_mgc_verify_notify_request_fun(),
+%% AckVerify = raraa_mgc_verify_trans_ack_fun(),
+%% DiscoVerify = fun raraa_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+raraa_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+raraa_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+raraa_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ raraa_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+raraa_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch raraa_do_verify_service_change_req(AR, Mid));
+raraa_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+raraa_do_verify_service_change_req(AR, Mid) ->
+ io:format("raraa_mgc_verify_service_change_req -> entry with"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [raraa_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+raraa_mgc_verify_notify_req_fun() ->
+ fun(Req) ->
+ raraa_mgc_verify_notify_req(Req)
+ end.
+-endif.
+
+raraa_mgc_verify_notify_req({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch raraa_mgc_do_verify_notify_req(AR));
+raraa_mgc_verify_notify_req(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+raraa_mgc_do_verify_notify_req(AR) ->
+ io:format("raraa_mgc_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = raraa,
+ Replies = [raraa_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_ack, AckData}, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+-ifndef(megaco_hipe_special).
+raraa_mgc_verify_handle_trans_ack_fun() ->
+ fun(Ack) ->
+ raraa_mgc_verify_handle_trans_ack(Ack)
+ end.
+-endif.
+
+raraa_mgc_verify_handle_trans_ack(
+ {handle_trans_ack, CH, ?VERSION, ok, raraa}) ->
+ io:format("raraa_mgc_verify_handle_trans_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+raraa_mgc_verify_handle_trans_ack(Crap) ->
+ io:format("raraa_mgc_verify_handle_trans_ack -> unknown"
+ "~n Crap: ~p~n", [Crap]),
+ {error, Crap, ok}.
+
+
+%% Disconnect verification
+raraa_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+raraa_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+raraa_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+raraa_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(raraa_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(raraa_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(raraa_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, raraa_mg_verify_service_change_rep_msg, []}).
+-define(raraa_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, raraa_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(raraa_mg_decode_msg_fun(Mod, Conf),
+ raraa_mg_decode_msg_fun(Mod, Conf)).
+-define(raraa_mg_encode_msg_fun(Mod, Conf),
+ raraa_mg_encode_msg_fun(Mod, Conf)).
+-define(raraa_mg_verify_service_change_rep_msg_fun(),
+ raraa_mg_verify_service_change_rep_msg_fun()).
+-define(raraa_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ raraa_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+raraa_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?raraa_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?raraa_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = raraa_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NotifyReq = raraa_mg_notify_request_msg(Mid, TermId,
+ TransId, ReqId, CtxId),
+ TransAck = raraa_mg_trans_ack_msg(Mid, TransId),
+ ScrVerifyFun = ?raraa_mg_verify_service_change_rep_msg_fun(),
+ NrVerifyFun = ?raraa_mg_verify_notify_rep_msg_fun(TermId,
+ TransId, ReqId, CtxId),
+%% ScrVerifyFun = raraa_mg_verify_service_change_rep_msg_fun(),
+%% NrVerifyFun = raraa_mg_verify_notify_rep_msg_fun(TermId,
+%% TransId, ReqId, CtxId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify-reply", {NrVerifyFun, 10000}},
+ {send, "transaction-ack", TransAck},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+raraa_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+raraa_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+raraa_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch raraa_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+raraa_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+raraa_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+raraa_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch raraa_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId, Rid, Cid))
+ end.
+-endif.
+
+raraa_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("raraa_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+raraa_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_message, Crap}}.
+
+raraa_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+raraa_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = raraa_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+raraa_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+raraa_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = raraa_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+raraa_mg_trans_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_and_no_ack(suite) ->
+ [];
+request_and_reply_and_no_ack(doc) ->
+ ["This test case tests that megaco handles a failed three-way-handshake,"
+ " i.e. when the ack never arrives"];
+request_and_reply_and_no_ack(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rarana),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rarana_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rarana_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(rarana_mgc_verify_handle_connect_fun(),
+ {?MODULE, rarana_mgc_verify_handle_connect, []}).
+-define(rarana_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, rarana_mgc_verify_service_change_req, [Mid]}).
+-define(rarana_mgc_verify_notify_req_fun(),
+ {?MODULE, rarana_mgc_verify_notify_req, []}).
+-define(rarana_mgc_verify_handle_trans_ack_fun(),
+ {?MODULE, rarana_mgc_verify_handle_trans_ack, []}).
+-define(rarana_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, rarana_mgc_verify_handle_disconnect, []}).
+-else.
+-define(rarana_mgc_verify_handle_connect_fun(),
+ fun rarana_mgc_verify_handle_connect/1).
+-define(rarana_mgc_verify_service_change_req_fun(Mid),
+ rarana_mgc_verify_service_change_req_fun(Mid)).
+-define(rarana_mgc_verify_notify_req_fun(),
+ rarana_mgc_verify_notify_req_fun()).
+-define(rarana_mgc_verify_handle_trans_ack_fun(),
+ rarana_mgc_verify_handle_trans_ack_fun()).
+-define(rarana_mgc_verify_handle_disconnect_fun(),
+ fun rarana_mgc_verify_handle_disconnect/1).
+-endif.
+
+rarana_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?rarana_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?rarana_mgc_verify_service_change_req_fun(Mid),
+ NrVerify = ?rarana_mgc_verify_notify_req_fun(),
+ AckVerify = ?rarana_mgc_verify_handle_trans_ack_fun(),
+ DiscoVerify = ?rarana_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun rarana_mgc_verify_handle_connect/1,
+%% ScrVerify = rarana_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify = rarana_mgc_verify_notify_request_fun(),
+%% AckVerify = rarana_mgc_verify_trans_ack_fun(),
+%% DiscoVerify = fun rarana_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ {megaco_update_user_info, reply_timer, 9000},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ %% {megaco_callback, nocall, 8000},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+rarana_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+rarana_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+rarana_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ rarana_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+rarana_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch rarana_do_verify_service_change_req(AR, Mid));
+rarana_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarana_do_verify_service_change_req(AR, Mid) ->
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [rarana_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+rarana_mgc_verify_notify_req_fun() ->
+ fun(Req) ->
+ rarana_mgc_verify_notify_req(Req)
+ end.
+-endif.
+
+rarana_mgc_verify_notify_req({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch rarana_mgc_do_verify_notify_req(AR));
+rarana_mgc_verify_notify_req(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarana_mgc_do_verify_notify_req(AR) ->
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = rarana,
+ Replies = [rarana_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_ack, AckData}, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+-ifndef(megaco_hipe_special).
+rarana_mgc_verify_handle_trans_ack_fun() ->
+ fun(Ack) ->
+ rarana_mgc_verify_handle_trans_ack(Ack)
+ end.
+-endif.
+
+rarana_mgc_verify_handle_trans_ack({handle_trans_ack, CH, ?VERSION,
+ {error, timeout}, rarana}) ->
+ io:format("rarana_mgc_verify_handle_trans_ack -> expected error: ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+rarana_mgc_verify_handle_trans_ack(Crap) ->
+ io:format("rarana_mgc_verify_trans_ack -> unknown"
+ "~n Crap: ~p~n", [Crap]),
+ {error, Crap, ok}.
+
+
+%% Disconnect verification
+rarana_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+rarana_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+rarana_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+rarana_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarana_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rarana_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rarana_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, rarana_mg_verify_service_change_rep_msg, []}).
+-define(rarana_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, rarana_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(rarana_mg_decode_msg_fun(Mod, Conf),
+ rarana_mg_decode_msg_fun(Mod, Conf)).
+-define(rarana_mg_encode_msg_fun(Mod, Conf),
+ rarana_mg_encode_msg_fun(Mod, Conf)).
+-define(rarana_mg_verify_service_change_rep_msg_fun(),
+ rarana_mg_verify_service_change_rep_msg_fun()).
+-define(rarana_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ rarana_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+rarana_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?rarana_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?rarana_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = rarana_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NotifyReq = rarana_mg_notify_request_msg(Mid, TermId,
+ TransId, ReqId, CtxId),
+ ScrVerifyFun = ?rarana_mg_verify_service_change_rep_msg_fun(),
+ NrVerifyFun = ?rarana_mg_verify_notify_rep_msg_fun(TermId,
+ TransId, ReqId, CtxId),
+%% ScrVerifyFun = rarana_mg_verify_service_change_rep_msg_fun(),
+%% NrVerifyFun = rarana_mg_verify_notify_rep_msg_fun(TermId,
+%% TransId, ReqId, CtxId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify-reply", {NrVerifyFun, 10000}},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+rarana_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarana_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarana_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch rarana_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+rarana_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+rarana_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rarana_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rarana_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId, Rid, Cid))
+ end.
+-endif.
+
+rarana_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("rarana_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+rarana_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_message, Crap}}.
+
+rarana_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarana_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = rarana_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarana_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarana_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = rarana_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_reply_and_late_ack(suite) ->
+ [];
+request_and_reply_and_late_ack(doc) ->
+ ["This test case tests that megaco handles three-way-handshake "
+ "when the ack is late (and requeire a retransmission)"];
+request_and_reply_and_late_ack(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rarala),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rarala_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rarala_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(rarala_mgc_verify_handle_connect_fun(),
+ {?MODULE, rarala_mgc_verify_handle_connect, []}).
+-define(rarala_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, rarala_mgc_verify_service_change_req, [Mid]}).
+-define(rarala_mgc_verify_notify_req_fun(),
+ {?MODULE, rarala_mgc_verify_notify_req, []}).
+-define(rarala_mgc_verify_handle_trans_ack_fun(),
+ {?MODULE, rarala_mgc_verify_handle_trans_ack, []}).
+-define(rarala_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, rarala_mgc_verify_handle_disconnect, []}).
+-else.
+-define(rarala_mgc_verify_handle_connect_fun(),
+ fun rarala_mgc_verify_handle_connect/1).
+-define(rarala_mgc_verify_service_change_req_fun(Mid),
+ rarala_mgc_verify_service_change_req_fun(Mid)).
+-define(rarala_mgc_verify_notify_req_fun(),
+ rarala_mgc_verify_notify_req_fun()).
+-define(rarala_mgc_verify_handle_trans_ack_fun(),
+ rarala_mgc_verify_handle_trans_ack_fun()).
+-define(rarala_mgc_verify_handle_disconnect_fun(),
+ fun rarala_mgc_verify_handle_disconnect/1).
+-endif.
+
+rarala_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ RepTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 2
+ },
+ ConnectVerify = ?rarala_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?rarala_mgc_verify_service_change_req_fun(Mid),
+ NrVerify = ?rarala_mgc_verify_notify_req_fun(),
+ AckVerify = ?rarala_mgc_verify_handle_trans_ack_fun(),
+ DiscoVerify = ?rarala_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun rarala_mgc_verify_handle_connect/1,
+%% ScrVerify = rarala_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify = rarala_mgc_verify_notify_request_fun(),
+%% AckVerify = rarala_mgc_verify_trans_ack_fun(),
+%% DiscoVerify = fun rarala_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ {megaco_update_user_info, reply_timer, RepTmr},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+rarala_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+rarala_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+rarala_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ rarala_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+rarala_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch rarala_do_verify_service_change_req(AR, Mid));
+rarala_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarala_do_verify_service_change_req(AR, Mid) ->
+ io:format("rarala_mgc_do_verify_service_change_req -> entry with"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [rarala_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+rarala_mgc_verify_notify_req_fun() ->
+ fun(Req) ->
+ rarala_mgc_verify_notify_req(Req)
+ end.
+-endif.
+
+rarala_mgc_verify_notify_req({handle_trans_request, _, ?VERSION, [AR]}) ->
+ (catch rarala_mgc_do_verify_notify_req(AR));
+rarala_mgc_verify_notify_req(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+rarala_mgc_do_verify_notify_req(AR) ->
+ io:format("rarala_mgc_do_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = rarala,
+ Replies = [rarala_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_ack, AckData}, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+-ifndef(megaco_hipe_special).
+rarala_mgc_verify_handle_trans_ack_fun() ->
+ fun(Ack) ->
+ rarala_mgc_verify_handle_trans_ack(Ack)
+ end.
+-endif.
+
+rarala_mgc_verify_handle_trans_ack(
+ {handle_trans_ack, CH, ?VERSION, ok, rarala}) ->
+ io:format("rarala_mgc_verify_handle_trans_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+rarala_mgc_verify_handle_trans_ack(Crap) ->
+ io:format("rarala_mgc_verify_handle_trans_ack -> unknown"
+ "~n Crap: ~p~n", [Crap]),
+ {error, Crap, ok}.
+
+
+%% Disconnect verification
+rarala_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+rarala_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+rarala_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+rarala_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rarala_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rarala_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rarala_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, rarala_mg_verify_service_change_rep_msg, []}).
+-define(rarala_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, rarala_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(rarala_mg_decode_msg_fun(Mod, Conf),
+ rarala_mg_decode_msg_fun(Mod, Conf)).
+-define(rarala_mg_encode_msg_fun(Mod, Conf),
+ rarala_mg_encode_msg_fun(Mod, Conf)).
+-define(rarala_mg_verify_service_change_rep_msg_fun(),
+ rarala_mg_verify_service_change_rep_msg_fun()).
+-define(rarala_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ rarala_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+rarala_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?rarala_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?rarala_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = rarala_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NotifyReq = rarala_mg_notify_request_msg(Mid, TermId,
+ TransId, ReqId, CtxId),
+ TransAck = rarala_mg_trans_ack_msg(Mid, TransId),
+ ScrVerifyFun = ?rarala_mg_verify_service_change_rep_msg_fun(),
+ NrVerifyFun = ?rarala_mg_verify_notify_rep_msg_fun(TermId,
+ TransId, ReqId, CtxId),
+%% ScrVerifyFun = rarala_mg_verify_service_change_rep_msg_fun(),
+%% NrVerifyFun = rarala_mg_verify_notify_rep_msg_fun(TermId,
+%% TransId, ReqId, CtxId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify-reply", {NrVerifyFun, 4000}},
+ {expect_receive, "notify-reply", {NrVerifyFun, 4000}},
+ {expect_receive, "notify-reply", {NrVerifyFun, 4000}},
+ {send, "transaction-ack", TransAck},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+rarala_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarala_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rarala_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch rarala_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+rarala_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+rarala_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rarala_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rarala_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId, Rid, Cid))
+ end.
+-endif.
+
+rarala_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("rarala_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+rarala_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_message, Crap}}.
+
+rarala_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarala_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = rarala_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarala_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rarala_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = rarala_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rarala_mg_trans_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+trans_req_and_reply_and_req(suite) ->
+ [];
+trans_req_and_reply_and_req(doc) ->
+ ["Receive a transaction request, send a reply (discard ack)"
+ "then receive the same reply again after the timeout. "
+ "The MGC is a megaco instance (megaco event sequence) and the "
+ "MG is emulated (tcp event sequence)"];
+trans_req_and_reply_and_req(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin, linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, trarar),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = trarar_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = trarar_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId], 60000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(trarar_mgc_verify_handle_connect_fun(),
+ {?MODULE, trarar_mgc_verify_handle_connect, []}).
+-define(trarar_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, trarar_mgc_verify_service_change_req, [Mid]}).
+-define(trarar_mgc_verify_notify_req_fun(Cid),
+ {?MODULE, trarar_mgc_verify_notify_req, [Cid]}).
+-define(trarar_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, trarar_mgc_verify_handle_disconnect, []}).
+-else.
+-define(trarar_mgc_verify_handle_connect_fun(),
+ fun trarar_mgc_verify_handle_connect/1).
+-define(trarar_mgc_verify_service_change_req_fun(Mid),
+ trarar_mgc_verify_service_change_req_fun(Mid)).
+-define(trarar_mgc_verify_notify_req_fun(Cid),
+ trarar_mgc_verify_notify_req_fun(Cid)).
+-define(trarar_mgc_verify_handle_disconnect_fun(),
+ fun trarar_mgc_verify_handle_disconnect/1).
+-endif.
+
+trarar_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+%% Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+%% ReqTmr = #megaco_incr_timer{wait_for = 500,
+%% factor = 1,
+%% max_retries = 1},
+ ConnectVerify = ?trarar_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?trarar_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify1 = ?trarar_mgc_verify_notify_req_fun(1),
+ NotifyReqVerify2 = ?trarar_mgc_verify_notify_req_fun(2),
+ NotifyReqVerify3 = ?trarar_mgc_verify_notify_req_fun(3),
+ NotifyReqVerify4 = ?trarar_mgc_verify_notify_req_fun(4),
+ DiscoVerify = ?trarar_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun trarar_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = trarar_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify1 = trarar_mgc_verify_notify_request_fun(1),
+%% NotifyReqVerify2 = trarar_mgc_verify_notify_request_fun(2),
+%% NotifyReqVerify3 = trarar_mgc_verify_notify_request_fun(3),
+%% NotifyReqVerify4 = trarar_mgc_verify_notify_request_fun(4),
+%% DiscoVerify = fun trarar_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, reply_timer, 2000},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify1},
+ {megaco_callback, handle_trans_request, NotifyReqVerify2},
+ {megaco_update_conn_info, reply_timer, 4000},
+ {megaco_callback, handle_trans_request, NotifyReqVerify3},
+ {megaco_callback, handle_trans_request, NotifyReqVerify4},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+trarar_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("trarar_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+trarar_mgc_verify_handle_connect(Else) ->
+ io:format("trarar_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+trarar_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ trarar_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+trarar_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch trarar_mgc_do_verify_service_change_req(AR, Mid));
+trarar_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+trarar_mgc_do_verify_service_change_req(AR, Mid) ->
+ io:format("trarar_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [trarar_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+-ifndef(megaco_hipe_special).
+trarar_mgc_verify_notify_req_fun(Cid) ->
+ fun(Req) ->
+ trarar_mgc_verify_notify_req(Req, Cid)
+ end.
+-endif.
+
+trarar_mgc_verify_notify_req({handle_trans_request, _, ?VERSION, [AR]}, Cid) ->
+ (catch trarar_mgc_do_verify_notify_req(AR, Cid));
+trarar_mgc_verify_notify_req(Crap, _Cid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+trarar_mgc_do_verify_notify_req(AR, Cid) ->
+ io:format("trarar_mgc_do_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n Cid: ~p"
+ "~n", [AR, Cid]),
+ {ContextID, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} when (CtxID == Cid) ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ Replies = [trarar_mgc_notify_reply_ar(ContextID, Tid)],
+ Reply = {discard_ack, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ {error, Err6, ErrReply6}
+ end.
+
+trarar_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("trarar_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+trarar_mgc_verify_handle_disconnect(Else) ->
+ io:format("trarar_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+trarar_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+trarar_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+%% trarar_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+%% AR = trarar_mgc_notify_reply_ar(Cid, TermId),
+%% TRes = cre_transResult([AR]),
+%% TR = cre_transReply(TransId, TRes),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(trarar_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(trarar_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(trarar_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, trarar_mg_verify_service_change_rep_msg, []}).
+-define(trarar_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, trarar_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(trarar_mg_decode_msg_fun(Mod, Conf),
+ trarar_mg_decode_msg_fun(Mod, Conf)).
+-define(trarar_mg_encode_msg_fun(Mod, Conf),
+ trarar_mg_encode_msg_fun(Mod, Conf)).
+-define(trarar_mg_verify_service_change_rep_msg_fun(),
+ trarar_mg_verify_service_change_rep_msg_fun()).
+-define(trarar_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ trarar_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+trarar_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?trarar_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?trarar_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = trarar_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq1 =
+ trarar_mg_notify_request_msg(Mid, TermId, 2, 1, 1),
+ NotifyReq2 =
+ trarar_mg_notify_request_msg(Mid, TermId, 2, 2, 2),
+ NotifyReq3 =
+ trarar_mg_notify_request_msg(Mid, TermId, 2, 3, 3),
+ NotifyReq4 =
+ trarar_mg_notify_request_msg(Mid, TermId, 2, 4, 4),
+ ScrVerifyFun = ?trarar_mg_verify_service_change_rep_msg_fun(),
+ NrVerifyFun1 =
+ ?trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 1, 1),
+ NrVerifyFun2 =
+ ?trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 2, 2),
+ NrVerifyFun3 =
+ ?trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 3, 3),
+ NrVerifyFun4 =
+ ?trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 4, 4),
+%% ScrVerifyFun = trarar_mg_verify_service_change_rep_msg_fun(),
+%% NrVerifyFun1 =
+%% trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 1, 1),
+%% NrVerifyFun2 =
+%% trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 2, 2),
+%% NrVerifyFun3 =
+%% trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 3, 3),
+%% NrVerifyFun4 =
+%% trarar_mg_verify_notify_rep_msg_fun(TermId, 2, 4, 4),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+
+ %% the original setting for reply timer is 2000
+ {send, "notify request 1", NotifyReq1},
+ {expect_receive, "notify-reply 1", {NrVerifyFun1, 2500}},
+ {sleep, 1000},
+ {send, "notify request 2", NotifyReq2},
+ {expect_receive, "notify-reply 2 (resend of 1)", {NrVerifyFun1, 2500}},
+ {sleep, 3000}, % reply timer is set to 2000
+ {send, "notify request 3 (same as 2)", NotifyReq2},
+ {expect_receive, "notify-reply 3", {NrVerifyFun2, 2500}},
+
+ %% reply timer is now set to 4000 but previous was 2000
+ %% so, 3000 is enough to let the timer running with the
+ %% previous settings (2000) to time out
+ {sleep, 3000},
+ {send, "notify request 4", NotifyReq3},
+ {expect_receive, "notify-reply 4", {NrVerifyFun3, 4500}},
+ {sleep, 5000},
+ {send, "notify request 5", NotifyReq4},
+ {expect_receive, "notify-reply 5", {NrVerifyFun4, 4500}},
+
+ {expect_nothing, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+trarar_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+trarar_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+trarar_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch trarar_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+trarar_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+trarar_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+trarar_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch trarar_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId, Rid, Cid))
+ end.
+-endif.
+
+trarar_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("trarar_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ io:format("trarar_mg_verify_notify_rep_msg -> "
+ "~n Body: ~p"
+ "~n", [Body]),
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ io:format("trarar_mg_verify_notify_rep_msg -> "
+ "~n Trans: ~p"
+ "~n", [Trans]),
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ io:format("trarar_mg_verify_notify_rep_msg -> "
+ "~n TR: ~p"
+ "~n", [TR]),
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ io:format("trarar_mg_verify_notify_rep_msg -> "
+ "~n TRes: ~p"
+ "~n", [TRes]),
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ io:format("trarar_mg_verify_notify_rep_msg -> "
+ "~n AR: ~p"
+ "~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+trarar_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_message, Crap}}.
+
+trarar_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+trarar_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = trarar_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+trarar_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+trarar_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = trarar_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+%% trarar_mg_trans_ack_msg(Mid, TransId) ->
+%% TR = cre_transRespAck(cre_transAck(TransId)),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pending_ack_plain(suite) ->
+ [];
+pending_ack_plain(doc) ->
+ ["Receive a request and handle it as a long request, "
+ "i.e. return with {pending, _} and expect a call to the "
+ "long request function"];
+pending_ack_plain(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, pap),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = pap_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = pap_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(pap_mgc_verify_handle_connect_fun(),
+ {?MODULE, pap_mgc_verify_handle_connect, []}).
+-define(pap_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, pap_mgc_verify_service_change_req, [Mid]}).
+-define(pap_mgc_verify_notify_req_fun(),
+ {?MODULE, pap_mgc_verify_notify_req, []}).
+-define(pap_mgc_verify_notify_req_long_fun(),
+ {?MODULE, pap_mgc_verify_notify_req_long, []}).
+-define(pap_mgc_verify_handle_trans_ack_fun(),
+ {?MODULE, pap_mgc_verify_handle_trans_ack, []}).
+-define(pap_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, pap_mgc_verify_handle_disconnect, []}).
+-else.
+-define(pap_mgc_verify_handle_connect_fun(),
+ fun pap_mgc_verify_handle_connect/1).
+-define(pap_mgc_verify_service_change_req_fun(Mid),
+ pap_mgc_verify_service_change_req_fun(Mid)).
+-define(pap_mgc_verify_notify_req_fun(),
+ pap_mgc_verify_notify_req_fun()).
+-define(pap_mgc_verify_notify_req_long_fun(),
+ pap_mgc_verify_notify_req_long_fun()).
+-define(pap_mgc_verify_handle_trans_ack_fun(),
+ pap_mgc_verify_handle_trans_ack_fun()).
+-define(pap_mgc_verify_handle_disconnect_fun(),
+ fun pap_mgc_verify_handle_disconnect/1).
+-endif.
+
+pap_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?pap_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?pap_mgc_verify_service_change_req_fun(Mid),
+ NrVerify1 = ?pap_mgc_verify_notify_req_fun(),
+ NrVerify2 = ?pap_mgc_verify_notify_req_long_fun(),
+ AckVerify = ?pap_mgc_verify_handle_trans_ack_fun(),
+ DiscoVerify = ?pap_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun pap_mgc_verify_handle_connect/1,
+%% ScrVerify = pap_mgc_verify_service_change_req_fun(Mid),
+%% NrVerify1 = pap_mgc_verify_notify_request_fun(),
+%% NrVerify2 = pap_mgc_verify_notify_request_long_fun(),
+%% AckVerify = pap_mgc_verify_trans_ack_fun(),
+%% DiscoVerify = fun pap_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 100},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {megaco_callback, handle_trans_request, NrVerify1},
+ {megaco_callback, handle_trans_long_request, NrVerify2},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+%% Connect verification
+pap_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+pap_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+%% Service Change verification
+-ifndef(megaco_hipe_special).
+pap_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ pap_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+pap_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ (catch pap_do_verify_service_change_req(AR, Mid));
+pap_mgc_verify_service_change_req(Crap, _Mid) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+pap_do_verify_service_change_req(AR, Mid) ->
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [pap_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+pap_mgc_verify_notify_req_fun() ->
+ fun(Req) ->
+ pap_mgc_verify_notify_req(Req)
+ end.
+-endif.
+
+pap_mgc_verify_notify_req({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("pap_mgc_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ Reply = {pending, AR},
+ {ok, AR, Reply};
+pap_mgc_verify_notify_req(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+%% Notify Request verification
+-ifndef(megaco_hipe_special).
+pap_mgc_verify_notify_req_long_fun() ->
+ fun(Req) ->
+ pap_mgc_verify_notify_req_long(Req)
+ end.
+-endif.
+
+pap_mgc_verify_notify_req_long(
+ {handle_trans_long_request, _, ?VERSION, AR}) ->
+ (catch pap_mgc_do_verify_notify_req_long(AR));
+pap_mgc_verify_notify_req_long(Crap) ->
+ ED = cre_ErrDesc(Crap),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+pap_mgc_do_verify_notify_req_long(AR) ->
+ io:format("pap_mgc_do_verify_notify_req_long -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ AckData = pap,
+ Replies = [pap_mgc_notify_reply_ar(Cid, Tid)],
+ Reply = {{handle_ack, AckData}, Replies},
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ throw({error, Err6, ErrReply6})
+ end.
+
+
+-ifndef(megaco_hipe_special).
+pap_mgc_verify_handle_trans_ack_fun() ->
+ fun(Ack) ->
+ pap_mgc_verify_handle_trans_ack(Ack)
+ end.
+-endif.
+
+pap_mgc_verify_handle_trans_ack({handle_trans_ack, CH, ?VERSION, ok, pap}) ->
+ io:format("pap_mgc_verify_handle_trans_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+pap_mgc_verify_handle_trans_ack(Crap) ->
+ io:format("pap_mgc_verify_handle_trans_ack -> unknown"
+ "~n Crap: ~p~n", [Crap]),
+ {error, Crap, ok}.
+
+
+%% Disconnect verification
+pap_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ {ok, CH, ok};
+pap_mgc_verify_handle_disconnect(Else) ->
+ {error, Else, ok}.
+
+pap_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+pap_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(pap_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(pap_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(pap_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, pap_mg_verify_service_change_rep_msg, []}).
+-define(pap_mg_verify_pending_msg_fun(TransId),
+ {?MODULE, pap_mg_verify_pending_msg, [TransId]}).
+-define(pap_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, pap_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(pap_mg_decode_msg_fun(Mod, Conf),
+ pap_mg_decode_msg_fun(Mod, Conf)).
+-define(pap_mg_encode_msg_fun(Mod, Conf),
+ pap_mg_encode_msg_fun(Mod, Conf)).
+-define(pap_mg_verify_service_change_rep_msg_fun(),
+ pap_mg_verify_service_change_rep_msg_fun()).
+-define(pap_mg_verify_pending_msg_fun(TransId),
+ pap_mg_verify_pending_msg_fun(TransId)).
+-define(pap_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ pap_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+pap_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?pap_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?pap_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = pap_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NotifyReq =
+ pap_mg_notify_request_msg(Mid, TermId, TransId, ReqId, CtxId),
+ TransAck = pap_mg_trans_ack_msg(Mid, TransId),
+ ScrVerifyFun = ?pap_mg_verify_service_change_rep_msg_fun(),
+ PendingVerifyFun =
+ ?pap_mg_verify_pending_msg_fun(TransId),
+ NrVerifyFun =
+ ?pap_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+%% ScrVerifyFun = pap_mg_verify_service_change_rep_msg_fun(),
+%% PendingVerifyFun =
+%% pap_mg_verify_pending_msg_fun(TransId),
+%% NrVerifyFun =
+%% pap_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "pending", {PendingVerifyFun, 4000}},
+ {expect_receive, "notify-reply", {NrVerifyFun, 4000}},
+ {send, "transaction-ack", TransAck},
+ {expect_nothing, 11000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+pap_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+pap_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+pap_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch pap_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+pap_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+pap_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+pap_mg_verify_pending_msg_fun(TransId) ->
+ fun(Msg) ->
+ (catch pap_mg_verify_pending_msg(Msg, TransId))
+ end.
+-endif.
+
+pap_mg_verify_pending_msg(#'MegacoMessage'{mess = Mess} = M, TransId) ->
+ io:format("pap_mg_verify_pending_msg -> entry with"
+ "~n M: ~p"
+ "~n TransId: ~p"
+ "~n", [M, TransId]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TP =
+ case Trans of
+ {transactionPending, TransPending} ->
+ TransPending;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case TP of
+ #'TransactionPending'{transactionId = TransId} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_transactionPending, TP}}
+ end;
+pap_mg_verify_pending_msg(Crap, _TransId) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+pap_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch pap_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId, Rid, Cid))
+ end.
+-endif.
+
+pap_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("pap_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+pap_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_message, Crap}}.
+
+pap_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+pap_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = pap_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+pap_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+pap_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = pap_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+pap_mg_trans_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+request_and_pending_and_late_reply(suite) ->
+ [];
+request_and_pending_and_late_reply(doc) ->
+ ["Receive a request and handle it as a long request, "
+ "i.e. return with {pending, _}. Then, expect the sender "
+ "to keep re-sending the request until the reply is sent."];
+request_and_pending_and_late_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rapalr),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rapalr_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rapalr_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(rapalr_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rapalr_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rapalr_mgc_verify_service_change_req_msg_fun(),
+ {?MODULE, rapalr_mgc_verify_service_change_req_msg, []}).
+-define(rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, rapalr_mgc_verify_notify_req_msg, [TermId, TransId, ReqId, CtxId]}).
+-define(rapalr_mgc_verify_trans_ack_msg_fun(TransId),
+ {?MODULE, rapalr_mgc_verify_trans_ack_msg, [TransId]}).
+-else.
+-define(rapalr_mgc_decode_msg_fun(Mod, Conf),
+ rapalr_mgc_decode_msg_fun(Mod, Conf)).
+-define(rapalr_mgc_encode_msg_fun(Mod, Conf),
+ rapalr_mgc_encode_msg_fun(Mod, Conf)).
+-define(rapalr_mgc_verify_service_change_req_msg_fun(),
+ rapalr_mgc_verify_service_change_req_msg_fun()).
+-define(rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId)).
+-define(rapalr_mgc_verify_trans_ack_msg_fun(TransId),
+ rapalr_mgc_verify_trans_ack_msg_fun(TransId)).
+-endif.
+
+rapalr_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ?rapalr_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?rapalr_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ServiceChangeRep = rapalr_mgc_service_change_reply_msg(Mid, 1),
+ TermId =
+ #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ Pending = rapalr_mgc_trans_pending_msg(Mid, TransId),
+ NotifyRep = rapalr_mgc_notify_reply_msg(Mid, TransId,
+ CtxId, TermId),
+ ScrVerifyFun = ?rapalr_mgc_verify_service_change_req_msg_fun(),
+ NrVerifyFun =
+ ?rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ AckVerifyFun = ?rapalr_mgc_verify_trans_ack_msg_fun(TransId),
+%% ScrVerifyFun = rapalr_mgc_verify_service_change_req_msg_fun(),
+%% NrVerifyFun =
+%% rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+%% AckVerifyFun = rapalr_mgc_verify_trans_ack_msg_fun(TransId),
+ EvSeq = [{debug, false},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_receive, "notify-request(1)", {NrVerifyFun, 4000}},
+ {send, "pending", Pending},
+ {expect_receive, "notify-request(2)", {NrVerifyFun, 4000}},
+ {expect_receive, "notify-request(3)", {NrVerifyFun, 4000}},
+ {send, "notify reply", NotifyRep},
+ {expect_receive, "ack", {AckVerifyFun, 4000}},
+ {sleep, 1000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+rapalr_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rapalr_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+rapalr_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch rapalr_mgc_verify_service_change_req_msg(Msg))
+ end.
+-endif.
+
+rapalr_mgc_verify_service_change_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+-ifndef(megaco_hipe_special).
+rapalr_mgc_verify_notify_req_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rapalr_mgc_verify_notify_req_msg(Msg,
+ TermId,
+ TransId, Rid, Cid))
+ end.
+-endif.
+
+rapalr_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("rapalr_mgc_verify_notify_req_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequests, CR}})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+rapalr_mgc_verify_notify_req_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+-ifndef(megaco_hipe_special).
+rapalr_mgc_verify_trans_ack_msg_fun(TransId) ->
+ fun(Msg) ->
+ (catch rapalr_mgc_verify_trans_ack_msg(Msg, TransId))
+ end.
+-endif.
+
+rapalr_mgc_verify_trans_ack_msg(#'MegacoMessage'{mess = Mess} = M,
+ TransId) ->
+ io:format("rapalr_mgc_verify_trans_ack_msg -> entry with"
+ "~n M: ~p"
+ "~n TransId: ~p"
+ "~n", [M, TransId]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TA =
+ case Trans of
+ {transactionResponseAck, [TransAck]} ->
+ TransAck;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case TA of
+ #'TransactionAck'{firstAck = TransId,
+ lastAck = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_transactionResponseAck, TA}})
+ end;
+rapalr_mgc_verify_trans_ack_msg(Crap, _TransId) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rapalr_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(1, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rapalr_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+rapalr_mgc_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ AR = rapalr_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, 'NULL', TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rapalr_mgc_trans_pending_msg(Mid, TransId) ->
+ TP = #'TransactionPending'{transactionId = TransId},
+ Body = {transactions, [{transactionPending, TP}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rapalr_mg_verify_handle_connect_fun(),
+ {?MODULE, rapalr_mg_verify_handle_connect, []}).
+-define(rapalr_mg_verify_service_change_rep_fun(),
+ {?MODULE, rapalr_mg_verify_service_change_rep, []}).
+-define(rapalr_mg_verify_notify_rep_fun(),
+ {?MODULE, rapalr_mg_verify_notify_rep, []}).
+-else.
+-define(rapalr_mg_verify_handle_connect_fun(),
+ rapalr_mg_verify_handle_connect_fun()).
+-define(rapalr_mg_verify_service_change_rep_fun(),
+ rapalr_mg_verify_service_change_rep_fun()).
+-define(rapalr_mg_verify_notify_rep_fun(),
+ rapalr_mg_verify_notify_rep_fun()).
+-endif.
+
+rapalr_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ LReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 2
+ },
+ ServiceChangeReq = rapalr_mg_service_change_request_ar(Mid, 1),
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = rapalr_mg_notify_request_ar(1, Tid, 1),
+ ConnectVerify = ?rapalr_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?rapalr_mg_verify_service_change_rep_fun(),
+ NotifyReplyVerify = ?rapalr_mg_verify_notify_rep_fun(),
+%% ConnectVerify = rapalr_mg_verify_handle_connect_fun(),
+%% ServiceChangeReplyVerify = rapalr_mg_verify_service_change_reply_fun(),
+%% NotifyReplyVerify = rapalr_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {megaco_update_user_info, long_request_resend, true},
+ {megaco_update_user_info, long_request_timer, LReqTmr},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+rapalr_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ rapalr_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+rapalr_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("rapalr_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rapalr_mg_verify_handle_connect(Else) ->
+ io:format("rapalr_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+rapalr_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ rapalr_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+rapalr_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch rapalr_mg_do_verify_service_change_rep(AR));
+rapalr_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+rapalr_mg_do_verify_service_change_rep(AR) ->
+ io:format("rapalr_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+rapalr_mg_verify_notify_rep_fun() ->
+ fun(Rep) ->
+ rapalr_mg_verify_notify_rep(Rep)
+ end.
+-endif.
+
+rapalr_mg_verify_notify_rep({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("rapalr_mg_verify_notify_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+rapalr_mg_verify_notify_rep(Else) ->
+ io:format("rapalr_mg_verify_notify_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+rapalr_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rapalr_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+dist(suite) ->
+ [];
+dist(Config) when is_list(Config) ->
+ [_Local, Dist] = ?ACQUIRE_NODES(2, Config),
+ d("dist -> start proxy",[]),
+ megaco_mess_user_test:start_proxy(),
+
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+ MgcMid = ipv4_mid(),
+ UserMod = megaco_mess_user_test,
+ d("dist -> start megaco app",[]),
+ ?VERIFY(ok, application:start(megaco)),
+ UserConfig = [{user_mod, UserMod}, {send_mod, UserMod},
+ {request_timer, infinity}, {reply_timer, infinity}],
+
+ d("dist -> start megaco user MG (~p)",[MgMid]),
+ ?VERIFY(ok, megaco:start_user(MgMid, UserConfig)),
+
+ d("dist -> start megaco user MGC (~p)",[MgcMid]),
+ ?VERIFY(ok, megaco:start_user(MgcMid, UserConfig)),
+
+ d("dist -> retrieve (user info) receive_handle for MG",[]),
+ MgRH = user_info(MgMid, receive_handle),
+
+ d("dist -> retrieve (user info) receive_handle for MGC",[]),
+ MgcRH = user_info(MgcMid, receive_handle),
+
+ d("dist -> start transport",[]),
+ {ok, MgPid, MgSH} =
+ ?VERIFY({ok, _, _}, UserMod:start_transport(MgRH, MgcRH)),
+ PrelMgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = preliminary_mid},
+ MgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = MgcMid},
+ MgcCH = #megaco_conn_handle{local_mid = MgcMid,
+ remote_mid = MgMid},
+
+ d("dist -> (MG) connect",[]),
+ ?SEND(megaco:connect(MgRH, PrelMid, MgSH, MgPid)), % Mg prel
+
+ d("dist -> (MG) await connect",[]),
+ ?USER({connect, PrelMgCH, _V, []}, ok),
+ ?RECEIVE([{res, _, {ok, PrelMgCH}}]),
+
+ d("dist -> (MG) send service change request",[]),
+ Req = service_change_request(),
+ ?SEND(megaco:call(PrelMgCH, [Req], [])),
+
+ d("dist -> (MGC) await auto-connect",[]),
+ ?USER({connect, MgcCH, _V, []}, ok), % Mgc auto
+
+
+ Rep = service_change_reply(MgcMid),
+ d("dist -> (MGC) "
+ "await service change request and send reply when received",[]),
+ ?USER({request, MgcCH, _V, [[Req]]}, {discard_ack, [Rep]}),
+
+ d("dist -> (MG) await connect",[]),
+ ?USER({connect, MgCH, _V, []}, ok), % Mg confirm
+
+ d("dist -> (MG) await service change reply",[]),
+ ?RECEIVE([{res, _, {1, {ok, [Rep]}}}]),
+
+ %% Dist
+ d("dist -> start megaco on ~p", [Dist]),
+ ?VERIFY(ok, rpc:call(Dist, megaco, start, [])),
+
+ d("dist -> start megaco user on ~p", [Dist]),
+ ?VERIFY(ok, rpc:call(Dist, megaco, start_user, [MgcMid, UserConfig])),
+
+ d("dist -> (MG) connect to MGC", []),
+ MgcPid = self(),
+ MgcSH = {element(2, MgSH), element(1, MgSH)},
+ ?SEND(rpc:call(Dist, megaco, connect, [MgcRH, MgMid, MgcSH, MgcPid])), % Mgc dist
+
+ d("dist -> (MGC) await auto-connect (from MG on ~p)", [Dist]),
+ ?USER({connect, MgcCH, _V, []}, ok), % Mgc dist auto
+ ?RECEIVE([{res, _, {ok, MgcCH}}]),
+
+ d("dist -> (~p:MG) send service change request",[Dist]),
+ ?SEND(rpc:call(Dist, megaco, call, [MgcCH, [Req], []])),
+
+ d("dist -> (MG????????) "
+ "await service change request and send reply when received",[]),
+ ?USER({request, MgCH, _V, [[Req]]}, {discard_ack, [Rep]}),
+ ?RECEIVE([{res, _, {1, {ok, [Rep]}}}]),
+
+ d("dist -> retreive some info",[]),
+ connections([MgCH, MgcCH]),
+ ?VERIFY([MgCH], megaco:user_info(MgMid, connections)),
+ ?VERIFY([MgcCH], megaco:user_info(MgcMid, connections)),
+
+ ?VERIFY([MgcCH], rpc:call(Dist, megaco, system_info, [connections])),
+ ?VERIFY([], rpc:call(Dist, megaco, user_info, [MgMid, connections])),
+ ?VERIFY([MgcCH], rpc:call(Dist, megaco, user_info, [MgcMid, connections])),
+
+ %% Shutdown
+
+ d("dist -> close down the shop...",[]),
+ Reason = shutdown,
+ ?SEND(megaco:disconnect(MgCH, Reason)),
+ ?USER({disconnect, MgCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+
+ ?SEND(megaco:disconnect(MgcCH, Reason)),
+ ?USER({disconnect, MgcCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?USER({disconnect, MgcCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgcMid)),
+
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+ d("dist -> done",[]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_4359(suite) ->
+ [];
+otp_4359(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Mid = {deviceName, "dummy_mid"},
+
+ io:format("otp_4359 -> start megaco application~n", []),
+ ?VERIFY(ok, application:start(megaco)),
+
+ %% megaco:enable_trace(max, io),
+ io:format("otp_4359 -> start and configure megaco user~n", []),
+ ?VERIFY(ok, megaco:start_user(Mid, [{send_mod, ?MODULE},
+ {request_timer, infinity},
+ {reply_timer, infinity}])),
+
+ io:format("otp_4359 -> update user info: user_mod -> ~p~n", [?MODULE]),
+ ?VERIFY(ok, megaco:update_user_info(Mid, user_mod, ?MODULE)),
+ io:format("otp_4359 -> update user info: user_args -> ~p~n", [self()]),
+ ?VERIFY(ok, megaco:update_user_info(Mid, user_args, [self()])),
+ io:format("otp_4359 -> retreive receive_handle~n", []),
+ RH0 = user_info(Mid, receive_handle),
+ io:format("otp_4359 -> RH0: ~p~n", [RH0]),
+ RH1 = RH0#megaco_receive_handle{send_mod = ?MODULE,
+ encoding_mod = megaco_compact_text_encoder,
+ encoding_config = []},
+
+ %% First an erroneous transaction (missing the transaction id number)
+ %% then an valid transaction.
+ M = "!/1 ml2 "
+ "T={C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}"
+ "T=1{C=${A=${M{O {MO=SR,RG=OFF,RV=OFF}}}}}",
+
+ %% Simulate incomming message
+ %% Will result in an (auto) connect first
+ io:format("otp_4359 -> simulate receive message~n", []),
+ megaco:receive_message(RH1, self(), self(), list_to_binary(M)),
+ io:format("otp_4359 -> await actions~n", []),
+ Actions = otp_4359_await_actions([{handle_connect, ignore},
+ {send_message, ?megaco_bad_request},
+ {handle_trans_request, ignore},
+ {send_message, ?megaco_not_implemented}]),
+ io:format("otp_4359 -> analyze actions~n", []),
+ otp_4359_analyze_result(RH1, Actions),
+
+ Conns = megaco:system_info(connections),
+ io:format("otp_4359 -> connections~n~p~n", [Conns]),
+ OKs = lists:duplicate(length(Conns),ok),
+ io:format("otp_4359 -> verify (all) connection disconnect~n", []),
+ ?VERIFY(OKs, [megaco:disconnect(CH, test_complete) || CH <- Conns]),
+ io:format("otp_4359 -> stop user (~p)~n", [Mid]),
+ stop_user(Mid),
+ io:format("otp_4359 -> stop megaco application~n", []),
+ ?VERIFY(ok, application:stop(megaco)),
+ io:format("otp_4359 -> make sure we have nothing in the message queue~n", []),
+ ?RECEIVE([]),
+ io:format("otp_4359 -> done~n", []),
+ ok.
+
+
+otp_4359_await_actions(Exp) ->
+ otp_4359_await_actions(Exp, []).
+
+otp_4359_await_actions([], Rep) ->
+ lists:reverse(Rep);
+otp_4359_await_actions([{M,I}|R] = _All, Rep) ->
+ receive
+ {M, Info} ->
+ io:format("otp_4359 -> received expected event [~w]~n", [M]),
+ otp_4359_await_actions(R, [{M, I, Info}|Rep])
+%% Else ->
+%% exit({received_unexpected_message, M, Else})
+%% %% io:format("received unexpected: ~p~n", [Else]),
+%% %% otp_4359_await_actions(All, Rep)
+ after 10000 ->
+ exit({timeout,megaco_test_lib:flush()} )
+ end.
+
+otp_4359_analyze_result(_RH, []) ->
+ ok;
+otp_4359_analyze_result(RH,
+ [{send_message, ExpErrorCode, EncodedMessage}|L]) ->
+ io:format("otp_4359_analyze_result -> send_message: ", []),
+ otp_4359_analyze_encoded_message(RH, ExpErrorCode, EncodedMessage),
+ otp_4359_analyze_result(RH,L);
+otp_4359_analyze_result(RH, [{M,ignore,_}|T]) ->
+ io:format("otp_4359_analyze_result -> ignoring ~p~n", [M]),
+ otp_4359_analyze_result(RH,T).
+
+otp_4359_analyze_encoded_message(RH, ExpErrorCode, M)
+ when is_record(RH, megaco_receive_handle) andalso is_binary(M) ->
+ #megaco_receive_handle{encoding_mod = Mod,
+ encoding_config = Conf} = RH,
+ case (catch Mod:decode_message(Conf, M)) of
+ {ok, #'MegacoMessage'{mess = #'Message'{messageBody = Body}}} ->
+ case Body of
+ {transactions, [{transactionReply,Reply}]} ->
+ case Reply of
+ #'TransactionReply'{transactionResult = Result} ->
+ case Result of
+ {transactionError,ED} when is_record(ED, 'ErrorDescriptor') ->
+ case ED#'ErrorDescriptor'.errorCode of
+ ExpErrorCode ->
+ io:format("error code ~p ok~n", [ExpErrorCode]),
+ ok;
+ Code ->
+ io:format("error code ~p erroneous~n", [Code]),
+ exit({unexpected_error_code, ExpErrorCode, Code})
+ end;
+ _ ->
+ io:format("unexpected trans result~n", []),
+ exit({unexpected_trans_result, Result})
+ end;
+ _ ->
+ io:format("unexpected trans reply~n", []),
+ exit({unexpected_trans_reply, Reply})
+ end;
+ _ ->
+ io:format("unexpected body~n", []),
+ exit({unexpected_body, Body})
+ end;
+
+ Else ->
+ io:format("unexpected decode result~n", []),
+ exit({unexpected_decode_result, Else})
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_4836(suite) ->
+ [];
+otp_4836(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_4836),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("start the MGC simulator (generator)"),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("create the MGC event sequence"),
+ MgcEvSeq = otp_4836_mgc_event_sequence(text, tcp),
+
+ d("start the MGC simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ ReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ %% 5000, %% Does not matter since we will not use this anyway...
+ LongReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ PendingTmr = 10000,
+ ReplyTmr = 16000,
+ MgConfig = [{request_timer, ReqTmr},
+ {long_request_timer, LongReqTmr},
+ {pending_timer, PendingTmr},
+ {reply_timer, ReplyTmr}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("[MG] send the notify"),
+ {ok, Reply} = (catch ?MG_NOTIF_RAR(Mg)),
+ {1, {ok, [AR]}} = Reply,
+ d("[MG] ActionReply: ~p", [AR]),
+
+ d("await the generator reply"),
+ await_completion([MgcId]),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ i("done", []),
+ ok.
+
+
+-ifdef(megaco_hipe_special).
+-define(otp_4836_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_4836_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_4836_mgc_verify_service_change_req_msg_fun(),
+ {?MODULE, otp_4836_mgc_verify_service_change_req_msg, []}).
+-define(otp_4836_mgc_verify_notify_req_msg_fun(),
+ {?MODULE, otp_4836_mgc_verify_notify_req_msg, []}).
+-else.
+-define(otp_4836_mgc_decode_msg_fun(Mod, Conf),
+ otp_4836_mgc_decode_msg_fun(Mod, Conf)).
+-define(otp_4836_mgc_encode_msg_fun(Mod, Conf),
+ otp_4836_mgc_encode_msg_fun(Mod, Conf)).
+-define(otp_4836_mgc_verify_service_change_req_msg_fun(),
+ otp_4836_mgc_verify_service_change_req_msg_fun()).
+-define(otp_4836_mgc_verify_notify_req_msg_fun(),
+ otp_4836_mgc_verify_notify_req_msg_fun()).
+-endif.
+
+otp_4836_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_4836_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_4836_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"ctrl"},
+ ServiceChangeReply = otp_4836_service_change_reply_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReply = otp_4836_notify_reply_msg(Mid, 2, 0, TermId),
+ Pending = otp_4836_pending_msg(Mid,2),
+ ServiceChangeVerifyFun = ?otp_4836_mgc_verify_service_change_req_msg_fun(),
+ NotifyReqVerifyFun = ?otp_4836_mgc_verify_notify_req_msg_fun(),
+ MgcEvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ServiceChangeVerifyFun, 10000}},
+ {send, "service-change-reply", ServiceChangeReply},
+ {expect_receive, "notify-request", {NotifyReqVerifyFun, 10000}},
+ {send, "pending 1", Pending},
+ {sleep, 100},
+ {send, "pending 2", Pending},
+ {sleep, 500},
+ {send, "notify-reply", NotifyReply},
+ {sleep, 2000}
+ ],
+ MgcEvSeq.
+
+otp_4836_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms,SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_4836_msg(Mid, TransId, CR, Cid).
+
+otp_4836_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_4836_msg(Mid, TransId, CR, Cid).
+
+otp_4836_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+otp_4836_pending_msg(Mid, TransId) ->
+ TP = #'TransactionPending'{transactionId = TransId},
+ Body = {transactions, [{transactionPending, TP}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+-ifndef(megaco_hipe_special).
+otp_4836_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+%% otp_4836_mgc_encode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% encode_msg(M, Mod, Conf, Ver)
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_4836_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+%% otp_4836_mgc_decode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% decode_msg(M, Mod, Conf, Ver)
+%% end.
+
+%% otp_4836_verify_msg_fun() ->
+%% fun(M) ->
+%% {ok, M}
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_4836_mgc_verify_service_change_req_msg_fun() ->
+ fun(M) ->
+ otp_4836_mgc_verify_service_change_req_msg(M)
+ end.
+-endif.
+
+otp_4836_mgc_verify_service_change_req_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{version = _V,
+ mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{transactionId = _Tid,
+ actions = [AR]} = TR,
+ #'ActionRequest'{contextId = _Cid,
+ contextRequest = _CtxReq,
+ contextAttrAuditReq = _CtxAar,
+ commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd,
+ optional = _Opt,
+ wildcardReturn = _WR} = CR,
+ {serviceChangeReq, SCR} = Cmd,
+ #'ServiceChangeRequest'{terminationID = _TermID,
+ serviceChangeParms = SCP} = SCR,
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
+ {ok, M};
+otp_4836_mgc_verify_service_change_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+otp_4836_mgc_verify_notify_req_msg_fun() ->
+ fun(M) ->
+ otp_4836_mgc_verify_notify_req_msg(M)
+ end.
+-endif.
+
+otp_4836_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{actions = [AR]} = TR,
+ #'ActionRequest'{commandRequests = [CR1,CR2]} = AR,
+ #'CommandRequest'{command = Cmd1} = CR1,
+ {notifyReq, NR1} = Cmd1,
+ #'NotifyRequest'{observedEventsDescriptor = OED1} = NR1,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE1]} = OED1,
+ #'ObservedEvent'{eventName = "al/of"} = OE1,
+ #'CommandRequest'{command = Cmd2} = CR2,
+ {notifyReq, NR2} = Cmd2,
+ #'NotifyRequest'{observedEventsDescriptor = OED2} = NR2,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE2]} = OED2,
+ #'ObservedEvent'{eventName = "al/of"} = OE2,
+ {ok, M};
+otp_4836_mgc_verify_notify_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5805(suite) ->
+ [];
+otp_5805(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_5805),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp_5805_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} =
+ megaco_test_megaco_generator:exec(Mgc, MgcEvSeq, timer:minutes(1)),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("start the MG simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("create the MG event sequence"),
+ MgEvSeq = otp_5805_mg_event_sequence(text, tcp),
+
+ d("start the MG simulation"),
+ {ok, MgId} =
+ megaco_test_tcp_generator:exec(Mg, MgEvSeq, timer:minutes(1)),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+-ifdef(megaco_hipe_special).
+-define(otp_5805_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_5805_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_5805_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, otp_5805_mg_verify_service_change_rep_msg, []}).
+-define(otp_5805_mg_verify_error_descriptor_msg_fun(),
+ {?MODULE, otp_5805_mg_verify_error_descriptor_msg, []}).
+-else.
+-define(otp_5805_mg_decode_msg_fun(Mod, Conf),
+ otp_5805_mg_decode_msg_fun(Mod, Conf)).
+-define(otp_5805_mg_encode_msg_fun(Mod, Conf),
+ otp_5805_mg_encode_msg_fun(Mod, Conf)).
+-define(otp_5805_mg_verify_service_change_rep_msg_fun(),
+ otp_5805_mg_verify_service_change_rep_msg_fun()).
+-define(otp_5805_mg_verify_error_descriptor_msg_fun(),
+ otp_5805_mg_verify_error_descriptor_msg_fun()).
+-endif.
+
+otp_5805_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_5805_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_5805_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = otp_5805_mg_service_change_request_msg(Mid, 1, 0),
+ NotifyReqNNV = otp_5805_mg_notify_request_msg("1"),
+ NotifyReqUV = otp_5805_mg_notify_request_msg("4"),
+ ServiceChangeReplyVerifyFun =
+ ?otp_5805_mg_verify_service_change_rep_msg_fun(),
+ EDVerify =
+ ?otp_5805_mg_verify_error_descriptor_msg_fun(),
+%% ServiceChangeReplyVerifyFun =
+%% otp_5805_mg_verify_service_change_rep_msg_fun(),
+%% EDVerify = otp_5805_mg_verify_error_descriptor_msg_fun(),
+ MgEvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ServiceChangeReplyVerifyFun, 5000}},
+ {sleep, 1000},
+ {send, "notify request (not negotiated version)", NotifyReqNNV},
+ {expect_receive, "error-descriptor", EDVerify},
+ {sleep, 1000},
+ {send, "notify request (unsupported version)", NotifyReqUV},
+ {expect_receive, "error-descriptor", EDVerify},
+
+ {expect_nothing, 4000},
+ disconnect
+ ],
+ MgEvSeq.
+
+-ifndef(megaco_hipe_special).
+otp_5805_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp_5805_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp_5805_mg_verify_service_change_rep_msg_fun() ->
+ fun(M) ->
+ otp_5805_mg_verify_service_change_rep_msg(M)
+ end.
+-endif.
+
+otp_5805_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = Body} ->
+ case Body of
+ {transactions, [Trans]} ->
+ case Trans of
+ {transactionReply, TR} ->
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res} ->
+ case Res of
+ {actionReplies, [AR]} ->
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CR]} ->
+ case CR of
+ {serviceChangeReply, SCR} ->
+ case SCR of
+ #'ServiceChangeReply'{
+ terminationID = _TermID,
+ serviceChangeResult = SCRes} ->
+ case SCRes of
+ {serviceChangeResParms, SCRP} ->
+ case SCRP of
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _MgcMid,
+ serviceChangeVersion = 2} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_scrp, SCRP}}
+ end;
+ _ ->
+ {error, {invalid_scres, SCRes}}
+ end;
+ _ ->
+ {error, {invalid_scr, SCR}}
+ end;
+ _ ->
+ {error, {invalid_cr, CR}}
+ end;
+ _ ->
+ {error, {invalid_ar, AR}}
+ end;
+ _ ->
+ {error, {invalid_tres, Res}}
+ end;
+ _ ->
+ {error, {invalid_tr, TR}}
+ end;
+ _ ->
+ {error, {invalid_trans, Trans}}
+ end;
+ _ ->
+ {error, {invalid_body, Body}}
+ end;
+ _ ->
+ {error, {invalid_mess, Mess}}
+ end;
+otp_5805_mg_verify_service_change_rep_msg(M) ->
+ {error, {invalid_message, M}}.
+
+
+-ifndef(megaco_hipe_special).
+otp_5805_mg_verify_error_descriptor_msg_fun() ->
+ fun(M) ->
+ otp_5805_mg_verify_error_descriptor_msg(M)
+ end.
+-endif.
+
+otp_5805_mg_verify_error_descriptor_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ case Mess of
+ #'Message'{version = 2,
+ mId = _MgMid,
+ messageBody = Body} ->
+ io:format("otp_5805_mg_verify_error_descriptor_msg_fun -> ok"
+ "~n Body: ~p"
+ "~n", [Body]),
+ case Body of
+ {messageError, ED} ->
+ case ED of
+ #'ErrorDescriptor'{
+ errorCode = ?megaco_version_not_supported} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_ed, ED}}
+ end;
+ _ ->
+ {error, {invalid_body, Body}}
+ end;
+ _ ->
+ {error, {invalid_mess, Mess}}
+ end;
+otp_5805_mg_verify_error_descriptor_msg(M) ->
+ {error, {invalid_message, M}}.
+
+otp_5805_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, 2, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_5805_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp_5805_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+%% otp_5805_mg_notify_request_ar(Rid, Tid, Cid) ->
+%% TT = cre_timeNotation("19990729", "22000000"),
+%% Ev = cre_obsEvent("al/of", TT),
+%% EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+%% NR = cre_notifyReq([Tid], EvsDesc),
+%% CMD = cre_command(NR),
+%% CR = cre_cmdReq(CMD),
+%% cre_actionReq(Cid, [CR]).
+
+otp_5805_mg_notify_request_msg(V) ->
+ M =
+"MEGACO/" ++ V ++ " mg
+Transaction = 2 {
+ Context = 1 {
+ Notify = 00000000/00000000/01101101 {
+ ObservedEvents = 1 {
+ 19990729T22000000:al/of
+ }
+ }
+ }
+}",
+ list_to_binary(M).
+
+
+%%
+%% MGC generator stuff
+%%
+
+-ifdef(megaco_hipe_special).
+-define(otp_5805_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp_5805_mgc_verify_handle_connect, []}).
+-define(otp_5805_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp_5805_mgc_verify_service_change_req, [Mid]}).
+-define(otp_5805_mgc_verify_handle_syntax_error_fun(),
+ {?MODULE, otp_5805_mgc_verify_handle_syntax_error, []}).
+-define(otp_5805_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp_5805_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp_5805_mgc_verify_handle_connect_fun(),
+ fun otp_5805_mgc_verify_handle_connect/1).
+-define(otp_5805_mgc_verify_service_change_req_fun(Mid),
+ otp_5805_mgc_verify_service_change_req_fun(Mid)).
+-define(otp_5805_mgc_verify_handle_syntax_error_fun(),
+ fun otp_5805_mgc_verify_handle_syntax_error/1).
+-define(otp_5805_mgc_verify_handle_disconnect_fun(),
+ fun otp_5805_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp_5805_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?otp_5805_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?otp_5805_mgc_verify_service_change_req_fun(Mid),
+ SyntaxErrorVerify1 = ?otp_5805_mgc_verify_handle_syntax_error_fun(),
+ SyntaxErrorVerify2 = ?otp_5805_mgc_verify_handle_syntax_error_fun(),
+ DiscoVerify = ?otp_5805_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun otp_5805_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = otp_5805_mgc_verify_service_change_req_fun(Mid),
+%% SyntaxErrorVerify1 = fun otp_5805_mgc_verify_handle_syntax_error/1,
+%% SyntaxErrorVerify2 = fun otp_5805_mgc_verify_handle_syntax_error/1,
+%% DiscoVerify = fun otp_5805_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request_sc, ServiceChangeReqVerify},
+ {megaco_update_conn_info, protocol_version, 2},
+ {megaco_callback, handle_syntax_error, SyntaxErrorVerify1},
+ {megaco_callback, handle_syntax_error, SyntaxErrorVerify2},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+otp_5805_mgc_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("otp_5805_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp_5805_mgc_verify_handle_connect({handle_connect, CH, V}) ->
+ io:format("otp_5805_mgc_verify_handle_connect -> unexpected version"
+ "~n CH: ~p"
+ "~n V: ~p"
+ "~n", [CH, V]),
+ {error, {unexpected_version, V}, ok};
+otp_5805_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_5805_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ otp_5805_mgc_verify_service_change_req(Ev, Mid)
+ end.
+-endif.
+
+otp_5805_mgc_verify_service_change_req({handle_trans_request, _, V, [AR]},
+ Mid) ->
+ io:format("otp_5805_mgc_verify_service_change_req -> ok so far"
+ "~n V: ~p"
+ "~n", [V]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeVersion = 2,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp_5805_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp_5805_err_desc(Parms),
+ ErrReply =
+ {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp_5805_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp_5805_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp_5805_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp_5805_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp_5805_mgc_verify_service_change_req(Else, _Mid) ->
+ ED = otp_5805_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp_5805_mgc_verify_handle_syntax_error({handle_syntax_error, CH, _, ED})
+ when is_record(ED, 'ErrorDescriptor') ->
+ io:format("otp_5805_mgc_verify_handle_syntax_error -> ok so far"
+ "~n CH: ~p"
+ "~n ED: ~p"
+ "~n", [CH, ED]),
+ case ED of
+ #'ErrorDescriptor'{errorCode = ?megaco_version_not_supported} ->
+ {ok, CH, reply};
+ #'ErrorDescriptor'{errorCode = Code} ->
+ {error, {invalid_errorCode, Code}, ok}
+ end;
+otp_5805_mgc_verify_handle_syntax_error(Else) ->
+ io:format("otp_5805_mgc_verify_handle_syntax_error -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp_5805_mgc_verify_handle_disconnect({handle_disconnect, CH, V, _R}) ->
+ io:format("otp_5805_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n V: ~p"
+ "~n _R: ~p"
+ "~n", [CH, V, _R]),
+ {ok, CH, ok};
+otp_5805_mgc_verify_handle_disconnect(Else) ->
+ io:format("otp_5805_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp_5805_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid, 2),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+%% otp_5805_mgc_notify_reply_ar(Cid, TermId) ->
+%% NR = cre_notifyReply([TermId]),
+%% CR = cre_cmdReply(NR),
+%% cre_actionReply(Cid, [CR]).
+
+
+otp_5805_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5881(suite) ->
+ [];
+otp_5881(Config) when is_list(Config) ->
+ ?SKIP("deprecated by OTP-5887"),
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_5881),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("start the MGC simulator (generator)"),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("create the MGC event sequence"),
+ MgcEvSeq = otp_5881_mgc_event_sequence(text, tcp),
+
+ d("start the MGC simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ ReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ %% 5000, %% Does not matter since we will not use this anyway...
+ LongReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ PendingTmr = 10000,
+ ReplyTmr = 16000,
+ MgConfig = [{request_timer, ReqTmr},
+ {long_request_timer, LongReqTmr},
+ {pending_timer, PendingTmr},
+ {reply_timer, ReplyTmr}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ i("[MG] verify transaction-id: undefined_serial"),
+ otp_5881_verify_trans_id(Mg, undefined_serial),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ i("[MG] verify transaction-id: 1"),
+ otp_5881_verify_trans_id(Mg, 1),
+
+ d("[MG] send the notify"),
+ {ok, Reply} = (catch ?MG_NOTIF_RAR(Mg)),
+ {1, {ok, [AR]}} = Reply,
+ d("[MG] ActionReply: ~p", [AR]),
+
+ i("[MG] verify transaction-id: 2"),
+ otp_5881_verify_trans_id(Mg, 2),
+
+ d("await the generator reply"),
+ await_completion([MgcId]),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ i("done", []),
+ ok.
+
+otp_5881_verify_trans_id(Mg, Expected) ->
+ case ?MG_CONN_INFO(Mg, trans_id) of
+ Expected ->
+ ok;
+ ErroneousValue ->
+ throw({unexpected_transaction_id_value, ErroneousValue, Expected})
+ end.
+
+
+-ifdef(megaco_hipe_special).
+-define(otp_5881_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_5881_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_5881_mgc_verify_service_change_req_msg_fun(),
+ {?MODULE, otp_5881_mgc_verify_service_change_req_msg, []}).
+-define(otp_5881_mgc_verify_notify_req_msg_fun(),
+ {?MODULE, otp_5881_mgc_verify_notify_req_msg, []}).
+-else.
+-define(otp_5881_mgc_decode_msg_fun(Mod, Conf),
+ otp_5881_mgc_decode_msg_fun(Mod, Conf)).
+-define(otp_5881_mgc_encode_msg_fun(Mod, Conf),
+ otp_5881_mgc_encode_msg_fun(Mod, Conf)).
+-define(otp_5881_mgc_verify_service_change_req_msg_fun(),
+ otp_5881_mgc_verify_service_change_req_msg_fun()).
+-define(otp_5881_mgc_verify_notify_req_msg_fun(),
+ otp_5881_mgc_verify_notify_req_msg_fun()).
+-endif.
+
+otp_5881_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_5881_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_5881_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"ctrl"},
+ ServiceChangeReply = otp_5881_service_change_reply_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReply = otp_5881_notify_reply_msg(Mid, 2, 0, TermId),
+ %% Pending = otp_5881_pending_msg(Mid,2),
+ ServiceChangeVerifyFun = ?otp_5881_mgc_verify_service_change_req_msg_fun(),
+ NotifyReqVerifyFun = ?otp_5881_mgc_verify_notify_req_msg_fun(),
+%% ServiceChangeVerifyFun = otp_5881_verify_service_change_req_msg_fun(),
+%% NotifyReqVerifyFun = otp_5881_verify_notify_request_fun(),
+ MgcEvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ServiceChangeVerifyFun, 10000}},
+ {send, "service-change-reply", ServiceChangeReply},
+ {expect_receive, "notify-request", {NotifyReqVerifyFun, 10000}},
+ {send, "notify-reply", NotifyReply},
+ {sleep, 2000}
+ ],
+ MgcEvSeq.
+
+-ifndef(megaco_hipe_special).
+otp_5881_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp_5881_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+otp_5881_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms,SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_5881_msg(Mid, TransId, CR, Cid).
+
+otp_5881_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_5881_msg(Mid, TransId, CR, Cid).
+
+otp_5881_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% otp_5881_pending_msg(Mid, TransId) ->
+%% TP = #'TransactionPending'{transactionId = TransId},
+%% Body = {transactions, [{transactionPending, TP}]},
+%% Mess = #'Message'{version = 1,
+%% mId = Mid,
+%% messageBody = Body},
+%% #'MegacoMessage'{mess = Mess}.
+
+
+-ifndef(megaco_hipe_special).
+otp_5881_mgc_verify_service_change_req_msg_fun() ->
+ fun(M) ->
+ otp_5881_mgc_verify_service_change_req_msg(M)
+ end.
+-endif.
+
+otp_5881_mgc_verify_service_change_req_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{version = _V,
+ mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{transactionId = _Tid,
+ actions = [AR]} = TR,
+ #'ActionRequest'{contextId = _Cid,
+ contextRequest = _CtxReq,
+ contextAttrAuditReq = _CtxAar,
+ commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd,
+ optional = _Opt,
+ wildcardReturn = _WR} = CR,
+ {serviceChangeReq, SCR} = Cmd,
+ #'ServiceChangeRequest'{terminationID = _TermID,
+ serviceChangeParms = SCP} = SCR,
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
+ {ok, M};
+otp_5881_mgc_verify_service_change_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+otp_5881_mgc_verify_notify_req_msg_fun() ->
+ fun(M) ->
+ otp_5881_mgc_verify_notify_req_msg(M)
+ end.
+-endif.
+
+otp_5881_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{actions = [AR]} = TR,
+ #'ActionRequest'{commandRequests = [CR1,CR2]} = AR,
+ #'CommandRequest'{command = Cmd1} = CR1,
+ {notifyReq, NR1} = Cmd1,
+ #'NotifyRequest'{observedEventsDescriptor = OED1} = NR1,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE1]} = OED1,
+ #'ObservedEvent'{eventName = "al/of"} = OE1,
+ #'CommandRequest'{command = Cmd2} = CR2,
+ {notifyReq, NR2} = Cmd2,
+ #'NotifyRequest'{observedEventsDescriptor = OED2} = NR2,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE2]} = OED2,
+ #'ObservedEvent'{eventName = "al/of"} = OE2,
+ {ok, M};
+otp_5881_mgc_verify_notify_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5887(suite) ->
+ [];
+otp_5887(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_5887),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("start the MGC simulator (generator)"),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("create the MGC event sequence"),
+ MgcEvSeq = otp_5887_mgc_event_sequence(text, tcp),
+
+ d("start the MGC simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ ReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ %% 5000, %% Does not matter since we will not use this anyway...
+ LongReqTmr = #megaco_incr_timer{wait_for = 3000,
+ factor = 1,
+ incr = 0,
+ max_retries = 3},
+ PendingTmr = 10000,
+ ReplyTmr = 16000,
+ MgConfig = [{request_timer, ReqTmr},
+ {long_request_timer, LongReqTmr},
+ {pending_timer, PendingTmr},
+ {reply_timer, ReplyTmr}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ i("[MG] conn info: ~n~p", [?MG_CONN_INFO(Mg, all)]),
+
+ i("[MG] verify conn transaction-id: 1"),
+ otp_5887_verify_conn_trans_id(Mg, 1),
+
+ i("[MG] user info: ~n~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] verify user transaction-id: undefined_serial"),
+ otp_5887_verify_user_trans_id(Mg, undefined_serial),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ i("[MG] conn info: ~n~p", [?MG_CONN_INFO(Mg, all)]),
+
+ i("[MG] verify conn transaction-id: 2"),
+ otp_5887_verify_conn_trans_id(Mg, 2),
+
+ i("[MG] user info: ~n~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] verify user transaction-id: 1"),
+ otp_5887_verify_user_trans_id(Mg, 1),
+
+ d("[MG] send the notify"),
+ {ok, Reply} = (catch ?MG_NOTIF_RAR(Mg)),
+ {1, {ok, [AR]}} = Reply,
+ d("[MG] ActionReply: ~p", [AR]),
+
+ i("[MG] conn info: ~n~p", [?MG_CONN_INFO(Mg, all)]),
+
+ i("[MG] verify conn transaction-id: 3"),
+ otp_5887_verify_conn_trans_id(Mg, 3),
+
+ i("[MG] user info: ~n~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] verify user transaction-id: 2"),
+ otp_5887_verify_user_trans_id(Mg, 2),
+
+ d("await the generator reply"),
+ await_completion([MgcId]),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ i("done", []),
+ ok.
+
+
+otp_5887_verify_conn_trans_id(Mg, Expected) ->
+ F = fun() -> (catch ?MG_CONN_INFO(Mg, trans_id)) end,
+ otp_5887_verify_trans_id(F, Expected).
+
+otp_5887_verify_user_trans_id(Mg, Expected) ->
+ F = fun() -> (catch ?MG_USER_INFO(Mg, trans_id)) end,
+ otp_5887_verify_trans_id(F, Expected).
+
+otp_5887_verify_trans_id(F, Expected) ->
+ case F() of
+ Expected ->
+ ok;
+ ErroneousValue ->
+ throw({unexpected_transaction_id_value, ErroneousValue, Expected})
+ end.
+
+
+-ifdef(megaco_hipe_special).
+-define(otp_5887_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_5887_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_5887_mgc_verify_service_change_req_msg_fun(),
+ {?MODULE, otp_5887_mgc_verify_service_change_req_msg, []}).
+-define(otp_5887_mgc_verify_notify_req_msg_fun(),
+ {?MODULE, otp_5887_mgc_verify_notify_req_msg, []}).
+-else.
+-define(otp_5887_mgc_decode_msg_fun(Mod, Conf),
+ otp_5887_mgc_decode_msg_fun(Mod, Conf)).
+-define(otp_5887_mgc_encode_msg_fun(Mod, Conf),
+ otp_5887_mgc_encode_msg_fun(Mod, Conf)).
+-define(otp_5887_mgc_verify_service_change_req_msg_fun(),
+ otp_5887_mgc_verify_service_change_req_msg_fun()).
+-define(otp_5887_mgc_verify_notify_req_msg_fun(),
+ otp_5887_mgc_verify_notify_req_msg_fun()).
+-endif.
+
+otp_5887_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_5887_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_5887_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"ctrl"},
+ ServiceChangeReply = otp_5887_service_change_reply_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReply = otp_5887_notify_reply_msg(Mid, 2, 0, TermId),
+ ServiceChangeVerifyFun = ?otp_5887_mgc_verify_service_change_req_msg_fun(),
+ NotifyReqVerifyFun = ?otp_5887_mgc_verify_notify_req_msg_fun(),
+%% ServiceChangeVerifyFun = otp_5887_verify_service_change_req_msg_fun(),
+%% NotifyReqVerifyFun = otp_5887_verify_notify_request_fun(),
+ MgcEvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ServiceChangeVerifyFun, 10000}},
+ {send, "service-change-reply", ServiceChangeReply},
+ {expect_receive, "notify-request", {NotifyReqVerifyFun, 10000}},
+ {send, "notify-reply", NotifyReply},
+ {sleep, 2000}
+ ],
+ MgcEvSeq.
+
+otp_5887_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms,SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_5887_msg(Mid, TransId, CR, Cid).
+
+otp_5887_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_5887_msg(Mid, TransId, CR, Cid).
+
+otp_5887_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%% otp_5887_pending_msg(Mid, TransId) ->
+%% TP = #'TransactionPending'{transactionId = TransId},
+%% Body = {transactions, [{transactionPending, TP}]},
+%% Mess = #'Message'{version = 1,
+%% mId = Mid,
+%% messageBody = Body},
+%% #'MegacoMessage'{mess = Mess}.
+
+
+-ifndef(megaco_hipe_special).
+otp_5887_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+%% otp_5887_mgc_encode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% encode_msg(M, Mod, Conf, Ver)
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_5887_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+%% otp_5887_mgc_decode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% decode_msg(M, Mod, Conf, Ver)
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_5887_mgc_verify_service_change_req_msg_fun() ->
+ fun(M) ->
+ otp_5887_mgc_verify_service_change_req_msg(M)
+ end.
+-endif.
+
+otp_5887_mgc_verify_service_change_req_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{version = _V,
+ mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{transactionId = _Tid,
+ actions = [AR]} = TR,
+ #'ActionRequest'{contextId = _Cid,
+ contextRequest = _CtxReq,
+ contextAttrAuditReq = _CtxAar,
+ commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd,
+ optional = _Opt,
+ wildcardReturn = _WR} = CR,
+ {serviceChangeReq, SCR} = Cmd,
+ #'ServiceChangeRequest'{terminationID = _TermID,
+ serviceChangeParms = SCP} = SCR,
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
+ {ok, M};
+otp_5887_mgc_verify_service_change_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+
+-ifndef(megaco_hipe_special).
+otp_5887_mgc_verify_notify_req_msg_fun() ->
+ fun(M) ->
+ otp_5887_mgc_verify_notify_req_msg(M)
+ end.
+-endif.
+
+otp_5887_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{actions = [AR]} = TR,
+ #'ActionRequest'{commandRequests = [CR1,CR2]} = AR,
+ #'CommandRequest'{command = Cmd1} = CR1,
+ {notifyReq, NR1} = Cmd1,
+ #'NotifyRequest'{observedEventsDescriptor = OED1} = NR1,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE1]} = OED1,
+ #'ObservedEvent'{eventName = "al/of"} = OE1,
+ #'CommandRequest'{command = Cmd2} = CR2,
+ {notifyReq, NR2} = Cmd2,
+ #'NotifyRequest'{observedEventsDescriptor = OED2} = NR2,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE2]} = OED2,
+ #'ObservedEvent'{eventName = "al/of"} = OE2,
+ {ok, M};
+otp_5887_mgc_verify_notify_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6253(suite) ->
+ [];
+otp_6253(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+
+ put(verbosity, debug),
+ put(tc, otp_6253),
+
+ d("otp_6253 -> start test case controller",[]),
+ ok = megaco_tc_controller:start_link(),
+
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+
+ ?VERIFY(ok, application:start(megaco)),
+ ?VERIFY(ok, megaco:start_user(MgMid, [{send_mod, megaco_mess_user_test},
+ {request_timer, infinity},
+ {reply_timer, infinity}])),
+
+ MgRH = user_info(MgMid, receive_handle),
+ {ok, PrelCH} = ?VERIFY({ok, _}, megaco:connect(MgRH, PrelMid, sh, self())),
+
+ connections([PrelCH]),
+ ?VERIFY([PrelCH], megaco:user_info(MgMid, connections)),
+
+ SC = service_change_request(),
+
+ %% Instruct the transport module to fail all send_message
+ d("otp_6253 -> instruct transport module to fail message send",[]),
+ ok = megaco_tc_controller:insert(allow_send_message, {fail, otp_6253}),
+
+ ?VERIFY({1, {error, {send_message_failed, otp_6253}}},
+ megaco:call(PrelCH, [SC], [])),
+
+ sleep(1000),
+
+ %% Instruct the transport module to cancel all send_message
+ d("otp_6253 -> instruct transport module to cancel message send",[]),
+ ok = megaco_tc_controller:insert(allow_send_message, {cancel, otp_6253}),
+
+ ?VERIFY({1, {error, {send_message_cancelled, otp_6253}}},
+ megaco:call(PrelCH, [SC], [])),
+
+ ?VERIFY(ok, megaco:disconnect(PrelCH, shutdown)),
+
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6275(suite) ->
+ [];
+otp_6275(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_6275),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("start the MGC simulator (generator)"),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("create the MGC event sequence"),
+ MgcEvSeq = otp_6275_mgc_event_sequence(text, tcp),
+
+ d("start the MGC simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp_6275_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("[MGC] await the generator reply"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6275_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_6275_mg_verify_handle_connect, []}).
+-define(otp_6275_mg_verify_notify_req_fun(),
+ {?MODULE, otp_6275_mg_verify_notify_req, []}).
+-define(otp_6275_mg_verify_handle_trans_rep_fun(),
+ {?MODULE, otp_6275_mg_verify_handle_trans_rep, []}).
+-else.
+-define(otp_6275_mg_verify_handle_connect_fun(),
+ otp_6275_mg_verify_handle_connect_fun()).
+-define(otp_6275_mg_verify_notify_req_fun(),
+ otp_6275_mg_verify_notify_req_fun()).
+-define(otp_6275_mg_verify_handle_trans_rep_fun(),
+ otp_6275_mg_verify_handle_trans_rep_fun()).
+-endif.
+
+otp_6275_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ otp_6275_mg_event_sequence2(Mid, RI).
+
+otp_6275_mg_event_sequence2(Mid, RI) ->
+ ServiceChangeReq = [otp_6275_mg_service_change_request_ar(Mid, 1)],
+ _Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ ConnectVerify = ?otp_6275_mg_verify_handle_connect_fun(),
+ NotifyReqVerify = ?otp_6275_mg_verify_notify_req_fun(),
+ TransReplyVerify = ?otp_6275_mg_verify_handle_trans_rep_fun(),
+%% ConnectVerify = otp_6275_mg_verify_handle_connect_fun(),
+%% NotifyReqVerify = otp_6275_mg_verify_notify_request_fun(),
+%% TransReplyVerify = otp_6275_mg_verify_trans_reply_fun(),
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ %% {megaco_update_user_info, recv_pending_limit, 4},
+ {megaco_update_user_info, request_timer, 3000},
+ start_transport,
+ {megaco_trace, disable}, %%100},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, TransReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_6275_mg_verify_handle_connect_fun() ->
+ fun(Event) ->
+ (catch otp_6275_mg_verify_handle_connect(Event))
+ end.
+-endif.
+
+otp_6275_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6275_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6275_mg_verify_handle_connect(Else) ->
+ io:format("otp_6275_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_6275_mg_verify_notify_req_fun() ->
+ fun(Event) ->
+ (catch otp_6275_mg_verify_notify_req(Event))
+ end.
+-endif.
+
+otp_6275_mg_verify_notify_req(
+ {handle_trans_request, _CH, ?VERSION, [AR]}) ->
+ io:format("otp_6275_mg_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ ET1 = lists:flatten(
+ io_lib:format("Invalid action request: ~w", [AR])),
+ EC1 = ?megaco_internal_gateway_error,
+ ED1 = #'ErrorDescriptor'{errorCode = EC1,
+ errorText = ET1},
+ throw({error, {invalid_ActionRequest, AR}, {discard_ack, ED1}})
+ end,
+
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ ET2 = lists:flatten(
+ io_lib:format("Invalid command request: ~w", [CR])),
+ EC2 = ?megaco_internal_gateway_error,
+ ED2 = #'ErrorDescriptor'{errorCode = EC2,
+ errorText = ET2},
+ throw({error, {invalid_CommandRequest, CR}, {discard_ack, ED2}})
+ end,
+
+ case Cmd of
+ {notifyReq, NotifyReq} ->
+ ET3 = "Unexpected request",
+ EC3 = ?megaco_transaction_req_received_before_servicechange_reply,
+ ED3 = #'ErrorDescriptor'{errorCode = EC3,
+ errorText = ET3},
+ throw({ok, {ok, NotifyReq}, {discard_ack, ED3}});
+ _ ->
+ ET4 = lists:flatten(
+ io_lib:format("Invalid command: ~w", [Cmd])),
+ EC4 = ?megaco_internal_gateway_error,
+ ED4 = #'ErrorDescriptor'{errorCode = EC4,
+ errorText = ET4},
+ throw({error, {invalid_command, Cmd}, {discard_ack, ED4}})
+ end;
+otp_6275_mg_verify_notify_req({Tag, CH, Version, ARs}) ->
+ io:format("otp_6275_mg_verify_notify_req -> ok"
+ "~n Tag: ~p"
+ "~n CH: ~p"
+ "~n Version: ~p"
+ "~n ARs: ~p"
+ "~n", [Tag, CH, Version, ARs]),
+ {error, {invalid_event, {Tag, CH, Version, ARs}}, ok};
+otp_6275_mg_verify_notify_req(Else) ->
+ io:format("otp_6275_mg_verify_notify_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_6275_mg_verify_handle_trans_rep_fun() ->
+ fun(Event) ->
+ (catch otp_6275_mg_verify_handle_trans_rep(Event))
+ end.
+-endif.
+
+otp_6275_mg_verify_handle_trans_rep(
+ {handle_trans_reply, CH, ?VERSION, {error, timeout} = Error, _}) ->
+ io:format("otp_6275_mg_verify_trans_rep -> expected error"
+ "~n", []),
+ case CH of
+ #megaco_conn_handle{remote_mid = preliminary_mid} ->
+ {ok, Error, error};
+ _ ->
+ {error, {unexpected_connection, CH}, error}
+ end;
+otp_6275_mg_verify_handle_trans_rep(
+ {handle_trans_reply, _CH, ?VERSION, Error, _}) ->
+ io:format("otp_6275_mg_verify_handle_trans_rep -> unexpected error"
+ "~n Error: ~p"
+ "~n", [Error]),
+ {error, Error, error};
+otp_6275_mg_verify_handle_trans_rep(Else) ->
+ io:format("otp_6275_mg_verify_handle_trans_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, error}.
+
+otp_6275_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6275_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_6275_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_6275_mgc_verify_service_change_req_msg_fun(),
+ {?MODULE, otp_6275_mgc_verify_service_change_req_msg, []}).
+-define(otp_6275_mgc_verify_notify_rep_msg_fun(),
+ {?MODULE, otp_6275_mgc_verify_notify_rep_msg, []}).
+-else.
+-define(otp_6275_mgc_decode_msg_fun(Mod, Conf),
+ otp_6275_mgc_decode_msg_fun(Mod, Conf)).
+-define(otp_6275_mgc_encode_msg_fun(Mod, Conf),
+ otp_6275_mgc_encode_msg_fun(Mod, Conf)).
+-define(otp_6275_mgc_verify_service_change_req_msg_fun(),
+ otp_6275_mgc_verify_service_change_req_msg_fun()).
+-define(otp_6275_mgc_verify_notify_rep_msg_fun(),
+ otp_6275_mgc_verify_notify_rep_msg_fun()).
+-endif.
+
+otp_6275_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_6275_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_6275_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"ctrl"},
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_6275_mgc_notify_request_msg(Mid, 2, 1, TermId, 1),
+ SCRVerifyFun = ?otp_6275_mgc_verify_service_change_req_msg_fun(),
+ NotifyReplyVerifyFun = ?otp_6275_mgc_verify_notify_rep_msg_fun(),
+%% SCRVerifyFun = otp_6275_mgc_verify_service_change_req_fun(),
+%% NotifyReplyVerifyFun = otp_6275_mgc_verify_notify_reply_fun(),
+ MgcEvSeq =
+ [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {SCRVerifyFun, 5000}},
+ {sleep, 1000}, %% Do _not_ send SC reply
+ {send, "notify-request", NotifyReq},
+ {expect_receive, "request before sc reply", {NotifyReplyVerifyFun, 5000}},
+ {sleep, 2000}
+ ],
+ MgcEvSeq.
+
+-ifndef(megaco_hipe_special).
+otp_6275_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+%% otp_6275_mgc_encode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% encode_msg(M, Mod, Conf, Ver)
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_6275_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+%% otp_6275_mgc_decode_msg_fun(Mod, Conf, Ver) ->
+%% fun(M) ->
+%% decode_msg(M, Mod, Conf, Ver)
+%% end.
+
+-ifndef(megaco_hipe_special).
+otp_6275_mgc_verify_service_change_req_msg_fun() ->
+ fun(M) ->
+ (catch otp_6275_mgc_verify_service_change_req_msg(M))
+ end.
+-endif.
+
+otp_6275_mgc_verify_service_change_req_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_6275_mgc_verify_service_change_req_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{messageBody = MB} ->
+ MB;
+ _ ->
+ throw({error, {invalid_mess, Mess}})
+ end,
+
+ Trans =
+ case Body of
+ {transactions, [Transaction]} ->
+ Transaction;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+
+ TR =
+ case Trans of
+ {transactionRequest, TransReq} ->
+ TransReq;
+ _ ->
+ throw({error, {invalid_transaction, Trans}})
+ end,
+
+ AR =
+ case TR of
+ #'TransactionRequest'{actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_TransactionRequest, AR}})
+ end,
+
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_ActionRequest, CR}})
+ end,
+
+ SCR =
+ case Cmd of
+ {serviceChangeReq, ServiceChangeReq} ->
+ ServiceChangeReq;
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+
+ SCP =
+ case SCR of
+ #'ServiceChangeRequest'{serviceChangeParms = ServiceChangeParms} ->
+ ServiceChangeParms;
+ _ ->
+ throw({error, {invalid_serviceChangeReq, SCR}})
+ end,
+
+ case SCP of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, SCP}}
+ end;
+otp_6275_mgc_verify_service_change_req_msg(Crap) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+-ifndef(megaco_hipe_special).
+otp_6275_mgc_verify_notify_rep_msg_fun() ->
+ fun(M) ->
+ (catch otp_6275_mgc_verify_notify_rep_msg(M))
+ end.
+-endif.
+
+otp_6275_mgc_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_6275_mgc_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{messageBody = MB} ->
+ MB;
+ _ ->
+ throw({error, {invalid_mess, Mess}})
+ end,
+
+ Trans =
+ case Body of
+ {transactions, [Transaction]} ->
+ Transaction;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transaction, Trans}})
+ end,
+
+ Res =
+ case TR of
+ #'TransactionReply'{transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+
+ ED =
+ case Res of
+ {transactionError, ErrorDesc} ->
+ ErrorDesc;
+ _ ->
+ throw({error, {invalid_TransactionReply, Res}})
+ end,
+
+ case ED of
+ #'ErrorDescriptor'{errorCode = ?megaco_transaction_req_received_before_servicechange_reply} ->
+ ok;
+ _ ->
+ throw({error, {invalid_transactionError, ED}})
+ end,
+ {ok, M};
+otp_6275_mgc_verify_notify_rep_msg(Crap) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+otp_6275_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_6275_mgc_notify_request_msg(Mid, TransId, Cid, TermId, Rid) ->
+ AR = otp_6275_mgc_notify_request_ar(Rid, TermId, Cid),
+ otp_6275_msg(Mid, TransId, AR).
+
+
+%% --
+
+otp_6275_msg(Mid, TransId, AR) ->
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case can only be run with the stack compiled with
+%% the MEGACO_TEST_CODE flag. Therefor there is no point in
+%% including this test case in the usual test suite
+-ifdef(MEGACO_TEST_CODE).
+otp_6276(suite) ->
+ [];
+otp_6276(doc) ->
+ "OTP-6276: Cancel when receiving reply raise condition";
+otp_6276(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_6276),
+ i("starting"),
+
+ d("create sequence controller"),
+ CtrlPid = otp_6276_sequence_controller_start(),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp_6276_mgc_event_sequence(text, tcp, CtrlPid),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the tcp-simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("send start order to sequence controller"),
+ CtrlPid ! {start, self(), Mgc, Mg},
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp_6276_mg_event_sequence(text, tcp, CtrlPid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the megaco-simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_6276_sequence_controller_start() ->
+ Self = self(),
+ erlang:spawn(fun() -> otp_6276_sequence_controller(Self) end).
+
+otp_6276_sequence_controller(Parent) ->
+ io:format("otp_6276_sequence_controller -> entry with"
+ "~n Parent: ~p"
+ "~n self(): ~p"
+ "~n", [Parent, self()]),
+
+ d("start tc controller"),
+ put(dbg,true),
+ ok = megaco_tc_controller:start_link(),
+
+
+ %% Await MGC announcement
+ Mgc =
+ receive
+ {announce_mgc, MgcPid} ->
+ MgcPid
+ end,
+ io:format("otp_6276_sequence_controller -> MGC announced: "
+ "~n Mgc: ~p"
+ "~n", [Mgc]),
+
+ %% Await MG announcement
+ Mg =
+ receive
+ {announce_mg, MgPid} ->
+ MgPid
+ end,
+ io:format("otp_6276_sequence_controller -> MG announced: "
+ "~n Mg: ~p"
+ "~n", [Mg]),
+
+ %% Await request_received notification
+ receive
+ {notify_request_received, Mgc} ->
+ io:format("otp_6276_sequence_controller -> "
+ "request received from MGC (~p)"
+ "~n", [Mgc]),
+ ok
+ end,
+
+ %% Make sure the cancel operation gets blocked midway:
+ megaco_tc_controller:insert(block_on_cancel, {cancel_block, self()}),
+
+ %% Send start cancel order
+ io:format("otp_6276_sequence_controller -> "
+ "send cancel start order to MG (~p)"
+ "~n", [Mg]),
+ Mg ! {start_cancel, self()},
+ receive
+ {started_cancel, Mg} ->
+ ok
+ end,
+ io:format("otp_6276_sequence_controller -> "
+ "cancel started - now await blocked"
+ "~n", []),
+
+ receive
+ {cancel_block, Mg} ->
+ ok
+ end,
+ io:format("otp_6276_sequence_controller -> "
+ "cancel blocked - now instruct MGC to send notify reply"
+ "~n", []),
+
+ %% Make sure the cancel operation gets blocked midway:
+ megaco_tc_controller:insert(block_on_reply, {reply_block, self()}),
+
+ %% Send NR-send order
+ Mgc ! {notify_reply_send, self()},
+ io:format("otp_6276_sequence_controller -> "
+ "NR-send order sent - now await notify reply blocked received"
+ "~n", []),
+
+ ReplyPid =
+ receive
+ {reply_block, Pid, true} ->
+ io:format("otp_6276_sequence_controller -> "
+ "notify reply blocked received from ~p (true) - "
+ "now unblock cancel"
+ "~n", [Pid]),
+ %% Pid ! {reply_block, self()},
+ Pid;
+ {reply_block, Pid, Info} ->
+ io:format("otp_6276_sequence_controller -> "
+ "notify reply blocked received from ~p: ~p"
+ "~n", [Pid, Info]),
+ Pid ! {reply_block, self()},
+ exit({unexpected_reply_block_info, Info})
+ end,
+
+ %% Send cancel continue (unblock) order
+ Mg ! {cancel_block, self()},
+ io:format("otp_6276_sequence_controller -> "
+ "cancel unblocked - now await notify-request cancelled"
+ "~n", []),
+
+ %% Await request cancelled
+ receive
+ {notify_request_cancelled, Mg} ->
+ ok;
+ {notify_request_cancelled, Pid} ->
+ io:format("otp_6276_sequence_controller -> "
+ "notify-request cancelled - from ~p"
+ "~n", [Pid]),
+ ok
+ end,
+ io:format("otp_6276_sequence_controller -> "
+ "notify-request cancelled - now unblock notify-reply"
+ "~n", []),
+
+ %% await notify reply result
+ ReplyPid ! {reply_block, self()},
+ io:format("otp_6276_sequence_controller -> "
+ "notify-reply unblocked - now await unexpected trans"
+ "~n", []),
+
+ %% Await unexpected trans
+ receive
+ {unexpected_trans, Mg, _Trans} ->
+ ok;
+ {unexpected_trans, Pid, _Trans} ->
+ io:format("otp_6276_sequence_controller -> "
+ "unexpected_trans - from ~p"
+ "~n", [Pid]),
+ ok
+ end,
+ io:format("otp_6276_sequence_controller -> "
+ "unexpected transaction received"
+ "~n", []),
+
+ %% Await unexpected trans
+ Mgc ! {done, self()},
+ receive
+ {done, Mgc} ->
+ ok
+ end,
+ io:format("otp_6276_sequence_controller -> MGC instructed we are done"
+ "~n", []),
+
+ d("stop tc controller"),
+ megaco_tc_controller:stop(),
+
+ io:format("otp_6276_sequence_controller -> done~n", []),
+
+ exit(normal).
+
+
+%%
+%% MGC generator stuff
+%%
+otp_6276_mgc_event_sequence(text, tcp, Ctrl) ->
+ Mid = {deviceName,"ctrl"},
+ EM = megaco_pretty_text_encoder,
+ EC = [],
+ otp_6276_mgc_event_sequence2(Mid, EM, EC, Ctrl).
+
+otp_6276_mgc_event_sequence2(Mid, EM, EC, Ctrl) ->
+ DecodeFun = otp_6276_mgc_decode_msg_fun(EM, EC),
+ EncodeFun = otp_6276_mgc_encode_msg_fun(EM, EC),
+ AnnounceMe = otp_6276_mgc_announce_fun(Ctrl),
+ ServiceChangeReqVerify =
+ otp_6276_mgc_verify_service_change_req_fun(Mid),
+ ServiceChangeReply =
+ otp_6276_mgc_service_change_reply_msg(Mid, 1, 0),
+ NotifyReqVerify = otp_6276_mgc_verify_notify_request_fun(Ctrl),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ AwaitNrSendOrder = otp_6276_mgc_await_notify_reply_send_order_fun(Ctrl),
+ NotifyReply = otp_6276_mgc_notify_reply_msg(Mid, 2, 0, TermId),
+ AwaitDoneOrder = otp_6276_mgc_await_done_order_fun(Ctrl),
+ EvSeq =
+ [
+ {trigger, AnnounceMe},
+ {debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-req",
+ {ServiceChangeReqVerify, 10000}},
+ {send, "service-change-reply", ServiceChangeReply},
+ {expect_receive, "notify-request", {NotifyReqVerify, 5000}},
+
+ {trigger, AwaitNrSendOrder},
+
+ {send, "notify-reply", NotifyReply},
+
+ {trigger, AwaitDoneOrder},
+
+ disconnect
+ ],
+ EvSeq.
+
+otp_6276_mgc_announce_fun(Pid) ->
+ fun() ->
+ Pid ! {announce_mgc, self()}
+ end.
+
+otp_6276_mgc_await_notify_reply_send_order_fun(Pid) ->
+ fun() ->
+ receive
+ {notify_reply_send, Pid} ->
+ Pid ! {notify_reply_send, self()}
+ end
+ end.
+
+otp_6276_mgc_await_done_order_fun(Pid) ->
+ fun() ->
+ receive
+ {done, Pid} ->
+ Pid ! {done, self()}
+ end
+ end.
+
+otp_6276_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+otp_6276_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+otp_6276_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms,SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_6276_mgc_msg(Mid, TransId, CR, Cid).
+
+otp_6276_mgc_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_6276_mgc_msg(Mid, TransId, CR, Cid).
+
+otp_6276_mgc_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+otp_6276_mgc_pending_msg(Mid, TransId) ->
+ TP = #'TransactionPending'{transactionId = TransId},
+ Body = {transactions, [{transactionPending, TP}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+otp_6276_mgc_verify_service_change_req_fun(_) ->
+ fun(#'MegacoMessage'{mess = Mess} = M) ->
+ #'Message'{version = _V,
+ mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{transactionId = _Tid,
+ actions = [AR]} = TR,
+ #'ActionRequest'{contextId = _Cid,
+ contextRequest = _CtxReq,
+ contextAttrAuditReq = _CtxAar,
+ commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd,
+ optional = _Opt,
+ wildcardReturn = _WR} = CR,
+ {serviceChangeReq, SCR} = Cmd,
+ #'ServiceChangeRequest'{terminationID = _TermID,
+ serviceChangeParms = SCP} = SCR,
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
+ {ok, M};
+ (M) ->
+ {error, {invalid_message, M}}
+ end.
+
+otp_6276_mgc_verify_notify_request_fun(Pid) ->
+ fun(M) ->
+ (catch otp_6276_mgc_verify_notify_request(M, Pid))
+ end.
+
+otp_6276_mgc_verify_notify_request(#'MegacoMessage'{mess = Mess} = M,
+ Pid) ->
+ io:format("otp_6276_mgc_verify_notify_request -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{messageBody = MessageBody} ->
+ MessageBody;
+ _ ->
+ throw({error, {invalid_mess, Mess}})
+ end,
+
+ Trans =
+ case Body of
+ {transactions, [Transaction]} ->
+ Transaction;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+
+ TR =
+ case Trans of
+ {transactionRequest, TransReq} ->
+ TransReq;
+ _ ->
+ throw({error, {invalid_transaction, Trans}})
+ end,
+
+ AR =
+ case TR of
+ #'TransactionRequest'{actions = [Action]} ->
+ Action;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+
+ io:format("otp_6276_mgc_verify_notify_request -> "
+ "~n AR: ~p"
+ "~n", [AR]),
+
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CommandReq]} ->
+ CommandReq;
+ _ ->
+ throw({error, {invalid_TransactionRequest, AR}})
+ end,
+
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_ActionRequest, CR}})
+ end,
+
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_CommandRequest, Cmd}})
+ end,
+
+ OED =
+ case NR of
+ #'NotifyRequest'{observedEventsDescriptor = ObsEvDesc} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ _ ->
+ throw({error, {invalid_NotifyRequest, OED}})
+ end,
+
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ok;
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OE}})
+ end,
+ io:format("otp_6276_mgc_verify_notify_request -> "
+ "send notify_request received to "
+ "~n Pid: ~p"
+ "~n self(): ~p"
+ "~n", [Pid, self()]),
+ Pid ! {notify_request_received, self()},
+ {ok, M};
+otp_6276_mgc_verify_notify_request(M, _Pid) ->
+ {error, {invalid_message, M}}.
+
+
+%%
+%% MG generator stuff
+%%
+otp_6276_mg_event_sequence(text, tcp, Ctrl) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ otp_6276_mg_event_sequence2(Mid, RI, Ctrl).
+
+otp_6276_mg_event_sequence2(Mid, RI, Ctrl) ->
+ AnnounceMe = otp_6276_mg_announce_fun(Ctrl),
+ ServiceChangeReq = [otp_6276_mg_service_change_request_ar(Mid, 1)],
+ ConnectVerify = fun otp_6276_mg_verify_handle_connect/1,
+ ServiceChangeReplyVerify =
+ fun otp_6276_mg_verify_service_change_reply/1,
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [otp_6276_mg_notify_request_ar(1, Tid, 1)],
+ AwaitCancelOrder = otp_6276_mg_await_cancel_order_fun(Ctrl),
+ TransReplyVerify = otp_6276_mg_verify_trans_reply_fun(Ctrl),
+ UnexpTransVerify = otp_6276_mg_verify_unexpected_trans_fun(Ctrl),
+ EvSeq = [
+ {trigger, AnnounceMe},
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, recv_pending_limit, 4},
+ start_transport,
+ {megaco_trace, disable}, %%100},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, NotifyReq, []},
+
+ {trigger, AwaitCancelOrder},
+
+ {megaco_cancel, otp_6276},
+
+ {megaco_callback, handle_trans_reply, TransReplyVerify},
+ {megaco_callback, handle_unexpected_trans, UnexpTransVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+otp_6276_mg_announce_fun(Pid) ->
+ fun() ->
+ Pid ! {announce_mg, self()}
+ end.
+
+otp_6276_mg_await_cancel_order_fun(Pid) ->
+ fun() ->
+ io:format("otp_6276_mg_await_cancel_order_fun -> entry with"
+ "~n Pid: ~p"
+ "~n self(): ~p"
+ "~n", [Pid, self()]),
+ receive
+ {start_cancel, Pid} ->
+ io:format("otp_6276_mg_await_cancel_order_fun -> "
+ "received cancel start order"
+ "~n Pid: ~p"
+ "~n self(): ~p"
+ "~n", [Pid, self()]),
+ Pid ! {started_cancel, self()}
+ end
+ end.
+
+otp_6276_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6276_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6276_mg_verify_handle_connect(Else) ->
+ io:format("otp_6276_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp_6276_mg_verify_service_change_reply({handle_trans_reply, _CH,
+ ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp_6276_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+otp_6276_mg_verify_service_change_reply(Else) ->
+ io:format("otp_6276_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp_6276_mg_verify_trans_reply_fun(Pid) ->
+ fun(Event) ->
+ otp_6276_mg_verify_trans_reply(Pid, Event)
+ end.
+
+otp_6276_mg_verify_trans_reply(Pid,
+ {handle_trans_reply, _CH, ?VERSION,
+ {error, {user_cancel, otp_6276}} = E, _}) ->
+ io:format("otp_6276_mg_verify_trans_reply -> expected error"
+ "~n", []),
+ Pid ! {notify_request_cancelled, self()},
+ {ok, E, error};
+otp_6276_mg_verify_trans_reply(_Pid,
+ {handle_trans_reply, _CH, ?VERSION,
+ {error, Reason} = E, _}) ->
+ io:format("otp_6276_mg_verify_trans_reply -> unexpected error"
+ "~n Reason: ~p"
+ "~n", [Reason]),
+ {error, E, error};
+otp_6276_mg_verify_trans_reply(_Pid,
+ {handle_trans_reply, _CH, ?VERSION, Result, _}) ->
+ io:format("otp_6276_mg_verify_trans_reply -> unexpected result"
+ "~n Result: ~p"
+ "~n", [Result]),
+ {error, Result, error};
+otp_6276_mg_verify_trans_reply(_Pid, Else) ->
+ io:format("otp_6276_mg_verify_trans_reply -> unknown event"
+ "~n Else: ~p"
+ "~n", [Else]),
+ {error, Else, error}.
+
+otp_6276_mg_verify_unexpected_trans_fun(Pid) ->
+ fun(Event) ->
+ otp_6276_mg_verify_unexpected_trans(Pid, Event)
+ end.
+
+otp_6276_mg_verify_unexpected_trans(Pid,
+ {handle_unexpected_trans, RH, ?VERSION, Trans}) ->
+ io:format("otp_6276_mg_verify_unexpected_trans -> expected event"
+ "~n RH: ~p"
+ "~n Trans: ~p"
+ "~n", [RH, Trans]),
+ Pid ! {unexpected_trans, self(), Trans},
+ {ok, Trans, error};
+otp_6276_mg_verify_unexpected_trans(_Pid, Else) ->
+ io:format("otp_6276_mg_verify_unexpected_trans -> unknown event"
+ "~n Else: ~p"
+ "~n", [Else]),
+ {error, Else, error}.
+
+otp_6276_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_6276_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+-else. % -ifdef(MEGACO_TEST_CODE).
+
+otp_6276(suite) ->
+ [];
+otp_6276(doc) ->
+ "OTP-6276";
+otp_6276(Config) when is_list(Config) ->
+
+ ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
+
+-endif. % -ifdef(MEGACO_TEST_CODE).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+otp_6442_resend_request1(suite) ->
+ [];
+otp_6442_resend_request1(Config) when is_list(Config) ->
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp6442rreq1),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgMid = {deviceName,"mg"},
+ MgEvSeq = otp_6442_resend_request1_mg_event_sequence(MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_6442_expect(fun otp_6442_rsrq1_verify_scr_msg/1, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("send the service change reply"),
+ MgcMid = {deviceName,"mgc"},
+ ServiceChangeReply = otp_6442_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+ i("await the transport module "
+ "notify-request send_message event from MG: "
+ "ignore"),
+ ok = otp_6442_expect(fun otp_6442_rsrq1_verify_first_nr_msg/1, 5000),
+
+ i("await the transport module "
+ "notify-request resend_message event from MG: "
+ "reply"),
+ {TransId2, Cid2, TermId2} =
+ otp_6442_expect(fun otp_6442_rsrq1_verify_second_nr_msg/1, 10000),
+
+ i("wait some before issuing the notify reply"),
+ sleep(500),
+
+ i("send the notify reply"),
+ NotifyReply =
+ otp_6442_mgc_notify_reply_msg(MgcMid, TransId2, Cid2, TermId2),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyReply),
+
+ d("await the generator reply"),
+ await_completion([MgId]),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_6442_expect(Verify, Timeout) when (Timeout > 0) ->
+ T = mtime(),
+ receive
+ Msg ->
+ case (catch Verify(Msg)) of
+ {ok, Result} ->
+ d("verified after ~p msec", [mtime() - T]),
+ Result;
+ skip ->
+ otp_6442_expect(Verify, to(Timeout, T));
+ {error, Reason} ->
+ exit({verification_failed, Reason})
+ end
+ after Timeout ->
+ exit(timeout)
+ end;
+otp_6442_expect(_, _Timeout) ->
+ exit(timeout).
+
+otp_6442_rsrq1_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected service change request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_6442_rsrq1_verify_scr_msg(
+ {transport_event, {send_message, _SH, BadMsg}, _Pid}) ->
+ io:format("otp_6442_rsrq1_verify_scr_msg -> error: "
+ "~n BadMsg: ~p"
+ "~n", [BadMsg]),
+ {error, {invalid_message, BadMsg}};
+otp_6442_rsrq1_verify_scr_msg({transport_event, BadEvent, _Pid}) ->
+ io:format("otp_6442_rsrq1_verify_scr_msg -> error: "
+ "~n BadEvent: ~p"
+ "~n", [BadEvent]),
+ {error, {invalid_message, BadEvent}};
+otp_6442_rsrq1_verify_scr_msg(Msg) ->
+ io:format("otp_6442_rsrq1_verify_scr_msg -> error: "
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrq1_verify_first_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected first notify request send message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, ok};
+otp_6442_rsrq1_verify_first_nr_msg(Msg) ->
+ io:format("otp_6442_rsrq1_verify_nr_msg -> error: "
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrq1_verify_second_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ io:format("otp_6442_rsrq1_verify_second_nr_msg -> "
+ "entry when received expected message with"
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionRequest, TransReq} = Transaction,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions} = TransReq,
+ [Action] = Actions,
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId]} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_6442_rsrq1_verify_second_nr_msg(Msg) ->
+ io:format("otp_6442_rsrq1_verify_second_nr_msg -> entry when error with"
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+
+otp_6442_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms, SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_6442_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_6442_mgc_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_6442_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_6442_mgc_reply_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6442_resend_request1_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_6442_resend_request1_mg_verify_handle_connect, []}).
+-define(otp_6442_resend_request1_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_6442_resend_request1_mg_verify_service_change_rep, []}).
+-define(otp_6442_resend_request1_mg_verify_notify_rep_fun(),
+ {?MODULE, otp_6442_resend_request1_mg_verify_notify_rep, []}).
+-else.
+-define(otp_6442_resend_request1_mg_verify_handle_connect_fun(),
+ otp_6442_resend_request1_mg_verify_handle_connect_fun()).
+-define(otp_6442_resend_request1_mg_verify_service_change_rep_fun(),
+ otp_6442_resend_request1_mg_verify_service_change_rep_fun()).
+-define(otp_6442_resend_request1_mg_verify_notify_rep_fun(),
+ otp_6442_resend_request1_mg_verify_notify_rep_fun()).
+-endif.
+
+otp_6442_resend_request1_mg_event_sequence(Mid) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ ServiceChangeReq =
+ otp_6442_resend_request1_mg_service_change_request_ar(Mid, 1),
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_6442_resend_request1_mg_notify_request_ar(1, Tid, 1),
+ ConnectVerify =
+ ?otp_6442_resend_request1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_6442_resend_request1_mg_verify_service_change_rep_fun(),
+ NotifyReplyVerify =
+ ?otp_6442_resend_request1_mg_verify_notify_rep_fun(),
+ %% ConnectVerify =
+ %% otp_6442_resend_request1_mg_verify_handle_connect_fun(),
+ %% ServiceChangeReplyVerify =
+ %% otp_6442_resend_request1_mg_verify_service_change_reply_fun(),
+ %% NotifyReplyVerify = otp_6442_resend_request1_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, resend_indication, false},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request1_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_6442_resend_request1_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_6442_resend_request1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6442_resend_request1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_request1_mg_verify_handle_connect(Else) ->
+ io:format("otp_6442_resend_request1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request1_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_request1_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_request1_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_6442_resend_request1_mg_do_verify_service_change_rep(AR));
+otp_6442_resend_request1_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+otp_6442_resend_request1_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_6442_resend_request1_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request1_mg_verify_notify_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_request1_mg_verify_notify_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_request1_mg_verify_notify_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ io:format("otp_6442_resend_request1_mg_verify_notify_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp_6442_resend_request1_mg_verify_notify_rep(Else) ->
+ io:format("otp_6442_resend_request1_mg_verify_notify_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp_6442_resend_request1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_6442_resend_request1_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6442_resend_request2(suite) ->
+ [];
+otp_6442_resend_request2(Config) when is_list(Config) ->
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp6442rreq2),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ Mid = {deviceName,"mg"},
+ MgcMid = {deviceName,"mgc"},
+ MgEvSeq = otp_6442_resend_request2_mg_event_sequence(Mid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_6442_expect(fun otp_6442_rsrq2_verify_scr_msg/1, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("send the service change reply"),
+ ServiceChangeReply = otp_6442_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+ i("await the transport module notify-request send_message event from MG: ignore"),
+ ok = otp_6442_expect(fun otp_6442_rsrq2_verify_first_nr_msg/1, 5000),
+
+ i("await the transport module notify-request resend_message event from MG: reply"),
+ {TransId2, Cid2, TermId2} =
+ otp_6442_expect(fun otp_6442_rsrq2_verify_second_nr_msg/1, 10000),
+
+ i("wait some before issuing the notify reply"),
+ sleep(500),
+
+ i("send the notify reply"),
+ NotifyReply = otp_6442_mgc_notify_reply_msg(MgcMid, TransId2, Cid2, TermId2),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyReply),
+
+ d("await the generator reply"),
+ await_completion([MgId]),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_6442_rsrq2_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected service change request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_6442_rsrq2_verify_scr_msg(Msg) ->
+ io:format("otp_6442_rsrq2_verify_nr_msg -> error: "
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrq2_verify_first_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected first notify request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, ok};
+otp_6442_rsrq2_verify_first_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrq2_verify_second_nr_msg(
+ {transport_event, {resend_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected second notify request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionRequest, TransReq} = Transaction,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions} = TransReq,
+ [Action] = Actions,
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId]} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_6442_rsrq2_verify_second_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6442_resend_request2_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_6442_resend_request2_mg_verify_handle_connect, []}).
+-define(otp_6442_resend_request2_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_6442_resend_request2_mg_verify_service_change_rep, []}).
+-define(otp_6442_resend_request2_mg_verify_notify_rep_fun(),
+ {?MODULE, otp_6442_resend_request2_mg_verify_notify_rep, []}).
+-else.
+-define(otp_6442_resend_request2_mg_verify_handle_connect_fun(),
+ otp_6442_resend_request2_mg_verify_handle_connect_fun()).
+-define(otp_6442_resend_request2_mg_verify_service_change_rep_fun(),
+ otp_6442_resend_request2_mg_verify_service_change_rep_fun()).
+-define(otp_6442_resend_request2_mg_verify_notify_rep_fun(),
+ otp_6442_resend_request2_mg_verify_notify_rep_fun()).
+-endif.
+
+otp_6442_resend_request2_mg_event_sequence(Mid) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_6442_resend_request2_mg_notify_request_ar(1, Tid, 1),
+ ServiceChangeReq =
+ otp_6442_resend_request2_mg_service_change_request_ar(Mid, 1),
+ ConnectVerify =
+ ?otp_6442_resend_request2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_6442_resend_request2_mg_verify_service_change_rep_fun(),
+ NotifyReplyVerify =
+ ?otp_6442_resend_request2_mg_verify_notify_rep_fun(),
+%% ConnectVerify =
+%% otp_6442_resend_request2_mg_verify_handle_connect_fun(),
+%% ServiceChangeReplyVerify =
+%% otp_6442_resend_request2_mg_verify_service_change_reply_fun(),
+%% NotifyReplyVerify = otp_6442_resend_request2_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, resend_indication, true},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request2_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_6442_resend_request2_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_6442_resend_request2_mg_verify_handle_connect(
+ {handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6442_resend_request2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_request2_mg_verify_handle_connect(Else) ->
+ io:format("otp_6442_resend_request2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request2_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_request2_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_request2_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_6442_resend_request2_mg_do_verify_service_change_rep(AR));
+otp_6442_resend_request2_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+otp_6442_resend_request2_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_6442_resend_request2_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_request2_mg_verify_notify_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_request2_mg_verify_notify_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_request2_mg_verify_notify_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ io:format("otp_6442_resend_request2_mg_verify_notify_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp_6442_resend_request2_mg_verify_notify_rep(Else) ->
+ io:format("otp_6442_resend_request2_mg_verify_notify_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp_6442_resend_request2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_6442_resend_request2_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6442_resend_reply1(suite) ->
+ [];
+otp_6442_resend_reply1(Config) when is_list(Config) ->
+ put(sname, "TEST"),
+ put(verbosity, debug),
+ put(tc, otp6442rrep1),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ Mid = {deviceName,"mg"},
+ MgcMid = {deviceName,"mgc"},
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ MgEvSeq = otp_6442_resend_reply1_mg_event_sequence(Mid, TermId),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_6442_expect(fun otp_6442_rsrp1_verify_scr_msg/1, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("simulate MGC sending the service change reply"),
+ ServiceChangeReply = otp_6442_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+
+ i("wait some before issuing the notify request"),
+ sleep(500),
+
+ i("simulate MGC sending the notify request"),
+ NotifyRequest = otp_6442_mgc_notify_request_msg(MgcMid, TermId, 2, 1),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyRequest),
+
+ i("await the transport module first notify-reply send_message event from MG: "
+ "ignore"),
+ otp_6442_expect(fun otp_6442_rsrp1_verify_first_nr_msg/1, 5000),
+
+ i("await the transport module second notify-reply send_message event from MG: "
+ "ack"),
+ {TransId, _, _} = otp_6442_expect(fun otp_6442_rsrp1_verify_second_nr_msg/1, 10000),
+
+ i("wait some before issuing the ack"),
+ sleep(500),
+
+ i("simulate MGC sending the ack"),
+ Ack = otp_6442_mgc_ack_msg(MgcMid, TransId),
+ megaco_test_generic_transport:incomming_message(Pid, Ack),
+
+
+ d("await the generator reply"),
+ await_completion([MgId]),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_6442_rsrp1_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected service change request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_6442_rsrp1_verify_scr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrp1_verify_first_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected first notify reply message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, ok};
+otp_6442_rsrp1_verify_first_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrp1_verify_second_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected second notify reply message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionReply, TransRep} = Transaction,
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} = TransRep,
+ {actionReplies, ActReps} = TransRes,
+ [ActRep] = ActReps,
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = CmdReps} = ActRep,
+ [CmdRep] = CmdReps,
+ {notifyReply, NR} = CmdRep,
+ #'NotifyReply'{terminationID = TermId} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_6442_rsrp1_verify_second_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+
+otp_6442_mgc_notify_request_msg(Mid, TermId, TransId, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(1, [Ev]),
+ NR = cre_notifyReq([TermId], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ AR = cre_actionReq(Cid, [CR]),
+ ARs = [AR],
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+otp_6442_mgc_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6442_resend_reply1_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_6442_resend_reply1_mg_verify_handle_connect, []}).
+-define(otp_6442_resend_reply1_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_6442_resend_reply1_mg_verify_service_change_rep, []}).
+-define(otp_6442_resend_reply1_mg_verify_notify_req_fun(TermId),
+ {?MODULE, otp_6442_resend_reply1_mg_verify_notify_req, [TermId]}).
+-define(otp_6442_resend_reply1_mg_verify_ack_fun(),
+ {?MODULE, otp_6442_resend_reply1_mg_verify_ack, []}).
+-else.
+-define(otp_6442_resend_reply1_mg_verify_handle_connect_fun(),
+ otp_6442_resend_reply1_mg_verify_handle_connect_fun()).
+-define(otp_6442_resend_reply1_mg_verify_service_change_rep_fun(),
+ otp_6442_resend_reply1_mg_verify_service_change_rep_fun()).
+-define(otp_6442_resend_reply1_mg_verify_notify_req_fun(TermId),
+ otp_6442_resend_reply1_mg_verify_notify_req_fun(TermId)).
+-define(otp_6442_resend_reply1_mg_verify_ack_fun(),
+ otp_6442_resend_reply1_mg_verify_ack_fun()).
+-endif.
+
+otp_6442_resend_reply1_mg_event_sequence(Mid, TermId) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ ServiceChangeReq =
+ otp_6442_resend_reply1_mg_service_change_request_ar(Mid, 1),
+ RepTmr = #megaco_incr_timer{wait_for = 2000,
+ factor = 1,
+ max_retries = 1},
+ ConnectVerify =
+ ?otp_6442_resend_reply1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_6442_resend_reply1_mg_verify_service_change_rep_fun(),
+ NotifyReqVerify =
+ ?otp_6442_resend_reply1_mg_verify_notify_req_fun(TermId),
+ AckVerify =
+ ?otp_6442_resend_reply1_mg_verify_ack_fun(),
+%% ConnectVerify =
+%% otp_6442_resend_reply1_mg_verify_handle_connect_fun(),
+%% ServiceChangeReplyVerify =
+%% otp_6442_resend_reply1_mg_verify_service_change_reply_fun(),
+%% NotifyReqVerify =
+%% otp_6442_resend_reply1_mg_verify_notify_request_fun(TermId),
+%% AckVerify =
+%% otp_6442_resend_reply1_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, resend_indication, false},
+ {megaco_update_user_info, reply_timer, RepTmr},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply1_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_6442_resend_reply1_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_6442_resend_reply1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6442_resend_reply1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_reply1_mg_verify_handle_connect(Else) ->
+ io:format("otp_6442_resend_reply1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply1_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_reply1_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_reply1_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_6442_resend_reply1_mg_do_verify_service_change_rep(AR));
+otp_6442_resend_reply1_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+otp_6442_resend_reply1_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_6442_resend_reply1_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply1_mg_verify_notify_req_fun(TermId) ->
+ fun(Req) ->
+ otp_6442_resend_reply1_mg_verify_notify_req(Req, TermId)
+ end.
+-endif.
+
+otp_6442_resend_reply1_mg_verify_notify_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, TermId) ->
+ io:format("otp_6442_resend_reply1_mg_verify_notify_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_ack, otp_6442_resend_reply1},
+ Reply = {HandleAck,
+ [otp_6442_resend_reply1_mg_notify_reply_ar(Cid, TermId)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp_6442_resend_reply1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp_6442_resend_reply1_mg_verify_notify_req(Else, TermId) ->
+ io:format("otp_6442_resend_reply1_mg_verify_notify_request -> unknown"
+ "~n Else: ~p"
+ "~n TermId: ~p"
+ "~n", [Else, TermId]),
+ ED = otp_6442_resend_reply1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp_6442_resend_reply1_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply1_mg_verify_ack_fun() ->
+ fun(Ack) ->
+ otp_6442_resend_reply1_mg_verify_ack(Ack)
+ end.
+-endif.
+
+otp_6442_resend_reply1_mg_verify_ack(
+ {handle_trans_ack, CH, ?VERSION, ok, otp_6442_resend_reply1}) ->
+ io:format("otp_6442_resend_reply1_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_reply1_mg_verify_ack(Else) ->
+ io:format("otp_6442_resend_reply1_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp_6442_resend_reply1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_6442_resend_reply1_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6442_resend_reply2(suite) ->
+ [];
+otp_6442_resend_reply2(Config) when is_list(Config) ->
+ put(sname, "TEST"),
+ put(verbosity, debug),
+ put(tc, otp6442rrep2),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ Mid = {deviceName,"mg"},
+ MgcMid = {deviceName,"mgc"},
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ MgEvSeq = otp_6442_resend_reply2_mg_event_sequence(Mid, TermId),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_6442_expect(fun otp_6442_rsrp2_verify_scr_msg/1, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("simulate MGC sending the service change reply"),
+ ServiceChangeReply = otp_6442_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+
+ i("wait some before issuing the notify request"),
+ sleep(500),
+
+ i("simulate MGC sending the notify request"),
+ NotifyRequest = otp_6442_mgc_notify_request_msg(MgcMid, TermId, 2, 1),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyRequest),
+
+ i("await the transport module notify-reply send_message event from MG: ignore"),
+ otp_6442_expect(otp_6442_rsrp2_verify_first_nr_msg_fun(), 5000),
+
+ i("await the transport module notify-reply resend_message event from MG: ack"),
+ {TransId, _, _} =
+ otp_6442_expect(otp_6442_rsrp2_verify_second_nr_msg_fun(), 10000),
+
+ i("wait some before issuing the ack"),
+ sleep(500),
+
+ i("simulate MGC sending the ack"),
+ Ack = otp_6442_mgc_ack_msg(MgcMid, TransId),
+ megaco_test_generic_transport:incomming_message(Pid, Ack),
+
+
+ d("await the generator reply"),
+ await_completion([MgId]),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_6442_rsrp2_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected service change request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_6442_rsrp2_verify_scr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrp2_verify_first_nr_msg_fun() ->
+ fun(E) ->
+ otp_6442_rsrp2_verify_first_nr_msg(E)
+ end.
+
+otp_6442_rsrp2_verify_first_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected first notify reply message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, ok};
+otp_6442_rsrp2_verify_first_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_6442_rsrp2_verify_second_nr_msg_fun() ->
+ fun(E) ->
+ otp_6442_rsrp2_verify_second_nr_msg(E)
+ end.
+
+otp_6442_rsrp2_verify_second_nr_msg(
+ {transport_event, {resend_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected second notify reply message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionReply, TransRep} = Transaction,
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} = TransRep,
+ {actionReplies, ActReps} = TransRes,
+ [ActRep] = ActReps,
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = asn1_NOVALUE,
+ commandReply = CmdReps} = ActRep,
+ [CmdRep] = CmdReps,
+ {notifyReply, NR} = CmdRep,
+ #'NotifyReply'{terminationID = TermId} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_6442_rsrp2_verify_second_nr_msg(Msg) ->
+ d("received expected bad second notify reply message: "
+ "~n Msg: ~p", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_6442_resend_reply2_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_6442_resend_reply2_mg_verify_handle_connect, []}).
+-define(otp_6442_resend_reply2_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_6442_resend_reply2_mg_verify_service_change_rep, []}).
+-define(otp_6442_resend_reply2_mg_verify_notify_req_fun(TermId),
+ {?MODULE, otp_6442_resend_reply2_mg_verify_notify_req, [TermId]}).
+-define(otp_6442_resend_reply2_mg_verify_ack_fun(),
+ {?MODULE, otp_6442_resend_reply2_mg_verify_ack, []}).
+-else.
+-define(otp_6442_resend_reply2_mg_verify_handle_connect_fun(),
+ otp_6442_resend_reply2_mg_verify_handle_connect_fun()).
+-define(otp_6442_resend_reply2_mg_verify_service_change_rep_fun(),
+ otp_6442_resend_reply2_mg_verify_service_change_rep_fun()).
+-define(otp_6442_resend_reply2_mg_verify_notify_req_fun(TermId),
+ otp_6442_resend_reply2_mg_verify_notify_req_fun(TermId)).
+-define(otp_6442_resend_reply2_mg_verify_ack_fun(),
+ otp_6442_resend_reply2_mg_verify_ack_fun()).
+-endif.
+
+otp_6442_resend_reply2_mg_event_sequence(Mid, TermId) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ ServiceChangeReq =
+ otp_6442_resend_reply2_mg_service_change_request_ar(Mid, 1),
+ RepTmr = #megaco_incr_timer{wait_for = 2000,
+ factor = 1,
+ max_retries = 1},
+ ConnectVerify =
+ ?otp_6442_resend_reply2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_6442_resend_reply2_mg_verify_service_change_rep_fun(),
+ NotifyReqVerify =
+ ?otp_6442_resend_reply2_mg_verify_notify_req_fun(TermId),
+ AckVerify =
+ ?otp_6442_resend_reply2_mg_verify_ack_fun(),
+%% ConnectVerify =
+%% otp_6442_resend_reply2_mg_verify_handle_connect_fun(),
+%% ServiceChangeReplyVerify =
+%% otp_6442_resend_reply2_mg_verify_service_change_reply_fun(),
+%% NotifyReqVerify =
+%% otp_6442_resend_reply2_mg_verify_notify_request_fun(TermId),
+%% AckVerify =
+%% otp_6442_resend_reply2_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, resend_indication, true},
+ {megaco_update_user_info, reply_timer, RepTmr},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply2_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_6442_resend_reply2_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_6442_resend_reply2_mg_verify_handle_connect(
+ {handle_connect, CH, ?VERSION}) ->
+ io:format("otp_6442_resend_reply2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_reply2_mg_verify_handle_connect(Else) ->
+ io:format("otp_6442_resend_reply2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply2_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_6442_resend_reply2_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_6442_resend_reply2_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_6442_resend_reply2_mg_do_verify_service_change_rep(AR));
+otp_6442_resend_reply2_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+otp_6442_resend_reply2_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_6442_resend_reply2_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply2_mg_verify_notify_req_fun(TermId) ->
+ fun(Req) ->
+ otp_6442_resend_reply2_mg_verify_notify_req(Req, TermId)
+ end.
+-endif.
+
+otp_6442_resend_reply2_mg_verify_notify_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, TermId) ->
+ io:format("otp_6442_resend_reply2_mg_verify_notify_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_ack, otp_6442_resend_reply2},
+ Reply = {HandleAck,
+ [otp_6442_resend_reply2_mg_notify_reply_ar(Cid, TermId)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp_6442_resend_reply2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp_6442_resend_reply2_mg_verify_notify_req(Else, TermId) ->
+ io:format("otp_6442_resend_reply2_mg_verify_notify_req -> unknown"
+ "~n Else: ~p"
+ "~n TermId: ~p"
+ "~n", [Else, TermId]),
+ ED = otp_6442_resend_reply2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp_6442_resend_reply2_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+-ifndef(megaco_hipe_special).
+otp_6442_resend_reply2_mg_verify_ack_fun() ->
+ fun(Ack) ->
+ otp_6442_resend_reply2_mg_verify_ack(Ack)
+ end.
+-endif.
+
+otp_6442_resend_reply2_mg_verify_ack(
+ {handle_trans_ack, CH, ?VERSION, ok, otp_6442_resend_reply2}) ->
+ io:format("otp_6442_resend_reply2_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp_6442_resend_reply2_mg_verify_ack(Else) ->
+ io:format("otp_6442_resend_reply2_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp_6442_resend_reply2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+otp_6442_resend_reply2_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6865_request_and_reply_plain_extra1(suite) ->
+ [];
+otp_6865_request_and_reply_plain_extra1(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+
+ put(sname, "TEST"),
+ put(verbosity, debug),
+ put(tc, otp6865e1),
+ i("starting"),
+
+ d("start test case controller",[]),
+ ok = megaco_tc_controller:start_link(),
+
+ %% Instruct the transport module to fail all send_message
+ d("instruct transport module to provide extra info: ",[]),
+ ExtraInfo = otp_6865_extra_info,
+ ok = megaco_tc_controller:insert(extra_transport_info, ExtraInfo),
+
+ d("start proxy",[]),
+ megaco_mess_user_test:start_proxy(),
+
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+ MgcMid = ipv4_mid(),
+ UserMod = megaco_mess_user_test,
+ d("start megaco app",[]),
+ ?VERIFY(ok, application:start(megaco)),
+ UserConfig = [{user_mod, UserMod}, {send_mod, UserMod},
+ {request_timer, infinity}, {reply_timer, infinity}],
+ d("start (MG) user ~p",[MgMid]),
+ ?VERIFY(ok, megaco:start_user(MgMid, UserConfig)),
+
+ d("start (MGC) user ~p",[MgcMid]),
+ ?VERIFY(ok, megaco:start_user(MgcMid, UserConfig)),
+
+ d("get receive info for ~p",[MgMid]),
+ MgRH = user_info(MgMid, receive_handle),
+ d("get receive info for ~p",[MgcMid]),
+ MgcRH = user_info(MgcMid, receive_handle),
+ d("start transport",[]),
+ {ok, MgPid, MgSH} =
+ ?VERIFY({ok, _, _}, UserMod:start_transport(MgRH, MgcRH)),
+ PrelMgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = preliminary_mid},
+ MgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = MgcMid},
+ MgcCH = #megaco_conn_handle{local_mid = MgcMid,
+ remote_mid = MgMid},
+ d("(MG) try connect to MGC",[]),
+ ?SEND(megaco:connect(MgRH, PrelMid, MgSH, MgPid)), % Mg prel
+ d("await connect from MG",[]),
+ ?USER({connect, PrelMgCH, _V, []}, ok),
+ ?RECEIVE([{res, _, {ok, PrelMgCH}}]),
+
+ d("(MG) send service change request",[]),
+ Req = service_change_request(),
+ ?SEND(megaco:call(PrelMgCH, [Req], [])),
+
+ d("(MGC) send service change reply",[]),
+ ?USER({connect, MgcCH, _V, [ExtraInfo]}, ok), % Mgc auto
+ Rep = service_change_reply(MgcMid),
+ ?USER({request, MgcCH, _V, [[Req], ExtraInfo]}, {discard_ack, [Rep]}),
+ ?USER({connect, MgCH, _V, [ExtraInfo]}, ok), % Mg confirm
+ ?RECEIVE([{res, _, {1, {ok, [Rep], ExtraInfo}}}]),
+
+ d("get (system info) connections",[]),
+ connections([MgCH, MgcCH]),
+ d("get (~p) connections",[MgMid]),
+ ?VERIFY([MgCH], megaco:user_info(MgMid, connections)),
+ d("get (~p) connections",[MgcMid]),
+ ?VERIFY([MgcCH], megaco:user_info(MgcMid, connections)),
+
+ Reason = shutdown,
+ d("(MG) disconnect",[]),
+ ?SEND(megaco:disconnect(MgCH, Reason)),
+ ?USER({disconnect, MgCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+
+ d("(MGC) disconnect",[]),
+ ?SEND(megaco:disconnect(MgcCH, Reason)),
+ ?USER({disconnect, MgcCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgcMid)),
+
+ d("stop megaco app",[]),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+
+ d("stop test case controller",[]),
+ ok = megaco_tc_controller:stop(),
+
+ d("done",[]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_6865_request_and_reply_plain_extra2(suite) ->
+ [];
+otp_6865_request_and_reply_plain_extra2(doc) ->
+ [];
+otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp6865e2),
+ i("starting"),
+
+ d("start tc controller"),
+ ok = megaco_tc_controller:start_link(),
+
+ %% Instruct the transport module to fail all send_message
+ d("instruct transport module to provide extra info: ", []),
+ ExtraInfo = otp6865e2_extra_info,
+ ok = megaco_tc_controller:insert(extra_transport_info, ExtraInfo),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp6865e2_mgc_event_sequence(ExtraInfo, text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp6865e2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId], 60000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("stop tc controller"),
+ ok = megaco_tc_controller:stop(),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp6865e2_mgc_verify_handle_connect_fun(ExtraInfo),
+ {?MODULE, otp6865e2_mgc_verify_handle_connect, [ExtraInfo]}).
+-define(otp6865e2_mgc_verify_service_change_req_fun(Mid, ExtraInfo),
+ {?MODULE, otp6865e2_mgc_verify_service_change_req, [Mid, ExtraInfo]}).
+-define(otp6865e2_mgc_verify_notify_req_fun(Cid, ExtraInfo, RequireAck),
+ {?MODULE, otp6865e2_mgc_verify_notify_req, [Cid, ExtraInfo, RequireAck]}).
+-define(otp6865e2_mgc_verify_reply_ack_fun(ExtraInfo),
+ {?MODULE, otp6865e2_mgc_verify_reply_ack, [ExtraInfo]}).
+-define(otp6865e2_mgc_verify_notify_reply_fun(ExtraInfo),
+ {?MODULE, otp6865e2_mgc_verify_notify_reply, [ExtraInfo]}).
+-define(otp6865e2_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp6865e2_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp6865e2_mgc_verify_handle_connect_fun(ExtraInfo),
+ otp6865e2_mgc_verify_handle_connect(ExtraInfo)).
+-define(otp6865e2_mgc_verify_service_change_req_fun(Mid, ExtraInfo),
+ otp6865e2_mgc_verify_service_change_req_fun(Mid, ExtraInfo)).
+-define(otp6865e2_mgc_verify_notify_req_fun(Cid, ExtraInfo, RequireAck),
+ otp6865e2_mgc_verify_notify_req_fun(Cid, ExtraInfo, RequireAck)).
+-define(otp6865e2_mgc_verify_reply_ack_fun(ExtraInfo),
+ otp6865e2_mgc_verify_reply_ack_fun(ExtraInfo)).
+-define(otp6865e2_mgc_verify_notify_reply_fun(ExtraInfo),
+ otp6865e2_mgc_verify_notify_reply_fun(ExtraInfo)).
+-define(otp6865e2_mgc_verify_handle_disconnect_fun(),
+ fun otp6865e2_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp6865e2_mgc_event_sequence(ExtraInfo, text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify =
+ ?otp6865e2_mgc_verify_handle_connect_fun(ExtraInfo),
+ ServiceChangeReqVerify =
+ ?otp6865e2_mgc_verify_service_change_req_fun(Mid, ExtraInfo),
+ NotifyReqVerify1 =
+ ?otp6865e2_mgc_verify_notify_req_fun(1, ExtraInfo, false),
+ NotifyReqVerify2 =
+ ?otp6865e2_mgc_verify_notify_req_fun(2, ExtraInfo, true),
+ AckVerify = ?otp6865e2_mgc_verify_reply_ack_fun(ExtraInfo),
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [otp6865e2_mgc_notify_request_ar(1, Tid, 1)],
+ NotifyReplyVerify = ?otp6865e2_mgc_verify_notify_reply_fun(ExtraInfo),
+ DiscoVerify =
+ ?otp6865e2_mgc_verify_handle_disconnect_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify1},
+ {megaco_callback, handle_trans_request, NotifyReqVerify2},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_cast, NotifyReq, []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mgc_verify_handle_connect(ExtraInfo) ->
+ fun(Req) ->
+ otp6865e2_mgc_verify_handle_connect(Req, ExtraInfo)
+ end.
+-endif.
+
+otp6865e2_mgc_verify_handle_connect({handle_connect, CH, ?VERSION, ExtraInfo},
+ ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp6865e2_mgc_verify_handle_connect(Else, ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p"
+ "~n ExtraInfo: ~p"
+ "~n", [Else, ExtraInfo]),
+ {error, {Else, ExtraInfo}, ok}.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mgc_verify_service_change_req_fun(Mid, ExtraInfo) ->
+ fun(Req) ->
+ otp6865e2_mgc_verify_service_change_req(Req, Mid, ExtraInfo)
+ end.
+-endif.
+
+otp6865e2_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR], ExtraInfo}, Mid, ExtraInfo) ->
+ (catch otp6865e2_mgc_do_verify_service_change_req(AR, Mid));
+otp6865e2_mgc_verify_service_change_req(Crap, _Mid, ExtraInfo) ->
+ ED = cre_ErrDesc({Crap, ExtraInfo}),
+ ErrReply = {discard_ack, ED},
+ {error, {Crap, ExtraInfo}, ErrReply}.
+
+otp6865e2_mgc_do_verify_service_change_req(AR, Mid) ->
+ io:format("otp6865e2_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p"
+ "~n Mid: ~p"
+ "~n", [AR, Mid]),
+ CR =
+ case AR of
+ #'ActionRequest'{commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Err4 = {invalid_termination_id, Tid},
+ ED4 = cre_ErrDesc(Tid),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ case Parms of
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ AckData = [otp6865e2_mgc_service_change_reply_ar(Mid, 1)],
+ Reply = {discard_ack, AckData},
+ {ok, AR, Reply};
+ _ ->
+ Err5 = {invalid_SCP, Parms},
+ ED5 = cre_ErrDesc(Parms),
+ ErrReply5 = {discard_ack, ED5},
+ {error, Err5, ErrReply5}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mgc_verify_notify_req_fun(Cid, ExtraInfo, RequireAck) ->
+ fun(Req) ->
+ otp6865e2_mgc_verify_notify_req(Req, Cid, ExtraInfo, RequireAck)
+ end.
+-endif.
+
+otp6865e2_mgc_verify_notify_req(
+ {handle_trans_request, _, ?VERSION, [AR], ExtraInfo},
+ Cid, ExtraInfo, RequireAck) ->
+ (catch otp6865e2_mgc_do_verify_notify_req(AR, Cid, RequireAck));
+otp6865e2_mgc_verify_notify_req(Crap, _Cid, ExtraInfo, _RequireAck) ->
+ ED = cre_ErrDesc({Crap, ExtraInfo}),
+ ErrReply = {discard_ack, ED},
+ {error, {Crap, ExtraInfo}, ErrReply}.
+
+otp6865e2_mgc_do_verify_notify_req(AR, Cid, RequireAck) ->
+ io:format("otp6865e2_mgc_do_verify_notify_req -> entry with"
+ "~n AR: ~p"
+ "~n Cid: ~p"
+ "~n RequireAck: ~p"
+ "~n", [AR, Cid, RequireAck]),
+ {ContextID, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = [CmdReq]} when (CtxID == Cid) ->
+ {CtxID, CmdReq};
+ _ ->
+ Err1 = {invalid_action_request, AR},
+ ED1 = cre_ErrDesc(AR),
+ ErrReply1 = {discard_ack, ED1},
+ throw({error, Err1, ErrReply1})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ Err2 = {invalid_command_request, CR},
+ ED2 = cre_ErrDesc(CR),
+ ErrReply2 = {discard_ack, ED2},
+ throw({error, Err2, ErrReply2})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ Err3 = {invalid_command, Cmd},
+ ED3 = cre_ErrDesc(Cmd),
+ ErrReply3 = {discard_ack, ED3},
+ throw({error, Err3, ErrReply3})
+ end,
+ {Tid, OED} =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermID],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ {TermID, ObsEvsDesc};
+ _ ->
+ Err4 = {invalid_NR, NR},
+ ED4 = cre_ErrDesc(NR),
+ ErrReply4 = {discard_ack, ED4},
+ throw({error, Err4, ErrReply4})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ Err5 = {invalid_OED, OED},
+ ED5 = cre_ErrDesc(NR),
+ ErrReply5 = {discard_ack, ED5},
+ throw({error, Err5, ErrReply5})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ Replies = [otp6865e2_mgc_notify_reply_ar(ContextID, Tid)],
+ Reply =
+ case RequireAck of
+ true ->
+ {{handle_ack, otp6865e2}, Replies};
+ false ->
+ {discard_ack, Replies}
+ end,
+ {ok, AR, Reply};
+ _ ->
+ Err6 = {invalid_OE, OE},
+ ED6 = cre_ErrDesc(OE),
+ ErrReply6 = {discard_ack, ED6},
+ {error, Err6, ErrReply6}
+ end.
+
+%% Ack verification
+-ifndef(megaco_hipe_special).
+otp6865e2_mgc_verify_reply_ack_fun(ExtraInfo) ->
+ fun(M) ->
+ otp6865e2_mgc_verify_reply_ack(M, ExtraInfo)
+ end.
+-endif.
+
+otp6865e2_mgc_verify_reply_ack(
+ {handle_trans_ack, _, ?VERSION, ok, otp6865e2, ExtraInfo}, ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_reply_ack -> ok~n", []),
+ {ok, ok, ok};
+otp6865e2_mgc_verify_reply_ack(
+ {handle_trans_ack, _, ?VERSION, AS, AD, ExtraInfo1} = Crap, ExtraInfo2) ->
+ io:format("otp6865e2_mgc_verify_reply_ack -> incorrect ack-status:"
+ "~n AS: ~p"
+ "~n AD: ~p"
+ "~n ExtraInfo1: ~p"
+ "~n ExtraInfo2: ~p"
+ "~n", [AS, AD, ExtraInfo1, ExtraInfo2]),
+ ED = cre_ErrDesc({invalid_ack_status,
+ {AS, AD, ExtraInfo1, ExtraInfo2}}),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply};
+otp6865e2_mgc_verify_reply_ack(Crap, ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_reply_ack -> invalid ack:"
+ "~n Crap: ~p"
+ "~n ExtraInfo: ~p"
+ "~n", [Crap, ExtraInfo]),
+ ED = cre_ErrDesc({Crap, ExtraInfo}),
+ ErrReply = {discard_ack, ED},
+ {error, Crap, ErrReply}.
+
+
+%% Notify reply verification
+-ifndef(megaco_hipe_special).
+otp6865e2_mgc_verify_notify_reply_fun(ExtraInfo) ->
+ fun(Rep) ->
+ otp6865e2_mgc_verify_notify_reply(Rep, ExtraInfo)
+ end.
+-endif.
+
+otp6865e2_mgc_verify_notify_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _, ExtraInfo}, ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p"
+ "~n ExtraInfo: ~p"
+ "~n", [AR, ExtraInfo]),
+ {ok, AR, ok};
+otp6865e2_mgc_verify_notify_reply(Else, ExtraInfo) ->
+ io:format("otp6865e2_mgc_verify_notify_reply -> received unknown event"
+ "~n Else: ~p"
+ "~n ExtraInfo: ~p"
+ "~n", [Else, ExtraInfo]),
+ {error, {Else, ExtraInfo}, ok}.
+
+
+%% Disconnect verification
+otp6865e2_mgc_verify_handle_disconnect(
+ {handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("otp6865e2_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+otp6865e2_mgc_verify_handle_disconnect(Else) ->
+ io:format("otp6865e2_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp6865e2_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+otp6865e2_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp6865e2_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp6865e2_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp6865e2_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp6865e2_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, otp6865e2_mg_verify_service_change_rep_msg, []}).
+-define(otp6865e2_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId, AckRequired),
+ {?MODULE, otp6865e2_mg_verify_notify_rep_msg, [TermId, TransId, ReqId, CtxId, AckRequired]}).
+-define(otp6865e2_mg_verify_notify_req_msg_fun(),
+ {?MODULE, otp6865e2_mg_verify_notify_req_msg, []}).
+-else.
+-define(otp6865e2_mg_decode_msg_fun(Mod, Conf),
+ otp6865e2_mg_decode_msg_fun(Mod, Conf)).
+-define(otp6865e2_mg_encode_msg_fun(Mod, Conf),
+ otp6865e2_mg_encode_msg_fun(Mod, Conf)).
+-define(otp6865e2_mg_verify_service_change_rep_msg_fun(),
+ otp6865e2_mg_verify_service_change_rep_msg_fun()).
+-define(otp6865e2_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId, AckRequired),
+ otp6865e2_mg_verify_notify_rep_msg_fun(TermId, TransId, ReqId, CtxId, AckRequired)).
+-define(otp6865e2_mg_verify_notify_req_msg_fun(),
+ otp6865e2_mg_verify_notify_req_msg_fun()).
+-endif.
+
+otp6865e2_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?otp6865e2_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp6865e2_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = otp6865e2_mg_service_change_request_msg(Mid, 1, 0),
+ ScrVerifyFun = ?otp6865e2_mg_verify_service_change_rep_msg_fun(),
+ TermId1 = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TermId2 = #megaco_term_id{id = ["00000000","00000000","10010010"]},
+ NotifyReq1 =
+ otp6865e2_mg_notify_request_msg(Mid, TermId1, 2, 1, 1),
+ NrVerifyFun1 =
+ ?otp6865e2_mg_verify_notify_rep_msg_fun(TermId1, 2, 1, 1, false),
+ NotifyReq2 =
+ otp6865e2_mg_notify_request_msg(Mid, TermId2, 3, 2, 2),
+ NrVerifyFun2 =
+ ?otp6865e2_mg_verify_notify_rep_msg_fun(TermId2, 3, 2, 2, true),
+ TransAck = otp6865e2_mg_trans_ack_msg(Mid, 3),
+ NotifyReqVerifyFun = ?otp6865e2_mg_verify_notify_req_msg_fun(),
+ NotifyReply = otp6865e2_mg_notify_reply_msg(Mid, 1, 0, TermId1),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ScrVerifyFun, 10000}},
+
+ %% the original setting for reply timer is 2000
+ {send, "notify request 1", NotifyReq1},
+ {expect_receive, "notify-reply 1", {NrVerifyFun1, 2500}},
+ {sleep, 1000},
+ {send, "notify request 2", NotifyReq2},
+ {expect_receive, "notify-reply 2", {NrVerifyFun2, 2500}},
+ {sleep, 100},
+ {send, "transacktion-ack", TransAck},
+ {expect_receive, "notify-request", {NotifyReqVerifyFun, 2500}},
+ {sleep, 100},
+ {send, "notify-reply", NotifyReply},
+
+ {expect_nothing, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mg_verify_service_change_rep_msg_fun() ->
+ fun(Msg) ->
+ (catch otp6865e2_mg_verify_service_change_rep_msg(Msg))
+ end.
+-endif.
+
+otp6865e2_mg_verify_service_change_rep_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ Body =
+ case Mess of
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ SCRes =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = ServChRes} ->
+ ServChRes;
+ _ ->
+ throw({error, {invalid_serviceChangeReply, SCR}})
+ end,
+ SCRP =
+ case SCRes of
+ {serviceChangeResParms, Parms} ->
+ Parms;
+ _ ->
+ throw({error, {invalid_serviceChangeResult, SCRes}})
+ end,
+ case SCRP of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeResParms, SCRP}}
+ end;
+otp6865e2_mg_verify_service_change_rep_msg(Crap) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mg_verify_notify_rep_msg_fun(TermId, TransId, Rid, Cid,
+ AckRequired) ->
+ fun(Msg) ->
+ (catch otp6865e2_mg_verify_notify_rep_msg(Msg,
+ TermId, TransId,
+ Rid, Cid,
+ AckRequired))
+ end.
+-endif.
+
+otp6865e2_mg_verify_notify_rep_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid, AckRequired) ->
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> "
+ "~n Body: ~p"
+ "~n", [Body]),
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> "
+ "~n Trans: ~p"
+ "~n", [Trans]),
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> "
+ "~n TR: ~p"
+ "~n", [TR]),
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = TransRes} when (AckRequired == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = 'NULL',
+ transactionResult = TransRes} when (AckRequired == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> "
+ "~n TRes: ~p"
+ "~n", [TRes]),
+ AR =
+ case TRes of
+ {actionReplies, [ActRes]} ->
+ ActRes;
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_rep_msg -> "
+ "~n AR: ~p"
+ "~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ throw({error, {invalid_actionReplies, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_notifyReply, NR}}
+ end;
+otp6865e2_mg_verify_notify_rep_msg(Crap, _TermId, _TransId, _Rid, _Cid, _AckRequired) ->
+ {error, {invalid_message, Crap}}.
+
+-ifndef(megaco_hipe_special).
+otp6865e2_mg_verify_notify_req_msg_fun() ->
+ fun(M) ->
+ otp6865e2_mg_verify_notify_req_msg(M)
+ end.
+-endif.
+
+otp6865e2_mg_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp6865e2_mg_verify_notify_req_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n Body: ~p"
+ "~n", [Body]),
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n Trans: ~p"
+ "~n", [Trans]),
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n TR: ~p"
+ "~n", [TR]),
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n AR: ~p"
+ "~n", [AR]),
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n CR: ~p"
+ "~n", [CR]),
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequests, CR}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n Cmd: ~p"
+ "~n", [Cmd]),
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n NR: ~p"
+ "~n", [NR]),
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [_TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n OED: ~p"
+ "~n", [OED]),
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ io:format("otp6865e2_mg_verify_notify_req_msg -> "
+ "~n OE: ~p"
+ "~n", [OE]),
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ io:format("otp6865e2_mg_verify_notify_req_msg -> verifyed"
+ "~n", []),
+ {ok, M};
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+otp6865e2_mg_verify_notify_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+otp6865e2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp6865e2_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp6865e2_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp6865e2_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp6865e2_mg_notify_request_msg(Mid, TermId, TransId, Rid, Cid) ->
+ AR = otp6865e2_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp6865e2_mg_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = {actionReplies, [AR]},
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp6865e2_mg_trans_ack_msg(Mid, TransId) ->
+ TR = cre_transRespAck(cre_transAck(TransId)),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7189(suite) ->
+ [];
+otp_7189(doc) ->
+ "...";
+otp_7189(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_7189),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp_7189_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp_7189_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId], 60000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_7189_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp_7189_mgc_verify_handle_connect, []}).
+-define(otp_7189_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp_7189_mgc_verify_service_change_req, [Mid]}).
+-define(otp_7189_mgc_verify_handle_trans_rep_fun(),
+ {?MODULE, otp_7189_mgc_verify_handle_trans_rep, []}).
+-define(otp_7189_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp_7189_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp_7189_mgc_verify_handle_connect_fun(),
+ otp_7189_mgc_verify_handle_connect_fun()).
+-define(otp_7189_mgc_verify_service_change_req_fun(Mid),
+ otp_7189_mgc_verify_service_change_req_fun(Mid)).
+-define(otp_7189_mgc_verify_handle_trans_rep_fun(),
+ otp_7189_mgc_verify_handle_trans_rep_fun()).
+-define(otp_7189_mgc_verify_handle_disconnect_fun(),
+ fun otp_7189_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp_7189_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [otp_7189_mgc_notify_req_ar(1, Tid, 1)],
+ ConnectVerify = ?otp_7189_mgc_verify_handle_connect_fun(),
+ ScrVerify = ?otp_7189_mgc_verify_service_change_req_fun(Mid),
+ TransReplyVerify = ?otp_7189_mgc_verify_handle_trans_rep_fun(),
+ PendingCountersVerify1 =
+ fun([{Counter, 1}]) ->
+ io:format("received expected recv pending counter:"
+ "~n Counter: ~p"
+ "~n", [Counter]),
+ ok;
+ (BadCounters) ->
+ io:format("ERROR: "
+ "received unexpected number of "
+ "recv pending counters "
+ "(expected one with counter value 1):"
+ "~n BadCounters: ~p"
+ "~n", [BadCounters]),
+ {error, {invalid_pending_counters, BadCounters}}
+ end,
+ PendingCountersVerify2 =
+ fun([]) ->
+ io:format("received expected number of recv pending counters (none)"
+ "~n", []),
+ ok;
+ (BadCounters) ->
+ io:format("ERROR: "
+ "received unexpected number of "
+ "recv pending counters "
+ "(expected none):"
+ "~n BadCounters: ~p"
+ "~n", [BadCounters]),
+ {error, {invalid_pending_counters, BadCounters}}
+ end,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, recv_pending_limit, 10},
+
+ {megaco_update_user_info, long_request_timer, timer:seconds(10)},
+ {megaco_user_info, all},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request, ScrVerify},
+ {sleep, 500},
+ {megaco_cast, NotifyReq, []},
+
+ %% Wait for 5 seconds to make sure we are on track
+ {megaco_callback, nocall, timer:seconds(5)},
+ {megaco_system_info, recv_pending_counters, PendingCountersVerify1},
+
+ %% Now wait for the timeout to hit
+ {megaco_callback, handle_trans_reply, TransReplyVerify},
+ {megaco_system_info, recv_pending_counters, PendingCountersVerify2},
+
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_7189_mgc_verify_handle_connect_fun() ->
+ fun(M) ->
+ otp_7189_mgc_verify_handle_connect(M)
+ end.
+-endif.
+
+otp_7189_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+otp_7189_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+otp_7189_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ otp_7189_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+otp_7189_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("otp_7189_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp_7189_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp_7189_err_desc(Parms),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp_7189_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp_7189_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp_7189_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp_7189_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp_7189_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("otp_7189_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp_7189_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp_7189_mgc_notify_req_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_7189_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+-ifndef(megaco_hipe_special).
+otp_7189_mgc_verify_handle_trans_rep_fun() ->
+ fun(Event) ->
+ (catch otp_7189_mgc_verify_handle_trans_rep(Event))
+ end.
+-endif.
+
+otp_7189_mgc_verify_handle_trans_rep(
+ {handle_trans_reply, CH, ?VERSION, {error, timeout} = Error, _}) ->
+ io:format("otp_6275_mgc_verify_trans_rep -> expected error"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, Error, error};
+otp_7189_mgc_verify_handle_trans_rep(
+ {handle_trans_reply, _CH, ?VERSION, Error, _}) ->
+ io:format("otp_6275_mgc_verify_handle_trans_rep -> unexpected error"
+ "~n Error: ~p"
+ "~n", [Error]),
+ {error, Error, error};
+otp_7189_mgc_verify_handle_trans_rep(Else) ->
+ io:format("otp_6275_mg_verify_handle_trans_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, error}.
+
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_7189_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_7189_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_7189_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, otp_7189_mg_verify_service_change_rep_msg, []}).
+-define(otp_7189_mg_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ {?MODULE, otp_7189_mg_verify_notify_req_msg, [TermId, TransId, ReqId, CtxId]}).
+-else.
+-define(otp_7189_mg_decode_msg_fun(Mod, Conf),
+ otp_7189_mg_decode_msg_fun(Mod, Conf)).
+-define(otp_7189_mg_encode_msg_fun(Mod, Conf),
+ otp_7189_mg_encode_msg_fun(Mod, Conf)).
+-define(otp_7189_mg_verify_service_change_rep_msg_fun(),
+ otp_7189_mg_verify_service_change_rep_msg_fun()).
+-define(otp_7189_mg_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ otp_7189_mg_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId)).
+-endif.
+
+otp_7189_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_7189_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_7189_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = otp_7189_mg_service_change_request_msg(Mid, 1, 0),
+ TermId =
+ #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ TransId = 1,
+ ReqId = 1,
+ CtxId = 1,
+ Pending = otp_7189_mg_trans_pending_msg(Mid, TransId),
+ ServiceChangeReplyVerifyFun =
+ ?otp_7189_mg_verify_service_change_rep_msg_fun(),
+ NotifyReqVerify = ?otp_7189_mg_verify_notify_req_msg_fun(TermId, TransId, ReqId, CtxId),
+ EvSeq = [
+ {debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ServiceChangeReplyVerifyFun, 2000}},
+ {expect_receive, "notify request", {NotifyReqVerify, 2000}},
+ {sleep, 100},
+ {send, "pending", Pending},
+ {expect_closed, timer:seconds(120)},
+ disconnect
+ ],
+ EvSeq.
+
+otp_7189_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+
+otp_7189_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+
+otp_7189_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_7189_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp_7189_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+-ifndef(megaco_hipe_special).
+otp_7189_mg_verify_service_change_rep_msg_fun() ->
+ fun(M) ->
+ otp_7189_mg_verify_service_change_rep_msg(M)
+ end.
+-endif.
+
+otp_7189_mg_verify_service_change_rep_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_7189_mg_verify_service_change_rep_msg -> "
+ "ok so far~n",[]),
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionReply, TR} = Trans,
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res} = TR,
+ {actionReplies, [AR]} = Res,
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CR]} = AR,
+ {serviceChangeReply, SCR} = CR,
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = SCRes} = SCR,
+ {serviceChangeResParms, SCRP} = SCRes,
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} = SCRP,
+ {ok, M};
+otp_7189_mg_verify_service_change_rep_msg(M) ->
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+otp_7189_mg_verify_notify_req_msg_fun(TermId, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch otp_7189_mg_verify_notify_req_msg(Msg,
+ TermId,
+ TransId, Rid, Cid))
+ end.
+-endif.
+
+otp_7189_mg_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M,
+ TermId, TransId, Rid, Cid) ->
+ io:format("otp_7189_mgc_verify_notify_req_msg -> entry with"
+ "~n M: ~p"
+ "~n TermId: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermId, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR, TransId}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequests, CR}})
+ end,
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+otp_7189_mg_verify_notify_req_msg(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+otp_7189_mg_trans_pending_msg(Mid, TransId) ->
+ TP = #'TransactionPending'{transactionId = TransId},
+ Body = {transactions, [{transactionPending, TP}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+otp_7189_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+otp_7259(suite) ->
+ [];
+otp_7259(doc) ->
+ ["This is a variant of ticket OTP-6442"];
+otp_7259(Config) when is_list(Config) ->
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp7259rr),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgMid = {deviceName,"mg"},
+ MgEvSeq = otp_7259_mg_event_sequence(MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_7259_expect(fun otp_7259_verify_scr_msg/1, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("send the service change reply"),
+ MgcMid = {deviceName,"mgc"},
+ ServiceChangeReply = otp_7259_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+ i("await the transport module "
+ "notify-request send_message event from MG: "
+ "ignore"),
+ ok = otp_7259_expect(fun otp_7259_verify_first_nr_msg/1, 5000),
+
+ i("await the transport module "
+ "notify-request resend_message event from MG: "
+ "reply"),
+ {TransId2, Cid2, TermId2} =
+ otp_7259_expect(fun otp_7259_verify_second_nr_msg/1, 10000),
+
+ i("wait some before issuing the notify reply"),
+ sleep(500),
+
+ i("send the notify reply"),
+ NotifyReply =
+ otp_7259_mgc_notify_reply_msg(MgcMid, TransId2, Cid2, TermId2),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyReply),
+
+ d("[MG] await the generator reply"),
+ await_completion([MgId], 5000),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_7259_expect(Verify, Timeout) when (Timeout > 0) ->
+ T = mtime(),
+ receive
+ Msg ->
+ case (catch Verify(Msg)) of
+ {ok, Result} ->
+ d("verified after ~p msec", [mtime() - T]),
+ Result;
+ skip ->
+ otp_7259_expect(Verify, to(Timeout, T));
+ {error, Reason} ->
+ exit({verification_failed, Reason})
+ end
+ after Timeout ->
+ exit(timeout)
+ end;
+otp_7259_expect(_, _Timeout) ->
+ exit(timeout).
+
+otp_7259_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg, Resend}}, Pid})
+ when is_record(Msg, 'MegacoMessage') andalso ((Resend =:= true) orelse (Resend =:= false)) ->
+ d("received expected service change request message: "
+ "~n Msg: ~p"
+ "~n Resend: ~p", [Msg, Resend]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_7259_verify_scr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_7259_verify_first_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg, Resend}}, Pid})
+ when is_record(Msg, 'MegacoMessage') andalso ((Resend =:= true) orelse (Resend =:= false)) ->
+ d("received expected first notify request send message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, ok};
+otp_7259_verify_first_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+otp_7259_verify_second_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg, Resend}}, Pid})
+ when is_record(Msg, 'MegacoMessage') andalso ((Resend =:= true) orelse (Resend =:= false)) ->
+ d("received expected second notify request send message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionRequest, TransReq} = Transaction,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions} = TransReq,
+ [Action] = Actions,
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId]} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_7259_verify_second_nr_msg(Msg) ->
+ {error, {invalid_message, Msg}}.
+
+
+otp_7259_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms, SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_7259_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_7259_mgc_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_7259_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_7259_mgc_reply_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_7259_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_7259_mg_verify_handle_connect, []}).
+-define(otp_7259_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_7259_mg_verify_service_change_rep, []}).
+-define(otp_7259_mg_verify_notify_rep_fun(),
+ {?MODULE, otp_7259_mg_verify_notify_rep, []}).
+-else.
+-define(otp_7259_mg_verify_handle_connect_fun(),
+ otp_7259_mg_verify_handle_connect_fun()).
+-define(otp_7259_mg_verify_service_change_rep_fun(),
+ otp_7259_mg_verify_service_change_rep_fun()).
+-define(otp_7259_mg_verify_notify_rep_fun(),
+ otp_7259_mg_verify_notify_rep_fun()).
+-endif.
+
+otp_7259_mg_event_sequence(Mid) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ ServiceChangeReq =
+ otp_7259_mg_service_change_request_ar(Mid, 1),
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_7259_mg_notify_request_ar(1, Tid, 1),
+ ConnectVerify =
+ ?otp_7259_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_7259_mg_verify_service_change_rep_fun(),
+ NotifyReplyVerify =
+ ?otp_7259_mg_verify_notify_rep_fun(),
+ EvSeq = [
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, resend_indication, flag},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_7259_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_7259_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_7259_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_7259_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_7259_mg_verify_handle_connect(Else) ->
+ io:format("otp_7259_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+otp_7259_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_7259_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_7259_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_7259_mg_do_verify_service_change_rep(AR));
+otp_7259_mg_verify_service_change_rep(Crap) ->
+ {error, Crap, ok}.
+
+otp_7259_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_7259_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_7259_mg_verify_notify_rep_fun() ->
+ fun(Rep) ->
+ otp_7259_mg_verify_notify_rep(Rep)
+ end.
+-endif.
+
+otp_7259_mg_verify_notify_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ io:format("otp_7259_mg_verify_notify_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp_7259_mg_verify_notify_rep(Else) ->
+ io:format("otp_7259_mg_verify_notify_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp_7259_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_7259_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7713(suite) ->
+ [];
+otp_7713(doc) ->
+ [];
+otp_7713(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp7713),
+ i("starting"),
+
+ d("start proxy",[]),
+ megaco_mess_user_test:start_proxy(),
+
+ Extra = otp7713_extra,
+ PrelMid = preliminary_mid,
+ MgMid = ipv4_mid(4711),
+ MgcMid = ipv4_mid(),
+ UserMod = megaco_mess_user_test,
+ d("start megaco app",[]),
+ ?VERIFY(ok, application:start(megaco)),
+ UserConfig = [{user_mod, UserMod}, {send_mod, UserMod},
+ {request_timer, infinity}, {reply_timer, infinity}],
+ d("start (MG) user ~p",[MgMid]),
+ ?VERIFY(ok, megaco:start_user(MgMid, UserConfig)),
+
+ d("start (MGC) user ~p",[MgcMid]),
+ ?VERIFY(ok, megaco:start_user(MgcMid, UserConfig)),
+
+ d("get receive info for ~p",[MgMid]),
+ MgRH = user_info(MgMid, receive_handle),
+ d("get receive info for ~p",[MgcMid]),
+ MgcRH = user_info(MgcMid, receive_handle),
+ d("start transport",[]),
+ {ok, MgPid, MgSH} =
+ ?VERIFY({ok, _, _}, UserMod:start_transport(MgRH, MgcRH)),
+ PrelMgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = preliminary_mid},
+ MgCH = #megaco_conn_handle{local_mid = MgMid,
+ remote_mid = MgcMid},
+ MgcCH = #megaco_conn_handle{local_mid = MgcMid,
+ remote_mid = MgMid},
+ d("(MG) try connect to MGC",[]),
+ ?SEND(megaco:connect(MgRH, PrelMid, MgSH, MgPid, Extra)), % Mg prel
+ d("await connect from MG", []),
+ ?USER({connect, PrelMgCH, _V, [Extra]}, ok),
+ ?RECEIVE([{res, _, {ok, PrelMgCH}}]),
+
+ d("(MG) send service change request",[]),
+ Req = service_change_request(),
+ ?SEND(megaco:call(PrelMgCH, [Req], [])),
+
+ d("(MGC) send service change reply",[]),
+ ?USER({connect, MgcCH, _V, []}, ok), % Mgc auto
+ Rep = service_change_reply(MgcMid),
+ ?USER({request, MgcCH, _V, [[Req]]}, {discard_ack, [Rep]}),
+ ?USER({connect, MgCH, _V, []}, ok), % Mg confirm
+ ?RECEIVE([{res, _, {1, {ok, [Rep]}}}]),
+
+ d("get (system info) connections",[]),
+ connections([MgCH, MgcCH]),
+ d("get (~p) connections",[MgMid]),
+ ?VERIFY([MgCH], megaco:user_info(MgMid, connections)),
+ d("get (~p) connections",[MgcMid]),
+ ?VERIFY([MgcCH], megaco:user_info(MgcMid, connections)),
+
+ Reason = shutdown,
+ d("(MG) disconnect",[]),
+ ?SEND(megaco:disconnect(MgCH, Reason)),
+ ?USER({disconnect, MgCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgMid)),
+
+ d("(MGC) disconnect",[]),
+ ?SEND(megaco:disconnect(MgcCH, Reason)),
+ ?USER({disconnect, MgcCH, _V, [{user_disconnect, Reason}]}, ok),
+ ?RECEIVE([{res, _, ok}]),
+ ?VERIFY(ok, megaco:stop_user(MgcMid)),
+
+ d("stop megaco app",[]),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+
+ d("done",[]),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_8183_request1(suite) ->
+ [];
+otp_8183_request1(Config) when is_list(Config) ->
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp8183r1),
+ i("starting"),
+
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
+
+ d("[MG] start the simulator "),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgMid = {deviceName,"mg"},
+ MgEvSeq = otp_8183_r1_mg_event_sequence(MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ i("await the transport module service change send_message event"),
+ Pid = otp_8183_expect(fun(Ev) -> otp_8183_r1_verify_scr_msg(Ev) end, 5000),
+
+ i("wait some before issuing the service change reply"),
+ sleep(500),
+
+ i("send the service change reply"),
+ MgcMid = {deviceName,"mgc"},
+ ServiceChangeReply = otp_8183_r1_mgc_service_change_reply_msg(MgcMid, 1, 1),
+ megaco_test_generic_transport:incomming_message(Pid, ServiceChangeReply),
+
+ i("await the transport module "
+ "notify-request send_message event from MG: "
+ "ignore"),
+ {TransId2, Cid2, TermId2} =
+ otp_8183_expect(fun(Ev) -> otp_8183_r1_verify_nr_msg(Ev) end, 5000),
+
+ i("wait some before issuing the notify reply (twice)"),
+ sleep(500),
+
+ i("send the notify reply, twice times"),
+ NotifyReply =
+ otp_8183_r1_mgc_notify_reply_msg(MgcMid, TransId2, Cid2, TermId2),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyReply),
+ megaco_test_generic_transport:incomming_message(Pid, NotifyReply),
+
+ d("await the generator reply"),
+ await_completion([MgId]),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+otp_8183_expect(Verify, Timeout) when (Timeout > 0) ->
+ T = mtime(),
+ receive
+ Msg ->
+ case (catch Verify(Msg)) of
+ {ok, Result} ->
+ d("verified after ~p msec", [mtime() - T]),
+ Result;
+ skip ->
+ otp_8183_expect(Verify, to(Timeout, T));
+ {error, Reason} ->
+ exit({verification_failed, Reason})
+ end
+ after Timeout ->
+ exit(timeout)
+ end;
+otp_8183_expect(_, _Timeout) ->
+ exit(timeout).
+
+otp_8183_r1_verify_scr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ d("received expected service change request message: "
+ "~n Msg: ~p", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ {ok, Pid};
+otp_8183_r1_verify_scr_msg(
+ {transport_event, {send_message, _SH, BadMsg}, _Pid}) ->
+ io:format("otp_8183_r1_verify_scr_msg -> error: "
+ "~n BadMsg: ~p"
+ "~n", [BadMsg]),
+ {error, {invalid_message, BadMsg}};
+otp_8183_r1_verify_scr_msg({transport_event, BadEvent, _Pid}) ->
+ io:format("otp_8183_r1_verify_scr_msg -> error: "
+ "~n BadEvent: ~p"
+ "~n", [BadEvent]),
+ {error, {invalid_message, BadEvent}};
+otp_8183_r1_verify_scr_msg(Msg) ->
+ io:format("otp_8183_r1_verify_scr_msg -> error: "
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+otp_8183_r1_verify_nr_msg(
+ {transport_event, {send_message, _SH, {message, Msg}}, Pid})
+ when is_record(Msg, 'MegacoMessage') ->
+ io:format("otp_8183_r1_verify_nr_msg -> "
+ "entry when received expected message with"
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ Reply = ok,
+ Pid ! {transport_reply, Reply, self()},
+ #'MegacoMessage'{mess = Mess} = Msg,
+ #'Message'{mId = _Mid,
+ messageBody = Body} = Mess,
+ {transactions, Transactions} = Body,
+ [Transaction] = Transactions,
+ {transactionRequest, TransReq} = Transaction,
+ #'TransactionRequest'{transactionId = TransId,
+ actions = Actions} = TransReq,
+ [Action] = Actions,
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CmdReqs} = Action,
+ [CmdReq] = CmdReqs,
+ #'CommandRequest'{command = Cmd} = CmdReq,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [TermId]} = NR,
+ {ok, {TransId, Cid, TermId}};
+otp_8183_r1_verify_nr_msg(Msg) ->
+ io:format("otp_8183_r1_verify_nr_msg -> entry when error with"
+ "~n Msg: ~p"
+ "~n", [Msg]),
+ {error, {invalid_message, Msg}}.
+
+otp_8183_r1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms, SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ otp_8183_r1_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_8183_r1_mgc_notify_reply_msg(Mid, TransId, Cid, TermId) ->
+ NR = #'NotifyReply'{terminationID = [TermId]},
+ CR = {notifyReply, NR},
+ otp_8183_r1_mgc_reply_msg(Mid, TransId, CR, Cid).
+
+otp_8183_r1_mgc_reply_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_8183_r1_mg_verify_handle_connect_fun(),
+ {?MODULE, otp_8183_r1_mg_verify_handle_connect, []}).
+-define(otp_8183_r1_mg_verify_service_change_rep_fun(),
+ {?MODULE, otp_8183_r1_mg_verify_service_change_rep, []}).
+-define(otp_8183_r1_mg_verify_notify_rep_fun(Nr
+ {?MODULE, otp_8183_r1_mg_verify_notify_rep, [Nr).
+-else.
+-define(otp_8183_r1_mg_verify_handle_connect_fun(),
+ otp_8183_r1_mg_verify_handle_connect_fun()).
+-define(otp_8183_r1_mg_verify_service_change_rep_fun(),
+ otp_8183_r1_mg_verify_service_change_rep_fun()).
+-define(otp_8183_r1_mg_verify_notify_rep_fun(Nr),
+ otp_8183_r1_mg_verify_notify_rep_fun(Nr)).
+-endif.
+
+otp_8183_r1_mg_event_sequence(Mid) ->
+ RI = [
+ {port, self()}, % This is just a trick to get my pid to the transport module
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_test_generic_transport}
+ ],
+ ServiceChangeReq =
+ otp_8183_r1_mg_service_change_request_ar(Mid, 1),
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_8183_r1_mg_notify_request_ar(1, Tid, 1),
+ ConnectVerify =
+ ?otp_8183_r1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify =
+ ?otp_8183_r1_mg_verify_service_change_rep_fun(),
+ NotifyReplyVerify =
+ fun(Nr) ->
+ ?otp_8183_r1_mg_verify_notify_rep_fun(Nr)
+ end,
+ EvSeq = [
+ {debug, true}, % false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], [{request_keep_alive_timeout, 5000}]},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify(1)},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify(2)},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_8183_r1_mg_verify_handle_connect_fun() ->
+ fun(Ev) ->
+ otp_8183_r1_mg_verify_handle_connect(Ev)
+ end.
+-endif.
+
+otp_8183_r1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp_8183_r1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp_8183_r1_mg_verify_handle_connect(Else) ->
+ io:format("otp_8183_r1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+otp_8183_r1_mg_verify_service_change_rep_fun() ->
+ fun(Rep) ->
+ otp_8183_r1_mg_verify_service_change_rep(Rep)
+ end.
+-endif.
+
+otp_8183_r1_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ (catch otp_8183_r1_mg_do_verify_service_change_rep(AR));
+otp_8183_r1_mg_verify_service_change_rep(Crap) ->
+ io:format("otp_8183_r1_mg_verify_service_change_rep -> crap"
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+otp_8183_r1_mg_do_verify_service_change_rep(AR) ->
+ io:format("otp_8183_r1_mg_do_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+-ifndef(megaco_hipe_special).
+otp_8183_r1_mg_verify_notify_rep_fun(Nr) ->
+ fun(Rep) ->
+ otp_8183_r1_mg_verify_notify_rep(Nr, Rep)
+ end.
+-endif.
+
+otp_8183_r1_mg_verify_notify_rep(Nr,
+ {handle_trans_reply, _CH, ?VERSION, {ok, Nr, [AR]}, _}) ->
+ io:format("otp_8183_r1_mg_verify_notify_rep -> ok"
+ "~n Nr: ~p"
+ "~n AR: ~p"
+ "~n", [Nr, AR]),
+ {ok, AR, ok};
+otp_8183_r1_mg_verify_notify_rep(Nr, Else) ->
+ io:format("otp_8183_r1_mg_verify_notify_rep -> unknown"
+ "~n Nr: ~p"
+ "~n Else: ~p"
+ "~n", [Nr, Else]),
+ {error, Else, ok}.
+
+
+otp_8183_r1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_8183_r1_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp8212_scr(MidStr) ->
+ Msg = "!/1 " ++ MidStr ++ " T=19731{C=-{SC=ROOT{SV{MT=RS,RE=\"901\"}}}}",
+ list_to_binary(Msg).
+
+otp_8212(suite) ->
+ [];
+otp_8212(doc) ->
+ [];
+otp_8212(Config) when is_list(Config) ->
+ %% ?ACQUIRE_NODES(1, Config),
+
+ put(verbosity, debug),
+ put(sname, "TEST"),
+ put(tc, otp8212),
+ i("starting"),
+
+ Extra = otp8212_extra,
+ NoMid = preliminary_mid,
+ LocalMid = {deviceName, "MGC"},
+ RemoteMidStr1 = "bgf1",
+ RemoteMid1 = {deviceName, RemoteMidStr1},
+ RemoteMidStr2 = "bgf2",
+ RemoteMid2 = {deviceName, RemoteMidStr2},
+ UserMod = megaco_mess_otp8212_test,
+
+ d("set megaco trace level to max",[]),
+ megaco:enable_trace(max, io),
+
+ d("start megaco app",[]),
+ ?VERIFY(ok, application:start(megaco)),
+
+ d("start local user (MGC) ~p", [LocalMid]),
+ UserConfig = [{user_mod, UserMod}, {send_mod, UserMod}],
+ ?VERIFY(ok, megaco:start_user(LocalMid, UserConfig)),
+
+ d("get (MGC) receive info for ~p", [LocalMid]),
+ RH0 = user_info(LocalMid, receive_handle),
+ RH = RH0#megaco_receive_handle{encoding_mod = megaco_mess_otp8212_test,
+ encoding_config = []},
+
+ d("do a pre-connect for ~p", [LocalMid]),
+ ControlPid = self(),
+ SendHandle = {RH, ControlPid, RemoteMidStr1, RemoteMidStr2},
+ ?VERIFY({ok, _}, megaco:connect(RH, NoMid, SendHandle, ControlPid)),
+
+ d("simulate incomming service change message from ~p",
+ [RemoteMidStr1]),
+ ?VERIFY(ok,
+ megaco:process_received_message(RH, ControlPid,
+ otp8212_scr,
+ otp8212_scr(RemoteMidStr1))),
+
+ d("get the updated connection handle", []),
+ [CH] = megaco:user_info(LocalMid, connections),
+
+ d("verify connection with ~p", [RemoteMidStr1]),
+ ?VERIFY(RemoteMid1, megaco:conn_info(CH, remote_mid)),
+
+ d("send a request to ~p but receive no reply but an unexpected call",
+ [RemoteMidStr1]),
+ Res = megaco:call(CH, ["action request"], [{request_timer, 2000}]),
+ d("request result: ~p", [Res]),
+ ?VERIFY({1, [{error, {wrong_mid, RemoteMid2, RemoteMid1, _}, {Extra, _}}]}, Res),
+
+ Conns = disconnect_all(LocalMid),
+ await_disconnected(Conns),
+
+ d("stop megaco user ~p",[LocalMid]),
+ ok = await_stopped_user(LocalMid),
+
+ d("stop megaco app",[]),
+ ?VERIFY(ok, application:stop(megaco)),
+ ?RECEIVE([]),
+
+ d("done",[]),
+ ok.
+
+disconnect_all(LocalMid) ->
+ Conns = megaco:user_info(LocalMid, connections),
+ d("[~p] disconnect from all connections: ~n~p", [LocalMid, Conns]),
+ lists:foreach(
+ fun(Conn) ->
+ d("[~p] disconnect from connection ~p", [LocalMid, Conn]),
+ DiscoRes = megaco:disconnect(Conn, {otp8212_done, self()}),
+ d("[~p] disconnect result: ~p", [LocalMid, DiscoRes])
+ end,
+ Conns),
+ Conns.
+
+await_disconnected([]) ->
+ ok;
+await_disconnected(Conns) ->
+ receive
+ {disconnected, Conn} ->
+ d("disconnected: ~p", [Conn]),
+ Conns2 = lists:delete(Conn, Conns),
+ await_disconnected(Conns2)
+ end.
+
+
+await_stopped_user(LocalMid) ->
+ await_stopped_user(LocalMid, 10).
+
+await_stopped_user(LocalMid, N) when N =< 0 ->
+ ?ERROR({failed_stopping_user, LocalMid});
+await_stopped_user(LocalMid, N) ->
+ case megaco:stop_user(LocalMid) of
+ ok ->
+ d("user stopped(~w)", [N]),
+ ok;
+ {error, {active_connections, _}} ->
+ d("still active connections when N = ~w", [N]),
+ Conns = disconnect_all(LocalMid),
+ await_disconnected(Conns),
+ ?SLEEP(500),
+ await_stopped_user(LocalMid, N-1)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_ErrDesc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+cre_serviceChangeParm(M,R,P) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R,
+ serviceChangeProfile = P}.
+
+cre_serviceChangeParm(M, V, R, P) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeVersion = V,
+ serviceChangeReason = R,
+ serviceChangeProfile = P}.
+
+cre_serviceChangeReq(Tid, Parms) ->
+ #'ServiceChangeRequest'{terminationID = Tid,
+ serviceChangeParms = Parms}.
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_obsEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name,
+ timeNotation = Not}.
+
+cre_obsEvsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = EvList}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid,
+ observedEventsDescriptor = EvsDesc}.
+
+cre_command(R) when is_record(R, 'NotifyRequest') ->
+ {notifyReq, R};
+cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
+ {serviceChangeReq, R}.
+
+cre_cmdReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = CmdReqs}.
+
+cre_transReq(TransId, ARs) when is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransId,
+ actions = ARs}.
+
+cre_transResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {transactionError, ED};
+cre_transResult([AR|_] = ARs) when is_record(AR, 'ActionReply') ->
+ {actionReplies, ARs}.
+
+cre_transReply(TransId, Res) ->
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = Res}.
+
+cre_transReply(TransId, IAR, Res) ->
+ #'TransactionReply'{transactionId = TransId,
+ immAckRequired = IAR,
+ transactionResult = Res}.
+
+
+%% --
+
+cre_serviceChangeResParm(Mid) ->
+ cre_serviceChangeResParm(Mid, ?VERSION).
+
+cre_serviceChangeResParm(Mid, V) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeVersion = V}.
+
+cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP};
+cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED}.
+
+cre_serviceChangeReply(Tid, Res) ->
+ #'ServiceChangeReply'{terminationID = Tid,
+ serviceChangeResult = Res}.
+
+cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
+ {notifyReply, R};
+cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
+ {serviceChangeReply, R}.
+
+cre_transRespAck(TransAck) when is_record(TransAck, 'TransactionAck') ->
+ [TransAck];
+cre_transRespAck(TRA) when is_list(TRA) ->
+ TRA.
+
+cre_transAck(TransId) ->
+ #'TransactionAck'{firstAck = TransId}.
+
+cre_notifyReply(Tid) ->
+ #'NotifyReply'{terminationID = Tid}.
+
+cre_actionReply(CtxId, CmdRep) ->
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdRep}.
+
+cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Ver}.
+
+cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
+ {transactionRequest, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
+ {transactionPending, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionReply') ->
+ {transactionReply, Trans};
+cre_transaction(Trans) when is_list(Trans) ->
+ {transactionResponseAck, Trans}.
+
+cre_transactions(Trans) when is_list(Trans) ->
+ {transactions, Trans}.
+
+cre_message(Version, Mid, Body) ->
+ #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}.
+
+cre_megacoMessage(Mess) ->
+ #'MegacoMessage'{mess = Mess}.
+
+service_change_request() ->
+ Parm = #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [?megaco_cold_boot]},
+ SCR = #'ServiceChangeRequest'{terminationID = [?megaco_root_termination_id],
+ serviceChangeParms = Parm},
+ CR = #'CommandRequest'{command = {serviceChangeReq, SCR}},
+ #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]}.
+
+service_change_reply(MgcMid) ->
+ Res = {serviceChangeResParms, #'ServiceChangeResParm'{serviceChangeMgcId = MgcMid}},
+ SCR = #'ServiceChangeReply'{terminationID = [?megaco_root_termination_id],
+ serviceChangeResult = Res},
+ #'ActionReply'{contextId = ?megaco_null_context_id,
+ commandReply = [{serviceChangeReply, SCR}]}.
+
+local_ip_address() ->
+ {ok, Hostname} = inet:gethostname(),
+ {ok, {A1, A2, A3, A4}} = inet:getaddr(Hostname, inet),
+ {A1, A2, A3, A4}.
+
+ipv4_mid() ->
+ ipv4_mid(asn1_NOVALUE).
+
+ipv4_mid(Port) ->
+ IpAddr = local_ip_address(),
+ Ip = tuple_to_list(IpAddr),
+ {ip4Address, #'IP4Address'{address = Ip, portNumber = Port}}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% -------------------------------------------------------------------------------
+%%% Megaco user callback interface
+%%% -------------------------------------------------------------------------------
+
+handle_connect(ConnHandle, ProtocolVersion, Pid) ->
+ Pid ! {handle_connect, {ConnHandle, ProtocolVersion}},
+ ok.
+
+handle_disconnect(_, _, {user_disconnect, test_complete}, _) ->
+ ok;
+handle_disconnect(ConnHandle, ProtocolVersion, Reason, Pid) ->
+ Pid ! {handle_disconnect, {ConnHandle, ProtocolVersion, Reason}},
+ ok.
+
+handle_syntax_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+ Pid ! {handle_syntax_error,{ConnHandle, ProtocolVersion, ErrorDescriptor}},
+ reply.
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+ Pid ! {handle_message_error,{ConnHandle, ProtocolVersion, ErrorDescriptor}},
+ reply.
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Pid) ->
+ Pid ! {handle_trans_request,{ConnHandle, ProtocolVersion, ActionRequests}},
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "not implemented yet"},
+ {discard_ack, ED}.
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, Data, Pid) ->
+ Pid ! {handle_trans_long_request,{ConnHandle, ProtocolVersion, Data}},
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "not implemented yet"},
+ {discard_ack, ED}.
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, Data, Pid) ->
+ Pid ! {handle_trans_reply,{ConnHandle, ProtocolVersion, ActualReply, Data}},
+ ok.
+
+handle_trans_ack(ConnHandle, ProtocolVersion, Status, Data, Pid) ->
+ Pid ! {handle_trans_ack,{ConnHandle, ProtocolVersion, Status, Data}},
+ ok.
+
+handle_unexpected_trans(ReceiveHandle, ProtocolVersion, Trans, Pid) ->
+ Pid ! {handle_unexpected_trans,
+ {ReceiveHandle, ProtocolVersion, Trans, Pid}},
+ ok.
+
+handle_trans_request_abort(ReceiveHandle, ProtocolVersion, TransNo, HandlerPid, Pid) ->
+ Pid ! {handle_trans_request_abort,
+ {ReceiveHandle, ProtocolVersion, TransNo, HandlerPid}},
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+encode_msg(M, Mod, Conf) ->
+ Mod:encode_message(Conf, M).
+
+%% encode_msg(M, Mod, Conf, Ver) ->
+%% Mod:encode_message(Conf, Ver, M).
+
+decode_msg(M, Mod, Conf) ->
+ Mod:decode_message(Conf, M).
+
+%% decode_msg(M, Mod, Conf, Ver) ->
+%% Mod:decode_message(Conf, Ver, M).
+
+
+
+%%% -------------------------------------------------------------------------------
+%%% Megaco transport module interface
+%%% -------------------------------------------------------------------------------
+
+send_message(Pid, Data) ->
+ Pid ! {send_message, Data},
+ ok.
+
+% block(Pid) ->
+% Pid ! {block, dummy},
+% ok.
+
+unblock(Pid) ->
+ Pid ! {unblock, dummy},
+ ok.
+
+% close(Pid) ->
+% Pid ! {close, dummy},
+% ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+user_info(Mid, Key) ->
+ case (catch megaco:user_info(Mid, Key)) of
+ {'EXIT', _} = Error ->
+ ?ERROR(Error);
+ Val ->
+ ?LOG("user_info -> ok: "
+ "~n ~p"
+ "~n", [Val]),
+ Val
+ end.
+
+
+stop_user(Mid) ->
+ case (catch megaco:stop_user(Mid)) of
+ {'EXIT', _} = Error ->
+ ?ERROR(Error);
+ Val ->
+ ?LOG("stop_user -> ok:"
+ "~n ~p"
+ "~n", [Val]),
+ Val
+ end.
+
+connections() ->
+ system_info(connections).
+
+connections(Conns0) ->
+ Conns1 = lists:sort(Conns0),
+ case lists:sort(connections()) of
+ Conns1 ->
+ ?LOG("connections -> ok:"
+ "~n ~p"
+ "~n", [Conns1]),
+ Conns1;
+ Conns2 ->
+ ?ERROR({Conns1, Conns2}),
+ Conns2
+ end.
+
+system_info(Key) ->
+ megaco:system_info(Key).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_completion(Ids) ->
+ case megaco_test_generator_lib:await_completion(Ids) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, Reply} ->
+ d("ERROR => Reply: ~n~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+await_completion(Ids, Timeout) ->
+ case megaco_test_generator_lib:await_completion(Ids, Timeout) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, Reply} ->
+ d("ERROR => Reply: ~n~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) -> receive after X -> ok end.
+
+% error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), now(), get(tc), "DBG", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+to(To, Start) ->
+ To - (mtime() - Start).
+
+%% Time in milli seconds
+mtime() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+%% random_init() ->
+%% {A,B,C} = now(),
+%% random:seed(A,B,C).
+
+%% random() ->
+%% 10 * random:uniform(50).
+
diff --git a/lib/megaco/test/megaco_mess_user_test.erl b/lib/megaco/test/megaco_mess_user_test.erl
new file mode 100644
index 0000000000..50284be549
--- /dev/null
+++ b/lib/megaco/test/megaco_mess_user_test.erl
@@ -0,0 +1,309 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: A fun implementation of user callbacks
+%%----------------------------------------------------------------------
+
+-module(megaco_mess_user_test).
+
+-behaviour(megaco_user).
+
+-export([
+ handle_connect/2, handle_connect/3,
+ handle_disconnect/3,
+ handle_syntax_error/3, handle_syntax_error/4,
+ handle_message_error/3, handle_message_error/4,
+ handle_trans_request/3, handle_trans_request/4,
+ handle_trans_long_request/3, handle_trans_long_request/4,
+ handle_trans_reply/4, handle_trans_reply/5,
+ handle_trans_ack/4, handle_trans_ack/5,
+ handle_unexpected_trans/3, handle_unexpected_trans/4,
+ handle_trans_request_abort/4, handle_trans_request_abort/5,
+ handle_segment_reply/5, handle_segment_reply/6
+ ]).
+
+-export([
+ start_proxy/0,
+ stop_proxy/0,
+ apply_proxy/1,
+ reply/3,
+
+ start_transport/2,
+ loop_transport/1, % Internal only
+ send_message/2,
+ resend_message/2
+ ]).
+
+-include("megaco_test_lib.hrl").
+-define(SERVER, ?MODULE).
+
+start_proxy() ->
+ yes = global:register_name(?SERVER, self()),
+ Pid = megaco_test_lib:proxy_start(?MODULE),
+ put(?MODULE, Pid),
+ Pid.
+
+stop_proxy() ->
+ global:unregister_name(?SERVER),
+ Pid = erase(?MODULE),
+ unlink(Pid),
+ exit(Pid, shutdown).
+
+whereis_proxy() ->
+ case get(?MODULE) of
+ undefined ->
+ exit(no_server, ?MODULE);
+ Pid when is_pid(Pid) ->
+ Pid
+ end.
+
+apply_proxy(Fun) ->
+ Pid = whereis_proxy(),
+ ?APPLY(Pid, Fun),
+ ok.
+
+reply(Mod, Line, Fun) when is_function(Fun) ->
+ receive
+ {?MODULE, Pid, UserCallback} ->
+ UserReply = Fun(UserCallback),
+ Pid ! {?MODULE, self(), UserReply},
+ UserReply;
+ Other ->
+ megaco_test_lib:error(Other, Mod, Line),
+ {error, Other}
+%% after 1000 ->
+%% megaco_test_lib:error(timeout, Mod, Line),
+%% {error, timeout}
+ end.
+
+call(UserCallback) ->
+ Request = {?MODULE, self(), UserCallback},
+ case global:whereis_name(?SERVER) of
+ undefined ->
+ exit({no_server, ?SERVER, Request});
+ Pid when is_pid(Pid) ->
+ ?LOG("call[~p] -> bang request: "
+ "~n ~p"
+ "~n", [Pid, Request]),
+ Pid ! Request,
+ call_await_reply(Pid)
+ end.
+
+call_await_reply(Pid) ->
+ receive
+ {?MODULE, Pid, UserReply} = _Reply ->
+ case UserReply of
+ {ok, Good} -> Good;
+ {error, Bad} -> exit(Bad)
+ end;
+ {'EXIT', Pid, Reason} = Bad ->
+ ?LOG("receive test case exit: ~p~n", [Bad]),
+ exit(Reason);
+ {'EXIT', _, _Reason} = Bad ->
+ ?LOG("receive unknown exit: ~p~n", [Bad]),
+ call_await_reply(Pid);
+ Bad ->
+ ?LOG("receive other: ~p~n", [Bad]),
+ exit(Bad)
+ end.
+
+%%----------------------------------------------------------------------
+%% Megaco user callback
+%%----------------------------------------------------------------------
+
+%% -- handle_connect/2 --
+
+handle_connect(ConnHandle, ProtocolVersion) ->
+%% io:format("~p~p[~p]: handle_connect -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n ProtocolVersion: ~p"
+%% "~n",
+%% [self(), ?MODULE, ?LINE, ConnHandle, ProtocolVersion]),
+ call({connect, ConnHandle, ProtocolVersion, []}).
+
+handle_connect(ConnHandle, ProtocolVersion, Extra) ->
+%% io:format(user,"~p~p[~p]: handle_connect -> entry with"
+%% "~n ConnHandle: ~p"
+%% "~n ProtocolVersion: ~p"
+%% "~n Extra: ~p"
+%% "~n",
+%% [self(), ?MODULE, ?LINE, ConnHandle, ProtocolVersion, Extra]),
+ call({connect, ConnHandle, ProtocolVersion, [Extra]}).
+
+
+%% -- handle_disconnect/3 --
+
+handle_disconnect(ConnHandle, ProtocolVersion, Reason) ->
+ %% io:format("~w:~w:~p:handle_disconnect -> entry with"
+ %% "~n ConnHandle: ~p"
+ %% "~n ProtocolVersion: ~p"
+ %% "~n Reason: ~p"
+ %% "~n",
+ %% [?MODULE, ?LINE, self(), ConnHandle, ProtocolVersion, Reason]),
+ call({disconnect, ConnHandle, ProtocolVersion, [Reason]}).
+
+
+%% -- handle_syntax_error/3,4 --
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor) ->
+ call({syntax_error, ReceiveHandle, ProtocolVersion, [ErrorDescriptor]}).
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Extra) ->
+ call({syntax_error, ReceiveHandle, ProtocolVersion, [ErrorDescriptor, Extra]}).
+
+
+%% -- handle_message_error/3,4 --
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor) ->
+ call({message_error, ConnHandle, ProtocolVersion, [ErrorDescriptor]}).
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Extra) ->
+ call({message_error, ConnHandle, ProtocolVersion, [ErrorDescriptor, Extra]}).
+
+
+%% -- handle_trans_request/3,4 --
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests) ->
+ call({request, ConnHandle, ProtocolVersion, [ActionRequests]}).
+
+handle_trans_request(ConnHandle, ProtocolVersion, ActionRequests, Extra) ->
+ call({request, ConnHandle, ProtocolVersion, [ActionRequests, Extra]}).
+
+%% -- handle_trans_long_request/3,4 --
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, RequestData) ->
+ call({long_request, ConnHandle, ProtocolVersion, [RequestData]}).
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, RequestData, Extra) ->
+ call({long_request, ConnHandle, ProtocolVersion, [RequestData, Extra]}).
+
+
+%% -- handle_trans_relpy/4,5 --
+
+handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, UserData) ->
+ call({reply, ConnHandle, ProtocolVersion, [UserReply, UserData]}).
+
+handle_trans_reply(ConnHandle, ProtocolVersion, UserReply, UserData, Extra) ->
+ call({reply, ConnHandle, ProtocolVersion, [UserReply, UserData, Extra]}).
+
+
+%% -- handle_trans_relpy/4,5 --
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData) ->
+ call({ack, ConnHandle, ProtocolVersion, [AckStatus, AckData]}).
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Extra) ->
+ call({ack, ConnHandle, ProtocolVersion, [AckStatus, AckData, Extra]}).
+
+
+%% -- handle_unexpected_trans/3,4 --
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans) ->
+ call({unepected_trans, ConnHandle, ProtocolVersion, [Trans]}).
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Extra) ->
+ call({unepected_trans, ConnHandle, ProtocolVersion, [Trans, Extra]}).
+
+
+%% -- handle_trans_request_abort/4,5 --
+
+handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId, Pid) ->
+ call({request_abort, ConnHandle, ProtocolVersion, [TransId, Pid]}).
+
+handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId, Pid, Extra) ->
+ call({request_abort, ConnHandle, ProtocolVersion, [TransId, Pid, Extra]}).
+
+
+%% -- handle_segment_reply/5,6 --
+
+handle_segment_reply(ConnHandle, ProtocolVersion, TransId, SN, SC) ->
+ call({segment_reply, ConnHandle, ProtocolVersion, [TransId, SN, SC]}).
+
+handle_segment_reply(ConnHandle, ProtocolVersion, TransId, SN, SC, Extra) ->
+ call({segment_reply, ConnHandle, ProtocolVersion, [TransId, SN, SC, Extra]}).
+
+
+%%----------------------------------------------------------------------
+%% The ultimate Megaco transport callback
+%%----------------------------------------------------------------------
+
+start_transport(MgReceiveHandle, MgcReceiveHandle) ->
+ MgControlPid = spawn_link(?MODULE, loop_transport, [self()]),
+ MgSendHandle = {MgcReceiveHandle, MgControlPid},
+ MgcControlPid = spawn_link(?MODULE, loop_transport, [self()]),
+ MgcSendHandle = {MgReceiveHandle, MgcControlPid},
+ SendHandle = {MgSendHandle, MgcSendHandle},
+ {ok, MgControlPid, SendHandle}.
+
+loop_transport(Parent) ->
+ receive
+ {'EXIT', _Pid, Reason} = Error ->
+ ok = io:format("transport stopped: ~p~n", [{Parent, Error}]),
+ exit(Reason)
+ end.
+
+send_message(Handles, Bin) ->
+ ?LOG("send_message -> entry with"
+ "~n Handles: ~p"
+ "~n", [Handles]),
+ case megaco_tc_controller:lookup(allow_send_message) of
+ {value, ok} ->
+ do_send_message(Handles, Bin);
+ {value, {fail, Reason}} ->
+ {error, Reason};
+ {value, {cancel, Reason}} ->
+ {cancel, Reason};
+ {value, {skip, Result}} ->
+ Result;
+ false ->
+ do_send_message(Handles, Bin)
+ end.
+
+resend_message(Handles, Bin) ->
+ ?LOG("resend_message -> entry with"
+ "~n Handles: ~p"
+ "~n", [Handles]),
+ case megaco_tc_controller:lookup(allow_resend_message) of
+ {value, ok} ->
+ do_send_message(Handles, Bin);
+ {value, {fail, Reason}} ->
+ {error, Reason};
+ {value, {cancel, Reason}} ->
+ {cancel, Reason};
+ {value, {skip, Result}} ->
+ Result;
+ false ->
+ do_send_message(Handles, Bin)
+ end.
+
+do_send_message({{RH, Pid} = LocalSendHandle, RemoteSendHandle}, Bin) ->
+ ?LOG("do_send_message -> entry with"
+ "~n RH: ~p"
+ "~n Pid: ~p"
+ "~n RemoteSendHandle: ~p"
+ "~n", [RH, Pid, RemoteSendHandle]),
+ SwappedSendHandle = {RemoteSendHandle, LocalSendHandle},
+ case megaco_tc_controller:lookup(extra_transport_info) of
+ {value, Extra} ->
+ megaco:receive_message(RH, Pid, SwappedSendHandle, Bin, Extra);
+ _ ->
+ megaco:receive_message(RH, Pid, SwappedSendHandle, Bin)
+ end.
diff --git a/lib/megaco/test/megaco_mib_test.erl b/lib/megaco/test/megaco_mib_test.erl
new file mode 100644
index 0000000000..2da6aa3bf3
--- /dev/null
+++ b/lib/megaco/test/megaco_mib_test.erl
@@ -0,0 +1,1619 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_mib_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(TEST_VERBOSITY, info). % silence | info | debug
+-define(MGC_VERBOSITY, info).
+-define(MG_VERBOSITY, info).
+
+-define(LOAD_COUNTER_START, 100).
+-define(A4444, ["11111111", "00000000", "00000000"]).
+
+-record(mgc, {parent = undefined,
+ tcp_sup = undefined,
+ udp_sup = undefined,
+ mid = undefined,
+ mg = []}).
+-record(mg, {parent = undefined,
+ mid = undefined,
+ conn_handle = undefined,
+ state = initiated,
+ load_counter = 0}).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ case Case of
+ traffic ->
+ Conf0 = lists:keydelete(tc_timeout, 1, Config),
+ Conf = [{tc_timeout, timer:minutes(5)}|Conf0],
+ megaco_test_lib:init_per_testcase(Case, Conf);
+ _ ->
+ megaco_test_lib:init_per_testcase(Case, Config)
+ end.
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ plain,
+ connect,
+ traffic
+ ],
+ Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+plain(suite) ->
+ [];
+plain(doc) ->
+ ["Test case for the basic statistics counter handling. "];
+plain(Config) when is_list(Config) ->
+ io:format("create test table 1~n", []),
+ Tab1 = megaco_test_cnt1,
+ megaco_stats:init(Tab1),
+
+ io:format("~ncreate test table 2~n", []),
+ Tab2 = megaco_test_cnt2,
+ megaco_stats:init(Tab2, [kalle, hobbe]),
+
+ io:format("~ntable 1 increments~n", []),
+ H1 = #megaco_conn_handle{local_mid = {deviceName, "a"},
+ remote_mid = {deviceName, "b"}},
+ H2 = #megaco_conn_handle{local_mid = {deviceName, "a"},
+ remote_mid = {deviceName, "c"}},
+ 1 = megaco_stats:inc(Tab1, H1, sune),
+ 2 = megaco_stats:inc(Tab1, H2, sune, 2),
+ 3 = megaco_stats:inc(Tab1, H1, gurka, 3),
+ 4 = megaco_stats:inc(Tab1, H2, sune, 2),
+ 4 = megaco_stats:inc(Tab1, H1, gurka),
+
+ io:format("~ntable 2 increments~n", []),
+ H3 = #megaco_conn_handle{local_mid = {deviceName, "e"},
+ remote_mid = {deviceName, "c"}},
+ H4 = #megaco_conn_handle{local_mid = {deviceName, "e"},
+ remote_mid = {deviceName, "d"}},
+ 1 = megaco_stats:inc(Tab2, H3, tomat),
+ 4 = megaco_stats:inc(Tab2, H3, tomat, 3),
+ 5 = megaco_stats:inc(Tab2, H4, paprika, 5),
+
+ io:format("~ntable 2 global increments~n", []),
+ 1 = megaco_stats:inc(Tab2, kalle),
+ 1 = megaco_stats:inc(Tab2, hobbe),
+ 2 = megaco_stats:inc(Tab2, hobbe),
+ 2 = megaco_stats:inc(Tab2, kalle),
+ 3 = megaco_stats:inc(Tab2, kalle),
+ 4 = megaco_stats:inc(Tab2, hobbe, 2),
+
+ io:format("~ntable 1 stats~n", []),
+ {ok, Stats1} = megaco_stats:get_stats(Tab1),
+ io:format("Stats1 = ~p~n", [Stats1]),
+ {value, {H1, H1Stats}} = lists:keysearch(H1, 1, Stats1),
+ Stats1_2 = lists:keydelete(H1, 1, Stats1),
+ {value, {H2, H2Stats}} = lists:keysearch(H2, 1, Stats1_2),
+ Stats1_3 = lists:keydelete(H2, 1, Stats1_2),
+ [] = Stats1_3,
+ io:format("H1Stats = ~p~n", [H1Stats]),
+ io:format("H2Stats = ~p~n", [H2Stats]),
+
+ {value, {sune, 1}} = lists:keysearch(sune, 1, H1Stats),
+ H1Stats_2 = lists:keydelete(sune, 1, H1Stats),
+ {value, {gurka, 4}} = lists:keysearch(gurka, 1, H1Stats_2),
+ H1Stats_3 = lists:keydelete(gurka, 1, H1Stats_2),
+ [] = H1Stats_3,
+
+ {value, {sune, 4}} = lists:keysearch(sune, 1, H2Stats),
+ H2Stats_2 = lists:keydelete(sune, 1, H2Stats),
+ [] = H2Stats_2,
+
+
+ %% --
+ io:format("~ntable 2 stats~n", []),
+ {ok, Stats2} = megaco_stats:get_stats(Tab2),
+ io:format("Stats2 = ~p~n", [Stats2]),
+ {ok, 3} = megaco_stats:get_stats(Tab2, kalle),
+ {ok, 4} = megaco_stats:get_stats(Tab2, hobbe),
+
+
+ %% --
+ io:format("~ntable 1 reset stats for ~p~n", [H1]),
+ megaco_stats:reset_stats(Tab1, H1),
+ {ok, Stats1_4} = megaco_stats:get_stats(Tab1),
+ io:format("Stats1_4 = ~p~n", [Stats1_4]),
+ {ok, 0} = megaco_stats:get_stats(Tab1, H1, sune),
+ {ok, 0} = megaco_stats:get_stats(Tab1, H1, gurka),
+
+
+ %% --
+ io:format("~ntable 2 reset stats for kalle and ~p~n", [H4]),
+ megaco_stats:reset_stats(Tab2, kalle),
+ megaco_stats:reset_stats(Tab2, H4),
+ {ok, Stats2_2} = megaco_stats:get_stats(Tab2),
+ io:format("Stats2_2 = ~p~n", [Stats2_2]),
+ {ok, 0} = megaco_stats:get_stats(Tab2, kalle),
+ {ok, 4} = megaco_stats:get_stats(Tab2, hobbe),
+ {ok, 4} = megaco_stats:get_stats(Tab2, H3, tomat),
+ {ok, 0} = megaco_stats:get_stats(Tab2, H4, paprika),
+ {ok, Stats4_4} = megaco_stats:get_stats(Tab2, H4),
+ io:format("Stats4_4 = ~p~n", [Stats4_4]),
+
+ %% --
+ io:format("~ntable 2 stats for nonexisting counters~n", []),
+ {error, _} = megaco_stats:get_stats(Tab2, kalla),
+ {error, _} = megaco_stats:get_stats(Tab2, H3, paprika),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+connect(suite) ->
+ [];
+connect(doc) ->
+ [];
+connect(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("connect -> starting"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ d("connect -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p", [MgcNode, Mg1Node, Mg2Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node, Mg2Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+ {ok, Mg1} =
+ start_mg(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
+ {ok, Mg2} =
+ start_mg(Mg2Node, {deviceName, "mg2"}, binary, udp, ?MG_VERBOSITY),
+
+ %% Collect the initial statistics (should be zero if anything)
+ {ok, Mg1Stats0} = get_stats(Mg1, 1),
+ d("connect -> stats for Mg1: ~n~p", [Mg1Stats0]),
+ {ok, Mg2Stats0} = get_stats(Mg2, 1),
+ d("connect -> stats for Mg2: ~n~p", [Mg2Stats0]),
+ {ok, MgcStats0} = get_stats(Mgc, 1),
+ d("connect -> stats for Mgc: ~n~p", [MgcStats0]),
+
+ %% Ask Mg1 to do a service change
+ {ok, Res1} = service_change(Mg1),
+ d("connect -> (Mg1) service change result: ~p", [Res1]),
+
+ %% Collect the statistics
+ {ok, Mg1Stats1} = get_stats(Mg1, 1),
+ d("connect -> stats for Mg1: ~n~p", [Mg1Stats1]),
+ {ok, MgcStats1} = get_stats(Mgc, 1),
+ d("connect -> stats (1) for Mgc: ~n~p", [MgcStats1]),
+ {ok, MgcStats2} = get_stats(Mgc, 2),
+ d("connect -> stats (2) for Mgc: ~n~p", [MgcStats2]),
+
+ %% Ask Mg2 to do a service change
+ {ok, Res2} = service_change(Mg2),
+ d("connect -> (Mg2) service change result: ~p", [Res2]),
+
+ %% Collect the statistics
+ {ok, Mg2Stats1} = get_stats(Mg2, 1),
+ d("connect -> stats for Mg1: ~n~p", [Mg2Stats1]),
+ {ok, MgcStats3} = get_stats(Mgc, 1),
+ d("connect -> stats (1) for Mgc: ~n~p", [MgcStats3]),
+ {ok, MgcStats4} = get_stats(Mgc, 2),
+ d("connect -> stats (2) for Mgc: ~n~p", [MgcStats4]),
+
+ %% Tell Mg1 to stop
+ stop(Mg1),
+
+ %% Collect the statistics
+ {ok, MgcStats5} = get_stats(Mgc, 1),
+ d("connect -> stats (1) for Mgc: ~n~p", [MgcStats5]),
+ {ok, MgcStats6} = get_stats(Mgc, 2),
+ d("connect -> stats (2) for Mgc: ~n~p", [MgcStats6]),
+
+ %% Tell Mg2 to stop
+ stop(Mg2),
+
+ %% Collect the statistics
+ {ok, MgcStats7} = get_stats(Mgc, 1),
+ d("connect -> stats (1) for Mgc: ~n~p", [MgcStats7]),
+ {ok, MgcStats8} = get_stats(Mgc, 2),
+ d("connect -> stats (2) for Mgc: ~n~p", [MgcStats8]),
+
+ %% Tell Mgc to stop
+ stop(Mgc),
+
+ i("connect -> done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+traffic(suite) ->
+ [];
+traffic(doc) ->
+ [];
+traffic(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("traffic -> starting"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ d("traffic -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode,
+ Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("traffic -> start the MGC"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("traffic -> start and connect the MGs"),
+ MgConf0 = [{Mg1Node, "mg1", text, tcp},
+ {Mg2Node, "mg2", text, udp},
+ {Mg3Node, "mg3", binary, tcp},
+ {Mg4Node, "mg4", binary, udp}],
+ MgConf = traffic_connect_mg(MgConf0, []),
+
+ %% Collect and check the MGs statistics
+ i("traffic -> collect and check the MGs stats"),
+ traffic_verify_mg_stats(MgConf, 1, 1),
+
+ %% Collect and check the MGC statistics
+ i("traffic -> collect and check the MGC stats"),
+ {ok, MgcStats1} = get_stats(Mgc, 1),
+ d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats1]),
+ traffic_verify_mgc_stats(Mgc, 1, 1),
+
+
+ sleep(1000),
+
+
+ %% And apply some load
+ i("traffic -> apply traffic load"),
+ ok = traffic_apply_load(MgConf),
+
+ %% Await completion of load part and the collect traffic
+ i("traffic -> await load competion"),
+ ok = traffic_await_load_complete(MgConf),
+
+
+ sleep(1000),
+
+
+ i("traffic -> collect and check the MGs statistics"),
+ traffic_verify_mg_stats(MgConf,
+ 1 + ?LOAD_COUNTER_START,
+ 1 + ?LOAD_COUNTER_START),
+
+ i("traffic -> collect and check the MGC statistics"),
+ {ok, MgcStats3} = get_stats(Mgc, 1),
+ d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats3]),
+ traffic_verify_mgc_stats(Mgc,
+ 1 + ?LOAD_COUNTER_START,
+ 1 + ?LOAD_COUNTER_START),
+
+
+ sleep(1000),
+
+
+ %% Reset counters
+ i("traffic -> reset the MGs statistics"),
+ traffic_reset_mg_stats(MgConf),
+ i("traffic -> collect and check the MGs statistics"),
+ traffic_verify_mg_stats(MgConf, 0, 0),
+
+ i("traffic -> reset the MGC statistics"),
+ traffic_reset_mgc_stats(Mgc),
+ i("traffic -> collect and check the MGC statistics"),
+ traffic_verify_mgc_stats(Mgc, 0, 0),
+
+
+ sleep(1000),
+
+
+ %% And apply some load
+ i("traffic -> apply traffic load"),
+ ok = traffic_apply_load(MgConf),
+
+ %% Await completion of load part and the collect traffic
+ i("traffic -> await load competion"),
+ ok = traffic_await_load_complete(MgConf),
+
+
+ sleep(1000),
+
+
+ i("traffic -> collect and check the MGs statistics"),
+ traffic_verify_mg_stats(MgConf,
+ ?LOAD_COUNTER_START,
+ ?LOAD_COUNTER_START),
+
+ i("traffic -> collect and check the MGC statistics"),
+ traffic_verify_mgc_stats(Mgc,
+ ?LOAD_COUNTER_START,
+ ?LOAD_COUNTER_START),
+
+
+ sleep(1000),
+
+
+ %% Tell MGs to stop
+ i("traffic -> stop the MGs"),
+ traffic_stop_mg(MgConf),
+
+
+ sleep(1000),
+
+
+ %% Collect the statistics
+ i("traffic -> collect the MGC statistics"),
+ {ok, MgcStats7} = get_stats(Mgc, 1),
+ d("traffic -> stats (1) for Mgc: ~n~p~n", [MgcStats7]),
+ {ok, MgcStats8} = get_stats(Mgc, 2),
+ d("traffic -> stats (2) for Mgc: ~n~p~n", [MgcStats8]),
+
+ %% Tell Mgc to stop
+ i("traffic -> stop the MGC"),
+ stop(Mgc),
+
+ i("traffic -> done", []),
+ ok.
+
+
+traffic_verify_mgc_stats(Pid, Out, In)
+ when is_pid(Pid) andalso is_integer(Out) andalso is_integer(In) ->
+ d("traffic_verify_mgc_stats -> entry with"
+ "~n Out: ~p"
+ "~n In: ~p", [Out, In]),
+ {ok, Stats} = get_stats(Pid, 2),
+ d("traffic_verify_mgc_stats -> stats (2) for Mgc: ~n~p~n", [Stats]),
+ traffic_verify_mgc_stats(Stats, Out, In);
+
+traffic_verify_mgc_stats(Stats, Out, In) when is_list(Stats) ->
+ d("traffic_verify_mgc_stats -> checking stats"),
+ Gen = traffic_verify_get_stats(gen, Stats),
+ Trans = traffic_verify_get_stats(trans, Stats),
+ traffic_verify_mgc_stats_gen(Gen),
+ traffic_verify_mgc_stats_trans(Trans, Out, In).
+
+traffic_verify_mgc_stats_gen([]) ->
+ d("traffic_verify_mgc_stats_gen -> done"),
+ ok;
+traffic_verify_mgc_stats_gen([{medGwyGatewayNumErrors, 0}|Stats]) ->
+ traffic_verify_mgc_stats_gen(Stats);
+traffic_verify_mgc_stats_gen([{medGwyGatewayNumErrors, Val}|_]) ->
+ exit({global_error_counter, Val, mgc});
+traffic_verify_mgc_stats_gen([{Handle, Counters}|Stats]) ->
+ N = {mgc, Handle, Handle},
+ traffic_verify_counter(N, medGwyGatewayNumErrors, Counters, 0),
+ traffic_verify_mgc_stats_gen(Stats).
+
+
+traffic_verify_mgc_stats_trans([], _Out, _In) ->
+ ok;
+traffic_verify_mgc_stats_trans([{Mod, Stats}|MgcStats], Out, In) ->
+ d("traffic_verify_mgc_stats_trans -> entry with"
+ "~n Mod: ~p"
+ "~n Stats: ~p", [Mod, Stats]),
+ traffic_verify_mgc_stats_trans(Mod, Stats, Out, In),
+ traffic_verify_mgc_stats_trans(MgcStats, Out, In).
+
+traffic_verify_mgc_stats_trans(_Mod, [], _Out, _In) ->
+ ok;
+traffic_verify_mgc_stats_trans(Mod, [{Handle,Counters}|Stats], Out, In) ->
+ N = {mgc, Mod, Handle},
+ traffic_verify_counter(N, medGwyGatewayNumErrors, Counters, 0),
+ traffic_verify_counter(N, medGwyGatewayNumOutMessages, Counters, Out),
+ traffic_verify_counter(N, medGwyGatewayNumInMessages, Counters, In),
+ traffic_verify_mgc_stats_trans(Mod, Stats, Out, In).
+
+
+traffic_verify_mg_stats(MgConf, Out, In)
+ when is_integer(Out) andalso is_integer(In) ->
+ d("traffic_verify_mg_stats -> entry with"
+ "~n Out: ~p"
+ "~n In: ~p", [Out, In]),
+ Stats = traffic_get_mg_stats(MgConf, []),
+ d("traffic_verify_mg_stats -> stats for MGs: ~n~p", [Stats]),
+ traffic_verify_mg_stats1(Stats, Out, In).
+
+traffic_verify_mg_stats1([], _, _) ->
+ ok;
+traffic_verify_mg_stats1([{Name, Stats}|MgStats], Out, In) ->
+ d("traffic_verify_mg_stats1 -> entry with"
+ "~n Name: ~s"
+ "~n Stats: ~p", [Name, Stats]),
+ Gen = traffic_verify_get_stats(gen, Stats),
+ Trans = traffic_verify_get_stats(trans, Stats),
+ traffic_verify_mg_stats_gen(Name, Gen),
+ traffic_verify_mg_stats_trans(Name, Trans, Out, In),
+ traffic_verify_mg_stats1(MgStats, Out, In).
+
+traffic_verify_mg_stats_gen(Mg, []) ->
+ d("traffic_verify_mg_stats_gen -> ~s checked out OK",[Mg]),
+ ok;
+traffic_verify_mg_stats_gen(Mg, [{medGwyGatewayNumErrors, 0}|Stats]) ->
+ traffic_verify_mg_stats_gen(Mg, Stats);
+traffic_verify_mg_stats_gen(Mg, [{medGwyGatewayNumErrors, Val}|_]) ->
+ exit({global_error_counter, Val, Mg});
+traffic_verify_mg_stats_gen(Mg, [{_Handle, Counters}|Stats]) ->
+ traffic_verify_counter(Mg, medGwyGatewayNumErrors, Counters, 0),
+ traffic_verify_mg_stats_gen(Mg, Stats).
+
+traffic_verify_mg_stats_trans(Mg, Counters, Out, In) ->
+ traffic_verify_counter(Mg, medGwyGatewayNumErrors, Counters, 0),
+ traffic_verify_counter(Mg, medGwyGatewayNumOutMessages, Counters, Out),
+ traffic_verify_counter(Mg, medGwyGatewayNumInMessages, Counters, In).
+
+
+traffic_verify_get_stats(S, Stats) ->
+ case lists:keysearch(S, 1, Stats) of
+ {value, {S, Val}} ->
+ Val;
+ false ->
+ exit({not_found, S, Stats})
+ end.
+
+traffic_verify_counter(Name, Counter, Counters, Expected) ->
+ case lists:keysearch(Counter, 1, Counters) of
+ {value, {Counter, Expected}} ->
+ ok;
+ {value, {Counter, Val}} ->
+ exit({illegal_counter_value, Counter, Val, Expected, Name});
+ false ->
+ exit({not_found, Counter, Counters, Name, Expected})
+ end.
+
+
+traffic_connect_mg([], Acc) ->
+ lists:reverse(Acc);
+traffic_connect_mg([{Node, Name, Coding, Trans}|Mg], Acc) ->
+ Pid = traffic_connect_mg(Node, Name, Coding, Trans),
+ traffic_connect_mg(Mg, [{Name, Pid}|Acc]).
+
+traffic_connect_mg(Node, Name, Coding, Trans) ->
+ Mid = {deviceName, Name},
+ {ok, Pid} = start_mg(Node, Mid, Coding, Trans, ?MG_VERBOSITY),
+
+ %% Ask the MGs to do a service change
+ {ok, Res} = service_change(Pid),
+ d("traffic_connect_mg -> (~s) service change result: ~p", [Name,Res]),
+
+ Pid.
+
+
+traffic_stop_mg(MGs) ->
+ [stop(Pid) || {_Name, Pid} <- MGs].
+
+
+traffic_get_mg_stats([], Acc) ->
+ lists:reverse(Acc);
+traffic_get_mg_stats([{Name, Pid}|Mgs], Acc) ->
+ {ok, Stats} = get_stats(Pid, 1),
+ d("traffic_get_mg_stats -> stats for ~s: ~n~p~n", [Name, Stats]),
+ traffic_get_mg_stats(Mgs, [{Name, Stats}|Acc]).
+
+
+traffic_apply_load([]) ->
+ ok;
+traffic_apply_load([{_,MG}|MGs]) ->
+ MG ! {apply_load, self(), ?LOAD_COUNTER_START},
+ receive
+ {apply_load_ack, MG} ->
+ traffic_apply_load(MGs);
+ {'EXIT', MG, Reason} ->
+ exit({mg_exit, MG, Reason})
+ after 10000 ->
+ exit({apply_load_ack_timeout, MG})
+ end.
+
+
+traffic_reset_mg_stats([]) ->
+ ok;
+traffic_reset_mg_stats([{Name, Pid}|MGs]) ->
+ d("traffic_reset_mg_stats -> resetting ~s", [Name]),
+ traffic_reset_stats(Pid),
+ traffic_reset_mg_stats(MGs).
+
+traffic_reset_mgc_stats(Mgc) ->
+ d("traffic_reset_mgc_stats -> resetting ~p", [Mgc]),
+ traffic_reset_stats(Mgc).
+
+traffic_reset_stats(Pid) ->
+ Pid ! {reset_stats, self()},
+ receive
+ {reset_stats_ack, Pid} ->
+ ok;
+ {'EXIT', Pid, Reason} ->
+ exit({client_exit, Pid, Reason})
+ after 10000 ->
+ exit({reset_stats_ack_timeout, Pid})
+ end.
+
+
+traffic_await_load_complete([]) ->
+ ok;
+traffic_await_load_complete(MGs0) ->
+ receive
+ {load_complete, Pid} ->
+ d("received load_complete from ~p", [Pid]),
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ traffic_await_load_complete(lists:delete(Pid, MGs1));
+ {'EXIT', Pid, Reason} ->
+ i("exit signal from ~p: ~p", [Pid, Reason]),
+ case lists:keymember(Pid, 2, MGs0) of
+ true ->
+ exit({mg_exit, Pid, Reason});
+ false ->
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ traffic_await_load_complete(lists:delete(Pid, MGs1))
+ end
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_mgc(Node, Mid, ET, Verbosity) ->
+ d("start mgc[~p]: ~p", [Node, Mid]),
+ RI = {receive_info, mk_recv_info(ET)},
+ Config = [{local_mid, Mid}, RI],
+ Pid = spawn_link(Node, ?MODULE, mgc, [self(), Verbosity, Config]),
+ await_started(Pid).
+
+mk_recv_info(ET) ->
+ mk_recv_info(ET, []).
+
+mk_recv_info([], Acc) ->
+ Acc;
+mk_recv_info([{text,tcp}|ET], Acc) ->
+ RI = [{encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp},
+ {port, 2944}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([{text,udp}|ET], Acc) ->
+ RI = [{encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_udp},
+ {port, 2944}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([{binary,tcp}|ET], Acc) ->
+ RI = [{encoding_module, megaco_ber_bin_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp},
+ {port, 2945}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([{binary,udp}|ET], Acc) ->
+ RI = [{encoding_module, megaco_ber_bin_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_udp},
+ {port, 2945}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([ET|_], _) ->
+ throw({error, {invaalid_encoding_transport, ET}}).
+
+mgc(Parent, Verbosity, Config) ->
+ process_flag(trap_exit, true),
+ put(verbosity, Verbosity),
+ put(sname, "MGC"),
+ i("mgc -> starting"),
+ {Mid, TcpSup, UdpSup} = mgc_init(Config),
+ notify_started(Parent),
+ S = #mgc{parent = Parent,
+ tcp_sup = TcpSup, udp_sup = UdpSup, mid = Mid},
+ i("mgc -> started"),
+ mgc_loop(S).
+
+mgc_init(Config) ->
+ d("mgc_init -> entry"),
+ Mid = get_conf(local_mid, Config),
+ RI = get_conf(receive_info, Config),
+ d("mgc_init -> start megaco"),
+ application:start(megaco),
+ d("mgc_init -> start megaco user"),
+ megaco:start_user(Mid, []),
+ d("mgc_init -> update user info (user_mod)"),
+ megaco:update_user_info(Mid, user_mod, ?MODULE),
+ d("mgc_init -> update user info (user_args)"),
+ megaco:update_user_info(Mid, user_args, [self()]),
+ d("mgc_init -> get user info (receive_handle)"),
+ RH = megaco:user_info(Mid,receive_handle),
+ d("mgc_init -> parse receive info"),
+ ListenTo = mgc_parse_receive_info(RI, RH),
+ d("mgc_init -> start transports"),
+ {Tcp, Udp} = mgc_start_transports(ListenTo),
+ {Mid, Tcp, Udp}.
+
+
+mgc_loop(S) ->
+ d("mgc_loop -> await request"),
+ receive
+ {stop, Parent} when S#mgc.parent == Parent ->
+ i("mgc_loop -> stopping", []),
+ Mid = S#mgc.mid,
+ (catch mgc_close_conns(Mid)),
+ megaco:stop_user(Mid),
+ application:stop(megaco),
+ i("mgc_loop -> stopped", []),
+ Parent ! {stopped, self()},
+ exit(normal);
+
+
+
+ %% Reset stats
+ {reset_stats, Parent} when S#mgc.parent == Parent ->
+ i("mgc_loop -> got request to reset stats counters"),
+ mgc_reset_stats(S#mgc.mid),
+ Parent ! {reset_stats_ack, self()},
+ mgc_loop(S);
+
+
+ %% Give me statistics
+ {statistics, 1, Parent} when S#mgc.parent == Parent ->
+ i("mgc_loop -> got request for statistics 1"),
+ {ok, Gen} = megaco:get_stats(),
+ GetTrans =
+ fun(CH) ->
+ Reason = {statistics, CH},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ {ok, Stats} =
+ case SendMod of
+ megaco_tcp -> megaco_tcp:get_stats(SendHandle);
+ megaco_udp -> megaco_udp:get_stats(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end,
+ {SendHandle, Stats}
+ end,
+ Mid = S#mgc.mid,
+ Trans =
+ lists:map(GetTrans, megaco:user_info(Mid, connections)),
+ Parent ! {statistics, 1, [{gen, Gen}, {trans, Trans}], self()},
+ mgc_loop(S);
+
+
+ {statistics, 2, Parent} when S#mgc.parent == Parent ->
+ i("mgc_loop -> got request for statistics 2"),
+ {ok, Gen} = megaco:get_stats(),
+ #mgc{tcp_sup = TcpSup, udp_sup = UdpSup} = S,
+ TcpStats = get_trans_stats(TcpSup, megaco_tcp),
+ UdpStats = get_trans_stats(UdpSup, megaco_udp),
+ Parent ! {statistics, 2, [{gen, Gen}, {trans, [TcpStats, UdpStats]}], self()},
+ mgc_loop(S);
+
+
+ %% Megaco callback messages
+ {request, Request, From} ->
+ d("mgc_loop -> received megaco request: ~n~p~n From: ~p",
+ [Request, From]),
+ Reply = mgc_handle_request(Request),
+ d("mgc_loop -> send request reply: ~n~p", [Reply]),
+ From ! {reply, Reply, self()},
+ mgc_loop(S);
+
+
+ {'EXIT', Pid, Reason} ->
+ error_msg("MGC received unexpected exit signal from ~p:~n~p",
+ [Pid, Reason]),
+ mgc_loop(S);
+
+
+ Invalid ->
+ i("mgc_loop -> received invalid request: ~p", [Invalid]),
+ mgc_loop(S)
+ end.
+
+
+mgc_reset_stats(Mid) ->
+ megaco:reset_stats(),
+ mgc_reset_trans_stats(megaco:user_info(Mid, connections), []).
+
+mgc_reset_trans_stats([], _Reset) ->
+ ok;
+mgc_reset_trans_stats([CH|CHs], Reset) ->
+ SendMod = megaco:conn_info(CH, send_mod),
+ case lists:member(SendMod, Reset) of
+ true ->
+ mgc_reset_trans_stats(CHs, Reset);
+ false ->
+ SendMod:reset_stats(),
+ mgc_reset_trans_stats(CHs, [SendMod|Reset])
+ end.
+
+
+mgc_close_conns(Mid) ->
+ Reason = {self(), ignore},
+ Disco = fun(CH) ->
+ (catch mgc_close_conn(CH, Reason))
+ end,
+ lists:map(Disco, megaco:user_info(Mid, connections)).
+
+mgc_close_conn(CH, Reason) ->
+ d("close connection to ~p", [CH#megaco_conn_handle.remote_mid]),
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ megaco:disconnect(CH, Reason),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end.
+
+get_trans_stats(P, SendMod) when is_pid(P) ->
+ case (catch SendMod:get_stats()) of
+ {ok, Stats} ->
+ {SendMod, Stats};
+ Else ->
+ {SendMod, Else}
+ end;
+get_trans_stats(_P, SendMod) ->
+ {SendMod, undefined}.
+
+mgc_parse_receive_info([], _RH) ->
+ throw({error, no_receive_info});
+mgc_parse_receive_info(RI, RH) ->
+ mgc_parse_receive_info(RI, RH, []).
+
+mgc_parse_receive_info([], _RH, ListenTo) ->
+ ListenTo;
+mgc_parse_receive_info([RI|RIs], RH, ListenTo) ->
+ d("mgc_parse_receive_info -> parse receive info"),
+ RH1 = mgc_parse_receive_info1(RI, RH),
+ case (catch mgc_parse_receive_info1(RI, RH)) of
+ {error, Reason} ->
+ i("failed parsing receive info: ~p~n~p", [RI, Reason]),
+ exit({failed_parsing_recv_info, RI, Reason});
+ RH1 ->
+ mgc_parse_receive_info(RIs, RH, [RH1|ListenTo])
+ end.
+
+mgc_parse_receive_info1(RI, RH) ->
+ d("mgc_parse_receive_info1 -> get encoding module"),
+ EM = get_encoding_module(RI),
+ d("mgc_parse_receive_info1 -> get encoding config"),
+ EC = get_encoding_config(RI, EM),
+ d("mgc_parse_receive_info1 -> get transport module"),
+ TM = get_transport_module(RI),
+ d("mgc_parse_receive_info1 -> get transport port"),
+ TP = get_transport_port(RI),
+ RH1 = RH#megaco_receive_handle{send_mod = TM,
+ encoding_mod = EM,
+ encoding_config = EC},
+ {TP, RH1}.
+
+
+mgc_start_transports([]) ->
+ throw({error, no_transport});
+mgc_start_transports(ListenTo) ->
+ mgc_start_transports(ListenTo, undefined, undefined).
+
+
+mgc_start_transports([], TcpSup, UdpSup) ->
+ {TcpSup, UdpSup};
+mgc_start_transports([{Port, RH}|ListenTo], TcpSup, UdpSup)
+ when RH#megaco_receive_handle.send_mod == megaco_tcp ->
+ TcpSup1 = mgc_start_tcp(RH, Port, TcpSup),
+ mgc_start_transports(ListenTo, TcpSup1, UdpSup);
+mgc_start_transports([{Port, RH}|ListenTo], TcpSup, UdpSup)
+ when RH#megaco_receive_handle.send_mod == megaco_udp ->
+ UdpSup1 = mgc_start_udp(RH, Port, UdpSup),
+ mgc_start_transports(ListenTo, TcpSup, UdpSup1);
+mgc_start_transports([{_Port, RH}|_ListenTo], _TcpSup, _UdpSup) ->
+ throw({error, {bad_send_mod, RH#megaco_receive_handle.send_mod}}).
+
+
+mgc_start_tcp(RH, Port, undefined) ->
+ d("start tcp transport"),
+ case megaco_tcp:start_transport() of
+ {ok, Sup} ->
+ mgc_start_tcp(RH, Port, Sup);
+ Else ->
+ throw({error, {failed_starting_tcp_transport, Else}})
+ end;
+mgc_start_tcp(RH, Port, Sup) when is_pid(Sup) ->
+ d("tcp listen on ~p", [Port]),
+ Opts = [{port, Port},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]}],
+ mgc_tcp_create_listen(Sup, Opts, 3).
+
+mgc_tcp_create_listen(Sup, Opts, N) ->
+ mgc_tcp_create_listen(Sup, Opts, N, 1, undefined).
+
+mgc_tcp_create_listen(_Sup, _Opts, N, N, InitialReason) ->
+ d("failed creating mgc tcp listen socket after ~p tries: ~p",
+ [N, InitialReason]),
+ throw({error, {failed_starting_tcp_listen, InitialReason}});
+mgc_tcp_create_listen(Sup, Opts, MaxN, N, _InitialReason)
+ when is_integer(N) andalso is_integer(MaxN) andalso (MaxN > N) ->
+ d("try create mgc tcp listen socket [~w]", [N]),
+ case megaco_tcp:listen(Sup, Opts) of
+ ok ->
+ Sup;
+ {error, {could_not_start_listener, {gen_tcp_listen, eaddrinuse} = Reason}} ->
+ sleep(N * 200),
+ mgc_tcp_create_listen(Sup, Opts, MaxN, N + 1, Reason);
+ {error, Reason} ->
+ throw({error, {failed_starting_tcp_listen, Reason}});
+ Else ->
+ throw({error, {failed_starting_tcp_listen, Else}})
+ end.
+
+
+mgc_start_udp(RH, Port, undefined) ->
+ d("start udp transport"),
+ case megaco_udp:start_transport() of
+ {ok, Sup} ->
+ mgc_start_udp(RH, Port, Sup);
+ Else ->
+ throw({error, {failed_starting_udp_transport, Else}})
+ end;
+mgc_start_udp(RH, Port, Sup) ->
+ d("open udp ~p", [Port]),
+ Opts = [{port, Port}, {receive_handle, RH}],
+ case megaco_udp:open(Sup, Opts) of
+ {ok, _SendHandle, _ControlPid} ->
+ Sup;
+ Else ->
+ exit({error, {failed_starting_udp_listen, Else}})
+ end.
+
+
+
+%% -----------------------
+%% Handle megaco callbacks
+%%
+
+mgc_handle_request({handle_connect, _CH, _PV}) ->
+ ok;
+mgc_handle_request({handle_disconnect, CH, _PV, R}) ->
+ megaco:cancel(CH, R), % Cancel the outstanding messages
+ ok;
+mgc_handle_request({handle_syntax_error, _RH, _PV, _ED}) ->
+ reply;
+mgc_handle_request({handle_message_error, _CH, _PV, _ED}) ->
+ no_reply;
+mgc_handle_request({handle_trans_request, CH, PV, ARs}) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only single service change on null context handled"},
+ case ARs of
+ [AR] ->
+ ContextId = AR#'ActionRequest'.contextId,
+ case AR#'ActionRequest'.commandRequests of
+ [CR] when ContextId == ?megaco_null_context_id ->
+ case CR#'CommandRequest'.command of
+ {serviceChangeReq, Req} ->
+ Rep = mgc_service_change(CH, PV, Req),
+ CmdRep = [{serviceChangeReply, Rep}],
+ {discard_ack,
+ [#'ActionReply'{contextId = ContextId,
+ commandReply = CmdRep}]};
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end;
+ _ ->
+ {discard_ack, ED}
+ end;
+mgc_handle_request({handle_trans_long_request, _CH, _PV, _RD}) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {discard_ack, ED};
+mgc_handle_request({handle_trans_reply, _CH, _PV, _AR, _RD}) ->
+ ok;
+mgc_handle_request({handle_trans_ack, _CH, _PV, _AS, _AD}) ->
+ ok.
+
+mgc_service_change(CH, _PV, SCR) ->
+ SCP = SCR#'ServiceChangeRequest'.serviceChangeParms,
+ #'ServiceChangeParm'{serviceChangeAddress = Address,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = [_Reason]} = SCP,
+ TermId = SCR#'ServiceChangeRequest'.terminationID,
+ if
+ TermId == [?megaco_root_termination_id] ->
+ MyMid = CH#megaco_conn_handle.local_mid,
+ Res = {serviceChangeResParms,
+ #'ServiceChangeResParm'{serviceChangeMgcId = MyMid,
+ serviceChangeAddress = Address,
+ serviceChangeProfile = Profile}},
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res};
+ true ->
+ Res = {errorDescriptor,
+ #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Only handled for root"}},
+
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Res}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_mg(Node, Mid, Encoding, Transport, Verbosity) ->
+ d("start mg[~p]: ~p", [Node, Mid]),
+ RI1 =
+ case Encoding of
+ text ->
+ [{encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {port,2944}];
+ binary ->
+ [{encoding_module, megaco_ber_bin_encoder},
+ {encoding_config, []},
+ {port,2945}]
+ end,
+ RI2 =
+ case Transport of
+ tcp ->
+ [{transport_module, megaco_tcp}];
+ udp ->
+ [{transport_module, megaco_udp}]
+ end,
+ RI = {receive_info, RI1 ++ RI2},
+ Config = [{local_mid, Mid}, RI],
+ Pid = spawn_link(Node, ?MODULE, mg, [self(), Verbosity, Config]),
+ await_started(Pid).
+
+
+mg(Parent, Verbosity, Config) ->
+ process_flag(trap_exit, true),
+ put(verbosity, Verbosity),
+ put(sname, "MG"),
+ i("mg -> starting"),
+ {Mid, ConnHandle} = mg_init(Config),
+ notify_started(Parent),
+ S = #mg{parent = Parent, mid = Mid, conn_handle = ConnHandle},
+ i("mg -> started"),
+ mg_loop(S).
+
+mg_init(Config) ->
+ d("mg_init -> entry"),
+ random_init(),
+ Mid = get_conf(local_mid, Config),
+ RI = get_conf(receive_info, Config),
+ d("mg_init -> start megaco"),
+ application:start(megaco),
+ d("mg_init -> start megaco user"),
+ megaco:start_user(Mid, []),
+ d("mg_init -> update user info (user_mod)"),
+ megaco:update_user_info(Mid, user_mod, ?MODULE),
+ d("mg_init -> update user info (user_args)"),
+ megaco:update_user_info(Mid, user_args, [self()]),
+ d("mg_init -> get user info (receive_handle)"),
+ RH = megaco:user_info(Mid,receive_handle),
+ d("mg_init -> parse receive info"),
+ {MgcPort,RH1} = mg_parse_receive_info(RI, RH),
+ d("mg_init -> start transport with"),
+ ConnHandle = mg_start_transport(MgcPort, RH1),
+ {Mid, ConnHandle}.
+
+mg_loop(#mg{state = State} = S) ->
+ d("mg_loop(~p) -> await request", [State]),
+ receive
+ {stop, Parent} when S#mg.parent == Parent ->
+ i("mg_loop(~p) -> stopping", [State]),
+ mg_close_conn(S#mg.conn_handle),
+ megaco:stop_user(S#mg.mid),
+ application:stop(megaco),
+ i("mg_loop(~p) -> stopped", [State]),
+ Parent ! {stopped, self()},
+ exit(normal);
+
+
+ {reset_stats, Parent} when S#mg.parent == Parent ->
+ i("mg_loop(~p) -> got request to reset stats counters", [State]),
+ %% mg_reset_stats(S#mgc.conn_handle),
+ mg_reset_stats(S#mg.conn_handle),
+ Parent ! {reset_stats_ack, self()},
+ mg_loop(S);
+
+
+
+ %% Give me statistics
+ {statistics, 1, Parent} when S#mg.parent == Parent ->
+ i("mg_loop(~p) -> got request for statistics 1", [State]),
+ {ok, Gen} = megaco:get_stats(),
+ CH = S#mg.conn_handle,
+ Reason = {statistics, CH},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ {ok, Trans} =
+ case SendMod of
+ megaco_tcp -> megaco_tcp:get_stats(SendHandle);
+ megaco_udp -> megaco_udp:get_stats(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end,
+ Parent ! {statistics, 1, [{gen, Gen}, {trans, Trans}], self()},
+ mg_loop(S);
+
+
+ %% Do a service change
+ {service_change, Parent} when S#mg.parent == Parent,
+ State == initiated ->
+ i("mg_loop(~p) -> received request to perform service change",
+ [State]),
+ Res = mg_service_change(S#mg.conn_handle),
+ d("mg_loop(~p) -> result: ~p", [State, Res]),
+ mg_loop(S#mg{state = connecting});
+
+
+ %% Apply some load
+ {apply_load, Parent, Times} when S#mg.parent == Parent ->
+ i("mg_loop(~p) -> received apply_load request", [State]),
+ apply_load_timer(),
+ Parent ! {apply_load_ack, self()},
+ mg_loop(S#mg{load_counter = Times - 1});
+
+
+ apply_load_timeout ->
+ d("mg_loop(~p) -> received apply_load timeout [~p]",
+ [State, S#mg.load_counter]),
+ mg_apply_load(S),
+ mg_loop(S);
+
+
+ %% Megaco callback messages
+ {request, Request, From} ->
+ d("mg_loop(~p) -> received megaco request: ~n~p~n From: ~p",
+ [State, Request, From]),
+ {Reply, NewS} = mg_handle_request(Request, S),
+ d("mg_loop(~p) -> send request reply: ~n~p",
+ [NewS#mg.state, Reply]),
+ From ! {reply, Reply, self()},
+ mg_loop(NewS);
+
+
+ {'EXIT', Pid, Reason} ->
+ error_msg("MG ~p received unexpected exit signal from ~p:~n~p",
+ [S#mg.mid, Pid, Reason]),
+ mg_loop(S);
+
+
+ Invalid ->
+ i("mg_loop(~p) -> received invalid request: ~p", [State, Invalid]),
+ mg_loop(S)
+
+ end.
+
+
+mg_reset_stats(CH) ->
+ megaco:reset_stats(),
+ case (catch megaco:conn_info(CH, send_mod)) of
+ {error, Reason} ->
+ error_msg("unexpected result when retrieving send module for "
+ "own connection ~p: ~p. "
+ "~nexiting...", [CH, Reason]),
+ exit({invalid_connection, CH, Reason});
+ {'EXIT', Reason} ->
+ error_msg("exit signal when retrieving send module for "
+ "own connection ~p: ~p. "
+ "~nexiting...", [CH, Reason]),
+ exit({invalid_connection, CH, Reason});
+ SendMod when is_atom(SendMod) ->
+ SendMod:reset_stats()
+ end.
+
+
+mg_close_conn(CH) ->
+ Reason = {self(), ignore},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ megaco:disconnect(CH, Reason),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end.
+
+% display_tuple(T) when tuple(T), size(T) > 0 ->
+% i("size(T): ~p", [size(T)]),
+% display_tuple(T,1).
+
+% display_tuple(T,P) when P > size(T) ->
+% ok;
+% display_tuple(T,P) ->
+% i("T[~p]: ~p", [P,element(P,T)]),
+% display_tuple(T,P+1).
+
+
+mg_parse_receive_info(RI, RH) ->
+ d("mg_parse_receive_info -> get encoding module"),
+ EM = get_encoding_module(RI),
+ d("mg_parse_receive_info -> get encoding config"),
+ EC = get_encoding_config(RI, EM),
+ d("mg_parse_receive_info -> get transport module"),
+ TM = get_transport_module(RI),
+ d("mg_parse_receive_info -> get transport port"),
+ TP = get_transport_port(RI),
+ RH1 = RH#megaco_receive_handle{send_mod = TM,
+ encoding_mod = EM,
+ encoding_config = EC},
+ {TP, RH1}.
+
+
+mg_start_transport(MgcPort,
+ #megaco_receive_handle{send_mod = megaco_tcp} = RH) ->
+ mg_start_tcp(MgcPort,RH);
+mg_start_transport(MgcPort,
+ #megaco_receive_handle{send_mod = megaco_udp} = RH) ->
+ mg_start_udp(MgcPort,RH);
+mg_start_transport(_, #megaco_receive_handle{send_mod = Mod}) ->
+ throw({error, {bad_send_mod, Mod}}).
+
+
+mg_start_tcp(MgcPort, RH) ->
+ d("start tcp transport"),
+ case megaco_tcp:start_transport() of
+ {ok, Sup} ->
+ {ok, LocalHost} = inet:gethostname(),
+ Opts = [{host, LocalHost},
+ {port, MgcPort},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]}],
+ case megaco_tcp:connect(Sup, Opts) of
+ {ok, SendHandle, ControlPid} ->
+ PrelMgcMid = preliminary_mid,
+ {ok, ConnHandle} =
+ megaco:connect(RH, PrelMgcMid,
+ SendHandle, ControlPid),
+ ConnHandle;
+ {error, Reason} ->
+ {error, {megaco_tcp_connect, Reason}}
+ end;
+ {error, Reason} ->
+ {error, {megaco_tcp_start_transport, Reason}}
+ end.
+
+
+mg_start_udp(MgcPort, RH) ->
+ d("start udp transport"),
+ case megaco_udp:start_transport() of
+ {ok, Sup} ->
+ {ok, LocalHost} = inet:gethostname(),
+ Opts = [{port, 0}, {receive_handle, RH}],
+ case megaco_udp:open(Sup, Opts) of
+ {ok, Handle, ControlPid} ->
+ MgcMid = preliminary_mid,
+ SendHandle = megaco_udp:create_send_handle(Handle,
+ LocalHost,
+ MgcPort),
+ {ok, ConnHandle} =
+ megaco:connect(RH, MgcMid,
+ SendHandle, ControlPid),
+ ConnHandle;
+ {error, Reason} ->
+ {error, {megaco_udp_open, Reason}}
+ end;
+ {error, Reason} ->
+ {error, {megaco_udp_start_transport, Reason}}
+ end.
+
+
+mg_service_change(ConnHandle) ->
+ mg_service_change(ConnHandle, restart, ?megaco_cold_boot).
+
+mg_service_change(ConnHandle, Method, Reason) ->
+ SCP = #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeReason = [Reason]},
+ TermId = [?megaco_root_termination_id],
+ SCR = #'ServiceChangeRequest'{terminationID = TermId,
+ serviceChangeParms = SCP},
+ CR = #'CommandRequest'{command = {serviceChangeReq, SCR}},
+ AR = #'ActionRequest'{contextId = ?megaco_null_context_id,
+ commandRequests = [CR]},
+ megaco:cast(ConnHandle, [AR], []).
+
+
+mg_notify_request(CH) ->
+ TimeStamp = cre_timeNotation("19990729", "22000000"),
+ Event = cre_observedEvent("al/of",TimeStamp),
+ Desc = cre_observedEventsDesc(2222,[Event]),
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = ?A4444}],Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ ActReq = cre_actionReq(?megaco_null_context_id, [CmdReq]),
+ megaco:cast(CH, [ActReq], [{reply_data, Desc}]).
+
+mg_apply_load(#mg{conn_handle = CH}) ->
+ mg_notify_request(CH).
+
+
+cre_actionReq(Cid, Cmds) ->
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Cmds}.
+
+cre_commandReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid, observedEventsDescriptor = EvsDesc}.
+
+cre_observedEventsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id, observedEventLst = EvList}.
+
+cre_observedEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name, timeNotation = Not}.
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+%% -----------------------
+%% Handle megaco callbacks
+%%
+
+mg_handle_request({handle_connect, CH, _PV},
+ #mg{state = connecting} = S) ->
+ {ok, S#mg{conn_handle = CH}};
+
+mg_handle_request({handle_disconnect, CH, _PV, _R}, S) ->
+ {ok, S#mg{conn_handle = CH}};
+
+mg_handle_request({handle_syntax_error, _RH, _PV, _ED}, S) ->
+ {reply, S};
+
+mg_handle_request({handle_message_error, CH, _PV, _ED}, S) ->
+ {no_reply, S#mg{conn_handle = CH}};
+
+mg_handle_request({handle_trans_request, CH, _PV, _AR}, S) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Transaction requests not handled"},
+ {{discard_ack, ED}, S#mg{conn_handle = CH}};
+
+mg_handle_request({handle_trans_long_request, CH, _PV, _RD}, S) ->
+ ED = #'ErrorDescriptor'{errorCode = ?megaco_not_implemented,
+ errorText = "Long transaction requests not handled"},
+ {{discard_ack, ED}, S#mg{conn_handle = CH}};
+
+mg_handle_request({handle_trans_reply, CH, _PV, _AR, _RD},
+ #mg{parent = Pid, state = connecting} = S) ->
+ %% Should really check this...
+ Pid ! {service_change_reply, ok, self()},
+ {ok, S#mg{conn_handle = CH, state = connected}};
+mg_handle_request({handle_trans_reply, _CH, _PV, {error, ED}, RD},
+ #mg{parent = Pid, load_counter = 0} = S)
+ when is_record(ED, 'ErrorDescriptor') andalso
+ is_record(RD, 'ObservedEventsDescriptor') ->
+ Pid ! {load_complete, self()},
+ {ok, S};
+mg_handle_request({handle_trans_reply, _CH, _PV, {error, ED}, RD},
+ #mg{load_counter = N} = S)
+ when is_record(ED, 'ErrorDescriptor') andalso
+ is_record(RD, 'ObservedEventsDescriptor') ->
+ apply_load_timer(),
+ {ok, S#mg{load_counter = N-1}};
+
+mg_handle_request({handle_trans_ack, _CH, _PV, _AS, _AD}, S) ->
+ {ok, S}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_started(Pid) ->
+ receive
+ {started, Pid} ->
+ d("await_started ~p: ok", [Pid]),
+ {ok, Pid};
+ {'EXIT', Pid, Reason} ->
+ i("await_started ~p: received exit signal: ~p", [Pid, Reason]),
+ exit({failed_starting, Pid, Reason})
+ after 10000 ->
+ i("await_started ~p: timeout", [Pid]),
+ exit({error, timeout})
+ end.
+
+stop(Pid) ->
+ d("stop ~p", [Pid]),
+ Pid ! {stop, self()},
+ receive
+ {stopped, Pid} ->
+ d("stop -> received stopped from ~p", [Pid]),
+ ok;
+ {'EXIT', Pid, Reason} ->
+ i("stop ~p: received exit signal: ~p", [Pid, Reason]),
+ exit({failed_stopping, Pid, Reason})
+ after 10000 ->
+ exit({error, timeout})
+ end.
+
+get_stats(Pid, No) ->
+ d("get_stats ~p", [Pid]),
+ Pid ! {statistics, No, self()},
+ receive
+ {statistics, No, Stats, Pid} ->
+ {ok, Stats};
+ {'EXIT', Pid, Reason} ->
+ i("get_stats ~p: received exit signal: ~p", [Pid, Reason]),
+ exit({failed_getting_stats, Pid, Reason})
+ after 10000 ->
+ exit({error, timeout})
+ end.
+
+service_change(Pid) ->
+ d("service_change ~p", [Pid]),
+ Pid ! {service_change, self()},
+ receive
+ {service_change_reply, Res, Pid} ->
+ {ok, Res};
+ {'EXIT', Pid, Reason} ->
+ i("service_change ~p: received exit signal: ~p", [Pid, Reason]),
+ exit({failed_service_change, Pid, Reason})
+ after 10000 ->
+ exit({error, timeout})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+notify_started(Parent) ->
+ Parent ! {started, self()}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% The megaco user callback interface
+
+handle_connect(CH, PV, Pid) ->
+% i("handle_connect -> entry with"
+% "~n CH: ~p"
+% "~n PV: ~p"
+% "~n Pid: ~p", [CH, PV, Pid]),
+ case CH#megaco_conn_handle.remote_mid of
+ preliminary_mid ->
+ %% Avoids deadlock
+ ok;
+ _ ->
+ Reply = request(Pid, {handle_connect, CH, PV}),
+% d("handle_connect -> Reply:~n~p", [Reply]),
+ Reply
+ end.
+
+handle_disconnect(_CH, _PV,
+ {user_disconnect, {Pid, ignore}},
+ Pid) ->
+% i("handle_disconnect(ignore) -> entry with"
+% "~n CH: ~p"
+% "~n PV: ~p", [CH, PV]),
+ %% Avoids deadlock
+ ok;
+handle_disconnect(CH, PV, R, Pid) ->
+% i("handle_disconnect -> entry with"
+% "~n CH: ~p"
+% "~n PV: ~p"
+% "~n R: ~p", [CH, PV, R]),
+ request(Pid, {handle_disconnect, CH, PV, R}).
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+% i("handle_syntax_error -> entry with"
+% "~n ReceiveHandle: ~p"
+% "~n ProtocolVersion: ~p"
+% "~n ErrorDescriptor: ~p",
+% [ReceiveHandle, ProtocolVersion, ErrorDescriptor]),
+ Req = {handle_syntax_error, ReceiveHandle, ProtocolVersion,
+ ErrorDescriptor},
+ request(Pid, Req).
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+% i("handle_message_error -> entry with"
+% "~n ConnHandle: ~p"
+% "~n ProtocolVersion: ~p"
+% "~n ErrorDescriptor: ~p",
+% [ConnHandle, ProtocolVersion, ErrorDescriptor]),
+ Req = {handle_message_error, ConnHandle, ProtocolVersion, ErrorDescriptor},
+ request(Pid, Req).
+
+handle_trans_request(CH, PV, AR, Pid) ->
+% i("handle_trans_request -> entry with"
+% "~n CH: ~p"
+% "~n PV: ~p"
+% "~n AR: ~p"
+% "~n Pid: ~p", [CH, PV, AR, Pid]),
+ Reply = request(Pid, {handle_trans_request, CH, PV, AR}),
+% i("handle_trans_request -> Reply:~n~p", [Reply]),
+ Reply.
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Pid) ->
+% i("handle_trans_long_request -> entry with"
+% "~n ConnHandle: ~p"
+% "~n ProtocolVersion: ~p"
+% "~n ReqData: ~p", [ConnHandle, ProtocolVersion, ReqData]),
+ Req = {handle_trans_long_request, ConnHandle, ProtocolVersion, ReqData},
+ request(Pid, Req).
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData, Pid) ->
+% i("handle_trans_reply -> entry with"
+% "~n ConnHandle: ~p"
+% "~n ProtocolVersion: ~p"
+% "~n ActualReply: ~p"
+% "~n ReplyData: ~p",
+% [ConnHandle, ProtocolVersion, ActualReply, ReplyData]),
+ Req = {handle_trans_reply, ConnHandle, ProtocolVersion,
+ ActualReply, ReplyData},
+ request(Pid, Req).
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Pid) ->
+% i("handle_trans_ack -> entry with"
+% "~n ConnHandle: ~p"
+% "~n ProtocolVersion: ~p"
+% "~n AckStatus: ~p"
+% "~n AckData: ~p",
+% [ConnHandle, ProtocolVersion, AckStatus, AckData]),
+ Req = {handle_trans_ack, ConnHandle, ProtocolVersion, AckStatus, AckData},
+ request(Pid, Req).
+
+
+request(Pid, Request) ->
+ Pid ! {request, Request, self()},
+ receive
+ {reply, Reply, Pid} ->
+ Reply
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) ->
+ receive after X -> ok end.
+
+
+error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+get_encoding_module(RI) ->
+ case (catch get_conf(encoding_module, RI)) of
+ {error, _} ->
+ undefined;
+ Val ->
+ Val
+ end.
+
+get_encoding_config(RI, EM) ->
+ case text_codec(EM) of
+ true ->
+ case megaco:system_info(text_config) of
+ [Conf] when is_list(Conf) ->
+ Conf;
+ _ ->
+ []
+ end;
+
+ false ->
+ get_conf(encoding_config, RI)
+ end.
+
+text_codec(megaco_compact_text_encoder) ->
+ true;
+text_codec(megaco_pretty_text_encoder) ->
+ true;
+text_codec(_) ->
+ false.
+
+
+get_transport_module(RI) ->
+ get_conf(transport_module, RI).
+
+get_transport_port(RI) ->
+ get_conf(port, RI).
+
+
+get_conf(Key, Config) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ exit({error, {not_found, Key, Config}})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), "", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), "DBG: ", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, P, F, A) ->
+ print(printable(Severity,Verbosity), P, F, A).
+
+print(true, P, F, A) ->
+ io:format("~s~p:~s: " ++ F ++ "~n", [P, self(), get(sname) | A]);
+print(_, _, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ 10 * random:uniform(50).
+
+apply_load_timer() ->
+ erlang:send_after(random(), self(), apply_load_timeout).
+
diff --git a/lib/megaco/test/megaco_mreq_test.erl b/lib/megaco/test/megaco_mreq_test.erl
new file mode 100644
index 0000000000..676acd8a12
--- /dev/null
+++ b/lib/megaco/test/megaco_mreq_test.erl
@@ -0,0 +1,470 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_mreq_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
+
+-define(LOAD_COUNTER_START, 10).
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+-define(MGC_START(Pid, Mid, ET, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)).
+-define(MGC_RESET_STATS(Pid), megaco_test_mgc:reset_stats(Pid)).
+-define(MGC_REQ_DISC(Pid,To), megaco_test_mgc:request_discard(Pid,To)).
+-define(MGC_REQ_PEND(Pid,To), megaco_test_mgc:request_pending(Pid,To)).
+-define(MGC_REQ_HAND(Pid), megaco_test_mgc:request_handle(Pid)).
+
+-define(MG_START(Pid, Mid, Enc, Transp, Verb),
+ megaco_test_mg:start(Pid, Mid, Enc, Transp, Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_GET_STATS(Pid, No), megaco_test_mg:get_stats(Pid, No)).
+-define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
+-define(MG_NOTIF_AR(Pid), megaco_test_mg:await_notify_reply(Pid)).
+-define(MG_CANCEL(Pid,R), megaco_test_mg:cancel_request(Pid,R)).
+-define(MG_APPLY_LOAD(Pid,CntStart), megaco_test_mg:apply_load(Pid,CntStart)).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ req_and_rep,
+ req_and_pending,
+ req_and_cancel
+ ],
+ Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+req_and_rep(suite) ->
+ [];
+req_and_rep(doc) ->
+ [];
+req_and_rep(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("req_and_rep -> starting"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ d("req_and_rep -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode,
+ Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("req_and_rep -> start the MGC"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("req_and_rep -> start and connect the MGs"),
+ MgConf0 = [{Mg1Node, "mg1", text, tcp, ?MG_VERBOSITY},
+ {Mg2Node, "mg2", text, udp, ?MG_VERBOSITY},
+ {Mg3Node, "mg3", binary, tcp, ?MG_VERBOSITY},
+ {Mg4Node, "mg4", binary, udp, ?MG_VERBOSITY}],
+ MgConf = req_and_rep_connect_mg(MgConf0, []),
+
+ %% Collect the (initial) MGs statistics
+ Stats1 = req_and_rep_get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for the MGs: ~n~p", [Stats1]),
+
+ %% Collect and check the MGC statistics
+ i("req_and_rep -> collect and check the MGC stats"),
+ {ok, MgcStats1} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats1]),
+
+
+ sleep(1000),
+
+
+ %% And apply some load
+ i("req_and_rep -> apply traffic load"),
+ ok = req_and_rep_apply_load(MgConf),
+
+ %% Await completion of load part and the collect traffic
+ i("req_and_rep -> await load completion"),
+ ok = req_and_rep_await_load_complete(MgConf),
+
+
+ sleep(1000),
+
+
+ i("req_and_rep -> collect the MGs statistics"),
+ Stats2 = req_and_rep_get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for MGs: ~n~p", [Stats2]),
+
+ i("req_and_rep -> collect the MGC statistics"),
+ {ok, MgcStats2} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats2]),
+
+
+ sleep(1000),
+
+
+ %% Reset counters
+ i("req_and_rep -> reset the MGs statistics"),
+ req_and_rep_reset_mg_stats(MgConf),
+ Stats3 = req_and_rep_get_mg_stats(MgConf, []),
+ d("req_and_rep -> stats for the MGs: ~n~p", [Stats3]),
+
+ i("req_and_rep -> reset the MGC statistics"),
+ req_and_rep_reset_mgc_stats(Mgc),
+ {ok, MgcStats3} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats3]),
+
+
+ sleep(1000),
+
+
+ %% Tell MGs to stop
+ i("req_and_rep -> stop the MGs"),
+ req_and_rep_stop_mg(MgConf),
+
+
+ sleep(1000),
+
+
+ %% Collect the statistics
+ i("req_and_rep -> collect the MGC statistics"),
+ {ok, MgcStats4} = ?MGC_GET_STATS(Mgc, 1),
+ d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats4]),
+ {ok, MgcStats5} = ?MGC_GET_STATS(Mgc, 2),
+ d("req_and_rep -> stats (2) for Mgc: ~n~p~n", [MgcStats5]),
+
+ %% Tell Mgc to stop
+ i("req_and_rep -> stop the MGC"),
+ ?MGC_STOP(Mgc),
+
+ i("req_and_rep -> done", []),
+ ok.
+
+
+req_and_rep_connect_mg([], Acc) ->
+ lists:reverse(Acc);
+req_and_rep_connect_mg([{Node, Name, Coding, Trans, Verb}|Mg], Acc) ->
+ Pid = req_and_rep_connect_mg(Node, Name, Coding, Trans, Verb),
+ req_and_rep_connect_mg(Mg, [{Name, Pid}|Acc]).
+
+req_and_rep_connect_mg(Node, Name, Coding, Trans, Verb) ->
+ Mid = {deviceName, Name},
+ {ok, Pid} = ?MG_START(Node, Mid, Coding, Trans, Verb),
+
+ %% Ask the MGs to do a service change
+ Res = ?MG_SERV_CHANGE(Pid),
+ d("req_and_rep_connect_mg -> (~s) service change result: ~p", [Name,Res]),
+
+ Pid.
+
+
+req_and_rep_stop_mg(MGs) ->
+ [?MG_STOP(Pid) || {_Name, Pid} <- MGs].
+
+
+req_and_rep_get_mg_stats([], Acc) ->
+ lists:reverse(Acc);
+req_and_rep_get_mg_stats([{Name, Pid}|Mgs], Acc) ->
+ {ok, Stats} = ?MG_GET_STATS(Pid, 1),
+ d("req_and_rep_get_mg_stats -> stats for ~s: ~n~p~n", [Name, Stats]),
+ req_and_rep_get_mg_stats(Mgs, [{Name, Stats}|Acc]).
+
+
+req_and_rep_apply_load([]) ->
+ ok;
+req_and_rep_apply_load([{_, MG}|MGs]) ->
+ ?MG_APPLY_LOAD(MG,?LOAD_COUNTER_START),
+ req_and_rep_apply_load(MGs).
+
+
+req_and_rep_reset_mg_stats([]) ->
+ ok;
+req_and_rep_reset_mg_stats([{Name, Pid}|MGs]) ->
+ d("req_and_rep_reset_mg_stats -> resetting ~s", [Name]),
+ ?MG_RESET_STATS(Pid),
+ req_and_rep_reset_mg_stats(MGs).
+
+req_and_rep_reset_mgc_stats(Mgc) ->
+ d("req_and_rep_reset_mgc_stats -> resetting ~p", [Mgc]),
+ ?MGC_RESET_STATS(Mgc).
+
+
+req_and_rep_await_load_complete([]) ->
+ ok;
+req_and_rep_await_load_complete(MGs0) ->
+ receive
+ {load_complete, Pid} ->
+ d("received load_complete from ~p", [Pid]),
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ req_and_rep_await_load_complete(lists:delete(Pid, MGs1));
+ {'EXIT', Pid, Reason} ->
+ i("exit signal from ~p: ~p", [Pid, Reason]),
+ case lists:keymember(Pid, 2, MGs0) of
+ true ->
+ exit({mg_exit, Pid, Reason});
+ false ->
+ MGs1 = lists:keydelete(Pid, 2, MGs0),
+ req_and_rep_await_load_complete(lists:delete(Pid, MGs1))
+ end
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+req_and_pending(suite) ->
+ [];
+req_and_pending(doc) ->
+ [];
+req_and_pending(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("req_and_pending -> starting"),
+
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+
+ d("req_and_pending -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p",
+ [MgcNode, Mg1Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("req_and_pending -> start the MGC"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("req_and_pending -> start the MG"),
+ {ok, Mg1} =
+ ?MG_START(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
+
+ i("req_and_pending -> connect the MG"),
+ Res1 = ?MG_SERV_CHANGE(Mg1),
+ d("req_and_pending -> service change result: ~p", [Res1]),
+
+ sleep(1000),
+
+ i("req_and_pending -> change request action to pending"),
+ {ok, _} = ?MGC_REQ_PEND(Mgc,3500),
+
+ i("req_and_pending -> send notify request"),
+ {ok, Res2} = ?MG_NOTIF_RAR(Mg1),
+ d("req_and_pending -> notify reply: ~p",[Res2]),
+
+ sleep(1000),
+
+ %% Tell MGs to stop
+ i("req_and_rep -> stop the MGs"),
+ ?MG_STOP(Mg1),
+
+ %% Tell Mgc to stop
+ i("req_and_pending -> stop the MGC"),
+ ?MGC_STOP(Mgc),
+
+ i("req_and_pending -> done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+req_and_cancel(suite) ->
+ [];
+req_and_cancel(doc) ->
+ [];
+req_and_cancel(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ i("req_and_cancel -> starting"),
+
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+
+ d("req_and_cancel -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p",
+ [MgcNode, Mg1Node]),
+ ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node],
+ ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("req_and_cancel -> start the MGC"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("req_and_cancel -> start the MG"),
+ {ok, Mg1} =
+ ?MG_START(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
+
+ i("req_and_cancel -> connect the MG"),
+ Res1 = ?MG_SERV_CHANGE(Mg1),
+ d("req_and_cancel -> service change result: ~p", [Res1]),
+
+
+ sleep(1000),
+
+ i("req_and_cancel -> change request action to pending"),
+ {ok, _} = ?MGC_REQ_DISC(Mgc,5000),
+
+ i("req_and_cancel -> send notify request"),
+ ?MG_NOTIF_REQ(Mg1),
+
+ d("req_and_cancel -> wait some to get it going",[]),
+ sleep(1000),
+
+ i("req_and_cancel -> now cancel the notify request"),
+ ok = ?MG_CANCEL(Mg1,req_and_cancel),
+
+ i("req_and_cancel -> now await the notify request result"),
+ Res2 = ?MG_NOTIF_AR(Mg1),
+ req_and_cancel_analyze_result(Res2),
+
+
+ %% Tell MGs to stop
+ i("req_and_rep -> stop the MGs"),
+ ?MG_STOP(Mg1),
+
+ %% Tell Mgc to stop
+ i("req_and_cancel -> stop the MGC"),
+ ?MGC_STOP(Mgc),
+
+ i("req_and_cancel -> done", []),
+ ok.% ?SKIP(not_implemented_yet).
+
+
+req_and_cancel_analyze_result({ok,{_PV,Res}}) ->
+ d("req_and_cancel -> notify request result: ~n ~p", [Res]),
+ req_and_cancel_analyze_result2(Res);
+req_and_cancel_analyze_result(Unexpected) ->
+ exit({unexpected_result,Unexpected}).
+
+req_and_cancel_analyze_result2([]) ->
+ ok;
+req_and_cancel_analyze_result2([{error,{user_cancel,req_and_cancel}}|Res]) ->
+ req_and_cancel_analyze_result2(Res);
+req_and_cancel_analyze_result2([Unknown|_Res]) ->
+ exit({unknown_result,Unknown}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) ->
+ receive after X -> ok end.
+
+
+error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), "", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), "DBG: ", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, P, F, A) ->
+ print(printable(Severity,Verbosity), P, F, A).
+
+print(true, P, F, A) ->
+ io:format("~s~p:~s: " ++ F ++ "~n", [P, self(), get(sname) | A]);
+print(_, _, _, _) ->
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ 10 * random:uniform(50).
+
+apply_load_timer() ->
+ erlang:send_after(random(), self(), apply_load_timeout).
+
diff --git a/lib/megaco/test/megaco_pending_limit_test.erl b/lib/megaco/test/megaco_pending_limit_test.erl
new file mode 100644
index 0000000000..1ca29c195c
--- /dev/null
+++ b/lib/megaco/test/megaco_pending_limit_test.erl
@@ -0,0 +1,2158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%% Testing the xxxOriginatingPendingLimit property of the
+%% root package
+%%----------------------------------------------------------------------
+-module(megaco_pending_limit_test).
+
+-export([t/0, t/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+-export([all/1,
+
+ sent/1,
+ sent_timer_late_reply/1,
+ sent_timer_exceeded/1,
+ sent_timer_exceeded_long/1,
+ sent_resend_late_reply/1,
+ sent_resend_exceeded/1,
+ sent_resend_exceeded_long/1,
+
+ recv/1,
+ recv_limit_exceeded1/1,
+ recv_limit_exceeded2/1,
+
+ tickets/1,
+ otp_4956/1,
+ otp_5310/1,
+ otp_5619/1
+
+ ]).
+
+-ifdef(megaco_hipe_special).
+-export([
+ %% Case: recv_limit_exceeded1
+ rle1_mgc_verify_service_change_req_msg/2,
+ rle1_mgc_verify_notify_req_msg/1,
+ rle1_mg_verify_handle_connect/1,
+ rle1_mg_verify_service_change_rep/1,
+ rle1_mg_verify_trans_rep/1,
+
+ %% Case: otp_4956
+ otp_4956_mgc_verify_handle_connect/1,
+ otp_4956_mgc_verify_service_change_req/2,
+ otp_4956_mgc_verify_notify_req1/1,
+ otp_4956_mgc_verify_notify_req2/1,
+ otp_4956_mgc_verify_handle_trans_req_abort/1,
+ otp_4956_mgc_verify_handle_disconnect/1,
+ otp_4956_mg_verify_service_change_rep_msg/1,
+ otp_4956_mg_verify_pending_msg/1,
+ otp_4956_mg_verify_pending_limit_msg/1,
+
+ %% Utility
+ encode_msg/3,
+ decode_msg/3
+ ]).
+-endif.
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
+
+-define(VERSION, 1).
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+-define(MGC_START(Pid, Mid, ET, Conf, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET, Conf, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)).
+-define(MGC_RESET_STATS(Pid), megaco_test_mgc:reset_stats(Pid)).
+-define(MGC_REQ_IGNORE(Pid), megaco_test_mgc:request_ignore(Pid)).
+-define(MGC_REQ_PIGNORE(Pid), megaco_test_mgc:request_pending_ignore(Pid)).
+-define(MGC_REQ_DISC(Pid,To), megaco_test_mgc:request_discard(Pid,To)).
+-define(MGC_REQ_PEND(Pid,To), megaco_test_mgc:request_pending(Pid,To)).
+-define(MGC_REQ_HAND(Pid, To), megaco_test_mgc:request_handle(Pid, To)).
+-define(MGC_REQ_HANDS(Pid), megaco_test_mgc:request_handle_sloppy(Pid)).
+-define(MGC_UPDATE_UI(Pid,Tag,Val),
+ megaco_test_mgc:update_user_info(Pid,Tag,Val)).
+-define(MGC_UPDATE_CI(Pid,Tag,Val),
+ megaco_test_mgc:update_conn_info(Pid,Tag,Val)).
+-define(MGC_USER_INFO(Pid,Tag), megaco_test_mgc:user_info(Pid,Tag)).
+-define(MGC_CONN_INFO(Pid,Tag), megaco_test_mgc:conn_info(Pid,Tag)).
+-define(MGC_ACK_INFO(Pid,To), megaco_test_mgc:ack_info(Pid,To)).
+-define(MGC_ABORT_INFO(Pid,To), megaco_test_mgc:abort_info(Pid,To)).
+-define(MGC_DISCO(Pid,Reason), megaco_test_mgc:disconnect(Pid,Reason)).
+
+-define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb),
+ megaco_test_mg:start(Pid, Mid, Enc, Transp, Conf, Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_GET_STATS(Pid, No), megaco_test_mg:get_stats(Pid, No)).
+-define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
+-define(MG_NOTIF_AR(Pid), megaco_test_mg:await_notify_reply(Pid)).
+-define(MG_CANCEL(Pid,R), megaco_test_mg:cancel_request(Pid,R)).
+-define(MG_APPLY_LOAD(Pid,CntStart), megaco_test_mg:apply_load(Pid,CntStart)).
+-define(MG_UPDATE_UI(Pid,Tag,Val),
+ megaco_test_mg:update_user_info(Pid,Tag,Val)).
+-define(MG_UPDATE_CI(Pid,Tag,Val),
+ megaco_test_mg:update_conn_info(Pid,Tag,Val)).
+-define(MG_USER_INFO(Pid,Tag), megaco_test_mg:user_info(Pid,Tag)).
+-define(MG_CONN_INFO(Pid,Tag), megaco_test_mg:conn_info(Pid,Tag)).
+-define(MG_GRP_REQ(Pid,N), megaco_test_mg:group_requests(Pid,N)).
+-define(MG_ECC(Pid, M, T, F), megaco_test_mg:enable_test_code(Pid,M,T,F)).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ [
+ sent,
+ recv,
+
+ %% Tickets last
+ tickets
+ ].
+
+sent(suite) ->
+ [
+ sent_timer_late_reply,
+ sent_timer_exceeded,
+ sent_timer_exceeded_long,
+ sent_resend_late_reply,
+ sent_resend_exceeded,
+ sent_resend_exceeded_long
+
+ ].
+
+recv(suite) ->
+ [
+ recv_limit_exceeded1,
+ recv_limit_exceeded2
+ ].
+
+tickets(suite) ->
+ [
+ otp_4956,
+ otp_5310,
+ otp_5619
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% Sent pending test cases %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sent_timer_late_reply(suite) ->
+ [];
+sent_timer_late_reply(doc) ->
+ "...";
+sent_timer_late_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_timer_late_reply),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ MgcConf = [{megaco_trace, false}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, MgcConf, ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConf = [{megaco_trace, io}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConf, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MGC] late reply to requests "
+ "(simulate that the request takes a long time)"),
+ {ok, _} = ?MGC_REQ_DISC(Mgc, 11000),
+
+ d("[MG] send the notify"),
+ {ok, Reply} = ?MG_NOTIF_RAR(Mg),
+ d("[MG] Reply: ~p", [Reply]),
+ case Reply of
+ {_Version, {ok, [_ActionReply]}} ->
+ ok;
+ _ ->
+ ?ERROR({unexpected_reply, Reply})
+ end,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sent_timer_exceeded(suite) ->
+ [];
+sent_timer_exceeded(doc) ->
+ "...";
+sent_timer_exceeded(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_timer_exceeded),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MGC] no reply to requests "
+ "(simulate that the request takes a __long__ time)"),
+ ?MGC_REQ_IGNORE(Mgc),
+
+ d("sleep 5 seconds to align trace output"),
+ sleep(5000),
+
+ d("[MG] send the notify"),
+ {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
+ d("[MG] ED: ~p", [ED]),
+ ErrorCode = ?megaco_number_of_transactionpending_exceeded,
+ ErrorCode = ED#'ErrorDescriptor'.errorCode,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sent_timer_exceeded_long(suite) ->
+ [];
+sent_timer_exceeded_long(doc) ->
+ "...";
+sent_timer_exceeded_long(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_timer_exceeded_long),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MGC] long request with no reply ~n"
+ " (simulate that we know that this will "
+ "take a while, but takes even longer...)"),
+ ?MGC_REQ_PIGNORE(Mgc),
+
+ d("[MG] send the notify"),
+ {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
+ d("[MG] ED: ~p", [ED]),
+ ErrorCode = ?megaco_number_of_transactionpending_exceeded,
+ ErrorCode = ED#'ErrorDescriptor'.errorCode,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case can only be run with the stack compiled with
+%% the MEGACO_TEST_CODE flag. Therefor there is no point in
+%% including this test case in the usual test suite
+-ifdef(MEGACO_TEST_CODE).
+sent_resend_late_reply(suite) ->
+ [];
+sent_resend_late_reply(doc) ->
+ "...";
+sent_resend_late_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_resend_late_reply),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = infinity,
+ %% PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ %% factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MG] update connection info request timer"),
+ RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
+
+ d("[MGC] no reply to requests "
+ "(simulate that the request takes a __long__ time)"),
+ ?MGC_REQ_IGNORE(Mgc),
+
+ d("[MG] set the 'init_request_timer' tag"),
+ EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
+ init_request_timer, fun init_request_timer/1)),
+ d("[MG] EccRes: ~p", [EccRes]),
+
+ d("[MGC] late reply to requests "
+ "(simulate that the request takes a long time)"),
+ ?MGC_REQ_DISC(Mgc, 11000),
+
+ d("[MG] send the notify"),
+ {ok, Reply} = (catch ?MG_NOTIF_RAR(Mg)),
+ d("[MG] Reply: ~p", [Reply]),
+ {_Version, {ok, [_ActionReply]}} = Reply,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+-else.
+
+sent_resend_late_reply(suite) ->
+ [];
+sent_resend_late_reply(doc) ->
+ "...";
+sent_resend_late_reply(Config) when is_list(Config) ->
+ ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
+
+-endif.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case can only be run with the stack compiled with
+%% the MEGACO_TEST_CODE flag. Therefor there is no point in
+%% including this test case in the usual test suite
+-ifdef(MEGACO_TEST_CODE).
+sent_resend_exceeded(suite) ->
+ [];
+sent_resend_exceeded(doc) ->
+ "...";
+sent_resend_exceeded(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_resend_exceeded),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = infinity,
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MG] update connection info request timer"),
+ RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
+
+ d("[MGC] no reply to requests "
+ "(simulate that the request takes a __long__ time)"),
+ ?MGC_REQ_IGNORE(Mgc),
+
+ d("[MG] set the 'init_request_timer' tag"),
+ EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
+ init_request_timer, fun init_request_timer/1)),
+ d("[MG] EccRes: ~p", [EccRes]),
+
+ d("[MG] send the notify"),
+ ED = (catch ?MG_NOTIF_RAR(Mg)),
+ d("[MG] ED: ~p", [ED]),
+ ErrorCode = ?megaco_number_of_transactionpending_exceeded,
+ #'ErrorDescriptor'{errorCode = ErrorCode} = ED,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+-else.
+
+sent_resend_exceeded(suite) ->
+ [];
+sent_resend_exceeded(doc) ->
+ "...";
+sent_resend_exceeded(Config) when is_list(Config) ->
+ ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
+
+-endif.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case can only be run with the stack compiled with
+%% the MEGACO_TEST_CODE flag. Therefor there is no point in
+%% including this test case in the usual test suite
+-ifdef(MEGACO_TEST_CODE).
+sent_resend_exceeded_long(suite) ->
+ [];
+sent_resend_exceeded_long(doc) ->
+ "...";
+sent_resend_exceeded_long(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, sent_resend_exceeded_long),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = infinity,
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("[MG] update connection info request timer"),
+ RequestTimer = #megaco_incr_timer{wait_for = timer:seconds(5),
+ factor = 1},
+ ?MG_UPDATE_CI(Mg, request_timer, RequestTimer),
+
+ d("[MGC] long request with no reply ~n"
+ " (simulate that we know that this will "
+ "take a while, but takes even longer...)"),
+ ?MGC_REQ_PIGNORE(Mgc),
+
+ d("[MG] set the 'init_request_timer' tag"),
+ EccRes = (catch ?MG_ECC(Mg, megaco_messenger,
+ init_request_timer, fun init_request_timer/1)),
+ d("[MG] EccRes: ~p", [EccRes]),
+
+ d("[MG] send the notify"),
+ ED = (catch ?MG_NOTIF_RAR(Mg)),
+ d("[MG] ED: ~p", [ED]),
+ ErrorCode = ?megaco_number_of_transactionpending_exceeded,
+ #'ErrorDescriptor'{errorCode = ErrorCode} = ED,
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+-else.
+
+sent_resend_exceeded_long(suite) ->
+ [];
+sent_resend_exceeded_long(doc) ->
+ "...";
+sent_resend_exceeded_long(Config) when is_list(Config) ->
+ ?SKIP("included only if compiled with USE_MEGACO_TEST_CODE=true").
+
+-endif.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% Received peinding test cases %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv_limit_exceeded1(suite) ->
+ [];
+recv_limit_exceeded1(doc) ->
+ "Received pending limit exceeded (exactly)";
+recv_limit_exceeded1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rle1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rle1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rle1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rle1_mgc_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(rle1_mgc_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(rle1_mgc_verify_service_change_req_msg_fun(Mid),
+ {?MODULE, rle1_mgc_verify_service_change_req_msg, [Mid]}).
+-define(rle1_mgc_verify_notify_req_msg_fun(),
+ {?MODULE, rle1_mgc_verify_notify_req_msg, []}).
+-else.
+-define(rle1_mgc_decode_msg_fun(Mod, Conf),
+ rle1_mgc_decode_msg_fun(Mod, Conf)).
+-define(rle1_mgc_encode_msg_fun(Mod, Conf),
+ rle1_mgc_encode_msg_fun(Mod, Conf)).
+-define(rle1_mgc_verify_service_change_req_msg_fun(Mid),
+ rle1_mgc_verify_service_change_req_msg_fun(Mid)).
+-define(rle1_mgc_verify_notify_req_msg_fun(),
+ rle1_mgc_verify_notify_req_msg_fun()).
+-endif.
+
+rle1_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ EM = megaco_pretty_text_encoder,
+ EC = [],
+ rle1_mgc_event_sequence2(Mid, EM, EC).
+
+rle1_mgc_event_sequence2(Mid, EM, EC) ->
+ DecodeFun = ?rle1_mgc_decode_msg_fun(EM, EC),
+ EncodeFun = ?rle1_mgc_encode_msg_fun(EM, EC),
+ ServiceChangeReply =
+ rle1_mgc_service_change_reply_msg(Mid, 1, 0),
+ Pending = rle1_mgc_pending_msg(Mid,2),
+ ServiceChangeReqVerify =
+ ?rle1_mgc_verify_service_change_req_msg_fun(Mid),
+ NotifyReqVerify = ?rle1_mgc_verify_notify_req_msg_fun(),
+%% ServiceChangeReqVerify =
+%% rle1_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = rle1_mgc_verify_notify_request_fun(),
+ EvSeq =
+ [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-req",
+ {ServiceChangeReqVerify, 10000}},
+ {send, "service-change-reply", ServiceChangeReply},
+ {expect_receive, "notify-request", {NotifyReqVerify, 5000}},
+ {sleep, 100},
+ {send, "pending 1", Pending},
+ {sleep, 100},
+ {send, "pending 2", Pending},
+ {sleep, 100},
+ {send, "pending 3", Pending},
+ {sleep, 100},
+ {send, "pending 4", Pending},
+ {sleep, 100},
+ {send, "pending 5", Pending},
+ {sleep, 1000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+rle1_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+
+rle1_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+rle1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ SCRP = #'ServiceChangeResParm'{serviceChangeMgcId = Mid},
+ SCRPs = {serviceChangeResParms,SCRP},
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = #'ServiceChangeReply'{terminationID = [Root],
+ serviceChangeResult = SCRPs},
+ CR = {serviceChangeReply, SCR},
+ rle1_mgc_msg(Mid, TransId, CR, Cid).
+
+rle1_mgc_msg(Mid, TransId, CR, Cid) ->
+ AR = #'ActionReply'{contextId = Cid,
+ commandReply = [CR]},
+ ARs = {actionReplies, [AR]},
+ TR = #'TransactionReply'{transactionId = TransId,
+ transactionResult = ARs},
+ Body = {transactions, [{transactionReply, TR}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+rle1_mgc_pending_msg(Mid, TransId) ->
+ TP = #'TransactionPending'{transactionId = TransId},
+ Body = {transactions, [{transactionPending, TP}]},
+ Mess = #'Message'{version = 1,
+ mId = Mid,
+ messageBody = Body},
+ #'MegacoMessage'{mess = Mess}.
+
+-ifndef(megaco_hipe_special).
+rle1_mgc_verify_service_change_req_msg_fun(Mid) ->
+ fun(M) ->
+ rle1_mgc_verify_service_change_req_msg(M, Mid)
+ end.
+-endif.
+
+rle1_mgc_verify_service_change_req_msg(#'MegacoMessage'{mess = Mess} = M,
+ _Mid1) ->
+ io:format("rle1_mgc_verify_service_change_req_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ #'Message'{version = _V,
+ mId = _Mid2,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{transactionId = _Tid,
+ actions = [AR]} = TR,
+ #'ActionRequest'{contextId = _Cid,
+ contextRequest = _CtxReq,
+ contextAttrAuditReq = _CtxAar,
+ commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd,
+ optional = _Opt,
+ wildcardReturn = _WR} = CR,
+ {serviceChangeReq, SCR} = Cmd,
+ #'ServiceChangeRequest'{terminationID = _TermID,
+ serviceChangeParms = SCP} = SCR,
+ #'ServiceChangeParm'{serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} = SCP,
+ {ok, M};
+rle1_mgc_verify_service_change_req_msg(M, _Mid) ->
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+rle1_mgc_verify_notify_req_msg_fun() ->
+ fun(M) ->
+ rle1_mgc_verify_notify_req_msg(M)
+ end.
+-endif.
+
+rle1_mgc_verify_notify_req_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rle1_mgc_verify_notify_req_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionRequest, TR} = Trans,
+ #'TransactionRequest'{actions = [AR]} = TR,
+ io:format("rle1_mgc_verify_notify_request_fun -> AR: "
+ "~n~p~n", [AR]),
+ #'ActionRequest'{commandRequests = [CR]} = AR,
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{observedEventsDescriptor = OED} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ {ok, M};
+rle1_mgc_verify_notify_req_msg(M) ->
+ {error, {invalid_message, M}}.
+
+% rle1_err_desc(T) ->
+% EC = ?megaco_internal_gateway_error,
+% ET = lists:flatten(io_lib:format("~w",[T])),
+% #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(rle1_mg_verify_handle_connect_fun(),
+ {?MODULE, rle1_mg_verify_handle_connect, []}).
+-define(rle1_mg_verify_service_change_rep_fun(),
+ {?MODULE, rle1_mg_verify_service_change_rep, []}).
+-define(rle1_mg_verify_trans_rep_fun(),
+ {?MODULE, rle1_mg_verify_trans_rep, []}).
+-else.
+-define(rle1_mg_verify_handle_connect_fun(),
+ fun rle1_mg_verify_handle_connect/1).
+-define(rle1_mg_verify_service_change_rep_fun(),
+ fun rle1_mg_verify_service_change_rep/1).
+-define(rle1_mg_verify_trans_rep_fun(),
+ fun rle1_mg_verify_trans_rep/1).
+-endif.
+
+rle1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ rle1_mg_event_sequence2(Mid, RI).
+
+rle1_mg_event_sequence2(Mid, RI) ->
+ ServiceChangeReq = [rle1_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [rle1_mg_notify_request_ar(1, Tid, 1)],
+ ConnectVerify = ?rle1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?rle1_mg_verify_service_change_rep_fun(),
+ TransReplyVerify = ?rle1_mg_verify_trans_rep_fun(),
+%% ConnectVerify = fun rle1_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun rle1_mg_verify_service_change_reply/1,
+%% TransReplyVerify = fun rle1_mg_verify_trans_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, recv_pending_limit, 4},
+ start_transport,
+ {megaco_trace, disable}, %%100},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, NotifyReq, []},
+ {megaco_callback, handle_trans_reply, TransReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+rle1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("rle1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rle1_mg_verify_handle_connect(Else) ->
+ io:format("rle1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+rle1_mg_verify_service_change_rep(
+ {handle_trans_reply, _CH, ?VERSION, {ok, [AR]}, _}) ->
+ io:format("rle1_mg_verify_service_change_rep -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+rle1_mg_verify_service_change_rep(Else) ->
+ io:format("rle1_mg_verify_service_change_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+rle1_mg_verify_trans_rep(
+ {handle_trans_reply, _CH, ?VERSION,
+ {error, exceeded_recv_pending_limit} = E, _}) ->
+ io:format("rle1_mg_verify_trans_rep -> expected error~n", []),
+ {ok, E , error};
+rle1_mg_verify_trans_rep(Else) ->
+ io:format("rle1_mg_verify_trans_rep -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, error}.
+
+rle1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rle1_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+
+%% ---
+
+recv_limit_exceeded2(suite) ->
+ [];
+recv_limit_exceeded2(doc) ->
+ "Received pending limit exceeded";
+recv_limit_exceeded2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rle2),
+ i("starting"),
+
+ _MgcNode = make_node_name(mgc),
+ _MgNode = make_node_name(mg),
+
+ ?SKIP(not_yet_implemented).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% Ticket test cases %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_4956(suite) ->
+ [];
+otp_4956(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_4956),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp_4956_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_tcp_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp_4956_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_tcp_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_tcp_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_4956_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp_4956_mgc_verify_handle_connect, []}).
+-define(otp_4956_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp_4956_mgc_verify_service_change_req, [Mid]}).
+-define(otp_4956_mgc_verify_notify_req1_fun(),
+ {?MODULE, otp_4956_mgc_verify_notify_req1, []}).
+-define(otp_4956_mgc_verify_notify_req2_fun(),
+ {?MODULE, otp_4956_mgc_verify_notify_req2, []}).
+-define(otp_4956_mgc_verify_handle_trans_req_abort_fun(),
+ {?MODULE, otp_4956_mgc_verify_handle_trans_req_abort, []}).
+-define(otp_4956_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp_4956_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp_4956_mgc_verify_handle_connect_fun(),
+ otp_4956_mgc_verify_handle_connect_fun()).
+-define(otp_4956_mgc_verify_service_change_req_fun(Mid),
+ otp_4956_mgc_verify_service_change_req_fun(Mid)).
+-define(otp_4956_mgc_verify_notify_req1_fun(),
+ otp_4956_mgc_verify_notify_req1_fun()).
+-define(otp_4956_mgc_verify_notify_req2_fun(),
+ otp_4956_mgc_verify_notify_req2_fun()).
+-define(otp_4956_mgc_verify_handle_trans_req_abort_fun(),
+ otp_4956_mgc_verify_handle_trans_req_abort_fun()).
+-define(otp_4956_mgc_verify_handle_disconnect_fun(),
+ fun otp_4956_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp_4956_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?otp_4956_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?otp_4956_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify1 = ?otp_4956_mgc_verify_notify_req1_fun(),
+ NotifyReqVerify2 = ?otp_4956_mgc_verify_notify_req2_fun(),
+ ReqAbortVerify = ?otp_4956_mgc_verify_handle_trans_req_abort_fun(),
+ DiscoVerify = ?otp_4956_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = otp_4956_mgc_verify_handle_connect_fun(),
+%% ServiceChangeReqVerify = otp_4956_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify1 = otp_4956_mgc_verify_notify_request_fun1(),
+%% NotifyReqVerify2 = otp_4956_mgc_verify_notify_request_fun2(),
+%% ReqAbortVerify = otp_4956_mgc_verify_handle_trans_request_abort_fun(),
+%% DiscoVerify = fun otp_4956_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ {megaco_update_user_info, sent_pending_limit, 4},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_conn_info, all},
+ {megaco_callback, handle_trans_request_sc, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request_1, NotifyReqVerify1},
+ {megaco_callback, handle_trans_request_abort, ReqAbortVerify},
+ {megaco_callback, nocall, 1000},
+ {megaco_callback, handle_trans_request_6, NotifyReqVerify2},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+-ifndef(megaco_hipe_special).
+otp_4956_mgc_verify_handle_connect_fun() ->
+ fun(M) ->
+ otp_4956_mgc_verify_handle_connect(M)
+ end.
+-endif.
+
+otp_4956_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ {ok, CH, ok};
+otp_4956_mgc_verify_handle_connect(Else) ->
+ {error, Else, ok}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Req) ->
+ otp_4956_mgc_verify_service_change_req(Req, Mid)
+ end.
+-endif.
+
+otp_4956_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("otp_4956_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p"
+ "~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp_4956_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp_4956_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp_4956_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp_4956_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp_4956_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp_4956_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp_4956_mgc_verify_service_change_req(Else, _Mid) ->
+ ED = otp_4956_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mgc_verify_notify_req1_fun() ->
+ fun(Req) ->
+ otp_4956_mgc_verify_notify_req1(Req)
+ end.
+-endif.
+
+otp_4956_mgc_verify_notify_req1({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp_4956_mgc_verify_notify_req1 -> entry with"
+ "~n AR: ~p"
+ "~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp_4956_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, 6500, AR, Reply};
+ _ ->
+ ED = otp_4956_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp_4956_mgc_verify_notify_req1(Else) ->
+ io:format("otp_4956_mgc_verify_notify_req1 -> entry with"
+ "~n Else: ~p"
+ "~n", [Else]),
+ ED = otp_4956_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mgc_verify_notify_req2_fun() ->
+ fun(Ev) ->
+ otp_4956_mgc_verify_notify_req2(Ev)
+ end.
+-endif.
+
+otp_4956_mgc_verify_notify_req2({handle_trans_request, _, ?VERSION, [AR]}) ->
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [_Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = ignore,
+ {ok, 100, AR, Reply};
+ _ ->
+ ED = otp_4956_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp_4956_mgc_verify_notify_req2(Else) ->
+ ED = otp_4956_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mgc_verify_handle_trans_req_abort_fun() ->
+ fun(Req) ->
+ otp_4956_mgc_verify_handle_trans_req_abort(Req)
+ end.
+-endif.
+
+otp_4956_mgc_verify_handle_trans_req_abort({handle_trans_request_abort,
+ CH, ?VERSION, 2, Pid}) ->
+ io:format("otp_4956_mgc_verify_handle_trans_req_abort -> ok"
+ "~n CH: ~p"
+ "~n Pid: ~p"
+ "~n", [CH, Pid]),
+ {ok, {CH, Pid}, ok};
+otp_4956_mgc_verify_handle_trans_req_abort({handle_trans_request_abort,
+ CH, Version, TransId, Pid}) ->
+ io:format("otp_4956_mgc_verify_handle_trans_req_abort -> error"
+ "~n CH: ~p"
+ "~n Version: ~p"
+ "~n TransId: ~p"
+ "~n Pid: ~p"
+ "~n", [CH, Version, TransId, Pid]),
+ {error, {error, {invalid_version_trans_id, Version, TransId}}, ok};
+otp_4956_mgc_verify_handle_trans_req_abort(Else) ->
+ io:format("otp_4956_mgc_verify_handle_trans_req_abort -> error"
+ "~n Else: ~p"
+ "~n", [Else]),
+ {error, Else, ok}.
+
+otp_4956_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, _R}) ->
+ io:format("otp_4956_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n _R: ~p"
+ "~n", [CH, _R]),
+ {ok, CH, ok};
+otp_4956_mgc_verify_handle_disconnect(Else) ->
+ io:format("otp_4956_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp_4956_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ AR.
+
+%% otp_4956_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+%% AR = otp_4956_mgc_service_change_reply_ar(Mid, Cid),
+%% TRes = cre_transResult([AR]),
+%% TR = cre_transReply(TransId, TRes),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+otp_4956_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+%% otp_4956_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+%% AR = otp_4956_mgc_notify_reply_ar(Cid, TermId),
+%% TRes = cre_transResult([AR]),
+%% TR = cre_transReply(TransId, TRes),
+%% Trans = cre_transaction(TR),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp_4956_mg_decode_msg_fun(Mod, Conf),
+ {?MODULE, decode_msg, [Mod, Conf]}).
+-define(otp_4956_mg_encode_msg_fun(Mod, Conf),
+ {?MODULE, encode_msg, [Mod, Conf]}).
+-define(otp_4956_mg_verify_service_change_rep_msg_fun(),
+ {?MODULE, otp_4956_mg_verify_service_change_rep_msg, []}).
+-define(otp_4956_mg_verify_pending_msg_fun(),
+ {?MODULE, otp_4956_mg_verify_pending_msg, []}).
+-define(otp_4956_mg_verify_pending_limit_msg_fun(),
+ {?MODULE, otp_4956_mg_verify_pending_limit_msg, []}).
+-else.
+-define(otp_4956_mg_decode_msg_fun(Mod, Conf),
+ otp_4956_mg_decode_msg_fun(Mod, Conf)).
+-define(otp_4956_mg_encode_msg_fun(Mod, Conf),
+ otp_4956_mg_encode_msg_fun(Mod, Conf)).
+-define(otp_4956_mg_verify_service_change_rep_msg_fun(),
+ otp_4956_mg_verify_service_change_rep_msg_fun()).
+-define(otp_4956_mg_verify_pending_msg_fun(),
+ otp_4956_mg_verify_pending_msg_fun()).
+-define(otp_4956_mg_verify_pending_limit_msg_fun(),
+ otp_4956_mg_verify_pending_limit_msg_fun()).
+-endif.
+
+otp_4956_mg_event_sequence(text, tcp) ->
+ DecodeFun = ?otp_4956_mg_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ?otp_4956_mg_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mg"},
+ ServiceChangeReq = otp_4956_mg_service_change_request_msg(Mid, 1, 0),
+ TermId = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = otp_4956_mg_notify_request_msg(Mid, 2, 1, TermId, 1),
+ ServiceChangeReplyVerifyFun = ?otp_4956_mg_verify_service_change_rep_msg_fun(),
+ PendingVerify = ?otp_4956_mg_verify_pending_msg_fun(),
+ PendingLimitVerify = ?otp_4956_mg_verify_pending_limit_msg_fun(),
+%% ServiceChangeReplyVerifyFun =
+%% otp_4956_mg_verify_service_change_rep_msg_fun(),
+%% PendingVerify = otp_4956_mg_verify_pending_msg_fun(),
+%% PendingLimitVerify = otp_4956_mg_verify_pending_limit_msg_fun(),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {connect, 2944},
+ {send, "service-change-request", ServiceChangeReq},
+ {expect_receive, "service-change-reply", {ServiceChangeReplyVerifyFun, 10000}},
+ {send, "notify request (first send)", NotifyReq},
+ {sleep, 100},
+ {send, "notify request (resend 1)", NotifyReq},
+ {expect_receive, "pending 1", {PendingVerify, 1000}},
+ {sleep, 1000},
+ {send, "notify request (resend 2)", NotifyReq},
+ {expect_receive, "pending 2", {PendingVerify, 1000}},
+ {sleep, 1000},
+ {send, "notify request (resend 3)", NotifyReq},
+ {expect_receive, "pending 3", {PendingVerify, 1000}},
+ {sleep, 1000},
+ {send, "notify request (resend 4)", NotifyReq},
+ {expect_receive, "pending 4", {PendingVerify, 1000}},
+ {sleep, 1000},
+ {send, "notify request (resend 5)", NotifyReq},
+ {expect_receive, "pending limit exceeded",
+ {PendingLimitVerify, 1000}},
+ {sleep, 4000},
+ {send, "notify request (resend 6)", NotifyReq},
+ {expect_nothing, 4000},
+ disconnect
+ ],
+ EvSeq.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mg_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ encode_msg(M, Mod, Conf)
+ end.
+
+otp_4956_mg_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ decode_msg(M, Mod, Conf)
+ end.
+-endif.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mg_verify_service_change_rep_msg_fun() ->
+ fun(M) ->
+ otp_4956_mg_verify_service_change_rep_msg(M)
+ end.
+-endif.
+
+otp_4956_mg_verify_service_change_rep_msg(
+ #'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_4956_mg_verify_service_change_rep_msg -> "
+ "ok so far~n",[]),
+ #'Message'{version = _V,
+ mId = _MgMid,
+ messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionReply, TR} = Trans,
+ #'TransactionReply'{transactionId = _Tid,
+ immAckRequired = asn1_NOVALUE,
+ transactionResult = Res} = TR,
+ {actionReplies, [AR]} = Res,
+ #'ActionReply'{contextId = _Cid,
+ errorDescriptor = asn1_NOVALUE,
+ contextReply = _CtxReq,
+ commandReply = [CR]} = AR,
+ {serviceChangeReply, SCR} = CR,
+ #'ServiceChangeReply'{terminationID = _TermID,
+ serviceChangeResult = SCRes} = SCR,
+ {serviceChangeResParms, SCRP} = SCRes,
+ #'ServiceChangeResParm'{serviceChangeMgcId = _MgcMid} = SCRP,
+ {ok, M};
+otp_4956_mg_verify_service_change_rep_msg(M) ->
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mg_verify_pending_msg_fun() ->
+ fun(M) ->
+ otp_4956_mg_verify_pending_msg(M)
+ end.
+-endif.
+
+otp_4956_mg_verify_pending_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_4956_mg_verify_pending_msg -> entry with"
+ "~n Mess. ~p"
+ "~n", [Mess]),
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionPending, TP} = Trans,
+ #'TransactionPending'{transactionId = _Id} = TP,
+ io:format("otp_4956_mg_verify_pending_msg -> done~n", []),
+ {ok, M};
+otp_4956_mg_verify_pending_msg(M) ->
+ io:format("otp_4956_mg_verify_pending_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ {error, {invalid_message, M}}.
+
+-ifndef(megaco_hipe_special).
+otp_4956_mg_verify_pending_limit_msg_fun() ->
+ fun(M) ->
+ otp_4956_mg_verify_pending_limit_msg(M)
+ end.
+-endif.
+
+otp_4956_mg_verify_pending_limit_msg(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("otp_4956_mg_verify_pending_limit_msg -> entry with"
+ "~n Mess: ~p"
+ "~n", [Mess]),
+ #'Message'{messageBody = Body} = Mess,
+ {transactions, [Trans]} = Body,
+ {transactionReply, TR} = Trans,
+ case element(4, TR) of
+ {transactionError, ED} ->
+ EC = ?megaco_number_of_transactionpending_exceeded,
+ #'ErrorDescriptor'{errorCode = EC} = ED,
+ {ok, M};
+ _ ->
+ {error, {invalid_transactionReply, TR}}
+ end;
+otp_4956_mg_verify_pending_limit_msg(M) ->
+ io:format("otp_4956_mg_verify_pending_limit_msg -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ {error, {invalid_message, M}}.
+
+otp_4956_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_4956_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp_4956_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp_4956_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp_4956_mg_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = otp_4956_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+otp_4956_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_5310(suite) ->
+ [];
+otp_5310(doc) ->
+ "...";
+otp_5310(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_5310),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(1),
+ factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info originating pending limit"),
+ PendingLimit = 3,
+ ?MGC_UPDATE_CI(Mgc, orig_pending_limit, PendingLimit),
+
+ ConnReps1 = ?MGC_CONN_INFO(Mgc, replies),
+ d("[MGC] ConnReps1: ~p", [ConnReps1]),
+ case filter_aborted1(ConnReps1, []) of
+ [{_, []}] ->
+ ok;
+ ConnFlt1 ->
+ ?ERROR({unexpected_reply_state, conn_info, ConnReps1, ConnFlt1})
+ end,
+ UserReps1 = ?MGC_USER_INFO(Mgc, replies),
+ d("[MGC] UserReps1: ~p", [UserReps1]),
+ case filter_aborted1(UserReps1, []) of
+ [{_, []}] ->
+ ok;
+ UserFlt1 ->
+ ?ERROR({unexpected_reply_state, user_info, UserReps1, UserFlt1})
+ end,
+
+ %% Instruct the MGC to never reply to requests
+ d("[MGC] don't reply to requests"),
+ ?MGC_REQ_IGNORE(Mgc),
+
+ %% We want to know when the abort comes...
+ d("[MGC] request abort inform"),
+ ?MGC_ABORT_INFO(Mgc, self()),
+
+ %% Make MG send a request
+ d("[MG] send the notify"),
+ {ok, {_ProtocolVersion, {error, ED}}} = ?MG_NOTIF_RAR(Mg),
+ d("[MG] ED: ~p", [ED]),
+ ErrorCode = ?megaco_number_of_transactionpending_exceeded,
+ ErrorCode = ED#'ErrorDescriptor'.errorCode,
+
+ %% Wait for the MGC to get aborted
+ d("[MGC] await the abort callback"),
+ {ok, TransId} = await_aborted(Mgc),
+ d("[MGC] aborted transaction: ~p", [TransId]),
+
+ %% Make sure we have one in aborted state
+ d("[MGC] how many is aborted (should be == 1)?"),
+ ConnReps2 = ?MGC_CONN_INFO(Mgc, replies),
+ case filter_aborted1(ConnReps2, []) of
+ [{_, [TransId]}] ->
+ ok;
+ [{_, []}] ->
+ ok; % has already been cleaned up...
+ ConnFlt2 ->
+ ?ERROR({unexpected_reply_state, conn_info, ConnReps2, ConnFlt2})
+ end,
+ d("[MGC] ConnReps2: ~p", [ConnReps2]),
+ UserReps2 = ?MGC_USER_INFO(Mgc, replies),
+ d("[MGC] UserReps2: ~p", [UserReps2]),
+ case filter_aborted1(UserReps2, []) of
+ [{_, [TransId]}] ->
+ ok;
+ [{_, []}] ->
+ ok; % has already been cleaned up...
+ UserFlt2 ->
+ ?ERROR({unexpected_reply_state, user_info, UserReps2, UserFlt2})
+ end,
+
+ %% do disconnect and the do cancel in the handle function
+ d("[MGC] disconnect"),
+ DiscoRes = ?MGC_DISCO(Mgc, cancel),
+ d("[MGC] DiscoRes: ~p", [DiscoRes]),
+
+ %% check number of reply records (should be no in aborted).
+ d("[MGC] check number of replies in aborted state (should be == 1)"),
+ ConnReps3 = ?MGC_CONN_INFO(Mgc, replies),
+ d("[MGC] ConnReps3: ~p", [ConnReps3]),
+ UserReps3 = ?MGC_USER_INFO(Mgc, replies),
+ d("[MGC] UserReps3: ~p", [UserReps3]),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+await_aborted(Mgc) ->
+ d("await_aborted"),
+ receive
+ {abort_received, Mgc, TransId} ->
+ {ok, TransId}
+ after 10000 ->
+ d("await_aborted - timeout"),
+ {error, timeout}
+ end.
+
+filter_aborted1([], Acc) ->
+ lists:reverse(Acc);
+filter_aborted1([{CH, Ab}|T], Acc) ->
+ filter_aborted1(T, [{CH, filter_aborted2(Ab, [])}|Acc]).
+
+filter_aborted2([], Aborted) ->
+ lists:reverse(Aborted);
+filter_aborted2([{TransId, aborted, _}|T], Aborted) ->
+ filter_aborted2(T, [TransId|Aborted]);
+filter_aborted2([{TransId, State, _}|T], Aborted) ->
+ d("Transaction ~w actually in state ~w", [TransId, State]),
+ filter_aborted2(T, Aborted);
+filter_aborted2([_|T], Aborted) ->
+ filter_aborted2(T, Aborted).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% The timeout times is a little odd in this test case. The (short)
+%% request timer is longer then the (long) request timer. This is
+%% simply to produce the effect that we want regarding max_retries =
+%% infinity_restartable. Also the pending timeout has to be shorter
+%% then "short" + "long" and longer then "long"
+
+otp_5619(suite) ->
+ [];
+otp_5619(doc) ->
+ "...";
+otp_5619(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_5619),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ MgcMid = {deviceName, "ctrl"},
+ ET = [{text, tcp}, {text, udp}, {binary, tcp}, {binary, udp}],
+ {ok, Mgc} = ?MGC_START(MgcNode, MgcMid, ET, [], ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ MgMid = {deviceName, "mg"},
+ MgConfig = [],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("[MG] update connection info long request timer"),
+ LongReqTmr = #megaco_incr_timer{wait_for = timer:seconds(1),
+ factor = 1,
+ max_retries = infinity_restartable},
+ ?MG_UPDATE_CI(Mg, long_request_timer, LongReqTmr),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("MGC conn info: ~p", [?MGC_CONN_INFO(Mgc, all)]),
+
+ d("[MGC] update connection info pending timer"),
+ PendingTimer = #megaco_incr_timer{wait_for = timer:seconds(3),
+ factor = 1},
+ ?MGC_UPDATE_CI(Mgc, pending_timer, PendingTimer),
+
+ d("[MGC] update connection info sent pending limit"),
+ PendingLimit = 5,
+ ?MGC_UPDATE_CI(Mgc, sent_pending_limit, PendingLimit),
+
+ d("MGC conn info: ~p", [?MG_CONN_INFO(Mgc, all)]),
+
+
+ d("[MGC] late reply to requests "
+ "(simulate that the request takes a long time)"),
+ {ok, _} = ?MGC_REQ_DISC(Mgc, 11000),
+
+
+ d("[MG] send the notify and await the timeout"),
+ {ok, Reply} = ?MG_NOTIF_RAR(Mg),
+ case Reply of
+ {_Version, {error, timeout}} ->
+ d("[MG] expected reply (timeout) received~n", []);
+ _ ->
+ ?ERROR({unexpected_reply, Reply})
+ end,
+
+
+ %% Tell MG to stop
+ i("[MG] stop~n"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop~n"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+%%
+%% Common message creation functions
+%%
+
+cre_serviceChangeParm(M,R,P) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R,
+ serviceChangeProfile = P}.
+
+cre_serviceChangeReq(Tid, Parms) ->
+ #'ServiceChangeRequest'{terminationID = Tid,
+ serviceChangeParms = Parms}.
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_obsEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name,
+ timeNotation = Not}.
+%% cre_obsEvent(Name, Not, Par) ->
+%% #'ObservedEvent'{eventName = Name,
+%% timeNotation = Not,
+%% eventParList = Par}.
+
+cre_obsEvsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = EvList}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid,
+ observedEventsDescriptor = EvsDesc}.
+
+cre_command(R) when is_record(R, 'NotifyRequest') ->
+ {notifyReq, R};
+cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
+ {serviceChangeReq, R}.
+
+cre_cmdReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = CmdReqs}.
+
+cre_transReq(TransId, ARs) when is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransId,
+ actions = ARs}.
+
+%% --
+
+cre_serviceChangeResParm(Mid) ->
+ cre_serviceChangeResParm(Mid, ?VERSION).
+
+cre_serviceChangeResParm(Mid, V) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeVersion = V}.
+
+cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP};
+cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED}.
+
+cre_serviceChangeReply(Tid, Res) ->
+ #'ServiceChangeReply'{terminationID = Tid,
+ serviceChangeResult = Res}.
+
+cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
+ {notifyReply, R};
+cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
+ {serviceChangeReply, R}.
+
+cre_notifyReply(Tid) ->
+ #'NotifyReply'{terminationID = Tid}.
+
+cre_actionReply(CtxId, CmdRep) ->
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdRep}.
+
+%% cre_transResult(ED) when record(ED, 'ErrorDescriptor') ->
+%% {transactionError, ED};
+%% cre_transResult([AR|_] = ARs) when record(AR, 'ActionReply') ->
+%% {actionReplies, ARs}.
+
+%% cre_transReply(TransId, Res) ->
+%% #'TransactionReply'{transactionId = TransId,
+%% transactionResult = Res}.
+
+%% --
+
+cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Ver}.
+
+cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
+ {transactionRequest, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
+ {transactionPending, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionReply') ->
+ {transactionReply, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionAck') ->
+ {transactionResponseAck, Trans}.
+
+cre_transactions(Trans) when is_list(Trans) ->
+ {transactions, Trans}.
+
+cre_message(Version, Mid, Body) ->
+ #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}.
+
+cre_megacoMessage(Mess) ->
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Transform a short timer to a long one.
+%% The purpose of this is to trick the stack
+%% to keep re-sending the request, even after
+%% having received the first pending (which
+%% indicates that the other side _IS_
+%% working on the request).
+-ifdef(MEGACO_TEST_CODE).
+
+init_request_timer({short, Ref}) ->
+ {long, Ref};
+init_request_timer(O) ->
+ O.
+
+-endif.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+encode_msg(M, Mod, Conf) ->
+ Mod:encode_message(Conf, M).
+
+%% encode_msg(M, Mod, Conf, Ver) ->
+%% Mod:encode_message(Conf, Ver, M).
+
+decode_msg(M, Mod, Conf) ->
+ Mod:decode_message(Conf, M).
+
+%% decode_msg(M, Mod, Conf, Ver) ->
+%% Mod:decode_message(Conf, Ver, M).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+%% tim() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_completion(Ids) ->
+ case megaco_test_generator_lib:await_completion(Ids) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, Reply} ->
+ d("ERROR => Reply: ~n~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+%% await_completion(Ids, Timeout) ->
+%% case megaco_test_generator_lib:await_completion(Ids, Timeout) of
+%% {ok, Reply} ->
+%% d("OK => Reply: ~n~p", [Reply]),
+%% ok;
+%% {error, Reply} ->
+%% d("ERROR => Reply: ~n~p", [Reply]),
+%% ?ERROR({failed, Reply})
+%% end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) -> receive after X -> ok end.
+
+%% error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), now(), get(tc), "DBG", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+%% print(F, A) ->
+%% io:format("*** [~s] ***"
+%% "~n " ++ F ++ "~n",
+%% [format_timestamp(now()) | A]).
+
+format_timestamp(Now) -> megaco:format_timestamp(Now).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% random_init() ->
+%% {A,B,C} = now(),
+%% random:seed(A,B,C).
+
+%% random() ->
+%% 10 * random:uniform(50).
+
+%% apply_load_timer() ->
+%% erlang:send_after(random(), self(), apply_load_timeout).
+
+
+
diff --git a/lib/megaco/test/megaco_profile.erl b/lib/megaco/test/megaco_profile.erl
new file mode 100644
index 0000000000..01fa0b5a14
--- /dev/null
+++ b/lib/megaco/test/megaco_profile.erl
@@ -0,0 +1,138 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% megaco_profile: Utility module used for megaco profiling
+%%----------------------------------------------------------------------
+
+-module(megaco_profile).
+
+-export([profile/2]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Execute Fun and profile it with fprof.
+profile(Slogan, Fun) when is_function(Fun) ->
+ Pids = [self()],
+ profile(Slogan, Fun, Pids).
+
+profile(Slogan, Fun, Pids) ->
+ TraceFile = lists:concat(["profile_", Slogan, "-fprof.trace"]),
+ DestFile = lists:concat(["profile_", Slogan, ".fprof"]),
+ TreeFile = lists:concat(["profile_", Slogan, ".calltree"]),
+ erlang:garbage_collect(),
+ {ok, _Pid} = fprof:start(),
+ TraceOpts = [start,
+ {cpu_time, false},
+ {procs, Pids},
+ {file, TraceFile}
+ ],
+ ok = fprof:trace(TraceOpts),
+ Res = (catch Fun()),
+ ok = fprof:trace(stop),
+ ok = fprof:profile([{file, TraceFile}]),
+ ok = fprof:analyse([{dest, DestFile}]),
+ ok = fprof:stop(),
+ ok = file:delete(TraceFile),
+ reformat_total(DestFile, TreeFile),
+ Res.
+
+reformat_total(FromFile, ToFile) ->
+ {ok, ConsultedFromFile} = file:consult(FromFile),
+ [_AnalysisOpts, [Totals] | Terms] = ConsultedFromFile,
+ {totals, _, TotalAcc, _} = Totals,
+ {ok, Fd} = file:open(ToFile, [write, raw]),
+ Indent = "",
+ log(Fd, Indent, TotalAcc, Totals),
+ Processes = split_processes(Terms, [], []),
+ Reformat = fun(P) -> reformat_process(Fd, " " ++ Indent, TotalAcc, P) end,
+ lists:foreach(Reformat, Processes),
+ file:close(Fd).
+
+
+split_processes([H | T], ProcAcc, TotalAcc) ->
+ if
+ is_tuple(H) ->
+ split_processes(T, [H | ProcAcc], TotalAcc);
+ is_list(H), ProcAcc =:= [] ->
+ split_processes(T, [H], TotalAcc);
+ is_list(H) ->
+ split_processes(T, [H], [lists:reverse(ProcAcc) | TotalAcc])
+ end;
+split_processes([], [], TotalAcc) ->
+ lists:reverse(TotalAcc);
+split_processes([], ProcAcc, TotalAcc) ->
+ lists:reverse([lists:reverse(ProcAcc) | TotalAcc]).
+
+reformat_process(Fd, Indent, TotalAcc, Terms) ->
+ case Terms of
+ [[{ProcLabel, _, _, _}] | All] -> ok;
+ [[{ProcLabel,_,_,_} | _] | All] -> ok
+ end,
+ [{_, {TopKey, TopCnt, TopAcc, TopOwn}, _} | _] = All,
+ Process = {ProcLabel, TopCnt, TopAcc, TopOwn},
+ log(Fd, Indent, TotalAcc, Process),
+ reformat_calls(Fd, " " ++ Indent, TotalAcc, TopKey, All, []).
+
+reformat_calls(Fd, Indent, TotalAcc, Key, Terms, Stack) ->
+ {_CalledBy, Current, Calls} = find(Key, Terms),
+ log(Fd, Indent, TotalAcc, Current),
+ case lists:member(Key, Stack) of
+ true ->
+ ok;
+ false ->
+ case Key of
+ {io_lib, _, _} ->
+ ok;
+ {disk_log, _, _} ->
+ ok;
+ {lists, flatten, _} ->
+ ok;
+ {lists, keysort, _} ->
+ ok;
+ _ ->
+ Fun = fun({NextKey, _, _, _}) ->
+ reformat_calls(Fd,
+ " " ++ Indent,
+ TotalAcc,
+ NextKey,
+ Terms,
+ [Key | Stack])
+ end,
+ lists:foreach(Fun, Calls)
+ end
+ end.
+
+find(Key, [{_, {Key, _, _, _}, _} = H | _]) ->
+ H;
+find(Key, [{_, {_, _, _, _}, _} | T]) ->
+ find(Key, T).
+
+log(Fd, Indent, Total, {Label, Cnt, Acc, Own}) ->
+ Percent = case Acc of
+ undefined -> 100;
+ _ -> trunc((lists:max([Acc, Own]) * 100) / Total)
+ end,
+ Label2 = io_lib:format("~p", [Label]),
+ IoList = io_lib:format("~s~p% ~s \t~p \t~p \t~p\n",
+ [Indent, Percent, Label2, Cnt, trunc(Acc), trunc(Own)]),
+ file:write(Fd, IoList).
+
diff --git a/lib/megaco/test/megaco_sdp_test.erl b/lib/megaco/test/megaco_sdp_test.erl
new file mode 100644
index 0000000000..e9bd550518
--- /dev/null
+++ b/lib/megaco/test/megaco_sdp_test.erl
@@ -0,0 +1,1286 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test application config
+%%----------------------------------------------------------------------
+
+-module(megaco_sdp_test).
+
+-export([all/1,
+ decode_encode/1,
+
+ tickets/1,
+ otp8123/1,
+
+ init_per_testcase/2, fin_per_testcase/2,
+
+ t/0, t/1]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/include/megaco_sdp.hrl").
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+all(suite) ->
+ [
+ decode_encode,
+ tickets
+ ].
+
+tickets(suite) ->
+ [
+ otp8123
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+decode_encode(suite) ->
+ [];
+decode_encode(Config) when is_list(Config) ->
+ io:format("decode_encode -> entry with"
+ "~n Config: ~p"
+ "~n", [Config]),
+
+ %%-------------------------------------
+ %% Test data
+ %%-------------------------------------
+
+ %% -- (PP) (ok) --
+ io:format("setup for protocol version 01 (ok)~n", []),
+ PP_V01_V = 0,
+ PP_V01 = cre_PropertyParm_v(PP_V01_V),
+ SDP_V01 = cre_sdp_v(PP_V01_V),
+ PP_V01_Exp = {ok, SDP_V01},
+ SDP_V01_Exp = {ok, PP_V01},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for protocol version 02 (ok)~n", []),
+ PP_V02_V = 100,
+ PP_V02 = cre_PropertyParm_v(PP_V02_V),
+ SDP_V02 = cre_sdp_v(PP_V02_V),
+ PP_V02_Exp = {ok, SDP_V02},
+ SDP_V02_Exp = {ok, PP_V02},
+
+
+ %% -- (PP) (error) --
+ io:format("setup for protocol version 03 (error)~n", []),
+ PP_V03_V = "sune",
+ PP_V03 = cre_PropertyParm_v(PP_V03_V),
+ SDP_V03 = cre_sdp_v(PP_V03_V),
+ PP_V03_Exp = {error, {invalid_protocol_version, PP_V03_V}},
+ SDP_V03_Exp = PP_V03_Exp,
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 01 (ok)~n", []),
+ PP_C01_CA = "123.123.123.120",
+ PP_C01 = cre_PropertyParm_c(ip4, PP_C01_CA),
+ SDP_C01 = cre_sdp_c(ip4, PP_C01_CA),
+ PP_C01_Exp = {ok, SDP_C01},
+ SDP_C01_Exp = {ok, PP_C01},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 02 (ok)~n", []),
+ PP_C02_TTL = 121,
+ PP_C02_Base = "123.123.123.121",
+ PP_C02 = cre_PropertyParm_c(ip4, PP_C02_Base, PP_C02_TTL),
+ SDP_C02_CA = #megaco_sdp_c_conn_addr{base = PP_C02_Base,
+ ttl = PP_C02_TTL},
+ SDP_C02 = cre_sdp_c(ip4, SDP_C02_CA),
+ PP_C02_Exp = {ok, SDP_C02},
+ SDP_C02_Exp = {ok, PP_C02},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 03 (ok)~n", []),
+ PP_C03_CA = "123.123.123.122",
+ PP_C03 = cre_PropertyParm_c(ip4, PP_C03_CA ++ "/"),
+ SDP_C03 = cre_sdp_c(ip4, PP_C03_CA),
+ PP_C03_Exp = {ok, SDP_C03},
+ SDP_C03_Exp = {ok, cre_PropertyParm_c(ip4, PP_C03_CA)},
+
+
+ %% -- (PP) (error) --
+ io:format("setup for connection info 04 (error)~n", []),
+ PP_C04_Base = "123.123.123.123",
+ PP_C04_TTL = "sune",
+ PP_C04_CA = PP_C04_Base ++ "/" ++ PP_C04_TTL,
+ PP_C04 = cre_PropertyParm_c(ip4, PP_C04_CA),
+ PP_C04_Exp = {error, {invalid_connection_data_conn_addr_ttl, "sune"}},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 05 (ok)~n", []),
+ PP_C05_TTL = 124,
+ PP_C05_NOF = 224,
+ PP_C05_Base = "123.123.123.124",
+ PP_C05 = cre_PropertyParm_c(ip4, PP_C05_Base, PP_C05_TTL,
+ PP_C05_NOF),
+ SDP_C05_CA = #megaco_sdp_c_conn_addr{base = PP_C05_Base,
+ ttl = PP_C05_TTL,
+ num_of = PP_C05_NOF},
+ SDP_C05 = cre_sdp_c(ip4, SDP_C05_CA),
+ PP_C05_Exp = {ok, SDP_C05},
+ SDP_C05_Exp = {ok, PP_C05},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 06 (ok)~n", []),
+ PP_C06_TTL = 125,
+ PP_C06_Base = "123.123.123.125",
+ PP_C06_CA = PP_C06_Base ++ "/" ++ integer_to_list(PP_C06_TTL) ++ "/",
+ PP_C06 = cre_PropertyParm_c(ip4, PP_C06_CA),
+ SDP_C06_CA = #megaco_sdp_c_conn_addr{base = PP_C06_Base,
+ ttl = PP_C06_TTL},
+ SDP_C06 = cre_sdp_c(ip4, SDP_C06_CA),
+ PP_C06_Exp = {ok, SDP_C06},
+ SDP_C06_Exp = {ok, cre_PropertyParm_c(ip4, PP_C06_Base ++ "/" ++ integer_to_list(PP_C06_TTL))},
+
+
+ %% -- (PP) (error) --
+ io:format("setup for connection info 07 (ok)~n", []),
+ PP_C07_NOF = "sune",
+ PP_C07_TTL = 125,
+ PP_C07_Base = "123.123.123.126",
+ PP_C07_CA = PP_C07_Base ++ "/" ++
+ integer_to_list(PP_C07_TTL) ++ "/" ++ PP_C07_NOF,
+ PP_C07 = cre_PropertyParm_c(ip4, PP_C07_CA),
+ SDP_C07_CA = #megaco_sdp_c_conn_addr{base = PP_C07_Base,
+ ttl = PP_C07_TTL,
+ num_of = PP_C07_NOF},
+ SDP_C07 = cre_sdp_c(ip4, SDP_C07_CA),
+ PP_C07_Exp = {error, {invalid_connection_data_conn_addr_num_of, PP_C07_NOF}},
+ SDP_C07_Exp = {error, {invalid_connection_data_conn_addr_num_of, PP_C07_NOF}},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for connection info 08 (ok)~n", []),
+ PP_C08_CA = "FF1E:03AD::7F2E:172A:1E24",
+ PP_C08 = cre_PropertyParm_c(ip6, PP_C08_CA),
+ SDP_C08 = cre_sdp_c(ip6, PP_C08_CA),
+ PP_C08_Exp = {ok, SDP_C08},
+ SDP_C08_Exp = {ok, PP_C08},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for media announcement 01 (ok)~n", []),
+ PP_M01_Media = audio,
+ PP_M01_Port = 2000,
+ PP_M01_Transport = "RTP/AVP",
+ PP_M01_FMT_LST = ["0"],
+ PP_M01 = cre_PropertyParm_m(PP_M01_Media,
+ PP_M01_Port,
+ PP_M01_Transport,
+ PP_M01_FMT_LST),
+ SDP_M01 = cre_sdp_m(PP_M01_Media, PP_M01_Port,
+ PP_M01_Transport, PP_M01_FMT_LST),
+ PP_M01_Exp = {ok, SDP_M01},
+ SDP_M01_Exp = {ok, PP_M01},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for media announcement 02 (ok)~n", []),
+ PP_M02_Media = audio,
+ PP_M02_Port = 2000,
+ PP_M02_NOP = 2,
+ PP_M02_Transport = "RTP/AVP",
+ PP_M02_FMT_LST = ["0"],
+ PP_M02 = cre_PropertyParm_m(PP_M02_Media, PP_M02_Port,
+ PP_M02_NOP, PP_M02_Transport,
+ PP_M02_FMT_LST),
+ SDP_M02 = cre_sdp_m(PP_M02_Media, PP_M02_Port, PP_M02_NOP,
+ PP_M02_Transport, PP_M02_FMT_LST),
+ PP_M02_Exp = {ok, SDP_M02},
+ SDP_M02_Exp = {ok, PP_M02},
+
+ %% -- (PP) (ok) --
+ io:format("setup for origin 01 (ok)~n", []),
+ PP_O01_Name = "kalle",
+ PP_O01_SID = 1414,
+ PP_O01_V = 2,
+ PP_O01_AT = ip4,
+ PP_O01_A = "126.12.64.4",
+ PP_O01 = cre_PropertyParm_o(PP_O01_Name, PP_O01_SID, PP_O01_V,
+ PP_O01_AT, PP_O01_A),
+ SDP_O01 = cre_sdp_o(PP_O01_Name, PP_O01_SID, PP_O01_V,
+ PP_O01_AT, PP_O01_A),
+ PP_O01_Exp = {ok, SDP_O01},
+ SDP_O01_Exp = {ok, PP_O01},
+
+
+ %% -- (PP) (ok) --
+ io:format("setup for origin 02 (ok)~n", []),
+ PP_O02_Name = "bobbe",
+ PP_O02_SID = 1515,
+ PP_O02_V = 3,
+ PP_O02_NT = in,
+ PP_O02_AT = ip6,
+ PP_O02_A = "2201:056D::112E:144A:1E24",
+ PP_O02 = cre_PropertyParm_o(PP_O02_Name, PP_O02_SID, PP_O02_V,
+ PP_O02_NT, PP_O02_AT, PP_O02_A),
+ SDP_O02 = cre_sdp_o(PP_O02_Name, PP_O02_SID, PP_O02_V, PP_O02_NT,
+ PP_O02_AT, PP_O02_A),
+ PP_O02_Exp = {ok, SDP_O02},
+ SDP_O02_Exp = {ok, PP_O02},
+
+
+ %% -- (PP) (ok) --
+ PP_A01_PL = 2,
+ PP_A01_EN = "G726-32",
+ PP_A01_CR = 8000,
+ PP_A01 = cre_PropertyParm_rtpmap(PP_A01_PL, PP_A01_EN, PP_A01_CR),
+ SDP_A01 = cre_sdp_a_rtpmap(PP_A01_PL, PP_A01_EN, PP_A01_CR),
+ PP_A01_Exp = {ok, SDP_A01},
+ SDP_A01_Exp = {ok, PP_A01},
+
+
+ %% -- (PP) (ok) --
+ PP_A02_PL = 2,
+ PP_A02_EN = "xxx",
+ PP_A02_CR = 42,
+ PP_A02_EP = ["1","2","3"],
+ PP_A02 = cre_PropertyParm_rtpmap(PP_A02_PL, PP_A02_EN,
+ PP_A02_CR, PP_A02_EP),
+ SDP_A02 = cre_sdp_a_rtpmap(PP_A02_PL, PP_A02_EN, PP_A02_CR, PP_A02_EP),
+ PP_A02_Exp = {ok, SDP_A02},
+ SDP_A02_Exp = {ok, PP_A02},
+
+
+ %% -- (PP) (ok) --
+ PP_A03_PT = 12,
+ PP_A03 = cre_PropertyParm_ptime(PP_A03_PT),
+ SDP_A03 = cre_sdp_a_ptime(PP_A03_PT),
+ PP_A03_Exp = {ok, SDP_A03},
+ SDP_A03_Exp = {ok, PP_A03},
+
+
+ %% -- (PP) (error) --
+ PP_A04_PT = "sune",
+ PP_A04 = cre_PropertyParm_ptime(PP_A04_PT),
+ SDP_A04 = cre_sdp_a_ptime(PP_A04_PT),
+ PP_A04_Exp = {error, {invalid_ptime_packet_time, PP_A04_PT}},
+ SDP_A04_Exp = {error, {invalid_ptime_packet_time, PP_A04_PT}},
+
+
+ %% -- (PP) (ok) --
+ PP_A05_QA = 10,
+ PP_A05 = cre_PropertyParm_quality(PP_A05_QA),
+ SDP_A05 = cre_sdp_a_quality(PP_A05_QA),
+ PP_A05_Exp = {ok, SDP_A05},
+ SDP_A05_Exp = {ok, PP_A05},
+
+
+ %% -- (PP) (error) --
+ PP_A06_QA = "sune",
+ PP_A06 = cre_PropertyParm_quality(PP_A06_QA),
+ SDP_A06 = cre_sdp_a_quality(PP_A06_QA),
+ PP_A06_Exp = {error, {invalid_quality_quality, PP_A06_QA}},
+ SDP_A06_Exp = {error, {invalid_quality_quality, PP_A06_QA}},
+
+
+ %% -- (PP) (ok) --
+ PP_A07_A = "recvonly",
+ PP_A07 = cre_PropertyParm_a(PP_A07_A),
+ SDP_A07 = cre_sdp_a(PP_A07_A),
+ PP_A07_Exp = {ok, SDP_A07},
+ SDP_A07_Exp = {ok, PP_A07},
+
+
+ %% -- (PP) (ok) --
+ PP_A08_V = portrait,
+ PP_A08 = cre_PropertyParm_orient(PP_A08_V),
+ SDP_A08 = cre_sdp_a_orient(PP_A08_V),
+ PP_A08_Exp = {ok, SDP_A08},
+ SDP_A08_Exp = {ok, PP_A08},
+
+
+ %% -- (PP) (ok) --
+ PP_A09_V = landscape,
+ PP_A09 = cre_PropertyParm_orient(PP_A09_V),
+ SDP_A09 = cre_sdp_a_orient(PP_A09_V),
+ PP_A09_Exp = {ok, SDP_A09},
+ SDP_A09_Exp = {ok, PP_A09},
+
+
+ %% -- (PP) (ok) --
+ PP_A10_V = seascape,
+ PP_A10 = cre_PropertyParm_orient(PP_A10_V),
+ SDP_A10 = cre_sdp_a_orient(PP_A10_V),
+ PP_A10_Exp = {ok, SDP_A10},
+ SDP_A10_Exp = {ok, PP_A10},
+
+
+ %% -- (PP) (error) --
+ PP_A11_V = gurka,
+ SDP_A11_V = atom_to_list(PP_A11_V),
+ PP_A11 = cre_PropertyParm_orient(PP_A11_V),
+ SDP_A11 = cre_sdp_a_orient(PP_A11_V),
+ PP_A11_Exp = {error, {invalid_orient_orientation, SDP_A11_V}},
+ SDP_A11_Exp = {error, {invalid_orient_orientation, PP_A11_V}},
+
+
+ %% -- (PP) (ok) --
+ PP_A12_V = "gurka",
+ PP_A12 = cre_PropertyParm_cat(PP_A12_V),
+ SDP_A12 = cre_sdp_a_cat(PP_A12_V),
+ PP_A12_Exp = {ok, SDP_A12},
+ SDP_A12_Exp = {ok, PP_A12},
+
+
+ %% -- (PP) (ok) --
+ PP_A13_V = "gurka",
+ PP_A13 = cre_PropertyParm_keywds(PP_A13_V),
+ SDP_A13 = cre_sdp_a_keywds(PP_A13_V),
+ PP_A13_Exp = {ok, SDP_A13},
+ SDP_A13_Exp = {ok, PP_A13},
+
+
+ %% -- (PP) (ok) --
+ PP_A14_V = "gurka 1.0",
+ PP_A14 = cre_PropertyParm_tool(PP_A14_V),
+ SDP_A14 = cre_sdp_a_tool(PP_A14_V),
+ PP_A14_Exp = {ok, SDP_A14},
+ SDP_A14_Exp = {ok, PP_A14},
+
+
+ %% -- (PP) (ok) --
+ PP_A15_V = 15,
+ PP_A15 = cre_PropertyParm_maxptime(PP_A15_V),
+ SDP_A15 = cre_sdp_a_maxptime(PP_A15_V),
+ PP_A15_Exp = {ok, SDP_A15},
+ SDP_A15_Exp = {ok, PP_A15},
+
+
+ %% -- (PP) (error) --
+ PP_A16_V = "gurka",
+ PP_A16 = cre_PropertyParm_maxptime(PP_A16_V),
+ SDP_A16 = cre_sdp_a_maxptime(PP_A16_V),
+ PP_A16_Exp = {error, {invalid_maxptime_maximum_packet_time, PP_A16_V}},
+ SDP_A16_Exp = {error, {invalid_maxptime_maximum_packet_time, PP_A16_V}},
+
+
+ %% -- (PP) (ok) --
+ PP_A17_V = "H332",
+ PP_A17 = cre_PropertyParm_type(PP_A17_V ),
+ SDP_A17 = cre_sdp_a_type(PP_A17_V),
+ PP_A17_Exp = {ok, SDP_A17},
+ SDP_A17_Exp = {ok, PP_A17},
+
+
+ %% -- (PP) (ok) --
+ PP_A18_V = "ISO-8859-1",
+ PP_A18 = cre_PropertyParm_charset(PP_A18_V),
+ SDP_A18 = cre_sdp_a_charset(PP_A18_V),
+ PP_A18_Exp = {ok, SDP_A18},
+ SDP_A18_Exp = {ok, PP_A18},
+
+
+ %% -- (PP) (ok) --
+ PP_A19_PT = "gurka",
+ PP_A19 = cre_PropertyParm_sdplang(PP_A19_PT),
+ SDP_A19 = cre_sdp_a_sdplang(PP_A19_PT),
+ PP_A19_Exp = {ok, SDP_A19},
+ SDP_A19_Exp = {ok, PP_A19},
+
+
+ %% -- (PP) (ok) --
+ PP_A20_PT = "gurka",
+ PP_A20 = cre_PropertyParm_lang(PP_A20_PT),
+ SDP_A20 = cre_sdp_a_lang(PP_A20_PT),
+ PP_A20_Exp = {ok, SDP_A20},
+ SDP_A20_Exp = {ok, PP_A20},
+
+
+ %% -- (PP) (ok) --
+ PP_A21_PT = "21.0",
+ PP_A21 = cre_PropertyParm_framerate(PP_A21_PT),
+ SDP_A21 = cre_sdp_a_framerate(PP_A21_PT),
+ PP_A21_Exp = {ok, SDP_A21},
+ SDP_A21_Exp = {ok, PP_A21},
+
+
+%% %% -- (PP) (ok) --
+%% PP_A22_PT = "ISO-8859-1",
+%% PP_A22 = cre_PropertyParm_(PP_A22_T),
+%% SDP_A22 = cre_sdp_a_(PP_A22_PT),
+%% PP_A22_Exp = {ok, SDP_A22},
+%% SDP_A22_Exp = {ok, PP_A22},
+
+
+ %% -- (PP) (ok) --
+ PP_A23_FORMAT = "125",
+ PP_A23_PARAM = "profile-level-id=222; max-br=1212; max-mbps=20200",
+ PP_A23 = cre_PropertyParm_a_fmtp(PP_A23_FORMAT, PP_A23_PARAM),
+ SDP_A23 = cre_sdp_a_fmtp(PP_A23_FORMAT, PP_A23_PARAM),
+ PP_A23_Exp = {ok, SDP_A23},
+ SDP_A23_Exp = {ok, PP_A23},
+
+
+ %% -- (PP) (ok) --
+ PP_B01_MOD = "2",
+ PP_B01_BW = 523,
+ PP_B01 = cre_PropertyParm_b(PP_B01_MOD, PP_B01_BW),
+ SDP_B01 = cre_sdp_b(PP_B01_MOD, PP_B01_BW),
+ PP_B01_Exp = {ok, SDP_B01},
+ SDP_B01_Exp = {ok, PP_B01},
+
+
+ %% -- (PP) (error) --
+ PP_B02_B = "sune",
+ PP_B02 = cre_PropertyParm("b", PP_B02_B),
+ PP_B02_Exp = {error, {invalid_PropertyParm,
+ {bandwidth_info, PP_B02_B, [PP_B02_B]}}},
+
+
+ %% -- (PP) (ok) --
+ PP_B03_MOD = "X",
+ PP_B03_BW = 525,
+ PP_B03 = cre_PropertyParm_b(PP_B03_MOD, PP_B03_BW),
+ SDP_B03 = cre_sdp_b(PP_B03_MOD, PP_B03_BW),
+ PP_B03_Exp = {ok, SDP_B03},
+ SDP_B03_Exp = {ok, PP_B03},
+
+
+ %% -- (PP) (error) --
+ PP_B04_BWT = "X",
+ PP_B04_BW = "sune",
+ PP_B04 = cre_PropertyParm_b(PP_B04_BWT, PP_B04_BW),
+ SDP_B04 = cre_sdp_b(PP_B04_BWT, PP_B04_BW),
+ PP_B04_Exp = {error, {invalid_bandwidth_bandwidth, PP_B04_BW}},
+ SDP_B04_Exp = {error, {invalid_bandwidth_bandwidth, PP_B04_BW}},
+
+
+ %% -- (PP) (ok) --
+ PP_T01_START = 1200,
+ PP_T01_STOP = 1300,
+ PP_T01 = cre_PropertyParm_t(PP_T01_START, PP_T01_STOP),
+ SDP_T01 = cre_sdp_t(PP_T01_START, PP_T01_STOP),
+ PP_T01_Exp = {ok, SDP_T01},
+ SDP_T01_Exp = {ok, PP_T01},
+
+
+ %% -- (PP) (ok) --
+ PP_R01_RPT = "10",
+ PP_R01_DUR = "100",
+ PP_R01_LOO = ["2", "4", "6"],
+ PP_R01 = cre_PropertyParm_r(PP_R01_RPT, PP_R01_DUR, PP_R01_LOO),
+ SDP_R01 = cre_sdp_r(PP_R01_RPT, PP_R01_DUR, PP_R01_LOO),
+ PP_R01_Exp = {ok, SDP_R01},
+ SDP_R01_Exp = {ok, PP_R01},
+
+
+ %% -- (PP) (ok) --
+ PP_Z01_LOA_V1 = #megaco_sdp_z_adjustement{time = "12121212",
+ offset = "-1h"},
+ PP_Z01_LOA_V2 = #megaco_sdp_z_adjustement{time = "34343434",
+ offset = "0"},
+ PP_Z01_LOA = [PP_Z01_LOA_V1, PP_Z01_LOA_V2],
+ PP_Z01 = cre_PropertyParm_z(PP_Z01_LOA),
+ SDP_Z01 = cre_sdp_z(PP_Z01_LOA),
+ PP_Z01_Exp = {ok, SDP_Z01},
+ SDP_Z01_Exp = {ok, PP_Z01},
+
+
+ %% -- (PP) (error) --
+ PP_Z02 = cre_PropertyParm("z", []),
+ SDP_Z02 = cre_sdp_z([]),
+ PP_Z02_Exp = {error, {invalid_tzones_list_of_adjustments, []}},
+ SDP_Z02_Exp = {error, {invalid_tzones_list_of_adjustments, []}},
+
+
+ %% -- (PP) (ok) --
+ PP_K01_M = prompt,
+ PP_K01_EK = undefined,
+ PP_K01 = cre_PropertyParm_k(PP_K01_M, PP_K01_EK),
+ SDP_K01 = cre_sdp_k(PP_K01_M),
+ PP_K01_Exp = {ok, SDP_K01},
+ SDP_K01_Exp = {ok, PP_K01},
+
+
+ %% -- (PP) (ok) --
+ PP_K02_M = clear,
+ PP_K02_EK = "whatever",
+ PP_K02 = cre_PropertyParm_k(PP_K02_M, PP_K02_EK),
+ SDP_K02 = cre_sdp_k(PP_K02_M, PP_K02_EK),
+ PP_K02_Exp = {ok, SDP_K02},
+ SDP_K02_Exp = {ok, PP_K02},
+
+
+ %% -- (PP) (ok) --
+ PP_K03_M = "method",
+ PP_K03_EK = "key",
+ PP_K03 = cre_PropertyParm_k(PP_K03_M, PP_K03_EK),
+ SDP_K03 = cre_sdp_k(PP_K03_M, PP_K03_EK),
+ PP_K03_Exp = {ok, SDP_K03},
+ SDP_K03_Exp = {ok, PP_K03},
+
+
+ %% -- (PP) (ok) --
+ PP_S01_SN = "new session",
+ PP_S01 = cre_PropertyParm_s(PP_S01_SN),
+ SDP_S01 = cre_sdp_s(PP_S01_SN),
+ PP_S01_Exp = {ok, SDP_S01},
+ SDP_S01_Exp = {ok, PP_S01},
+
+
+ %% -- (PP) (ok) --
+ PP_I01_SD = "Session and Media Information",
+ PP_I01 = cre_PropertyParm_i(PP_I01_SD),
+ SDP_I01 = cre_sdp_i(PP_I01_SD),
+ PP_I01_Exp = {ok, SDP_I01},
+ SDP_I01_Exp = {ok, PP_I01},
+
+
+ %% -- (PP) (ok) --
+ PP_U01_URI = "http://www.erlang.org/",
+ PP_U01 = cre_PropertyParm_u(PP_U01_URI),
+ SDP_U01 = cre_sdp_u(PP_U01_URI),
+ PP_U01_Exp = {ok, SDP_U01},
+ SDP_U01_Exp = {ok, PP_U01},
+
+
+ %% -- (PP) (ok) --
+ PP_E01_EMAIL = "[email protected]",
+ PP_E01 = cre_PropertyParm_e(PP_E01_EMAIL),
+ SDP_E01 = cre_sdp_e(PP_E01_EMAIL),
+ PP_E01_Exp = {ok, SDP_E01},
+ SDP_E01_Exp = {ok, PP_E01},
+
+
+ %% -- (PP) (ok) --
+ PP_P01_PHONE = "+1 713 555 1234",
+ PP_P01 = cre_PropertyParm_p(PP_P01_PHONE),
+ SDP_P01 = cre_sdp_p(PP_P01_PHONE),
+ PP_P01_Exp = {ok, SDP_P01},
+ SDP_P01_Exp = {ok, PP_P01},
+
+
+ %% -- (PP) (error) --
+ PP_N01 = cre_PropertyParm("not_recognized", "whatever"),
+ PP_N01_Exp = {error, undefined_PropertyParm},
+
+
+ %% -- (PG) (ok) --
+ PG01 = [{PP_V01, ok},
+ {PP_C01, ok},
+ {PP_M01, ok}],
+
+
+ %% -- (PG) (ok) --
+ PG02 = [{PP_V02, ok},
+ {PP_C05, ok},
+ {PP_A02, ok}],
+
+
+ %% -- (PG) (error) --
+ PG03 = [{PP_V03, error},
+ {PP_C08, ok},
+ {PP_M02, ok}],
+
+
+ %% -- (PG) (error) --
+ PG04 = [{PP_V02, ok},
+ {PP_C04, error},
+ {PP_C07, error}],
+
+
+ %% -- (PGs) (ok) --
+ PGS01 = [PG01, PG02],
+
+
+ %% -- (PGs) (error) --
+ PGS02 = [PG01, PG04],
+
+
+ Instructions =
+ [
+ pp_dec_instruction("version 01 - dec [ok]", PP_V01, PP_V01_Exp),
+ pp_enc_instruction("version 01 - enc [ok]", SDP_V01, SDP_V01_Exp),
+ pp_dec_instruction("version 02 - dec [ok]", PP_V02, PP_V02_Exp),
+ pp_enc_instruction("version 02 - enc [ok]", SDP_V02, SDP_V02_Exp),
+ pp_dec_instruction("version 03 - dec [error]", PP_V03, PP_V03_Exp),
+ pp_enc_instruction("version 03 - enc [error]", SDP_V03, SDP_V03_Exp),
+ pp_dec_instruction("connection info 01 - dec [ok]", PP_C01, PP_C01_Exp),
+ pp_enc_instruction("connection info 01 - enc [ok]", SDP_C01, SDP_C01_Exp),
+ pp_dec_instruction("connection info 02 - dec [ok]", PP_C02, PP_C02_Exp),
+ pp_enc_instruction("connection info 02 - enc [ok]", SDP_C02, SDP_C02_Exp),
+ pp_dec_instruction("connection info 03 - dec [ok]", PP_C03, PP_C03_Exp),
+ pp_enc_instruction("connection info 03 - enc [ok]", SDP_C03, SDP_C03_Exp),
+ pp_dec_instruction("connection info 04 - dec [error]", PP_C04, PP_C04_Exp),
+
+ pp_dec_instruction("connection info 05 - dec [ok]", PP_C05, PP_C05_Exp),
+ pp_enc_instruction("connection info 05 - enc [ok]", SDP_C05, SDP_C05_Exp),
+ pp_dec_instruction("connection info 06 - dec [ok]", PP_C06, PP_C06_Exp),
+ pp_enc_instruction("connection info 06 - enc [ok]", SDP_C06, SDP_C06_Exp),
+ pp_dec_instruction("connection info 07 - dec [error]", PP_C07, PP_C07_Exp),
+ pp_enc_instruction("connection info 07 - enc [error]", SDP_C07, SDP_C07_Exp),
+ pp_dec_instruction("connection info 08 - dec [ok]", PP_C08, PP_C08_Exp),
+ pp_enc_instruction("connection info 08 - enc [ok]", SDP_C08, SDP_C08_Exp),
+ pp_dec_instruction("media announcement 01 - dec [ok]", PP_M01, PP_M01_Exp),
+ pp_enc_instruction("media announcement 01 - enc [ok]", SDP_M01, SDP_M01_Exp),
+ pp_dec_instruction("media announcement 02 - dec [ok]", PP_M02, PP_M02_Exp),
+ pp_enc_instruction("media announcement 02 - enc [ok]", SDP_M02, SDP_M02_Exp),
+ pp_dec_instruction("origin 01 - dec [ok]", PP_O01, PP_O01_Exp),
+ pp_enc_instruction("origin 01 - enc [ok]", SDP_O01, SDP_O01_Exp),
+ pp_dec_instruction("origin 02 - dec [ok]", PP_O02, PP_O02_Exp),
+ pp_enc_instruction("origin 02 - enc [ok]", SDP_O02, SDP_O02_Exp),
+ pp_dec_instruction("attributes 01 - dec [ok]", PP_A01, PP_A01_Exp),
+ pp_enc_instruction("attributes 01 - enc [ok]", SDP_A01, SDP_A01_Exp),
+ pp_dec_instruction("attributes 02 - dec [ok]", PP_A02, PP_A02_Exp),
+ pp_enc_instruction("attributes 02 - enc [ok]", SDP_A02, SDP_A02_Exp),
+ pp_dec_instruction("attributes 03 - dec [ok]", PP_A03, PP_A03_Exp),
+ pp_enc_instruction("attributes 03 - enc [ok]", SDP_A03, SDP_A03_Exp),
+ pp_dec_instruction("attributes 04 - dec [error]", PP_A04, PP_A04_Exp),
+ pp_enc_instruction("attributes 04 - enc [error]", SDP_A04, SDP_A04_Exp),
+ pp_dec_instruction("attributes 05 - dec [ok]", PP_A05, PP_A05_Exp),
+ pp_enc_instruction("attributes 05 - enc [ok]", SDP_A05, SDP_A05_Exp),
+ pp_dec_instruction("attributes 06 - dec [error]", PP_A06, PP_A06_Exp),
+ pp_enc_instruction("attributes 06 - dec [error]", SDP_A06, SDP_A06_Exp),
+ pp_dec_instruction("attributes 07 - dec [ok]", PP_A07, PP_A07_Exp),
+ pp_enc_instruction("attributes 07 - enc [ok]", SDP_A07, SDP_A07_Exp),
+ pp_dec_instruction("attributes 08 - dec [ok]", PP_A08, PP_A08_Exp),
+ pp_enc_instruction("attributes 08 - enc [ok]", SDP_A08, SDP_A08_Exp),
+
+ pp_dec_instruction("attributes 09 - dec [ok]", PP_A09, PP_A09_Exp),
+ pp_enc_instruction("attributes 09 - enc [ok]", SDP_A09, SDP_A09_Exp),
+ pp_dec_instruction("attributes 10 - dec [ok]", PP_A10, PP_A10_Exp),
+ pp_enc_instruction("attributes 10 - enc [ok]", SDP_A10, SDP_A10_Exp),
+ pp_dec_instruction("attributes 11 - dec [error]", PP_A11, PP_A11_Exp),
+ pp_enc_instruction("attributes 11 - enc [error]", SDP_A11, SDP_A11_Exp),
+
+ pp_dec_instruction("attributes 12 - dec [ok]", PP_A12, PP_A12_Exp),
+ pp_enc_instruction("attributes 12 - enc [ok]", SDP_A12, SDP_A12_Exp),
+ pp_dec_instruction("attributes 13 - dec [ok]", PP_A13, PP_A13_Exp),
+ pp_enc_instruction("attributes 13 - enc [ok]", SDP_A13, SDP_A13_Exp),
+ pp_dec_instruction("attributes 14 - dec [ok]", PP_A14, PP_A14_Exp),
+ pp_enc_instruction("attributes 14 - enc [ok]", SDP_A14, SDP_A14_Exp),
+ pp_dec_instruction("attributes 15 - dec [ok]", PP_A15, PP_A15_Exp),
+ pp_enc_instruction("attributes 15 - enc [ok]", SDP_A15, SDP_A15_Exp),
+ pp_dec_instruction("attributes 16 - dec [error]", PP_A16, PP_A16_Exp),
+ pp_enc_instruction("attributes 16 - enc [error]", SDP_A16, SDP_A16_Exp),
+ pp_dec_instruction("attributes 17 - dec [ok]", PP_A17, PP_A17_Exp),
+ pp_enc_instruction("attributes 17 - enc [ok]", SDP_A17, SDP_A17_Exp),
+ pp_dec_instruction("attributes 18 - dec [ok]", PP_A18, PP_A18_Exp),
+ pp_enc_instruction("attributes 18 - enc [ok]", SDP_A18, SDP_A18_Exp),
+ pp_dec_instruction("attributes 19 - dec [ok]", PP_A19, PP_A19_Exp),
+ pp_enc_instruction("attributes 19 - enc [ok]", SDP_A19, SDP_A19_Exp),
+ pp_dec_instruction("attributes 20 - dec [ok]", PP_A20, PP_A20_Exp),
+ pp_enc_instruction("attributes 20 - enc [ok]", SDP_A20, SDP_A20_Exp),
+ pp_dec_instruction("attributes 21 - dec [ok]", PP_A21, PP_A21_Exp),
+ pp_enc_instruction("attributes 21 - enc [ok]", SDP_A21, SDP_A21_Exp),
+ pp_dec_instruction("attributes 23 - dec [ok]", PP_A23, PP_A23_Exp),
+ pp_enc_instruction("attributes 24 - enc [ok]", SDP_A23, SDP_A23_Exp),
+
+ pp_dec_instruction("bandwidth 01 - dec [ok]", PP_B01, PP_B01_Exp),
+ pp_enc_instruction("bandwidth 01 - enc [ok]", SDP_B01, SDP_B01_Exp),
+ pp_dec_instruction("bandwidth 02 - dec [ok]", PP_B02, PP_B02_Exp),
+
+ pp_dec_instruction("bandwidth 03 - dec [ok]", PP_B03, PP_B03_Exp),
+ pp_enc_instruction("bandwidth 03 - enc [ok]", SDP_B03, SDP_B03_Exp),
+ pp_dec_instruction("bandwidth 04 - dec [error]", PP_B04, PP_B04_Exp),
+ pp_enc_instruction("bandwidth 04 - enc [error]", SDP_B04, SDP_B04_Exp),
+ pp_dec_instruction("times 01 - dec [ok]", PP_T01, PP_T01_Exp),
+ pp_enc_instruction("times 01 - enc [ok]", SDP_T01, SDP_T01_Exp),
+ pp_dec_instruction("repeat times 01 - dec [ok]", PP_R01, PP_R01_Exp),
+ pp_enc_instruction("repeat times 01 - enc [ok]", SDP_R01, SDP_R01_Exp),
+ pp_dec_instruction("time zones 01 - dec [ok]", PP_Z01, PP_Z01_Exp),
+ pp_enc_instruction("time zones 01 - enc [ok]", SDP_Z01, SDP_Z01_Exp),
+ pp_dec_instruction("time zones 02 - dec [error]", PP_Z02, PP_Z02_Exp),
+ pp_enc_instruction("time zones 02 - enc [error]", SDP_Z02, SDP_Z02_Exp),
+ pp_dec_instruction("encryption keys 01 - dec [ok]", PP_K01, PP_K01_Exp),
+ pp_enc_instruction("encryption keys 01 - enc [ok]", SDP_K01, SDP_K01_Exp),
+ pp_dec_instruction("encryption keys 01 - dec [ok]", PP_K02, PP_K02_Exp),
+ pp_enc_instruction("encryption keys 01 - enc [ok]", SDP_K02, SDP_K02_Exp),
+ pp_dec_instruction("encryption keys 01 - dec [ok]", PP_K03, PP_K03_Exp),
+ pp_enc_instruction("encryption keys 01 - enc [ok]", SDP_K03, SDP_K03_Exp),
+ pp_dec_instruction("session name 01 - dec [ok]", PP_S01, PP_S01_Exp),
+ pp_enc_instruction("session name 01 - enc [ok]", SDP_S01, SDP_S01_Exp),
+ pp_dec_instruction("session and media information 01 - dec [ok]", PP_I01, PP_I01_Exp),
+ pp_enc_instruction("session and media information 01 - enc [ok]", SDP_I01, SDP_I01_Exp),
+ pp_dec_instruction("uri 01 - dec [ok]", PP_U01, PP_U01_Exp),
+ pp_enc_instruction("uri 01 - enc [ok]", SDP_U01, SDP_U01_Exp),
+ pp_dec_instruction("email 01 - dec [ok]", PP_E01, PP_E01_Exp),
+ pp_enc_instruction("email 01 - enc [ok]", SDP_E01, SDP_E01_Exp),
+ pp_dec_instruction("phone 01 - dec [ok]", PP_P01, PP_P01_Exp),
+ pp_enc_instruction("phone 01 - enc [ok]", SDP_P01, SDP_P01_Exp),
+ pp_dec_instruction("undefined 01 - dec [error]", PP_N01, PP_N01_Exp),
+
+ pg_dec_instruction("property group 01 - ok", PG01),
+ pg_dec_instruction("property group 02 - ok", PG02),
+ pg_dec_instruction("property group 03 - error", PG03),
+ pg_dec_instruction("property group 04 - error", PG04),
+
+ pgs_dec_instruction("property groups 01 - ok", PGS01),
+ pgs_dec_instruction("property groups 02 - error", PGS02)
+
+ ],
+ exec(Instructions).
+
+
+verify_decode_pg([], []) ->
+ ok;
+verify_decode_pg([{PP, error}|PPs], [{PP, _Err}|SDPs]) ->
+ verify_decode_pg(PPs, SDPs);
+verify_decode_pg([{PP, ok}|_], [{PP, _Err}|_]) ->
+ error;
+verify_decode_pg([{_PP, _ExpStatus}|PG], [_SDP|SDP_PG]) ->
+ verify_decode_pg(PG, SDP_PG).
+
+verify_decode_pgs(PGS, SDP_PGS) ->
+ verify_decode_pg(lists:flatten(PGS), lists:flatten(SDP_PGS)).
+
+
+%% ===============================================================
+
+otp8123(suite) ->
+ [];
+otp8123(Config) when is_list(Config) ->
+ io:format("otp8123 -> entry with"
+ "~n Config: ~p"
+ "~n", [Config]),
+
+ Instructions =
+ [
+ pg_dec_instruction("property group 01 - dec [ok]", otp8123_pg1()),
+ pg_dec_instruction("property group 02 - dec [ok]", otp8123_pg2()),
+ pg_dec_instruction("property group 03 - dec [ok]", otp8123_pg3()),
+ pg_dec_instruction("property group 04 - dec [ok]", otp8123_pg4())
+ ],
+ exec(Instructions),
+ ok.
+
+otp8123_pg1() ->
+ PP1 = #'PropertyParm'{name = "m",
+ value = ["audio 49154 RTP/AVP 8"]},
+ PP2 = #'PropertyParm'{name = "a",
+ value = ["maxptime: 30"]},
+ PP3 = #'PropertyParm'{name = "a",
+ value = ["ptime:2"]},
+ PP4 = #'PropertyParm'{name = "a",
+ value = ["tpmap:8 PCMA/8000/1"]},
+ PG = [PP1, PP2, PP3, PP4],
+ [{PP, ok} || PP <- PG].
+
+otp8123_pg2() ->
+ PP1 = #'PropertyParm'{name = "m",
+ value = ["audio 49154 RTP/AVP 8"]},
+ PP2 = #'PropertyParm'{name = "a",
+ value = ["maxptime: 30 "]},
+ PP3 = #'PropertyParm'{name = "a",
+ value = ["ptime:2"]},
+ PP4 = #'PropertyParm'{name = "a",
+ value = ["tpmap:8 PCMA/8000/1"]},
+ PG = [PP1, PP2, PP3, PP4],
+ [{PP, ok} || PP <- PG].
+
+otp8123_pg3() ->
+ PP1 = #'PropertyParm'{name = "m",
+ value = ["audio 49154 RTP/AVP 8"]},
+ PP2 = #'PropertyParm'{name = "a",
+ value = ["maxptime:30"]},
+ PP3 = #'PropertyParm'{name = "a",
+ value = ["ptime: 2"]},
+ PP4 = #'PropertyParm'{name = "a",
+ value = ["tpmap:8 PCMA/8000/1"]},
+ PG = [PP1, PP2, PP3, PP4],
+ [{PP, ok} || PP <- PG].
+
+otp8123_pg4() ->
+ PP1 = #'PropertyParm'{name = "m",
+ value = ["audio 49154 RTP/AVP 8"]},
+ PP2 = #'PropertyParm'{name = "a",
+ value = ["maxptime:30"]},
+ PP3 = #'PropertyParm'{name = "a",
+ value = ["ptime: 2 "]},
+ PP4 = #'PropertyParm'{name = "a",
+ value = ["tpmap:8 PCMA/8000/1"]},
+ PG = [PP1, PP2, PP3, PP4],
+ [{PP, ok} || PP <- PG].
+
+
+
+%% ===============================================================
+%%
+%% Instruction engine
+%%
+
+instr_verify_pp(Expected) ->
+ fun(Res) ->
+ case Res of
+ Expected -> ok;
+ _ -> {error, Expected}
+ end
+ end.
+
+instr_verify_dec_pg(Data) ->
+ fun({ok, SDP}) ->
+ verify_decode_pg(Data, SDP);
+ (_Bad) ->
+ error
+ end.
+
+instr_verify_dec_pgs(Data) ->
+ fun({ok, SDP}) ->
+ verify_decode_pgs(Data, SDP);
+ (_Bad) ->
+ error
+ end.
+
+
+pp_dec_instruction(Desc, Data, Exp) ->
+ dec_instruction(Desc, Data, instr_verify_pp(Exp)).
+
+pp_enc_instruction(Desc, Data, Exp) ->
+ enc_instruction(Desc, Data, instr_verify_pp(Exp)).
+
+pg_dec_instruction(Desc, Data0) ->
+ Data = [D || {D, _} <- Data0],
+ dec_instruction(Desc, Data, instr_verify_dec_pg(Data0)).
+
+pgs_dec_instruction(Desc, Data0) ->
+ Data = [[D || {D, _} <- PG] || PG <- Data0],
+ dec_instruction(Desc, Data, instr_verify_dec_pgs(Data0)).
+
+dec_instruction(Desc, Data, Verify) ->
+ instruction(Desc, fun(D) -> megaco:decode_sdp(D) end, Data, Verify).
+
+enc_instruction(Desc, Data, Verify) ->
+ instruction(Desc, fun(D) -> megaco:encode_sdp(D) end, Data, Verify).
+
+instruction(Desc, Cmd, Data, Verify) ->
+ {Desc, Cmd, Data, Verify}.
+
+exec(Instructions) ->
+ exec(Instructions, []).
+
+exec([], []) ->
+ ok;
+exec([], Acc) ->
+ {error, lists:reverse(Acc)};
+exec([Instr|Instructions], Acc) ->
+ case exec_instruction(Instr) of
+ ok ->
+ exec(Instructions, Acc);
+ Error ->
+ exec(Instructions, [Error|Acc])
+ end.
+
+
+exec_instruction({Desc, Cmd, Data, Verify}) ->
+ io:format("~n"
+ "*** Test ~s ***"
+ "~n", [Desc]),
+ Res = (catch Cmd(Data)),
+ case (catch Verify(Res)) of
+ ok ->
+ ok;
+ error ->
+ {error, {instruction_failed, {Desc, Data, Res}}};
+ {error, Expected} ->
+ {error, {instruction_failed, {Desc, Data, Res, Expected}}};
+ Else ->
+ {error, {verification_error, {Desc, Data, Res, Else}}}
+ end.
+
+
+%% ===============================================================
+%%
+%% Utility functions to generate PropertyParm records
+%%
+
+cre_PropertyParm_p(Num) when is_list(Num) ->
+ cre_PropertyParm("p", Num).
+
+cre_sdp_p(PN) ->
+ #megaco_sdp_p{phone_number = PN}.
+
+cre_PropertyParm_e(Email) when is_list(Email) ->
+ cre_PropertyParm("e", Email).
+
+cre_sdp_e(E) ->
+ #megaco_sdp_e{email = E}.
+
+cre_PropertyParm_u(URI) when is_list(URI) ->
+ cre_PropertyParm("u", URI).
+
+cre_sdp_u(U) ->
+ #megaco_sdp_u{uri = U}.
+
+cre_PropertyParm_i(SessionDescr) when is_list(SessionDescr) ->
+ cre_PropertyParm("i", SessionDescr).
+
+cre_sdp_i(SD) ->
+ #megaco_sdp_i{session_descriptor = SD}.
+
+cre_PropertyParm_s(Name) when is_list(Name) ->
+ cre_PropertyParm("s", Name).
+
+cre_sdp_s(N) ->
+ #megaco_sdp_s{name = N}.
+
+cre_PropertyParm_k(prompt, _) ->
+ cre_PropertyParm("k", "prompt");
+cre_PropertyParm_k(clear, EncryptionKey) when is_list(EncryptionKey) ->
+ cre_PropertyParm("k", "clear:" ++ EncryptionKey);
+cre_PropertyParm_k(base64, EncryptionKey) when is_list(EncryptionKey) ->
+ cre_PropertyParm("k", "base64:" ++ EncryptionKey);
+cre_PropertyParm_k(uri, EncryptionKey) when is_list(EncryptionKey) ->
+ cre_PropertyParm("k", "uri:" ++ EncryptionKey);
+cre_PropertyParm_k(Method, EncryptionKey)
+ when is_list(Method) and is_list(EncryptionKey) ->
+ cre_PropertyParm("k", Method ++ ":" ++ EncryptionKey).
+
+cre_sdp_k(M) ->
+ #megaco_sdp_k{method = M}.
+cre_sdp_k(M, EK) ->
+ #megaco_sdp_k{method = M, encryption_key = EK}.
+
+cre_PropertyParm_z([H | _] = LOA) when is_record(H, megaco_sdp_z_adjustement) ->
+ F = fun(#megaco_sdp_z_adjustement{time = T, offset = O}, Str) ->
+ Str ++ " " ++ T ++ " " ++ O
+ end,
+ cre_PropertyParm("z", lists:foldl(F, [], LOA)).
+
+cre_sdp_z(LOA) ->
+ #megaco_sdp_z{list_of_adjustments = LOA}.
+
+cre_PropertyParm_r(Repeat, Duration, ListOfOffsets)
+ when is_list(Repeat) and is_list(Duration) and is_list(ListOfOffsets) ->
+ F = fun(Elem, Str) -> Str ++ " " ++ Elem end,
+ Val = Repeat ++ " " ++ Duration ++ lists:foldl(F, [], ListOfOffsets),
+ cre_PropertyParm("r", Val).
+
+cre_sdp_r(Repeat, Duration, ListOfOffsets) ->
+ #megaco_sdp_r{repeat_interval = Repeat,
+ active_duration = Duration,
+ list_of_offsets = ListOfOffsets}.
+
+cre_PropertyParm_t(Start, Stop)
+ when is_list(Start) and is_list(Stop) ->
+ cre_PropertyParm("t", Start ++ " " ++ Stop);
+cre_PropertyParm_t(Start, Stop) ->
+ cre_PropertyParm_t(i2s(Start), i2s(Stop)).
+
+cre_sdp_t(Start, Stop) ->
+ #megaco_sdp_t{start = Start, stop = Stop}.
+
+cre_PropertyParm_b(BwType, Bandwidth)
+ when is_list(BwType) and is_integer(Bandwidth) ->
+ cre_PropertyParm_b(BwType, i2s(Bandwidth));
+cre_PropertyParm_b(BwType, Bandwidth)
+ when is_list(BwType) and is_list(Bandwidth) ->
+ cre_PropertyParm("b", BwType ++ ":" ++ Bandwidth).
+
+cre_sdp_b(BWT, BW) ->
+ #megaco_sdp_b{bwtype = BWT, bandwidth = BW}.
+
+
+cre_PropertyParm_cat(Cat) when is_list(Cat) ->
+ cre_PropertyParm_a("cat", Cat).
+
+cre_sdp_a_cat(C) ->
+ #megaco_sdp_a_cat{category = C}.
+
+
+cre_PropertyParm_keywds(KeyWds) when is_list(KeyWds) ->
+ cre_PropertyParm_a("keywds", KeyWds).
+
+cre_sdp_a_keywds(KW) ->
+ #megaco_sdp_a_keywds{keywords = KW}.
+
+
+cre_PropertyParm_tool(NameAndVersion) when is_list(NameAndVersion) ->
+ cre_PropertyParm_a("tool", NameAndVersion).
+
+cre_sdp_a_tool(NAV) ->
+ #megaco_sdp_a_tool{name_and_version = NAV}.
+
+
+cre_PropertyParm_ptime(PacketTime) when is_integer(PacketTime) ->
+ cre_PropertyParm_ptime(i2s(PacketTime));
+cre_PropertyParm_ptime(PacketTime) when is_list(PacketTime) ->
+ cre_PropertyParm_a("ptime", PacketTime).
+
+cre_sdp_a_ptime(PT) ->
+ #megaco_sdp_a_ptime{packet_time = PT}.
+
+
+cre_PropertyParm_maxptime(MaxPacketTime) when is_integer(MaxPacketTime) ->
+ cre_PropertyParm_maxptime(i2s(MaxPacketTime));
+cre_PropertyParm_maxptime(MaxPacketTime) when is_list(MaxPacketTime) ->
+ cre_PropertyParm_a("maxptime", MaxPacketTime).
+
+cre_sdp_a_maxptime(PT) ->
+ #megaco_sdp_a_maxptime{maximum_packet_time = PT}.
+
+
+cre_PropertyParm_rtpmap(Payload, EncName, ClockRate) ->
+ cre_PropertyParm_rtpmap(Payload, EncName, ClockRate, []).
+
+cre_PropertyParm_rtpmap(Payload, EncName, ClockRate, EncPar)
+ when is_integer(Payload) and
+ is_list(EncName) and
+ is_integer(ClockRate) and
+ is_list(EncPar) ->
+ F = fun(Elem, Str) -> Str ++ "/" ++ Elem end,
+ Val =
+ integer_to_list(Payload) ++ " " ++
+ EncName ++ "/" ++ integer_to_list(ClockRate) ++
+ lists:foldl(F, [], EncPar),
+ cre_PropertyParm_a("rtpmap", Val).
+
+cre_sdp_a_rtpmap(Payload, EncName, ClockRate) ->
+ #megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate}.
+cre_sdp_a_rtpmap(Payload, EncName, ClockRate, EncParms) ->
+ #megaco_sdp_a_rtpmap{payload_type = Payload,
+ encoding_name = EncName,
+ clock_rate = ClockRate,
+ encoding_parms = EncParms}.
+
+cre_PropertyParm_orient(Orientation) when is_atom(Orientation) ->
+ cre_PropertyParm_orient(atom_to_list(Orientation));
+cre_PropertyParm_orient(Orientation) when is_list(Orientation) ->
+ cre_PropertyParm_a("orient", Orientation).
+
+cre_sdp_a_orient(O) ->
+ #megaco_sdp_a_orient{orientation = O}.
+
+cre_PropertyParm_type(CT) when is_list(CT) ->
+ cre_PropertyParm_a("type", CT).
+
+cre_sdp_a_type(CT) ->
+ #megaco_sdp_a_type{conf_type = CT}.
+
+cre_PropertyParm_charset(CS) when is_list(CS) ->
+ cre_PropertyParm_a("charset", CS).
+
+cre_sdp_a_charset(CS) ->
+ #megaco_sdp_a_charset{char_set = CS}.
+
+cre_PropertyParm_sdplang(L) when is_list(L) ->
+ cre_PropertyParm_a("sdplang", L).
+
+cre_sdp_a_sdplang(L) ->
+ #megaco_sdp_a_sdplang{tag = L}.
+
+cre_PropertyParm_lang(L) when is_list(L) ->
+ cre_PropertyParm_a("lang", L).
+
+cre_sdp_a_lang(L) ->
+ #megaco_sdp_a_lang{tag = L}.
+
+cre_PropertyParm_framerate(FR) when is_list(FR) ->
+ cre_PropertyParm_a("framerate", FR).
+
+cre_sdp_a_framerate(FR) ->
+ #megaco_sdp_a_framerate{frame_rate = FR}.
+
+cre_PropertyParm_quality(Quality) when is_integer(Quality) ->
+ cre_PropertyParm_quality(i2s(Quality));
+cre_PropertyParm_quality(Quality) when is_list(Quality) ->
+ cre_PropertyParm_a("quality", Quality).
+
+cre_sdp_a_quality(Qa) ->
+ #megaco_sdp_a_quality{quality = Qa}.
+
+cre_PropertyParm_a(Attr, AttrValue)
+ when is_list(Attr) and is_list(AttrValue) ->
+ cre_PropertyParm("a", Attr ++ ":" ++ AttrValue).
+
+cre_PropertyParm_a(Attr) when is_list(Attr) ->
+ cre_PropertyParm("a", Attr).
+
+cre_PropertyParm_a_fmtp(Format, Param)
+ when is_list(Format) and is_list(Param) ->
+ cre_PropertyParm_a("fmtp", Format ++ " " ++ Param).
+
+cre_sdp_a_fmtp(Fmt, Parm) ->
+ #megaco_sdp_a_fmtp{format = Fmt, param = Parm}.
+
+cre_sdp_a(Attr) ->
+ #megaco_sdp_a{attribute = Attr}.
+
+%% cre_sdp_a(Attr, Val) ->
+%% #megaco_sdp_a{attribute = Attr,
+%% value = Val}.
+
+cre_PropertyParm_o(User, SID, Version, AddrType, Addr) ->
+ cre_PropertyParm_o(User, SID, Version, in, AddrType, Addr).
+
+cre_PropertyParm_o(User, SID, Version, NetType, AddrType, Addr)
+ when is_list(User) and
+ is_integer(SID) and
+ is_integer(Version) and
+ is_list(NetType) or (NetType == in) and
+ is_list(AddrType) or ((AddrType == ip4) or (AddrType == ip6)) and
+ is_list(Addr) ->
+ NT = case NetType of
+ in -> "IN";
+ _ -> NetType
+ end,
+ AT = case AddrType of
+ ip4 -> "IP4";
+ ip6 -> "IP6";
+ _ -> AddrType
+ end,
+ Val =
+ User ++ " " ++
+ i2s(SID) ++ " " ++
+ i2s(Version) ++ " " ++
+ NT ++ " " ++
+ AT ++ " " ++
+ Addr,
+ cre_PropertyParm("o", Val).
+
+cre_sdp_o(Name, SID, V, AddrType, Addr) ->
+ cre_sdp_o(Name, SID, V, in, AddrType, Addr).
+cre_sdp_o(Name, SID, V, NetType, AddrType, Addr) ->
+ #megaco_sdp_o{user_name = Name,
+ session_id = SID,
+ version = V,
+ network_type = NetType,
+ address_type = AddrType,
+ address = Addr}.
+
+cre_PropertyParm_m(Media, Port, Transport, FmtList)
+ when is_atom(Media) ->
+ cre_PropertyParm_m(atom_to_list(Media),
+ Port, Transport, FmtList);
+cre_PropertyParm_m(Media, Port0, Transport, FmtList)
+ when is_list(Media) and is_list(Transport) and is_list(FmtList) ->
+ Port = i2s(Port0),
+ Val =
+ Media ++ " " ++ Port ++ " " ++ Transport ++ " " ++ val(FmtList),
+ cre_PropertyParm("m", Val).
+
+cre_PropertyParm_m(Media, Port, NumPorts, Transport, FmtList)
+ when is_atom(Media) ->
+ cre_PropertyParm_m(atom_to_list(Media),
+ Port, NumPorts, Transport, FmtList);
+cre_PropertyParm_m(Media, Port0, NumPorts0, Transport, FmtList)
+ when is_list(Media) and is_list(Transport) and is_list(FmtList) ->
+ Port = i2s(Port0),
+ NumPorts = i2s(NumPorts0),
+ Val =
+ Media ++ " " ++ Port ++ "/" ++ NumPorts ++ " " ++ Transport ++
+ " " ++ val(FmtList),
+ cre_PropertyParm("m", Val).
+
+cre_sdp_m(Media, Port, Transport, FmtList) ->
+ #megaco_sdp_m{media = Media,
+ port = Port,
+ transport = Transport,
+ fmt_list = FmtList}.
+
+cre_sdp_m(Media, Port, NumPorts, Transport, FmtList) ->
+ #megaco_sdp_m{media = Media,
+ port = Port,
+ num_ports = NumPorts,
+ transport = Transport,
+ fmt_list = FmtList}.
+
+
+cre_PropertyParm_c(ip4, ConnAddr) ->
+ cre_PropertyParm_c("IP4", ConnAddr);
+cre_PropertyParm_c(ip6, ConnAddr) ->
+ cre_PropertyParm_c("IP6", ConnAddr);
+cre_PropertyParm_c(AddrType, ConnAddr)
+ when is_list(AddrType) and is_list(ConnAddr) ->
+ Val = "IN " ++ AddrType ++ " " ++ ConnAddr,
+ cre_PropertyParm("c", Val).
+
+cre_PropertyParm_c(ip4, Base, TTL) ->
+ cre_PropertyParm_c("IP4", Base, i2s(TTL));
+cre_PropertyParm_c(AddrType, Base, TTL)
+ when is_list(AddrType) and
+ is_list(Base) and
+ is_list(TTL) ->
+ Val = "IN " ++ AddrType ++ " " ++ Base ++ "/" ++ TTL,
+ cre_PropertyParm("c", Val).
+
+cre_PropertyParm_c(ip4, Base, TTL, NumOf) ->
+ cre_PropertyParm_c("IP4", Base, i2s(TTL), i2s(NumOf));
+cre_PropertyParm_c(AddrType, Base, TTL, NumOf)
+ when is_list(AddrType) and
+ is_list(Base) and
+ is_list(TTL) and
+ is_list(NumOf) ->
+ Val =
+ "IN " ++ AddrType ++ " " ++ Base ++ "/" ++ TTL ++ "/" ++ NumOf,
+ cre_PropertyParm("c", Val).
+
+
+cre_sdp_c(AddrType, ConnAddr) ->
+ cre_sdp_c(in, AddrType, ConnAddr).
+
+cre_sdp_c(NetType, AddrType, ConnAddr) ->
+ #megaco_sdp_c{network_type = NetType,
+ address_type = AddrType,
+ connection_addr = ConnAddr}.
+
+
+cre_PropertyParm_v(Version) when is_integer(Version) ->
+ cre_PropertyParm_v(integer_to_list(Version));
+cre_PropertyParm_v(Version) when is_list(Version) ->
+ cre_PropertyParm("v", Version).
+
+cre_sdp_v(Version) ->
+ #megaco_sdp_v{version = Version}.
+
+
+cre_PropertyParm(Name, Val) when is_list(Name) and is_list(Val) ->
+ #'PropertyParm'{name = Name, value = [Val]}.
+
+
+val(Vals) ->
+ val(Vals, " ").
+val([Head|Tail], Sep) ->
+ lists:foldl(fun(E, S) -> S ++ Sep ++ E end, Head, Tail).
+
+i2s(I) when is_integer(I) ->
+ integer_to_list(I);
+i2s(S) when is_list(S) ->
+ S.
+
+
+%% error(Reason) ->
+%% throw({error, Reason}).
diff --git a/lib/megaco/test/megaco_segment_test.erl b/lib/megaco/test/megaco_segment_test.erl
new file mode 100644
index 0000000000..ef07ee54b1
--- /dev/null
+++ b/lib/megaco/test/megaco_segment_test.erl
@@ -0,0 +1,7819 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Test the segment package introduced in v3 of the megaco std.
+%%----------------------------------------------------------------------
+-module(megaco_segment_test).
+
+-export([t/0, t/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+-export([all/1,
+
+ send/1,
+ send_segmented_msg_plain1/1,
+ send_segmented_msg_plain2/1,
+ send_segmented_msg_plain3/1,
+ send_segmented_msg_plain4/1,
+ send_segmented_msg_ooo1/1,
+ send_segmented_msg_missing_seg_reply1/1,
+ send_segmented_msg_missing_seg_reply2/1,
+
+ recv/1,
+ recv_segmented_msg_plain/1,
+ recv_segmented_msg_ooo_seg/1,
+ recv_segmented_msg_missing_seg1/1,
+ recv_segmented_msg_missing_seg2/1,
+
+ tickets/1
+
+ ]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v3.hrl").
+
+-define(TEST_VERBOSITY, debug).
+
+-define(VERSION, 3).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ [
+ send,
+ recv
+
+ %% Tickets last
+ %% tickets
+ ].
+
+send(suite) ->
+ [
+ send_segmented_msg_plain1,
+ send_segmented_msg_plain2,
+ send_segmented_msg_plain3,
+ send_segmented_msg_plain4,
+ send_segmented_msg_ooo1,
+ send_segmented_msg_missing_seg_reply1,
+ send_segmented_msg_missing_seg_reply2
+ ].
+
+recv(suite) ->
+ [
+ recv_segmented_msg_plain,
+ recv_segmented_msg_ooo_seg,
+ recv_segmented_msg_missing_seg1,
+ recv_segmented_msg_missing_seg2
+ ].
+
+tickets(suite) ->
+ [
+ ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% Segmented reply send test cases %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+send_segmented_msg_plain1(suite) ->
+ [];
+send_segmented_msg_plain1(doc) ->
+ "First plain test that it is possible to send segmented messages. "
+ "Send window = infinity. ";
+send_segmented_msg_plain1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmp1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmp1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmp1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmp1_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmp1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmp1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmp1_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmp1_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TransId = 2,
+ NotifyReq = ssmp1_mgc_notify_request_msg(Mid, TransId,
+ TermId1, CtxId1,
+ TermId2, CtxId2),
+ NrVerifyFun1 =
+ ssmp1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmp1_mgc_verify_notify_reply_segment_msg_fun(2, true, TransId,
+ TermId2, CtxId2),
+ SegmentRep1 = ssmp1_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmp1_mgc_segment_reply_msg(Mid, TransId, 2, true),
+ TransAck = ssmp1_mgc_trans_ack_msg(Mid, TransId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_nothing, timer:seconds(1)},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 2000}},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {send, "segment reply 1", SegmentRep1},
+ {sleep, 100},
+ {send, "segment reply 2", SegmentRep2},
+ {sleep, 100}, % {expect_nothing, 500},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, timer:seconds(5)},
+ disconnect
+ ],
+ EvSeq.
+
+ssmp1_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmp1_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmp1_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmp1_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmp1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmp1_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmp1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmp1_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmp1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmp1_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmp1_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmp1_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp1_mgc_notify_request_msg(Mid, TransId, TermId1, Cid1, TermId2, Cid2) ->
+ AR1 = ssmp1_mgc_notify_request_ar(1, TermId1, Cid1),
+ AR2 = ssmp1_mgc_notify_request_ar(2, TermId2, Cid2),
+ TR = cre_transReq(TransId, [AR1, AR2]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp1_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmp1_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp1_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmp1_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmp1_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmp1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmp1_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmp1_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmp1_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ NotifyReqVerify = ssmp1_mg_verify_notify_request_fun(Tid1, Tid2),
+ AckVerify = ssmp1_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, segment_send, infinity},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ {sleep, 1000},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 5000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmp1_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmp1_mg_verify_handle_connect(Ev) end.
+
+ssmp1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmp1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmp1_mg_verify_handle_connect(Else) ->
+ io:format("ssmp1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmp1_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmp1_mg_verify_scr(Rep) end.
+
+ssmp1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmp1_mg_do_verify_scr(AR));
+ssmp1_mg_verify_scr(Crap) ->
+ io:format("ssmp1_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmp1_mg_do_verify_scr(AR) ->
+ io:format("ssmp1_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmp1_mg_verify_notify_request_fun(Tid1, Tid2) ->
+ fun(Req) ->
+ ssmp1_mg_verify_notify_request(Req, Tid1, Tid2)
+ end.
+
+ssmp1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, [AR1, AR2]}, Tid1, Tid2) ->
+ (catch ssmp1_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2));
+ssmp1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tid1, _Tid2) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmp1_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tid1, _Tid2) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmp1_mg_verify_notify_request(Crap, _Tid1, _Tid2) ->
+ io:format("ssmp1_mg_verify_notify_request -> unknown request"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p"
+ "~n Crap: ~p"
+ "~n", [_Tid1, _Tid2, Crap]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmp1_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2) ->
+ io:format("ssmp1_mg_do_verify_notify_request -> ok"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p"
+ "~n AR1: ~p"
+ "~n AR2: ~p"
+ "~n", [Tid1, Tid2, AR1, AR2]),
+ ActionReply1 = ssmp1_mg_do_verify_notify_request(Tid1, AR1),
+ ActionReply2 = ssmp1_mg_do_verify_notify_request(Tid2, AR2),
+ Reply = {{handle_ack, ssmp1}, [ActionReply1, ActionReply2]},
+ {ok, [AR1, AR2], Reply}.
+
+ssmp1_mg_do_verify_notify_request(Tid, AR) ->
+ io:format("ssmp1_mg_do_verify_notify_request -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmp1_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmp1_mg_verify_ack_fun() ->
+ fun(Event) -> ssmp1_mg_verify_ack(Event) end.
+
+ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp1}) ->
+ io:format("ssmp1_mg_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
+ io:format("ssmp1_mg_verify_ack -> error"
+ "~n CrapAckData: ~p"
+ "~n CH: ~p"
+ "~n", [CrapAckData, CH]),
+ {error, {unknown_ack_data, CrapAckData, CH}, ok};
+ssmp1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ io:format("ssmp1_mg_verify_ack -> error"
+ "~n BadAckStatus: ~p"
+ "~n BadAckData: ~p"
+ "~n CH: ~p"
+ "~n", [BadAckStatus, BadAckData, CH]),
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmp1_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmp1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp1_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_plain2(suite) ->
+ [];
+send_segmented_msg_plain2(doc) ->
+ "Second plain test that it is possible to send segmented messages. "
+ "Send window = infinity. ";
+send_segmented_msg_plain2(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmp2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmp2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmp2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmp2_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmp2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmp2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmp2_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmp2_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TransId = 2,
+ NotifyReq = ssmp2_mgc_notify_request_msg(Mid, TransId,
+ TermId1, CtxId1,
+ TermId2, CtxId2),
+ NrVerifyFun1 =
+ ssmp2_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmp2_mgc_verify_notify_reply_segment_msg_fun(2, true, TransId,
+ TermId2, CtxId2),
+ SegmentRep1 = ssmp2_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmp2_mgc_segment_reply_msg(Mid, TransId, 2, true),
+ TransAck = ssmp2_mgc_trans_ack_msg(Mid, TransId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_nothing, timer:seconds(1)},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 2000}},
+ {send, "segment reply 1", SegmentRep1},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {send, "segment reply 2", SegmentRep2},
+ {sleep, 100}, % {expect_nothing, 500},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, timer:seconds(5)},
+ disconnect
+ ],
+ EvSeq.
+
+ssmp2_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmp2_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmp2_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmp2_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmp2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmp2_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmp2_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmp2_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmp2_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmp2_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmp2_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmp2_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp2_mgc_notify_request_msg(Mid, TransId, TermId1, Cid1, TermId2, Cid2) ->
+ AR1 = ssmp2_mgc_notify_request_ar(1, TermId1, Cid1),
+ AR2 = ssmp2_mgc_notify_request_ar(2, TermId2, Cid2),
+ TR = cre_transReq(TransId, [AR1, AR2]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp2_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp2_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmp2_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp2_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmp2_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmp2_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmp2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmp2_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmp2_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmp2_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ NotifyReqVerify = ssmp2_mg_verify_notify_request_fun(Tid1, Tid2),
+ AckVerify = ssmp2_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, segment_send, infinity},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ {sleep, 1000},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 5000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmp2_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmp2_mg_verify_handle_connect(Ev) end.
+
+ssmp2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmp2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmp2_mg_verify_handle_connect(Else) ->
+ io:format("ssmp2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmp2_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmp2_mg_verify_scr(Rep) end.
+
+ssmp2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmp2_mg_do_verify_scr(AR));
+ssmp2_mg_verify_scr(Crap) ->
+ io:format("ssmp2_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmp2_mg_do_verify_scr(AR) ->
+ io:format("ssmp2_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmp2_mg_verify_notify_request_fun(Tid1, Tid2) ->
+ fun(Req) -> ssmp2_mg_verify_notify_request(Req, Tid1, Tid2) end.
+
+ssmp2_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, [AR1, AR2]}, Tid1, Tid2) ->
+ (catch ssmp2_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2));
+ssmp2_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tid1, _Tid2) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmp2_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tid1, _Tid2) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmp2_mg_verify_notify_request(Crap, _Tid1, _Tid2) ->
+ io:format("ssmp2_mg_verify_notify_request -> unknown request"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p"
+ "~n Crap: ~p"
+ "~n", [_Tid1, _Tid2, Crap]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmp2_mg_do_verify_notify_request(Tid1, Tid2, AR1, AR2) ->
+ io:format("ssmp2_mg_do_verify_notify_request -> ok"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p"
+ "~n AR1: ~p"
+ "~n AR2: ~p"
+ "~n", [Tid1, Tid2, AR1, AR2]),
+ ActionReply1 = ssmp2_mg_do_verify_notify_request(Tid1, AR1),
+ ActionReply2 = ssmp2_mg_do_verify_notify_request(Tid2, AR2),
+ Reply = {{handle_ack, ssmp2}, [ActionReply1, ActionReply2]},
+ {ok, [AR1, AR2], Reply}.
+
+ssmp2_mg_do_verify_notify_request(Tid, AR) ->
+ io:format("ssmp2_mg_do_verify_notify_request -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmp2_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmp2_mg_verify_ack_fun() ->
+ fun(Event) -> ssmp2_mg_verify_ack(Event) end.
+
+ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp2}) ->
+ io:format("ssmp2_mg_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
+ {error, {unknown_ack_data, CrapAckData, CH}, ok};
+ssmp2_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmp2_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmp2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp2_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_plain3(suite) ->
+ [];
+send_segmented_msg_plain3(doc) ->
+ "Third plain test that it is possible to send segmented messages. "
+ "Send window = 1. ";
+send_segmented_msg_plain3(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmp3),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmp3_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmp3_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmp3_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmp3_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmp3_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmp3_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmp3_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ CtxId3 = 3,
+ TermId4 =
+ #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ CtxId4 = 4,
+ TermId5 =
+ #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ CtxId5 = 5,
+ TermId6 =
+ #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ CtxId6 = 6,
+ TermId7 =
+ #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ CtxId7 = 7,
+ TermId8 =
+ #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ CtxId8 = 8,
+ TransId = 2,
+ TermIDs = [TermId1, TermId2, TermId3, TermId4,
+ TermId5, TermId6, TermId7, TermId8],
+ CIDs = [CtxId1, CtxId2, CtxId3, CtxId4,
+ CtxId5, CtxId6, CtxId7, CtxId8],
+ NotifyReq = ssmp3_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
+ NrVerifyFun1 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
+ TermId2, CtxId2),
+ NrVerifyFun3 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
+ TermId3, CtxId3),
+ NrVerifyFun4 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
+ TermId4, CtxId4),
+ NrVerifyFun5 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
+ TermId5, CtxId5),
+ NrVerifyFun6 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
+ TermId6, CtxId6),
+ NrVerifyFun7 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
+ TermId7, CtxId7),
+ NrVerifyFun8 =
+ ssmp3_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
+ TermId8, CtxId8),
+ SegmentRep1 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 2, false),
+ SegmentRep3 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 3, false),
+ SegmentRep4 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 4, false),
+ SegmentRep5 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 5, false),
+ SegmentRep6 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 6, false),
+ SegmentRep7 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 7, false),
+ SegmentRep8 = ssmp3_mgc_segment_reply_msg(Mid, TransId, 8, true),
+ TransAck = ssmp3_mgc_trans_ack_msg(Mid, TransId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_nothing, 1000},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 1", SegmentRep1},
+
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 2", SegmentRep2},
+
+ {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 3", SegmentRep3},
+
+ {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 4", SegmentRep4},
+
+ {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 5", SegmentRep5},
+
+ {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 6", SegmentRep6},
+
+ {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 7", SegmentRep7},
+
+ {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
+ {expect_nothing, 200},
+ {send, "segment reply 8", SegmentRep8},
+
+ {expect_nothing, 200},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+ssmp3_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmp3_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmp3_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmp3_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmp3_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmp3_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmp3_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmp3_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmp3_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmp3_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmp3_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmp3_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp3_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
+ ARs = ssmp3_mgc_notify_request_ars(TermIDs, CIDs),
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp3_mgc_notify_request_ars(TermIDs, CIDs) ->
+ ssmp3_mgc_notify_request_ars(TermIDs, CIDs, []).
+
+ssmp3_mgc_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmp3_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
+ AR = ssmp3_mgc_notify_request_ar(100+CID, TermID, CID),
+ ssmp3_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
+
+ssmp3_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp3_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmp3_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp3_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmp3_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmp3_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmp3_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmp3_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmp3_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmp3_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
+ NotifyReqVerify = ssmp3_mg_verify_notify_request_fun(Tids),
+ AckVerify = ssmp3_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, segment_send, 1},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ {sleep, 500},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 5000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmp3_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmp3_mg_verify_handle_connect(Ev) end.
+
+ssmp3_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmp3_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmp3_mg_verify_handle_connect(Else) ->
+ io:format("ssmp3_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmp3_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmp3_mg_verify_scr(Rep) end.
+
+ssmp3_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmp3_mg_do_verify_scr(AR));
+ssmp3_mg_verify_scr(Crap) ->
+ io:format("ssmp3_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmp3_mg_do_verify_scr(AR) ->
+ io:format("ssmp3_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmp3_mg_verify_notify_request_fun(Tids) ->
+ fun(Req) -> ssmp3_mg_verify_notify_request(Req, Tids) end.
+
+ssmp3_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
+ when length(ARs) == length(Tids) ->
+ (catch ssmp3_mg_do_verify_notify_request(Tids, ARs));
+ssmp3_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmp3_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tids) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmp3_mg_verify_notify_request(Crap, _Tids) ->
+ io:format("ssmp3_mg_verify_notify_request -> unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p"
+ "~n", [Crap, _Tids]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmp3_mg_do_verify_notify_request(Tids, ARs) ->
+ io:format("ssmp3_mg_do_verify_notify_request -> ok"
+ "~n Tids: ~p"
+ "~n ARs: ~p"
+ "~n", [Tids, ARs]),
+ ActionReplies = ssmp3_mg_do_verify_notify_request_ars(Tids, ARs),
+ io:format("ssmp3_mg_do_verify_notify_request -> ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
+ Reply = {{handle_ack, ssmp3}, ActionReplies},
+ {ok, ARs, Reply}.
+
+ssmp3_mg_do_verify_notify_request_ars(Tids, ARs) ->
+ ssmp3_mg_do_verify_notify_request_ars(Tids, ARs, []).
+
+ssmp3_mg_do_verify_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmp3_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
+ ActionReply = ssmp3_mg_do_verify_notify_request_ar(Tid, AR),
+ ssmp3_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
+
+ssmp3_mg_do_verify_notify_request_ar(Tid, AR) ->
+ io:format("ssmp3_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmp3_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmp3_mg_verify_ack_fun() ->
+ fun(Event) -> ssmp3_mg_verify_ack(Event) end.
+
+ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp3}) ->
+ io:format("ssmp3_mg_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
+ {error, {unknown_ack_data, CrapAckData, CH}, ok};
+ssmp3_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmp3_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmp3_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp3_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_plain4(suite) ->
+ [];
+send_segmented_msg_plain4(doc) ->
+ "Forth plain test that it is possible to send segmented messages. "
+ "Send window = 3. ";
+send_segmented_msg_plain4(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmp4),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmp4_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmp4_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmp4_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmp4_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmp4_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmp4_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmp4_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ CtxId3 = 3,
+ TermId4 =
+ #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ CtxId4 = 4,
+ TermId5 =
+ #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ CtxId5 = 5,
+ TermId6 =
+ #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ CtxId6 = 6,
+ TermId7 =
+ #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ CtxId7 = 7,
+ TermId8 =
+ #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ CtxId8 = 8,
+ TransId = 2,
+ TermIDs = [TermId1, TermId2, TermId3, TermId4,
+ TermId5, TermId6, TermId7, TermId8],
+ CIDs = [CtxId1, CtxId2, CtxId3, CtxId4,
+ CtxId5, CtxId6, CtxId7, CtxId8],
+ NotifyReq = ssmp4_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
+ NrVerifyFun1 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
+ TermId2, CtxId2),
+ NrVerifyFun3 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
+ TermId3, CtxId3),
+ NrVerifyFun4 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
+ TermId4, CtxId4),
+ NrVerifyFun5 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
+ TermId5, CtxId5),
+ NrVerifyFun6 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
+ TermId6, CtxId6),
+ NrVerifyFun7 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
+ TermId7, CtxId7),
+ NrVerifyFun8 =
+ ssmp4_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
+ TermId8, CtxId8),
+ SegmentRep1 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 2, false),
+ SegmentRep3 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 3, false),
+ SegmentRep4 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 4, false),
+ SegmentRep5 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 5, false),
+ SegmentRep6 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 6, false),
+ SegmentRep7 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 7, false),
+ SegmentRep8 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 8, true),
+ TransAck = ssmp4_mgc_trans_ack_msg(Mid, TransId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_nothing, 1000},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 1", SegmentRep1},
+ {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 2", SegmentRep2},
+ {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 3", SegmentRep3},
+ {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 4", SegmentRep4},
+ {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 5", SegmentRep5},
+ {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 6", SegmentRep6},
+ {expect_nothing, 1000},
+ {send, "segment reply 7", SegmentRep7},
+ {expect_nothing, 1000},
+ {send, "segment reply 8", SegmentRep8},
+ {expect_nothing, 1000},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+ssmp4_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmp4_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmp4_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmp4_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmp4_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmp4_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmp4_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmp4_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmp4_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmp4_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmp4_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmp4_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp4_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
+ ARs = ssmp4_mgc_notify_request_ars(TermIDs, CIDs),
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp4_mgc_notify_request_ars(TermIDs, CIDs) ->
+ ssmp4_mgc_notify_request_ars(TermIDs, CIDs, []).
+
+ssmp4_mgc_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmp4_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
+ AR = ssmp4_mgc_notify_request_ar(100+CID, TermID, CID),
+ ssmp4_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
+
+ssmp4_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp4_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmp4_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmp4_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmp4_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmp4_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmp4_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmp4_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmp4_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmp4_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
+ NotifyReqVerify = ssmp4_mg_verify_notify_request_fun(Tids),
+ AckVerify = ssmp4_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, segment_send, 3},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ {sleep, 1000},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 15000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmp4_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmp4_mg_verify_handle_connect(Ev) end.
+
+ssmp4_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmp4_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmp4_mg_verify_handle_connect(Else) ->
+ io:format("ssmp4_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmp4_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmp4_mg_verify_scr(Rep) end.
+
+ssmp4_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmp4_mg_do_verify_scr(AR));
+ssmp4_mg_verify_scr(Crap) ->
+ io:format("ssmp4_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmp4_mg_do_verify_scr(AR) ->
+ io:format("ssmp4_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmp4_mg_verify_notify_request_fun(Tids) ->
+ fun(Req) -> ssmp4_mg_verify_notify_request(Req, Tids) end.
+
+ssmp4_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
+ when length(ARs) == length(Tids) ->
+ (catch ssmp4_mg_do_verify_notify_request(Tids, ARs));
+ssmp4_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmp4_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tids) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmp4_mg_verify_notify_request(Crap, _Tids) ->
+ io:format("ssmp4_mg_verify_notify_request -> unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p"
+ "~n", [Crap, _Tids]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmp4_mg_do_verify_notify_request(Tids, ARs) ->
+ io:format("ssmp4_mg_do_verify_notify_request -> ok"
+ "~n Tids: ~p"
+ "~n ARs: ~p"
+ "~n", [Tids, ARs]),
+ ActionReplies = ssmp4_mg_do_verify_notify_request_ars(Tids, ARs),
+ io:format("ssmp4_mg_do_verify_notify_request -> ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
+ Reply = {{handle_ack, ssmp4}, ActionReplies},
+ {ok, ARs, Reply}.
+
+ssmp4_mg_do_verify_notify_request_ars(Tids, ARs) ->
+ ssmp4_mg_do_verify_notify_request_ars(Tids, ARs, []).
+
+ssmp4_mg_do_verify_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmp4_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
+ ActionReply = ssmp4_mg_do_verify_notify_request_ar(Tid, AR),
+ ssmp4_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
+
+ssmp4_mg_do_verify_notify_request_ar(Tid, AR) ->
+ io:format("ssmp4_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmp4_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmp4_mg_verify_ack_fun() ->
+ fun(Event) -> ssmp4_mg_verify_ack(Event) end.
+
+ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp4}) ->
+ io:format("ssmp4_mg_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
+ {error, {unknown_ack_data, CrapAckData, CH}, ok};
+ssmp4_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmp4_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmp4_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmp4_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_ooo1(suite) ->
+ [];
+send_segmented_msg_ooo1(doc) ->
+ "First segment out of order test. "
+ "Tests that it is possible to send segmented messages, when the "
+ "segment reply is sent out-of-order. "
+ "Send window = 3. ";
+send_segmented_msg_ooo1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmo1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmo1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmo1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmo1_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmo1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmo1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmo1_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmo1_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ CtxId3 = 3,
+ TermId4 =
+ #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ CtxId4 = 4,
+ TermId5 =
+ #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ CtxId5 = 5,
+ TermId6 =
+ #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ CtxId6 = 6,
+ TermId7 =
+ #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ CtxId7 = 7,
+ TermId8 =
+ #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ CtxId8 = 8,
+ TransId = 2,
+ TermIDs = [TermId1, TermId2, TermId3, TermId4,
+ TermId5, TermId6, TermId7, TermId8],
+ CIDs = [CtxId1, CtxId2, CtxId3, CtxId4,
+ CtxId5, CtxId6, CtxId7, CtxId8],
+ NotifyReq = ssmo1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
+ NrVerifyFun1 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
+ TermId2, CtxId2),
+ NrVerifyFun3 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
+ TermId3, CtxId3),
+ NrVerifyFun4 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
+ TermId4, CtxId4),
+ NrVerifyFun5 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
+ TermId5, CtxId5),
+ NrVerifyFun6 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
+ TermId6, CtxId6),
+ NrVerifyFun7 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
+ TermId7, CtxId7),
+ NrVerifyFun8 =
+ ssmo1_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
+ TermId8, CtxId8),
+ SegmentRep1 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 2, false),
+ SegmentRep3 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 3, false),
+ SegmentRep4 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 4, false),
+ SegmentRep5 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 5, false),
+ SegmentRep6 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 6, false),
+ SegmentRep7 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 7, false),
+ SegmentRep8 = ssmo1_mgc_segment_reply_msg(Mid, TransId, 8, true),
+ TransAck = ssmo1_mgc_trans_ack_msg(Mid, TransId),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_nothing, 1000},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 2 [1]", SegmentRep2},
+ {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 1 [2]", SegmentRep1},
+ {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 3 [3]", SegmentRep3},
+ {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 5 [4]", SegmentRep5},
+ {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 4 [5]", SegmentRep4},
+ {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 6", SegmentRep6},
+ {expect_nothing, 1000},
+ {send, "segment reply 7", SegmentRep7},
+ {expect_nothing, 1000},
+ {send, "segment reply 8", SegmentRep8},
+ {expect_nothing, 1000},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+ssmo1_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmo1_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmo1_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmo1_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmo1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmo1_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmo1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmo1_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmo1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmo1_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmo1_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmo1_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmo1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
+ ARs = ssmo1_mgc_notify_request_ars(TermIDs, CIDs),
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmo1_mgc_notify_request_ars(TermIDs, CIDs) ->
+ ssmo1_mgc_notify_request_ars(TermIDs, CIDs, []).
+
+ssmo1_mgc_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmo1_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
+ AR = ssmo1_mgc_notify_request_ar(100+CID, TermID, CID),
+ ssmo1_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
+
+ssmo1_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmo1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmo1_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmo1_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmo1_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmo1_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmo1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmo1_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmo1_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmo1_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
+ NotifyReqVerify = ssmo1_mg_verify_notify_request_fun(Tids),
+ AckVerify = ssmo1_mg_verify_ack_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, segment_send, 3},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ {sleep, 1000},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 15000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmo1_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmo1_mg_verify_handle_connect(Ev) end.
+
+ssmo1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmo1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmo1_mg_verify_handle_connect(Else) ->
+ io:format("ssmo1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmo1_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmo1_mg_verify_scr(Rep) end.
+
+ssmo1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmo1_mg_do_verify_scr(AR));
+ssmo1_mg_verify_scr(Crap) ->
+ io:format("ssmo1_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmo1_mg_do_verify_scr(AR) ->
+ io:format("ssmo1_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmo1_mg_verify_notify_request_fun(Tids) ->
+ fun(Req) -> ssmo1_mg_verify_notify_request(Req, Tids) end.
+
+ssmo1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
+ when length(ARs) == length(Tids) ->
+ (catch ssmo1_mg_do_verify_notify_request(Tids, ARs));
+ssmo1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmo1_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tids) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmo1_mg_verify_notify_request(Crap, _Tids) ->
+ io:format("ssmo1_mg_verify_notify_request -> unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p"
+ "~n", [Crap, _Tids]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmo1_mg_do_verify_notify_request(Tids, ARs) ->
+ io:format("ssmo1_mg_do_verify_notify_request -> ok"
+ "~n Tids: ~p"
+ "~n ARs: ~p"
+ "~n", [Tids, ARs]),
+ ActionReplies = ssmo1_mg_do_verify_notify_request_ars(Tids, ARs),
+ io:format("ssmo1_mg_do_verify_notify_request -> ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
+ Reply = {{handle_ack, ssmp4}, ActionReplies},
+ {ok, ARs, Reply}.
+
+ssmo1_mg_do_verify_notify_request_ars(Tids, ARs) ->
+ ssmo1_mg_do_verify_notify_request_ars(Tids, ARs, []).
+
+ssmo1_mg_do_verify_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmo1_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
+ ActionReply = ssmo1_mg_do_verify_notify_request_ar(Tid, AR),
+ ssmo1_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
+
+ssmo1_mg_do_verify_notify_request_ar(Tid, AR) ->
+ io:format("ssmo1_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmo1_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmo1_mg_verify_ack_fun() ->
+ fun(Event) -> ssmo1_mg_verify_ack(Event) end.
+
+ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, ssmp4}) ->
+ io:format("ssmo1_mg_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, ok, CrapAckData}) ->
+ {error, {unknown_ack_data, CrapAckData, CH}, ok};
+ssmo1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmo1_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmo1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmo1_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_missing_seg_reply1(suite) ->
+ [];
+send_segmented_msg_missing_seg_reply1(doc) ->
+ "First missing segment test. "
+ "Tests that the callbacks and error messages are delivered "
+ "when a segment reply goes missing. Ack expected. "
+ "Send window = 3. ";
+send_segmented_msg_missing_seg_reply1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmmsr1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmmsr1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmmsr1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ %% Await MGC ready for segments
+ d("await MGC trigger event"),
+ MgcPid =
+ receive
+ {ready_for_segments, mgc, Pid1} ->
+ d("received MGC trigger event"),
+ Pid1
+ after 5000 ->
+ d("timeout waiting for MGC trigger event: ~p",
+ [megaco_test_lib:flush()]),
+ ?ERROR(timeout_MGC_trigger_event)
+ end,
+
+ %% Await MG ready for segments
+ d("await MG trigger event"),
+ MgPid =
+ receive
+ {ready_for_segments, mg, Pid2} ->
+ d("received MG trigger event"),
+ Pid2
+ after 5000 ->
+ d("timeout waiting for MG trigger event: ~p",
+ [megaco_test_lib:flush()]),
+ ?ERROR(timeout_MG_trigger_event)
+ end,
+
+ %% Instruct the MG to continue
+ d("send continue to MG"),
+ MgPid ! {continue_with_segments, self()},
+
+ sleep(500),
+
+ %% Instruct the MGC to continue
+ d("send continue to MGC"),
+ MgcPid ! {continue_with_segments, self()},
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmmsr1_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmmsr1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmmsr1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmmsr1_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmmsr1_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ CtxId3 = 3,
+ TermId4 =
+ #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ CtxId4 = 4,
+ TermId5 =
+ #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ CtxId5 = 5,
+ TermId6 =
+ #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ CtxId6 = 6,
+ TermId7 =
+ #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ CtxId7 = 7,
+ TermId8 =
+ #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ CtxId8 = 8,
+ TransId = 2,
+ TermIDs = [TermId1, TermId2, TermId3, TermId4,
+ TermId5, TermId6, TermId7, TermId8],
+ CIDs = [CtxId1, CtxId2, CtxId3, CtxId4,
+ CtxId5, CtxId6, CtxId7, CtxId8],
+ NotifyReq = ssmmsr1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
+ NrVerifyFun1 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
+ TermId2, CtxId2),
+ NrVerifyFun3 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(3, false, TransId,
+ TermId3, CtxId3),
+ NrVerifyFun4 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(4, false, TransId,
+ TermId4, CtxId4),
+ NrVerifyFun5 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(5, false, TransId,
+ TermId5, CtxId5),
+ NrVerifyFun6 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(6, false, TransId,
+ TermId6, CtxId6),
+ NrVerifyFun7 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(7, false, TransId,
+ TermId7, CtxId7),
+ NrVerifyFun8 =
+ ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(8, true, TransId,
+ TermId8, CtxId8),
+ SegmentRep1 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ SegmentRep2 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 2, false),
+ %% SegmentRep3 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 3, false),
+ SegmentRep4 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 4, false),
+ SegmentRep5 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 5, false),
+ SegmentRep6 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 6, false),
+ SegmentRep7 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 7, false),
+ SegmentRep8 = ssmmsr1_mgc_segment_reply_msg(Mid, TransId, 8, true),
+ TransAck = ssmmsr1_mgc_trans_ack_msg(Mid, TransId),
+ ReadyForSegments = ssmmsr1_mgc_ready_for_segments_fun(),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ %% {expect_nothing, 1000},
+ {trigger, "segment send sync trigger", ReadyForSegments},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 1 [1]", SegmentRep1},
+ {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 2 [2]", SegmentRep2},
+ {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 4 [3]", SegmentRep4},
+ {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 5 [4]", SegmentRep5},
+ {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 6 [5]", SegmentRep6},
+ {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
+ {expect_nothing, 1000},
+ {send, "segment reply 7 [6]", SegmentRep7},
+ {expect_nothing, 1000},
+ {send, "segment reply 8 [7]", SegmentRep8},
+ {expect_nothing, 1000},
+ {send, "transaction-ack", TransAck},
+ {expect_closed, 5000},
+ disconnect
+ ],
+ EvSeq.
+
+ssmmsr1_mgc_ready_for_segments_fun() ->
+ TC = self(),
+ fun() ->
+ io:format("ssmmsr1_mgc_ready_for_segments_fun -> entry~n", []),
+ TC ! {ready_for_segments, mgc, self()},
+ receive
+ {continue_with_segments, TC} ->
+ io:format("ssmmsr1_mgc_ready_for_segments_fun -> "
+ "received continue~n", []),
+ ok
+ end
+ end.
+
+ssmmsr1_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmmsr1_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmmsr1_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmmsr1_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmmsr1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmmsr1_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmmsr1_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmmsr1_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmmsr1_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmmsr1_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmmsr1_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmmsr1_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr1_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
+ ARs = ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs),
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs) ->
+ ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs, []).
+
+ssmmsr1_mgc_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmmsr1_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
+ AR = ssmmsr1_mgc_notify_request_ar(100+CID, TermID, CID),
+ ssmmsr1_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
+
+ssmmsr1_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmmsr1_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmmsr1_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr1_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmmsr1_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+ssmmsr1_mgc_trans_ack_msg(Mid, TransId) ->
+ TA = cre_transAck(TransId),
+ Trans = cre_transaction([TA]),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmmsr1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmmsr1_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmmsr1_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmmsr1_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
+ NotifyReqVerify = ssmmsr1_mg_verify_notify_request_fun(Tids),
+ AckVerify = ssmmsr1_mg_verify_ack_fun(),
+ ReadyForSegments = ssmmsr1_mg_ready_for_segments_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, reply_timer, 20000},
+ {megaco_update_conn_info, segment_send, 3},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ %% {sleep, 1000},
+ {trigger, ReadyForSegments},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 15000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmmsr1_mg_ready_for_segments_fun() ->
+ TC = self(),
+ fun() ->
+ io:format("ssmmsr1_mg_ready_for_segments_fun -> entry~n", []),
+ TC ! {ready_for_segments, mg, self()},
+ receive
+ {continue_with_segments, TC} ->
+ io:format("ssmmsr1_mg_ready_for_segments_fun -> "
+ "received continue~n", []),
+ ok
+ end
+ end.
+
+ssmmsr1_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmmsr1_mg_verify_handle_connect(Ev) end.
+
+ssmmsr1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmmsr1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmmsr1_mg_verify_handle_connect(Else) ->
+ io:format("ssmmsr1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmmsr1_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmmsr1_mg_verify_scr(Rep) end.
+
+ssmmsr1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmmsr1_mg_do_verify_scr(AR));
+ssmmsr1_mg_verify_scr(Crap) ->
+ io:format("ssmmsr1_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmmsr1_mg_do_verify_scr(AR) ->
+ io:format("ssmmsr1_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmmsr1_mg_verify_notify_request_fun(Tids) ->
+ fun(Req) -> ssmmsr1_mg_verify_notify_request(Req, Tids) end.
+
+ssmmsr1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
+ when length(ARs) == length(Tids) ->
+ (catch ssmmsr1_mg_do_verify_notify_request(Tids, ARs));
+ssmmsr1_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmmsr1_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tids) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmmsr1_mg_verify_notify_request(Crap, _Tids) ->
+ io:format("ssmmsr1_mg_verify_notify_request -> unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p"
+ "~n", [Crap, _Tids]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmmsr1_mg_do_verify_notify_request(Tids, ARs) ->
+ io:format("ssmmsr1_mg_do_verify_notify_request -> ok"
+ "~n Tids: ~p"
+ "~n ARs: ~p"
+ "~n", [Tids, ARs]),
+ ActionReplies = ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs),
+ io:format("ssmmsr1_mg_do_verify_notify_request -> ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
+ Reply = {{handle_ack, ssmmsr1}, ActionReplies},
+ {ok, ARs, Reply}.
+
+ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs) ->
+ ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs, []).
+
+ssmmsr1_mg_do_verify_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmmsr1_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
+ ActionReply = ssmmsr1_mg_do_verify_notify_request_ar(Tid, AR),
+ ssmmsr1_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
+
+ssmmsr1_mg_do_verify_notify_request_ar(Tid, AR) ->
+ io:format("ssmmsr1_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmmsr1_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmmsr1_mg_verify_ack_fun() ->
+ fun(Event) -> ssmmsr1_mg_verify_ack(Event) end.
+
+ssmmsr1_mg_verify_ack({handle_trans_ack, CH, ?VERSION, AckStatus, ssmmsr1}) ->
+ io:format("ssmmsr1_mg_verify_ack -> "
+ "~n AckStatus: ~p"
+ "~n CH: ~p"
+ "~n", [AckStatus, CH]),
+ case AckStatus of
+ {error, Reason} ->
+ case Reason of
+ {segment_failure, SegInfo} when is_list(SegInfo) ->
+ case lists:keysearch(segments_not_acked, 1, SegInfo) of
+ {value, {segments_not_acked, [3]}} ->
+ {ok, CH, ok};
+ {value, {segments_not_acked, SNs}} ->
+ X = {unexpected_not_acked_segments, SNs},
+ {error, X, ok};
+ false ->
+ X = {unexpected_seg_info, SegInfo},
+ {error, X, ok}
+ end;
+ _ ->
+ X = {unexpected_reason, Reason},
+ {error, X, ok}
+ end;
+ _ ->
+ X = {unexpected_ack_status, AckStatus},
+ {error, X, ok}
+ end;
+ssmmsr1_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmmsr1_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmmsr1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmmsr1_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+send_segmented_msg_missing_seg_reply2(suite) ->
+ [];
+send_segmented_msg_missing_seg_reply2(doc) ->
+ "First missing segment test. "
+ "Tests that the callbacks and error messages are delivered "
+ "when a segment reply goes missing. Ack expected. "
+ "Send window = 1. ";
+send_segmented_msg_missing_seg_reply2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, ssmmsr2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = ssmmsr2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = ssmmsr2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ %% Await MGC ready for segments
+ d("await MGC trigger event"),
+ MgcPid =
+ receive
+ {ready_for_segments, mgc, Pid1} ->
+ d("received MGC trigger event"),
+ Pid1
+ after 5000 ->
+ d("timeout waiting for MGC trigger event: ~p",
+ [megaco_test_lib:flush()]),
+ ?ERROR(timeout_MGC_trigger_event)
+ end,
+
+ %% Await MG ready for segments
+ d("await MG trigger event"),
+ MgPid =
+ receive
+ {ready_for_segments, mg, Pid2} ->
+ d("received MG trigger event"),
+ Pid2
+ after 5000 ->
+ d("timeout waiting for MG trigger event: ~p",
+ [megaco_test_lib:flush()]),
+ ?ERROR(timeout_MG_trigger_event)
+ end,
+
+ %% Instruct the MG to continue
+ d("send continue to MG"),
+ MgPid ! {continue_with_segments, self()},
+
+ sleep(500),
+
+ %% Instruct the MGC to continue
+ d("send continue to MGC"),
+ MgcPid ! {continue_with_segments, self()},
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+
+%%
+%% MGC generator stuff
+%%
+
+ssmmsr2_mgc_event_sequence(text, tcp) ->
+ DecodeFun = ssmmsr2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = ssmmsr2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = ssmmsr2_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = ssmmsr2_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ CtxId1 = 1,
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ CtxId2 = 2,
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ CtxId3 = 3,
+ TermId4 =
+ #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ CtxId4 = 4,
+ TermId5 =
+ #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ CtxId5 = 5,
+ TermId6 =
+ #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ CtxId6 = 6,
+ TermId7 =
+ #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ CtxId7 = 7,
+ TermId8 =
+ #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ CtxId8 = 8,
+ TransId = 2,
+ TermIDs = [TermId1, TermId2, TermId3, TermId4,
+ TermId5, TermId6, TermId7, TermId8],
+ CIDs = [CtxId1, CtxId2, CtxId3, CtxId4,
+ CtxId5, CtxId6, CtxId7, CtxId8],
+ NotifyReq = ssmmsr2_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs),
+ NrVerifyFun1 =
+ ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(1, false, TransId,
+ TermId1, CtxId1),
+ NrVerifyFun2 =
+ ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(2, false, TransId,
+ TermId2, CtxId2),
+ SegmentRep1 = ssmmsr2_mgc_segment_reply_msg(Mid, TransId, 1, false),
+ ReadyForSegments = ssmmsr2_mgc_ready_for_segments_fun(),
+ EvSeq = [{debug, true},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ %% {expect_nothing, 1000},
+ {trigger, "segment send sync trigger", ReadyForSegments},
+ {send, "notify request", NotifyReq},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
+ {send, "segment reply 1", SegmentRep1},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
+ {expect_closed, 20000},
+ disconnect
+ ],
+ EvSeq.
+
+ssmmsr2_mgc_ready_for_segments_fun() ->
+ TC = self(),
+ fun() ->
+ io:format("ssmmsr2_mgc_ready_for_segments_fun -> entry~n", []),
+ TC ! {ready_for_segments, mgc, self()},
+ receive
+ {continue_with_segments, TC} ->
+ io:format("ssmmsr2_mgc_ready_for_segments_fun -> "
+ "received continue~n", []),
+ ok
+ end
+ end.
+
+ssmmsr2_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+ssmmsr2_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+ssmmsr2_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch ssmmsr2_mgc_verify_service_change_req(Msg))
+ end.
+
+ssmmsr2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("ssmmsr2_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+ssmmsr2_mgc_verify_notify_reply_segment_msg_fun(SN, Last,
+ TransId, TermId, Cid) ->
+ fun(Msg) ->
+ (catch ssmmsr2_mgc_verify_notify_reply_segment(Msg,
+ SN, Last,
+ TransId, TermId, Cid))
+ end.
+
+ssmmsr2_mgc_verify_notify_reply_segment(#'MegacoMessage'{mess = Mess} = M,
+ SN, Last, TransId, TermId, Cid) ->
+ io:format("ssmmsr2_mgc_verify_notify_reply_segment -> entry with"
+ "~n M: ~p"
+ "~n SN: ~p"
+ "~n Last: ~p"
+ "~n TransId: ~p"
+ "~n TermId: ~p"
+ "~n Cid: ~p"
+ "~n", [M, SN, Last, TransId, TermId, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionReply, TransReply} ->
+ TransReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ TRes =
+ case TR of
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} when (Last == false) ->
+ TransRes;
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = TransRes,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when (Last == true) ->
+ TransRes;
+ _ ->
+ throw({error, {invalid_transactionReply, TR}})
+ end,
+ AR =
+ case TRes of
+ {actionReplies, [ActionReply]} ->
+ ActionReply;
+ {actionReplies, ActionReplies} ->
+ throw({error, {invalid_actionReplies, ActionReplies}});
+ _ ->
+ throw({error, {invalid_transactionResult, TRes}})
+ end,
+ CR =
+ case AR of
+ #'ActionReply'{contextId = Cid,
+ commandReply = [CommandReply]} ->
+ CommandReply;
+ #'ActionReply'{contextId = Cid,
+ commandReply = CommandReplies} ->
+ throw({error, {invalid_commandReplies, CommandReplies}});
+ _ ->
+ throw({error, {invalid_actionReply, AR}})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ throw({error, {invalid_commandReply, CR}})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [TermId],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ {error, {invalid_NotifyReply, NR}}
+ end;
+ssmmsr2_mgc_verify_notify_reply_segment(Crap,
+ _SN, _Last, _TransId, _TermId, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+
+ssmmsr2_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr2_mgc_notify_request_msg(Mid, TransId, TermIDs, CIDs) ->
+ ARs = ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs),
+ TR = cre_transReq(TransId, ARs),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs) ->
+ ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs, []).
+
+ssmmsr2_mgc_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmmsr2_mgc_notify_request_ars([TermID|TermIDs], [CID|CIDs], Acc) ->
+ AR = ssmmsr2_mgc_notify_request_ar(100+CID, TermID, CID),
+ ssmmsr2_mgc_notify_request_ars(TermIDs, CIDs, [AR|Acc]).
+
+ssmmsr2_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation(integer_to_list(19990720+Rid),
+ integer_to_list(22000000+Rid)),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmmsr2_mgc_segment_reply_msg(Mid, TransId, SN, Last) ->
+ SR = ssmmsr2_mgc_segment_reply(TransId, SN, Last),
+ Trans = cre_transaction(SR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+ssmmsr2_mgc_segment_reply(TransId, SN, true) ->
+ cre_segReply(TransId, SN, 'NULL');
+ssmmsr2_mgc_segment_reply(TransId, SN, false) ->
+ cre_segReply(TransId, SN, asn1_NOVALUE).
+
+%% ssmmsr2_mgc_trans_ack_msg(Mid, TransId) ->
+%% TA = cre_transAck(TransId),
+%% Trans = cre_transaction([TA]),
+%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+%% cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+ssmmsr2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ssmmsr2_mg_verify_handle_connect_fun(),
+ ServiceChangeReq = ssmmsr2_mg_service_change_request_ar(Mid, 1),
+ ServiceChangeReplyVerify = ssmmsr2_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tid4 = #megaco_term_id{id = ["00000000","00000000","00000004"]},
+ Tid5 = #megaco_term_id{id = ["00000000","00000000","00000005"]},
+ Tid6 = #megaco_term_id{id = ["00000000","00000000","00000006"]},
+ Tid7 = #megaco_term_id{id = ["00000000","00000000","00000007"]},
+ Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
+ Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
+ NotifyReqVerify = ssmmsr2_mg_verify_notify_request_fun(Tids),
+ AckVerify = ssmmsr2_mg_verify_ack_fun(),
+ ReadyForSegments = ssmmsr2_mg_ready_for_segments_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, reply_timer, 12000},
+ {megaco_update_conn_info, segment_send, 1},
+ {megaco_update_conn_info, max_pdu_size, 128},
+ %% {sleep, 1000},
+ {trigger, ReadyForSegments},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify, 15000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+ssmmsr2_mg_ready_for_segments_fun() ->
+ TC = self(),
+ fun() ->
+ io:format("ssmmsr2_mg_ready_for_segments_fun -> entry~n", []),
+ TC ! {ready_for_segments, mg, self()},
+ receive
+ {continue_with_segments, TC} ->
+ io:format("ssmmsr2_mg_ready_for_segments_fun -> "
+ "received continue~n", []),
+ ok
+ end
+ end.
+
+ssmmsr2_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> ssmmsr2_mg_verify_handle_connect(Ev) end.
+
+ssmmsr2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("ssmmsr2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+ssmmsr2_mg_verify_handle_connect(Else) ->
+ io:format("ssmmsr2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+ssmmsr2_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> ssmmsr2_mg_verify_scr(Rep) end.
+
+ssmmsr2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch ssmmsr2_mg_do_verify_scr(AR));
+ssmmsr2_mg_verify_scr(Crap) ->
+ io:format("ssmmsr2_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+ssmmsr2_mg_do_verify_scr(AR) ->
+ io:format("ssmmsr2_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+ssmmsr2_mg_verify_notify_request_fun(Tids) ->
+ fun(Req) -> ssmmsr2_mg_verify_notify_request(Req, Tids) end.
+
+ssmmsr2_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, Tids)
+ when length(ARs) == length(Tids) ->
+ (catch ssmmsr2_mg_do_verify_notify_request(Tids, ARs));
+ssmmsr2_mg_verify_notify_request(
+ {handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ {error, {invalid_action_requests, ARs}, ok};
+ssmmsr2_mg_verify_notify_request(
+ {handle_trans_request, CH, V, ARs}, _Tids) ->
+ {error, {invalid_trans_request, {CH, V, ARs}}, ok};
+ssmmsr2_mg_verify_notify_request(Crap, _Tids) ->
+ io:format("ssmmsr2_mg_verify_notify_request -> unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p"
+ "~n", [Crap, _Tids]),
+ {error, {unexpected_event, Crap}, ok}.
+
+ssmmsr2_mg_do_verify_notify_request(Tids, ARs) ->
+ io:format("ssmmsr2_mg_do_verify_notify_request -> ok"
+ "~n Tids: ~p"
+ "~n ARs: ~p"
+ "~n", [Tids, ARs]),
+ ActionReplies = ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs),
+ io:format("ssmmsr2_mg_do_verify_notify_request -> ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
+ Reply = {{handle_ack, ssmmsr2}, ActionReplies},
+ {ok, ARs, Reply}.
+
+ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs) ->
+ ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs, []).
+
+ssmmsr2_mg_do_verify_notify_request_ars([], [], Acc) ->
+ lists:reverse(Acc);
+ssmmsr2_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
+ ActionReply = ssmmsr2_mg_do_verify_notify_request_ar(Tid, AR),
+ ssmmsr2_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
+
+ssmmsr2_mg_do_verify_notify_request_ar(Tid, AR) ->
+ io:format("ssmmsr2_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ {Cid, CR} =
+ case AR of
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = [CmdReq]} ->
+ {CtxId, CmdReq};
+ _ ->
+ Reason1 = {invalid_actionRequest, AR},
+ throw({error, Reason1, ok})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}, ok})
+ end,
+ OED =
+ case Cmd of
+ {notifyReq,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = ObsEvDesc,
+ errorDescriptor = asn1_NOVALUE}} ->
+ ObsEvDesc;
+ _ ->
+ throw({error, {invalid_command, Cmd}, ok})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEv]} ->
+ ObsEv;
+ #'ObservedEventsDescriptor'{observedEventLst = ObsEvLst} ->
+ throw({error, {invalid_observedEventLst, ObsEvLst}, ok});
+ _ ->
+ throw({error, {invalid_ObservedEventsDescriptor, OED}, ok})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ssmmsr2_mg_notify_reply_ar(Cid, Tid);
+ _ ->
+ throw({error, {invalid_ObservedEvent, OE}, ok})
+ end.
+
+
+ssmmsr2_mg_verify_ack_fun() ->
+ fun(Event) -> (catch ssmmsr2_mg_verify_ack(Event)) end.
+
+ssmmsr2_mg_verify_ack({handle_trans_ack, CH, ?VERSION, AckStatus, ssmmsr2}) ->
+ io:format("ssmmsr2_mg_verify_ack -> "
+ "~n AckStatus: ~p"
+ "~n CH: ~p"
+ "~n", [AckStatus, CH]),
+ case AckStatus of
+ {error, Reason} ->
+ case Reason of
+ {segment_failure, SegInfo} when is_list(SegInfo) ->
+ io:format("ssmmsr2_mg_verify_ack -> verify not acked"
+ "~n", []),
+ case lists:keysearch(segments_not_acked, 1, SegInfo) of
+ {value, {segments_not_acked, [2]}} ->
+ ok;
+ {value, {segments_not_acked, SNs}} ->
+ X = {unexpected_not_acked_segments, SNs},
+ throw({error, X, ok});
+ false ->
+ X = {unexpected_seg_info, SegInfo},
+ throw({error, X, ok})
+ end,
+ io:format("ssmmsr2_mg_verify_ack -> verify not sent"
+ "~n", []),
+ case lists:keysearch(segments_not_sent, 1, SegInfo) of
+ {value, {segments_not_sent, NotSent}} ->
+ case [3,4,5,6,7,8] -- NotSent of
+ [] ->
+ {ok, CH, ok};
+ _ ->
+ Y = {unexpected_not_sent_segments,
+ NotSent},
+ throw({error, Y, ok})
+ end;
+ false ->
+ Y = {unexpected_seg_info, SegInfo},
+ throw({error, Y, ok})
+ end;
+ _ ->
+ X = {unexpected_reason, Reason},
+ {error, X, ok}
+ end;
+ _ ->
+ X = {unexpected_ack_status, AckStatus},
+ {error, X, ok}
+ end;
+ssmmsr2_mg_verify_ack({handle_trans_ack, CH, ?VERSION,
+ BadAckStatus, BadAckData}) ->
+ {error, {unknown_ack_status, BadAckStatus, BadAckData, CH}, ok};
+ssmmsr2_mg_verify_ack(BadEvent) ->
+ {error, {unknown_event, BadEvent}, ok}.
+
+
+ssmmsr2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+ssmmsr2_mg_notify_reply_ar(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% %%%
+%%% Segmented reply received test cases %%%
+%%% %%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv_segmented_msg_plain(suite) ->
+ [];
+recv_segmented_msg_plain(doc) ->
+ "Received segmented megaco message [plain]";
+recv_segmented_msg_plain(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rsmp),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rsmp_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rsmp_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+rsmp_mgc_event_sequence(text, tcp) ->
+ DecodeFun = rsmp_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = rsmp_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = rsmp_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = rsmp_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ TermIds = [TermId1, TermId2, TermId3],
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NrVerifyFun =
+ rsmp_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
+ NotifyRep1 = rsmp_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
+ NotifyRep2 = rsmp_mgc_notify_reply_msg(2, Mid, TransId, CtxId, TermId2),
+ NotifyRep3 = rsmp_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
+ SrVerifyFun1 = rsmp_mgc_verify_segment_reply_msg_fun(1, TransId),
+ SrVerifyFun2 = rsmp_mgc_verify_segment_reply_msg_fun(2, TransId),
+ SrVerifyFun3 = rsmp_mgc_verify_segment_reply_msg_fun(3, TransId),
+ AckVerifyFun = rsmp_mgc_verify_trans_ack_msg_fun(TransId),
+ EvSeq = [{debug, false},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {sleep, 500},
+
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_receive, "notify-request(1)", {NrVerifyFun, 4000}},
+ {sleep, 500},
+
+ {send, "notify reply - segment 1", NotifyRep1},
+ {expect_receive, "segment reply 1", {SrVerifyFun1, 2000}},
+ {sleep, 500},
+
+ {send, "notify reply - segment 2", NotifyRep2},
+ {expect_receive, "segment reply 2", {SrVerifyFun2, 2000}},
+ {sleep, 500},
+
+ {send, "notify reply - segment 3 (last)", NotifyRep3},
+ {expect_receive, "segment reply 3 (last)", {SrVerifyFun3, 2000}},
+ {expect_receive, "ack", {AckVerifyFun, 4000}},
+ {sleep, 1000},
+ disconnect
+ ],
+ EvSeq.
+
+rsmp_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+rsmp_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+rsmp_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch rsmp_mgc_verify_service_change_req(Msg))
+ end.
+
+rsmp_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rsmp_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+rsmp_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rsmp_mgc_verify_notify_req(Msg,
+ TermIds, TransId, Rid, Cid))
+ end.
+
+rsmp_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
+ TermIds, TransId, Rid, Cid) ->
+ io:format("rsmp_mgc_verify_notify_req -> entry with"
+ "~n M: ~p"
+ "~n TermIds: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermIds, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ Cmds =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Commands} ->
+ Commands;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ ok = rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds),
+ {ok, M};
+rsmp_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmp_mgc_verify_notify_req_cmds([], []) ->
+ ok;
+rsmp_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
+ rsmp_mgc_verify_notify_req_cmd(TermId, Cmd),
+ rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds);
+rsmp_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
+ throw({error, {invalid_commands, TermIds, Cmds}}).
+
+rsmp_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
+ io:format("rsmp_mgc_verify_notify_req_cmd -> entry with"
+ "~n TermId: ~p"
+ "~n Cmd: ~p"
+ "~n", [TermId, Cmd]),
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ok;
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+rsmp_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
+ io:format("rsmp_mgc_verify_notify_req_cmd -> invalid"
+ "~n BadCmdReq: ~p"
+ "~n", [BadCmdReq]),
+ throw({error, {invalid_CommandRequest, BadCmdReq}}).
+
+rsmp_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
+ fun(Msg) ->
+ (catch rsmp_mgc_verify_segment_reply(Msg, SN, TransId))
+ end.
+
+rsmp_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
+ SN, TransId) ->
+ io:format("rsmp_mgc_verify_segment_reply -> entry with"
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [SN, TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ SR =
+ case Trans of
+ {segmentReply, SegmentReply} ->
+ SegmentReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case SR of
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when SN == 3 ->
+ {ok, M};
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_segmentReply, SR}})
+ end;
+rsmp_mgc_verify_segment_reply(Crap, SN, TransId) ->
+ io:format("rsmp_mgc_verify_segment_reply -> invalid: "
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, TransId, Crap]),
+ {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
+
+rsmp_mgc_verify_trans_ack_msg_fun(TransId) ->
+ fun(Msg) ->
+ (catch rsmp_mgc_verify_trans_ack(Msg, TransId))
+ end.
+
+rsmp_mgc_verify_trans_ack(#'MegacoMessage'{mess = Mess} = M, TransId) ->
+ io:format("rsmp_mgc_verify_trans_ack -> entry with"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TA =
+ case Trans of
+ {transactionResponseAck, [TransAck]} ->
+ TransAck;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case TA of
+ #'TransactionAck'{firstAck = TransId,
+ lastAck = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_transactionResponseAck, TA}})
+ end;
+rsmp_mgc_verify_trans_ack(Crap, _TransId) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmp_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rsmp_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+rsmp_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
+ AR = rsmp_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR =
+ if
+ SN == 3 ->
+ cre_transReply(TransId, TRes, SN, 'NULL');
+ true ->
+ cre_transReply(TransId, TRes, SN)
+ end,
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+rsmp_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = rsmp_mg_service_change_request_ar(Mid, 1),
+ ConnectVerify = rsmp_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = rsmp_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tids = [Tid1, Tid2, Tid3],
+ NotifyReq = rsmp_mg_notify_request_ar(1, Tids, 1),
+ NotifyReplyVerify1 = rsmp_mg_verify_notify_reply_fun(1, Tid1),
+ NotifyReplyVerify2 = rsmp_mg_verify_notify_reply_fun(2, Tid2),
+ NotifyReplyVerify3 = rsmp_mg_verify_notify_reply_fun(3, Tid3),
+ EvSeq = [
+ {debug, true},
+ %% {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_user_info, protocol_version, ?VERSION},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify2},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+
+rsmp_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> rsmp_mg_verify_handle_connect(Ev) end.
+
+rsmp_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("rsmp_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rsmp_mg_verify_handle_connect(Else) ->
+ io:format("rsmp_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+rsmp_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> rsmp_mg_verify_scr(Rep) end.
+
+rsmp_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch rsmp_mg_do_verify_scr(AR));
+rsmp_mg_verify_scr(Crap) ->
+ io:format("rsmp_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+rsmp_mg_do_verify_scr(AR) ->
+ io:format("rsmp_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+rsmp_mg_verify_notify_reply_fun(SN, Tid) ->
+ fun(Rep) -> rsmp_mg_verify_notify_reply(Rep, SN, Tid) end.
+
+rsmp_mg_verify_notify_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
+ when ((SN =:= 3) andalso (Last =:= true)) orelse
+ ((SN =/= 3) andalso (Last =:= false)) ->
+ (catch rsmp_mg_do_verify_notify_reply(Tid, AR));
+rsmp_mg_verify_notify_reply(
+ {handle_trans_reply, _CH, Version, {ok, {SN1, Last, ARs}}, _}, SN2, Tid) ->
+ io:format("rsmp_mg_verify_notify_reply -> unknown reply"
+ "~n Version: ~p"
+ "~n SN1: ~p"
+ "~n Last: ~p"
+ "~n ARs: ~p"
+ "~n SN2: ~p"
+ "~n Tid: ~p"
+ "~n", [Version, SN1, Last, ARs, SN2, Tid]),
+ Crap = {unexpected_segment_data, [SN1, Last, ARs, SN2, Tid]},
+ {error, Crap, ok};
+rsmp_mg_verify_notify_reply(Crap, SN, Tid) ->
+ io:format("rsmp_mg_verify_notify_reply -> unknown reply"
+ "~n SN: ~p"
+ "~n Tid: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Tid, Crap]),
+ {error, Crap, ok}.
+
+rsmp_mg_do_verify_notify_reply(Tid, AR) ->
+ io:format("rsmp_mg_do_verify_notify_reply -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [Tid],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, AR, ok};
+ _ ->
+ Reason3 = {invalid_NotifyReply, NR},
+ {error, Reason3, ok}
+ end.
+
+
+rsmp_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rsmp_mg_notify_request_ar(Rid, Tids, Cid) ->
+ rsmp_mg_notify_request_ar(Rid, Tids, Cid, []).
+
+rsmp_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
+ cre_actionReq(Cid, lists:reverse(Cmds));
+rsmp_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ rsmp_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
+
+%% rsmp_internalError(Text) ->
+%% Code = ?megaco_internal_gateway_error,
+%% cre_errorDesc(Code, Text).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv_segmented_msg_ooo_seg(suite) ->
+ [];
+recv_segmented_msg_ooo_seg(doc) ->
+ "Received segmented megaco message [out-of-order segments]";
+recv_segmented_msg_ooo_seg(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rsmos),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rsmos_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rsmos_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+rsmos_mgc_event_sequence(text, tcp) ->
+ DecodeFun = rsmos_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = rsmos_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = rsmos_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = rsmos_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ TermIds = [TermId1, TermId2, TermId3],
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NrVerifyFun =
+ rsmos_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
+ NotifyRep1 = rsmos_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
+ NotifyRep2 = rsmos_mgc_notify_reply_msg(2, Mid, TransId, CtxId, TermId2),
+ NotifyRep3 = rsmos_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
+ SrVerifyFun1 = rsmos_mgc_verify_segment_reply_msg_fun(1, TransId),
+ SrVerifyFun2 = rsmos_mgc_verify_segment_reply_msg_fun(2, TransId),
+ SrVerifyFun3 = rsmos_mgc_verify_segment_reply_msg_fun(3, TransId),
+ AckVerifyFun = rsmos_mgc_verify_trans_ack_msg_fun(TransId),
+ EvSeq = [{debug, false},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_receive, "notify-request", {NrVerifyFun, 4000}},
+ {send, "notify reply - segment 3", NotifyRep3},
+ {expect_receive, "segment reply 3", {SrVerifyFun3, 2000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 2", NotifyRep2},
+ {expect_receive, "segment reply 2", {SrVerifyFun2, 2000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 1 (last)", NotifyRep1},
+ {expect_receive, "segment reply 1 (last)", {SrVerifyFun1, 2000}},
+ {expect_receive, "ack", {AckVerifyFun, 4000}},
+ {expect_nothing, 10000},
+ disconnect
+ ],
+ EvSeq.
+
+rsmos_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+rsmos_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+rsmos_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch rsmos_mgc_verify_service_change_req(Msg))
+ end.
+
+rsmos_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rsmos_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+rsmos_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rsmos_mgc_verify_notify_req(Msg,
+ TermIds, TransId, Rid, Cid))
+ end.
+
+rsmos_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
+ TermIds, TransId, Rid, Cid) ->
+ io:format("rsmos_mgc_verify_notify_req -> entry with"
+ "~n M: ~p"
+ "~n TermIds: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermIds, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ Cmds =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Commands} ->
+ Commands;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ ok = rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds),
+ {ok, M};
+rsmos_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmos_mgc_verify_notify_req_cmds([], []) ->
+ ok;
+rsmos_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
+ rsmos_mgc_verify_notify_req_cmd(TermId, Cmd),
+ rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds);
+rsmos_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
+ throw({error, {invalid_commands, TermIds, Cmds}}).
+
+rsmos_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
+ io:format("rsmos_mgc_verify_notify_req_cmd -> entry with"
+ "~n TermId: ~p"
+ "~n Cmd: ~p"
+ "~n", [TermId, Cmd]),
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ok;
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+rsmos_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
+ io:format("rsmos_mgc_verify_notify_req_cmd -> invalid"
+ "~n BadCmdReq: ~p"
+ "~n", [BadCmdReq]),
+ throw({error, {invalid_CommandRequest, BadCmdReq}}).
+
+rsmos_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
+ fun(Msg) ->
+ (catch rsmos_mgc_verify_segment_reply(Msg, SN, TransId))
+ end.
+
+rsmos_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
+ SN, TransId) ->
+ io:format("rsmos_mgc_verify_segment_reply -> entry with"
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [SN, TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ SR =
+ case Trans of
+ {segmentReply, SegmentReply} ->
+ SegmentReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case SR of
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when SN == 3 ->
+ {ok, M};
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_segmentReply, SR}})
+ end;
+rsmos_mgc_verify_segment_reply(Crap, SN, TransId) ->
+ io:format("rsmos_mgc_verify_segment_reply -> invalid: "
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, TransId, Crap]),
+ {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
+
+rsmos_mgc_verify_trans_ack_msg_fun(TransId) ->
+ fun(Msg) ->
+ (catch rsmos_mgc_verify_trans_ack(Msg, TransId))
+ end.
+
+rsmos_mgc_verify_trans_ack(#'MegacoMessage'{mess = Mess} = M, TransId) ->
+ io:format("rsmos_mgc_verify_trans_ack -> entry with"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TA =
+ case Trans of
+ {transactionResponseAck, [TransAck]} ->
+ TransAck;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case TA of
+ #'TransactionAck'{firstAck = TransId,
+ lastAck = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_transactionResponseAck, TA}})
+ end;
+rsmos_mgc_verify_trans_ack(Crap, _TransId) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmos_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rsmos_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+rsmos_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
+ AR = rsmos_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR =
+ if
+ SN == 3 ->
+ cre_transReply(TransId, TRes, SN, 'NULL');
+ true ->
+ cre_transReply(TransId, TRes, SN)
+ end,
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+rsmos_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = rsmos_mg_service_change_request_ar(Mid, 1),
+ ConnectVerify = rsmos_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = rsmos_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tids = [Tid1, Tid2, Tid3],
+ NotifyReq = rsmos_mg_notify_request_ar(1, Tids, 1),
+ NotifyReplyVerify1 = rsmos_mg_verify_notify_reply_fun(1, Tid1),
+ NotifyReplyVerify2 = rsmos_mg_verify_notify_reply_fun(2, Tid2),
+ NotifyReplyVerify3 = rsmos_mg_verify_notify_reply_fun(3, Tid3),
+ DiscoVerify = rsmos_mg_verify_handle_disco_fun(),
+ EvSeq = [
+ {debug, true},
+ %% {megaco_trace, disable},
+ {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {megaco_update_user_info, segment_recv_timer, 3000},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify2},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+rsmos_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> rsmos_mg_verify_handle_connect(Ev) end.
+
+rsmos_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("rsmos_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rsmos_mg_verify_handle_connect(Else) ->
+ io:format("rsmos_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+rsmos_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> rsmos_mg_verify_scr(Rep) end.
+
+rsmos_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch rsmos_mg_do_verify_scr(AR));
+rsmos_mg_verify_scr(Crap) ->
+ io:format("rsmos_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+rsmos_mg_do_verify_scr(AR) ->
+ io:format("rsmos_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+rsmos_mg_verify_notify_reply_fun(SN, Tid) ->
+ fun(Rep) -> rsmos_mg_verify_notify_reply(Rep, SN, Tid) end.
+
+rsmos_mg_verify_notify_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
+ when ((SN == 1) and (Last == true)) or
+ ((SN =/= 1) and (Last == false)) ->
+ (catch rsmos_mg_do_verify_notify_reply(Tid, AR));
+rsmos_mg_verify_notify_reply(Crap, SN, Tid) ->
+ io:format("rsmos_mg_verify_notify_reply -> unknown reply"
+ "~n SN: ~p"
+ "~n Tid: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Tid, Crap]),
+ {error, Crap, ok}.
+
+rsmos_mg_do_verify_notify_reply(Tid, AR) ->
+ io:format("rsmos_mg_do_verify_notify_reply -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [Tid],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, AR, ok};
+ _ ->
+ Reason3 = {invalid_NotifyReply, NR},
+ {error, Reason3, ok}
+ end.
+
+rsmos_mg_verify_handle_disco_fun() ->
+ fun(Ev) -> rsmos_mg_verify_handle_disconnect(Ev) end.
+
+rsmos_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
+ io:format("rsmos_mg_verify_handle_disconnect -> ok"
+ "~n R: ~p"
+ "~n", [R]),
+ case R of
+ {no_controlling_process,shutdown} ->
+ {ok, R, ok};
+ _ ->
+ {error, {unexpected_reason, R}, ok}
+ end;
+rsmos_mg_verify_handle_disconnect(Crap) ->
+ io:format("rsmos_mg_verify_handle_disconnect -> invalid: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+
+rsmos_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rsmos_mg_notify_request_ar(Rid, Tids, Cid) ->
+ rsmos_mg_notify_request_ar(Rid, Tids, Cid, []).
+
+rsmos_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
+ cre_actionReq(Cid, lists:reverse(Cmds));
+rsmos_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ rsmos_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv_segmented_msg_missing_seg1(suite) ->
+ [];
+recv_segmented_msg_missing_seg1(doc) ->
+ "Received segmented megaco message with one segment missing "
+ "using plain integer recv segment timer";
+recv_segmented_msg_missing_seg1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rsmms1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rsmms1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rsmms1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+rsmms1_mgc_event_sequence(text, tcp) ->
+ DecodeFun = rsmms1_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = rsmms1_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = rsmms1_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = rsmms1_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ TermIds = [TermId1, TermId2, TermId3],
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NrVerifyFun =
+ rsmms1_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
+ NotifyRep1 =
+ rsmms1_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
+ NotifyRep3 =
+ rsmms1_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
+ SrVerifyFun1 = rsmms1_mgc_verify_segment_reply_msg_fun(1, TransId),
+ SrVerifyFun3 = rsmms1_mgc_verify_segment_reply_msg_fun(3, TransId),
+ MissingSegVerifyFun = rsmms1_mgc_verify_missing_segment_fun("2"),
+ EvSeq = [{debug, false},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_receive, "notify-request", {NrVerifyFun, 4000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 1", NotifyRep1},
+ {expect_receive, "segment reply 1", {SrVerifyFun1, 2000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 3", NotifyRep3},
+ {expect_receive, "segment reply 3", {SrVerifyFun3, 2000}},
+ {expect_receive, "missing segment error", {MissingSegVerifyFun, 4000}},
+ {expect_nothing, 10000},
+ disconnect
+ ],
+ EvSeq.
+
+rsmms1_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+rsmms1_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+rsmms1_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch rsmms1_mgc_verify_service_change_req(Msg))
+ end.
+
+rsmms1_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rsmms1_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+rsmms1_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rsmms1_mgc_verify_notify_req(Msg,
+ TermIds, TransId, Rid, Cid))
+ end.
+
+rsmms1_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
+ TermIds, TransId, Rid, Cid) ->
+ io:format("rsmms1_mgc_verify_notify_req -> entry with"
+ "~n M: ~p"
+ "~n TermIds: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermIds, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ Cmds =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Commands} ->
+ Commands;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ ok = rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds),
+ {ok, M};
+rsmms1_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmms1_mgc_verify_notify_req_cmds([], []) ->
+ ok;
+rsmms1_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
+ rsmms1_mgc_verify_notify_req_cmd(TermId, Cmd),
+ rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds);
+rsmms1_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
+ throw({error, {invalid_commands, TermIds, Cmds}}).
+
+rsmms1_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
+ io:format("rsmms1_mgc_verify_notify_req_cmd -> entry with"
+ "~n TermId: ~p"
+ "~n Cmd: ~p"
+ "~n", [TermId, Cmd]),
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ok;
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+rsmms1_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
+ io:format("rsmms1_mgc_verify_notify_req_cmd -> invalid"
+ "~n BadCmdReq: ~p"
+ "~n", [BadCmdReq]),
+ throw({error, {invalid_CommandRequest, BadCmdReq}}).
+
+rsmms1_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
+ fun(Msg) ->
+ (catch rsmms1_mgc_verify_segment_reply(Msg, SN, TransId))
+ end.
+
+rsmms1_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
+ SN, TransId) ->
+ io:format("rsmms1_mgc_verify_segment_reply -> entry with"
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [SN, TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ SR =
+ case Trans of
+ {segmentReply, SegmentReply} ->
+ SegmentReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case SR of
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when SN == 3 ->
+ {ok, M};
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_segmentReply, SR}})
+ end;
+rsmms1_mgc_verify_segment_reply(Crap, SN, TransId) ->
+ io:format("rsmms1_mgc_verify_segment_reply -> invalid: "
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, TransId, Crap]),
+ {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
+
+
+rsmms1_mgc_verify_missing_segment_fun(SN) ->
+ fun(Msg) -> (catch rsmms1_mgc_verify_missing_segment(Msg, SN)) end.
+
+rsmms1_mgc_verify_missing_segment(#'MegacoMessage'{mess = Mess} = M, Text) ->
+ io:format("rsmms1_mgc_verify_missing_segment -> entry with"
+ "~n Text: ~p"
+ "~n M: ~p"
+ "~n", [Text, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ case Body of
+ {messageError,
+ #'ErrorDescriptor'{errorCode = ?megaco_segments_not_received,
+ errorText = Text}} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_messageError, Body}})
+ end;
+rsmms1_mgc_verify_missing_segment(Crap, _SN) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmms1_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rsmms1_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+rsmms1_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
+ AR = rsmms1_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR =
+ if
+ SN == 3 ->
+ cre_transReply(TransId, TRes, SN, 'NULL');
+ true ->
+ cre_transReply(TransId, TRes, SN)
+ end,
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+rsmms1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = rsmms1_mg_service_change_request_ar(Mid, 1),
+ ConnectVerify = rsmms1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = rsmms1_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tids = [Tid1, Tid2, Tid3],
+ NotifyReq = rsmms1_mg_notify_request_ar(1, Tids, 1),
+ NotifyReplyVerify1 = rsmms1_mg_verify_notify_reply_fun(1, Tid1),
+ NotifyReplyVerify3 = rsmms1_mg_verify_notify_reply_fun(3, Tid3),
+ SegTimeoutVerify = rsmms1_mg_verify_segment_timeout_fun(2),
+ DiscoVerify = rsmms1_mg_verify_handle_disco_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {megaco_update_user_info, segment_recv_timer, 3000},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
+ {megaco_callback, handle_trans_reply, SegTimeoutVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+rsmms1_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> rsmms1_mg_verify_handle_connect(Ev) end.
+
+rsmms1_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("rsmms1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rsmms1_mg_verify_handle_connect(Else) ->
+ io:format("rsmms1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+rsmms1_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> rsmms1_mg_verify_scr(Rep) end.
+
+rsmms1_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch rsmms1_mg_do_verify_scr(AR));
+rsmms1_mg_verify_scr(Crap) ->
+ io:format("rsmms1_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+rsmms1_mg_do_verify_scr(AR) ->
+ io:format("rsmms1_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+rsmms1_mg_verify_notify_reply_fun(SN, Tid) ->
+ fun(Rep) -> rsmms1_mg_verify_notify_reply(Rep, SN, Tid) end.
+
+rsmms1_mg_verify_notify_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
+ when (Last == false) ->
+ (catch rsmms1_mg_do_verify_notify_reply(Tid, AR));
+rsmms1_mg_verify_notify_reply(Crap, SN, Tid) ->
+ io:format("rsmms1_mg_verify_notify_reply -> unknown reply"
+ "~n SN: ~p"
+ "~n Tid: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Tid, Crap]),
+ {error, Crap, ok}.
+
+rsmms1_mg_do_verify_notify_reply(Tid, AR) ->
+ io:format("rsmms1_mg_do_verify_notify_reply -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [Tid],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, AR, ok};
+ _ ->
+ Reason3 = {invalid_NotifyReply, NR},
+ {error, Reason3, ok}
+ end.
+
+rsmms1_mg_verify_segment_timeout_fun(SN) ->
+ fun(Rep) -> rsmms1_mg_verify_segment_timeout(Rep, SN) end.
+
+rsmms1_mg_verify_segment_timeout(
+ {handle_trans_reply, _CH, ?VERSION, {error, Reason}, _}, SN) ->
+ case Reason of
+ {segment_timeout, [SN]} ->
+ {ok, Reason, ok};
+ _ ->
+ {error, {invalid_reason, Reason}, ok}
+ end;
+rsmms1_mg_verify_segment_timeout(Crap, SN) ->
+ io:format("rsmms1_mg_verify_segment_timeout -> unknown reply"
+ "~n SN: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Crap]),
+ {error, Crap, ok}.
+
+rsmms1_mg_verify_handle_disco_fun() ->
+ fun(Ev) -> rsmms1_mg_verify_handle_disconnect(Ev) end.
+
+rsmms1_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
+ io:format("rsmms1_mg_verify_handle_disconnect -> ok"
+ "~n R: ~p"
+ "~n", [R]),
+ case R of
+ {no_controlling_process,shutdown} ->
+ {ok, R, ok};
+ _ ->
+ {error, {unexpected_reason, R}, ok}
+ end;
+rsmms1_mg_verify_handle_disconnect(Crap) ->
+ io:format("rsmms1_mg_verify_handle_disconnect -> invalid: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+
+rsmms1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rsmms1_mg_notify_request_ar(Rid, Tids, Cid) ->
+ rsmms1_mg_notify_request_ar(Rid, Tids, Cid, []).
+
+rsmms1_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
+ cre_actionReq(Cid, lists:reverse(Cmds));
+rsmms1_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ rsmms1_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+recv_segmented_msg_missing_seg2(suite) ->
+ [];
+recv_segmented_msg_missing_seg2(doc) ->
+ "Received segmented megaco message with one segment missing "
+ "using incremental recv segment timer";
+recv_segmented_msg_missing_seg2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, rsmms2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = rsmms2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_tcp_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = rsmms2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_tcp_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+
+rsmms2_mgc_event_sequence(text, tcp) ->
+ DecodeFun = rsmms2_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
+ EncodeFun = rsmms2_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
+ Mid = {deviceName,"mgc"},
+ ScrVerifyFun = rsmms2_mgc_verify_service_change_req_msg_fun(),
+ ServiceChangeRep = rsmms2_mgc_service_change_reply_msg(Mid, 1),
+ TermId1 =
+ #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ TermId2 =
+ #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ TermId3 =
+ #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ TermIds = [TermId1, TermId2, TermId3],
+ TransId = 2,
+ ReqId = 1,
+ CtxId = 1,
+ NrVerifyFun =
+ rsmms2_mgc_verify_notify_req_msg_fun(TermIds, TransId, ReqId, CtxId),
+ NotifyRep1 =
+ rsmms2_mgc_notify_reply_msg(1, Mid, TransId, CtxId, TermId1),
+ NotifyRep3 =
+ rsmms2_mgc_notify_reply_msg(3, Mid, TransId, CtxId, TermId3),
+ SrVerifyFun1 = rsmms2_mgc_verify_segment_reply_msg_fun(1, TransId),
+ SrVerifyFun3 = rsmms2_mgc_verify_segment_reply_msg_fun(3, TransId),
+ MissingSegVerifyFun = rsmms2_mgc_verify_missing_segment_fun("2"),
+ EvSeq = [{debug, false},
+ {decode, DecodeFun},
+ {encode, EncodeFun},
+ {listen, 2944},
+ {expect_accept, any},
+ {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {send, "service-change-reply", ServiceChangeRep},
+ {expect_receive, "notify-request", {NrVerifyFun, 4000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 1", NotifyRep1},
+ {expect_receive, "segment reply 1", {SrVerifyFun1, 2000}},
+ {sleep, 1000},
+ {send, "notify reply - segment 3", NotifyRep3},
+ {expect_receive, "segment reply 3", {SrVerifyFun3, 2000}},
+ {expect_receive, "missing segment error", {MissingSegVerifyFun, 4000}},
+ {expect_nothing, 10000},
+ disconnect
+ ],
+ EvSeq.
+
+rsmms2_mgc_encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+
+rsmms2_mgc_decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+
+rsmms2_mgc_verify_service_change_req_msg_fun() ->
+ fun(Msg) ->
+ (catch rsmms2_mgc_verify_service_change_req(Msg))
+ end.
+
+rsmms2_mgc_verify_service_change_req(#'MegacoMessage'{mess = Mess} = M) ->
+ io:format("rsmms2_mgc_verify_service_change_req -> entry with"
+ "~n M: ~p"
+ "~n", [M]),
+ Body =
+ case Mess of
+ #'Message'{version = 1,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = _TransId,
+ actions = [ActionReq]} ->
+ ActionReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ CR =
+ case AR of
+ #'ActionRequest'{contextId = _Cid,
+ commandRequests = [CmdReq]} ->
+ CmdReq;
+ _ ->
+ throw({error, {invalid_action, AR}})
+ end,
+ Cmd =
+ case CR of
+ #'CommandRequest'{command = Command} ->
+ Command;
+ _ ->
+ throw({error, {invalid_commandRequest, CR}})
+ end,
+ {Tid, Parms} =
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [TermID],
+ serviceChangeParms = ServChParms}} ->
+ {TermID, ServChParms};
+ _ ->
+ throw({error, {invalid_command, Cmd}})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ throw({error, {invalid_terminationID, Tid}})
+ end,
+ case Parms of
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ restart, % serviceChangeMethod
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion,
+ {'ServiceChangeProfile',"resgw",1}, % serviceChangeProfile
+ [[$9,$0,$1|_]], % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ } ->
+ {ok, M};
+ _ ->
+ {error, {invalid_serviceChangeParms, Parms}}
+ end.
+
+rsmms2_mgc_verify_notify_req_msg_fun(TermIds, TransId, Rid, Cid) ->
+ fun(Msg) ->
+ (catch rsmms2_mgc_verify_notify_req(Msg,
+ TermIds, TransId, Rid, Cid))
+ end.
+
+rsmms2_mgc_verify_notify_req(#'MegacoMessage'{mess = Mess} = M,
+ TermIds, TransId, Rid, Cid) ->
+ io:format("rsmms2_mgc_verify_notify_req -> entry with"
+ "~n M: ~p"
+ "~n TermIds: ~p"
+ "~n TransId: ~p"
+ "~n Rid: ~p"
+ "~n Cid: ~p"
+ "~n", [M, TermIds, TransId, Rid, Cid]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ TR =
+ case Trans of
+ {transactionRequest, TransRequest} ->
+ TransRequest;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ AR =
+ case TR of
+ #'TransactionRequest'{transactionId = TransId,
+ actions = [ActReq]} ->
+ ActReq;
+ _ ->
+ throw({error, {invalid_transactionRequest, TR}})
+ end,
+ Cmds =
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Commands} ->
+ Commands;
+ _ ->
+ throw({error, {invalid_actions, AR}})
+ end,
+ ok = rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds),
+ {ok, M};
+rsmms2_mgc_verify_notify_req(Crap, _TermId, _TransId, _Rid, _Cid) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmms2_mgc_verify_notify_req_cmds([], []) ->
+ ok;
+rsmms2_mgc_verify_notify_req_cmds([TermId|TermIds], [Cmd|Cmds]) ->
+ rsmms2_mgc_verify_notify_req_cmd(TermId, Cmd),
+ rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds);
+rsmms2_mgc_verify_notify_req_cmds(TermIds, Cmds) ->
+ throw({error, {invalid_commands, TermIds, Cmds}}).
+
+rsmms2_mgc_verify_notify_req_cmd(TermId, #'CommandRequest'{command = Cmd}) ->
+ io:format("rsmms2_mgc_verify_notify_req_cmd -> entry with"
+ "~n TermId: ~p"
+ "~n Cmd: ~p"
+ "~n", [TermId, Cmd]),
+ NR =
+ case Cmd of
+ {notifyReq, NotifReq} ->
+ NotifReq;
+ _ ->
+ throw({error, {invalid_command}})
+ end,
+ OED =
+ case NR of
+ #'NotifyRequest'{terminationID = [TermId],
+ observedEventsDescriptor = ObsEvsDesc,
+ errorDescriptor = asn1_NOVALUE} ->
+ ObsEvsDesc;
+ _ ->
+ throw({error, {invalid_notifyReq, NR}})
+ end,
+ OE =
+ case OED of
+ #'ObservedEventsDescriptor'{observedEventLst = [ObsEvLst]} ->
+ ObsEvLst;
+ _ ->
+ throw({error, {invalid_observedEventsDescriptor, OED}})
+ end,
+ case OE of
+ #'ObservedEvent'{eventName = "al/of"} ->
+ ok;
+ _ ->
+ throw({error, {invalid_observedEventLst, OE}})
+ end;
+rsmms2_mgc_verify_notify_req_cmd(_, BadCmdReq) ->
+ io:format("rsmms2_mgc_verify_notify_req_cmd -> invalid"
+ "~n BadCmdReq: ~p"
+ "~n", [BadCmdReq]),
+ throw({error, {invalid_CommandRequest, BadCmdReq}}).
+
+rsmms2_mgc_verify_segment_reply_msg_fun(SN, TransId) ->
+ fun(Msg) ->
+ (catch rsmms2_mgc_verify_segment_reply(Msg, SN, TransId))
+ end.
+
+rsmms2_mgc_verify_segment_reply(#'MegacoMessage'{mess = Mess} = M,
+ SN, TransId) ->
+ io:format("rsmms2_mgc_verify_segment_reply -> entry with"
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n M: ~p"
+ "~n", [SN, TransId, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _MgMid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ Trans =
+ case Body of
+ {transactions, [Transactions]} ->
+ Transactions;
+ _ ->
+ throw({error, {invalid_messageBody, Body}})
+ end,
+ SR =
+ case Trans of
+ {segmentReply, SegmentReply} ->
+ SegmentReply;
+ _ ->
+ throw({error, {invalid_transactions, Trans}})
+ end,
+ case SR of
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = 'NULL'} when SN == 3 ->
+ {ok, M};
+ #'SegmentReply'{transactionId = TransId,
+ segmentNumber = SN,
+ segmentationComplete = asn1_NOVALUE} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_segmentReply, SR}})
+ end;
+rsmms2_mgc_verify_segment_reply(Crap, SN, TransId) ->
+ io:format("rsmms2_mgc_verify_segment_reply -> invalid: "
+ "~n SN: ~p"
+ "~n TransId: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, TransId, Crap]),
+ {error, {invalid_MegacoMessage, Crap, SN, TransId}}.
+
+
+rsmms2_mgc_verify_missing_segment_fun(SN) ->
+ fun(Msg) -> (catch rsmms2_mgc_verify_missing_segment(Msg, SN)) end.
+
+rsmms2_mgc_verify_missing_segment(#'MegacoMessage'{mess = Mess} = M, Text) ->
+ io:format("rsmms2_mgc_verify_missing_segment -> entry with"
+ "~n Text: ~p"
+ "~n M: ~p"
+ "~n", [Text, M]),
+ Body =
+ case Mess of
+ #'Message'{version = ?VERSION,
+ mId = _Mid,
+ messageBody = MsgBody} ->
+ MsgBody;
+ _ ->
+ throw({error, {invalid_Message, Mess}})
+ end,
+ case Body of
+ {messageError,
+ #'ErrorDescriptor'{errorCode = ?megaco_segments_not_received,
+ errorText = Text}} ->
+ {ok, M};
+ _ ->
+ throw({error, {invalid_messageError, Body}})
+ end;
+rsmms2_mgc_verify_missing_segment(Crap, _SN) ->
+ {error, {invalid_MegacoMessage, Crap}}.
+
+rsmms2_mgc_service_change_reply_msg(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ AR = cre_actionReply(Cid, [CR]),
+ TRes = cre_transResult([AR]),
+ TR = {'TransactionReply', 1, asn1_NOVALUE, TRes},
+ Trans = cre_transaction(TR),
+ Mess = cre_message(1, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+rsmms2_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+rsmms2_mgc_notify_reply_msg(SN, Mid, TransId, Cid, TermId) ->
+ AR = rsmms2_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR =
+ if
+ SN == 3 ->
+ cre_transReply(TransId, TRes, SN, 'NULL');
+ true ->
+ cre_transReply(TransId, TRes, SN)
+ end,
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+rsmms2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ SegRecvTmr = #megaco_incr_timer{wait_for = 1000,
+ factor = 1,
+ incr = 0,
+ max_retries = 2
+ },
+ ServiceChangeReq = rsmms2_mg_service_change_request_ar(Mid, 1),
+ ConnectVerify = rsmms2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = rsmms2_mg_verify_service_change_reply_fun(),
+ Tid1 = #megaco_term_id{id = ["00000000","00000000","00000001"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000000","00000002"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000000","00000003"]},
+ Tids = [Tid1, Tid2, Tid3],
+ NotifyReq = rsmms2_mg_notify_request_ar(1, Tids, 1),
+ NotifyReplyVerify1 = rsmms2_mg_verify_notify_reply_fun(1, Tid1),
+ NotifyReplyVerify3 = rsmms2_mg_verify_notify_reply_fun(3, Tid3),
+ SegTimeoutVerify = rsmms2_mg_verify_segment_timeout_fun(2),
+ DiscoVerify = rsmms2_mg_verify_handle_disco_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ %% {megaco_trace, max},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {megaco_update_user_info, segment_recv_timer, SegRecvTmr},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, [ServiceChangeReq], []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {megaco_update_conn_info, protocol_version, ?VERSION},
+ {sleep, 1000},
+ {megaco_cast, [NotifyReq], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify1},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify3},
+ {megaco_callback, handle_trans_reply, SegTimeoutVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+rsmms2_mg_verify_handle_connect_fun() ->
+ fun(Ev) -> rsmms2_mg_verify_handle_connect(Ev) end.
+
+rsmms2_mg_verify_handle_connect({handle_connect, CH, 1}) ->
+ io:format("rsmms2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+rsmms2_mg_verify_handle_connect(Else) ->
+ io:format("rsmms2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+rsmms2_mg_verify_service_change_reply_fun() ->
+ fun(Rep) -> rsmms2_mg_verify_scr(Rep) end.
+
+rsmms2_mg_verify_scr({handle_trans_reply, _CH, 1, {ok, [AR]}, _}) ->
+ (catch rsmms2_mg_do_verify_scr(AR));
+rsmms2_mg_verify_scr(Crap) ->
+ io:format("rsmms2_mg_verify_scr -> error: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+rsmms2_mg_do_verify_scr(AR) ->
+ io:format("rsmms2_mg_do_verify_scr -> ok: "
+ "~n AR: ~p~n", [AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ SCR =
+ case CR of
+ {serviceChangeReply, ServChRep} ->
+ ServChRep;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ {Tid, SCRes} =
+ case SCR of
+ #'ServiceChangeReply'{terminationID = [TermID],
+ serviceChangeResult = Res} ->
+ {TermID, Res};
+ _ ->
+ Reason3 = {invalid_service_change_reply, SCR},
+ throw({error, Reason3, ok})
+ end,
+ case Tid of
+ #megaco_term_id{contains_wildcards = false, id = ["root"]} ->
+ ok;
+ _ ->
+ Reason4 = {invalid_termination_id, Tid},
+ throw({error, Reason4, ok})
+ end,
+ SCRParm =
+ case SCRes of
+ {serviceChangeResParms, ServChResParms} ->
+ ServChResParms;
+ _ ->
+ Reason5 = {invalid_serviceChangeResult, SCRes},
+ throw({error, Reason5, ok})
+ end,
+ case SCRParm of
+ #'ServiceChangeResParm'{serviceChangeMgcId = _RemoteMid} ->
+ {ok, AR, ok};
+ _ ->
+ Reason6 = {invalid_service_change_result, SCRParm},
+ {error, Reason6, ok}
+ end.
+
+rsmms2_mg_verify_notify_reply_fun(SN, Tid) ->
+ fun(Rep) -> rsmms2_mg_verify_notify_reply(Rep, SN, Tid) end.
+
+rsmms2_mg_verify_notify_reply(
+ {handle_trans_reply, _CH, ?VERSION, {ok, {SN, Last, [AR]}}, _}, SN, Tid)
+ when (Last == false) ->
+ (catch rsmms2_mg_do_verify_notify_reply(Tid, AR));
+rsmms2_mg_verify_notify_reply(Crap, SN, Tid) ->
+ io:format("rsmms2_mg_verify_notify_reply -> unknown reply"
+ "~n SN: ~p"
+ "~n Tid: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Tid, Crap]),
+ {error, Crap, ok}.
+
+rsmms2_mg_do_verify_notify_reply(Tid, AR) ->
+ io:format("rsmms2_mg_do_verify_notify_reply -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p"
+ "~n", [Tid, AR]),
+ CR =
+ case AR of
+ #'ActionReply'{commandReply = [CmdRep]} ->
+ CmdRep;
+ _ ->
+ Reason1 = {invalid_action_reply, AR},
+ throw({error, Reason1, ok})
+ end,
+ NR =
+ case CR of
+ {notifyReply, NotifyReply} ->
+ NotifyReply;
+ _ ->
+ Reason2 = {invalid_command_reply, CR},
+ throw({error, Reason2, ok})
+ end,
+ case NR of
+ #'NotifyReply'{terminationID = [Tid],
+ errorDescriptor = asn1_NOVALUE} ->
+ {ok, AR, ok};
+ _ ->
+ Reason3 = {invalid_NotifyReply, NR},
+ {error, Reason3, ok}
+ end.
+
+rsmms2_mg_verify_segment_timeout_fun(SN) ->
+ fun(Rep) -> rsmms2_mg_verify_segment_timeout(Rep, SN) end.
+
+rsmms2_mg_verify_segment_timeout(
+ {handle_trans_reply, _CH, ?VERSION, {error, Reason}, _}, SN) ->
+ case Reason of
+ {segment_timeout, [SN]} ->
+ {ok, Reason, ok};
+ _ ->
+ {error, {invalid_reason, Reason}, ok}
+ end;
+rsmms2_mg_verify_segment_timeout(Crap, SN) ->
+ io:format("rsmms2_mg_verify_segment_timeout -> unknown reply"
+ "~n SN: ~p"
+ "~n Crap: ~p"
+ "~n", [SN, Crap]),
+ {error, Crap, ok}.
+
+rsmms2_mg_verify_handle_disco_fun() ->
+ fun(Ev) -> rsmms2_mg_verify_handle_disconnect(Ev) end.
+
+rsmms2_mg_verify_handle_disconnect({handle_disconnect, _CH, ?VERSION, R}) ->
+ io:format("rsmms2_mg_verify_handle_disconnect -> ok"
+ "~n R: ~p"
+ "~n", [R]),
+ case R of
+ {no_controlling_process,shutdown} ->
+ {ok, R, ok};
+ _ ->
+ {error, {unexpected_reason, R}, ok}
+ end;
+rsmms2_mg_verify_handle_disconnect(Crap) ->
+ io:format("rsmms2_mg_verify_handle_disconnect -> invalid: "
+ "~n Crap: ~p"
+ "~n", [Crap]),
+ {error, Crap, ok}.
+
+
+rsmms2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+rsmms2_mg_notify_request_ar(Rid, Tids, Cid) ->
+ rsmms2_mg_notify_request_ar(Rid, Tids, Cid, []).
+
+rsmms2_mg_notify_request_ar(_Rid, [], Cid, Cmds) ->
+ cre_actionReq(Cid, lists:reverse(Cmds));
+rsmms2_mg_notify_request_ar(Rid, [Tid|Tids], Cid, Cmds) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ rsmms2_mg_notify_request_ar(Rid, Tids, Cid, [CR|Cmds]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Common message creation functions
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% cre_errorDesc(Code, Text) when is_list(Text) ->
+%% #'ErrorDescriptor'{errorCode = Code, errorText = Text};
+%% cre_errorDesc(Code, Text0) ->
+%% Text = lists:flatten(io_lib:format("~w",[Text0])),
+%% #'ErrorDescriptor'{errorCode = Code, errorText = Text}.
+
+cre_segReply(TransId, SN, SC) ->
+ megaco_test_msg_v3_lib:cre_SegmentReply(TransId, SN, SC).
+
+cre_serviceChangeParm(M,R,P) ->
+ %% Version 1 'ServiceChangeParm'
+ {'ServiceChangeParm',
+ M, % serviceChangeMethod,
+ asn1_NOVALUE, % serviceChangeAddress
+ ?VERSION, % serviceChangeVersion
+ P, % serviceChangeProfile
+ R, % serviceChangeReason
+ asn1_NOVALUE, % serviceChangeDelay
+ asn1_NOVALUE, % serviceChangeMgcId
+ asn1_NOVALUE, % timeStamp
+ asn1_NOVALUE % nonStandardData
+ }.
+
+cre_serviceChangeReq(Tid, Parms) ->
+ #'ServiceChangeRequest'{terminationID = Tid,
+ serviceChangeParms = Parms}.
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_obsEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name,
+ timeNotation = Not}.
+%% cre_obsEvent(Name, Not, Par) ->
+%% #'ObservedEvent'{eventName = Name,
+%% timeNotation = Not,
+%% eventParList = Par}.
+
+cre_obsEvsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = EvList}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid,
+ observedEventsDescriptor = EvsDesc}.
+
+cre_command(R) when is_record(R, 'NotifyRequest') ->
+ {notifyReq, R};
+cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
+ {serviceChangeReq, R}.
+
+cre_cmdReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = CmdReqs}.
+
+cre_transReq(TransId, ARs) when is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransId,
+ actions = ARs}.
+
+%% --
+
+cre_serviceChangeResParm(Mid) ->
+ cre_serviceChangeResParm(Mid, ?VERSION).
+
+cre_serviceChangeResParm(Mid, V) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeVersion = V}.
+
+cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP};
+cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED}.
+
+cre_serviceChangeReply(Tid, Res) ->
+ #'ServiceChangeReply'{terminationID = Tid,
+ serviceChangeResult = Res}.
+
+cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
+ {notifyReply, R};
+cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
+ {serviceChangeReply, R}.
+
+cre_notifyReply(Tid) ->
+ #'NotifyReply'{terminationID = Tid}.
+
+cre_actionReply(CtxId, CmdRep) ->
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdRep}.
+
+cre_transResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {transactionError, ED};
+cre_transResult([AR|_] = ARs) when is_record(AR, 'ActionReply') ->
+ {actionReplies, ARs}.
+
+%% cre_transReply(TransId, Res) ->
+%% #'TransactionReply'{transactionId = TransId,
+%% transactionResult = Res}.
+
+cre_transReply(TransId, Res, SN) ->
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = Res,
+ segmentNumber = SN}.
+
+cre_transReply(TransId, Res, SN, SC) ->
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = Res,
+ segmentNumber = SN,
+ segmentationComplete = SC}.
+
+cre_transAck(TransId) ->
+ megaco_test_msg_v3_lib:cre_TransactionAck(TransId).
+
+
+%% --
+
+cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Ver}.
+
+cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
+ {transactionRequest, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
+ {transactionPending, Trans};
+cre_transaction(Trans)
+ when is_record(Trans, 'TransactionReply') or
+ (is_tuple(Trans) and (element(1, Trans) == 'TransactionReply')) ->
+ {transactionReply, Trans};
+cre_transaction(Trans) when is_list(Trans) ->
+ {transactionResponseAck, Trans};
+cre_transaction(SR) when is_record(SR, 'SegmentReply') ->
+ {segmentReply, SR}.
+
+cre_transactions(Trans) when is_list(Trans) ->
+ {transactions, Trans}.
+
+cre_message(Version, Mid, Body) ->
+ #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}.
+
+cre_megacoMessage(Mess) ->
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Transform a short timer to a long one.
+%% The purpose of this is to trick the stack
+%% to keep re-sending the request, even after
+%% having received the first pending (which
+%% indicates that the other side _IS_
+%% working on the request).
+-ifdef(MEGACO_TEST_CODE).
+
+init_request_timer({short, Ref}) ->
+ {long, Ref};
+init_request_timer(O) ->
+ O.
+
+-endif.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_completion(Ids) ->
+ case megaco_test_generator_lib:await_completion(Ids) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, {OK, ERROR}} ->
+ d("ERROR => "
+ "~n OK: ~p"
+ "~n ERROR: ~p", [OK, ERROR]),
+ ?ERROR({failed, ERROR});
+ {error, Reply} ->
+ d("ERROR => "
+ "~n Reply: ~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+%% await_completion(Ids, Timeout) ->
+%% case megaco_test_generator_lib:await_completion(Ids, Timeout) of
+%% {ok, Reply} ->
+%% d("OK => Reply: ~n~p", [Reply]),
+%% ok;
+%% {error, {OK, ERROR}} ->
+%% d("ERROR => "
+%% "~n OK: ~p"
+%% "~n ERROR: ~p", [OK, ERROR]),
+%% ?ERROR({failed, ERROR});
+%% {error, Reply} ->
+%% d("ERROR => Reply: ~n~p", [Reply]),
+%% ?ERROR({failed, Reply})
+%% end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% tim() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) -> receive after X -> ok end.
+
+%% error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), now(), get(tc), "DBG", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(sname), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+format_timestamp(Now) -> megaco:format_timestamp(Now).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% random_init() ->
+%% {A,B,C} = now(),
+%% random:seed(A,B,C).
+
+%% random() ->
+%% 10 * random:uniform(50).
+
+%% apply_load_timer() ->
+%% erlang:send_after(random(), self(), apply_load_timeout).
+
+
+
diff --git a/lib/megaco/test/megaco_tc_controller.erl b/lib/megaco/test/megaco_tc_controller.erl
new file mode 100644
index 0000000000..dedf45e321
--- /dev/null
+++ b/lib/megaco/test/megaco_tc_controller.erl
@@ -0,0 +1,171 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(megaco_tc_controller).
+
+-export([start_link/0, stop/0,
+ insert/2, lookup/1, delete/1]).
+-export([init/2]).
+
+-include("megaco_test_lib.hrl").
+
+-define(SERVER, ?MODULE).
+-define(TABLE, ?MODULE).
+
+start_link() ->
+ p("start_link -> entry"),
+ Pid = spawn_link(?MODULE, init, [self(),get(dbg)]),
+ receive
+ {tc_started, Pid, Reply} ->
+ p("start_link -> ~n ~p", [Reply]),
+ Reply
+ end.
+
+stop() ->
+ request(stop, undefined).
+
+insert(Key, Val) ->
+ request(insert, {Key, Val}).
+
+lookup(Key) ->
+ case request(lookup, Key) of
+ {value, _} = Value ->
+ Value;
+ _ ->
+ false
+ end.
+
+delete(Key) ->
+ request(delete, Key).
+
+request(Tag, Data) ->
+ p("request -> entry with"
+ "~n Tag: ~p"
+ "~n Data: ~p", [Tag, Data]),
+ case global:whereis_name(?SERVER) of
+ Pid when is_pid(Pid) ->
+ Pid ! {Tag, self(), Data},
+ receive
+ {Tag, Pid, Reply} ->
+ p("request -> response: "
+ "~n Reply: ~p", [Reply]),
+ Reply
+ end;
+ _ ->
+ {error, not_started}
+ end.
+
+init(Parent, true) ->
+ put(dbg,true),
+ init(Parent);
+init(Parent, _) ->
+ init(Parent).
+
+init(Parent) ->
+ p("init -> entry with"
+ "~n Parent: ~p", [Parent]),
+ ets:new(?TABLE, [named_table, protected, set]),
+ case global:register_name(?SERVER, self()) of
+ yes ->
+ p("init -> registration ok"),
+ Parent ! {tc_started, self(), ok},
+ loop(Parent);
+ no ->
+ p("init -> registration failed"),
+ Parent ! {tc_started, self(), {error, already_registered}},
+ exit(normal)
+ end.
+
+loop(Parent) ->
+ p("loop -> entry"),
+ receive
+ {insert, Parent, {Key, Val}} ->
+ p("loop -> received insert request when"
+ "~n Key: ~p"
+ "~n Val: ~p", [Key, Val]),
+ ets:insert(?TABLE, {Key, Val}),
+ Parent ! {insert, self(), ok};
+ {delete, Parent, Key} ->
+ p("loop -> received delete request when"
+ "~n Key: ~p", [Key]),
+ ets:delete(?TABLE, Key),
+ Parent ! {delete, self(), ok};
+ {lookup, From, Key} when is_pid(From) ->
+ p("loop -> received lookup request when"
+ "~n Key: ~p", [Key]),
+ case ets:lookup(?TABLE, Key) of
+ [{Key, Val}] ->
+ p("loop -> lookup: ~p", [Val]),
+ From ! {lookup, self(), {value, Val}};
+ _ ->
+ p("loop -> lookup unsuccessful"),
+ From ! {lookup, self(), false}
+ end;
+ {stop, Parent, _} ->
+ p("loop -> received stop request"),
+ ets:delete(?TABLE),
+ global:unregister_name(?SERVER),
+ Parent ! {stop, self(), ok},
+ exit(normal);
+
+ {'EXIT', Parent, Reason} when is_pid(Parent) ->
+ p("loop -> received exit signal from parent"
+ "~n Reason: ~p", [Reason]),
+ exit(Reason);
+
+ {UnknownRequest, Parent, UnknownData} when is_pid(Parent) ->
+ p("loop -> received unknown request when"
+ "~n UnknownRequest: ~p"
+ "~n UnknownData: ~p", [UnknownRequest, UnknownData]),
+ Error = {error, {unknown_request, {UnknownRequest, UnknownData}}},
+ Parent ! {UnknownRequest, self(), Error};
+
+ {Request, From, Data} when is_pid(From) ->
+ p("loop -> received request from unknown when"
+ "~n Request: ~p"
+ "~n From: ~p"
+ "~n Data: ~p", [Request, From, Data]),
+ Error = {error, {unknown_request, {Request, Data}}},
+ Parent ! {Request, self(), Error};
+
+ Crap ->
+ p("loop -> received crap: "
+ "~n Crap: ~p"
+ "~nwhen"
+ "~n Parent: ~p", [Crap, Parent]),
+ ok
+ end,
+ loop(Parent).
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(dbg), F, A).
+
+p(true, F, A) ->
+ io:format("~w:~p:" ++ F ++ "~n", [?MODULE, self()|A]);
+p(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_tcp_test.erl b/lib/megaco/test/megaco_tcp_test.erl
new file mode 100644
index 0000000000..31c88489fe
--- /dev/null
+++ b/lib/megaco/test/megaco_tcp_test.erl
@@ -0,0 +1,1253 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(megaco_tcp_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("megaco/src/tcp/megaco_tcp.hrl").
+-include("megaco_test_lib.hrl").
+
+%% -compile(export_all).
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+
+ start/1,
+ start_normal/1,
+ start_invalid_opt/1,
+ start_and_stop/1,
+
+ sending/1,
+ sendreceive/1,
+ block_unblock/1,
+
+ errors/1,
+ socket_failure/1,
+ accept_process/1,
+ accept_supervisor/1,
+ connection_supervisor/1,
+ tcp_server/1,
+
+ init_per_testcase/2, fin_per_testcase/2,
+
+ t/0, t/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+-export([
+ receive_message/4,
+ process_received_message/4
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+-record(command, {id, desc, cmd}).
+-record(server, {parent, transport_ref, control_pid, handle}).
+-record(client, {parent, transport_ref, control_pid, handle}).
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: t/0
+%% Description: Run all test cases
+%%----------------------------------------------------------------------
+t() -> megaco_test_lib:t(?MODULE).
+
+
+%%----------------------------------------------------------------------
+%% Function: t/1
+%% Description: Run the specified test cases
+%%----------------------------------------------------------------------
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%%======================================================================
+%% Test server callbacks
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: init_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+
+%%----------------------------------------------------------------------
+%% Function: fin_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(suite) ->
+ [
+ start,
+ sending,
+ errors
+ ].
+
+start(suite) ->
+ [
+ start_normal,
+ start_invalid_opt,
+ start_and_stop
+ ].
+
+sending(suite) ->
+ [
+ sendreceive,
+ block_unblock
+ ].
+
+errors(suite) ->
+ [
+ socket_failure,
+ accept_process,
+ accept_supervisor,
+ connection_supervisor,
+ tcp_server
+ ].
+
+
+%% ------------------ start ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_normal(suite) ->
+ [];
+start_normal(Config) when is_list(Config) ->
+ put(sname, "start_normal"),
+ p("BEGIN TEST-CASE"),
+ Options = [{port, 20000}, {receive_handle, apa}],
+ {ok, Pid} = start_case(Options, ok),
+ megaco_tcp:stop_transport(Pid),
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_invalid_opt(suite) ->
+ [];
+start_invalid_opt(Config) when is_list(Config) ->
+ put(sname, "start_invalid_opt"),
+ p("BEGIN TEST-CASE"),
+ Options = [{port, 20000}, {receivehandle, apa}],
+ ok = start_case(Options, error),
+ p("done"),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop(suite) ->
+ [];
+start_and_stop(doc) ->
+ ["This test case sets up a connection and then cloises it. "
+ "No data is sent. "];
+start_and_stop(Config) when is_list(Config) ->
+ put(sname, "start_and_stop"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = start_and_stop_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = start_and_stop_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+start_and_stop_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ server_await_nothing(State, 6000)
+ end},
+
+ #command{id = 6,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+
+start_and_stop_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 7,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+%% ------------------ sending ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sendreceive(suite) ->
+ [];
+sendreceive(Config) when is_list(Config) ->
+ put(sname, "sendreceive"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = sendreceive_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = sendreceive_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+sendreceive_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await nothing before sending a message (hejsan)",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 11,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+sendreceive_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 6,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 7,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #command{id = 8,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 11,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 12,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+block_unblock(suite) ->
+ [];
+block_unblock(Config) when is_list(Config) ->
+ put(sname, "block_unblock"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = block_unblock_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = block_unblock_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {listening, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ ok =
+ receive
+ {blocked, Client} ->
+ p("received blocked message from client [~p] => "
+ "send continue to server [~p]~n", [Client, Server]),
+ Server ! {continue, self()},
+ ok
+ after 5000 ->
+ {error, timeout}
+ end,
+
+ await_command_handler_completion([Server, Client], timer:seconds(30)),
+ p("done"),
+ ok.
+
+
+block_unblock_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Listen",
+ cmd = fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify listening",
+ cmd = fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ server_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 9,
+ desc = "Await nothing before sending a message (hejsan)",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 11,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 10000)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #command{id = 14,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 15,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+block_unblock_client_commands(ServerPort, ServerHost) ->
+ Opts = [{port, ServerPort}, {host, ServerHost}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 4,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #command{id = 5,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 6,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 7,
+ desc = "Await nothing before blocking",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Block",
+ cmd = fun(State) ->
+ client_block(State)
+ end},
+
+ #command{id = 9,
+ desc = "Notify blocked",
+ cmd = fun(State) ->
+ client_notify_blocked(State)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before unblocking",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 11,
+ desc = "Unblock",
+ cmd = fun(State) ->
+ client_unblock(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 100)
+ end},
+
+ #command{id = 13,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 14,
+ desc = "Await nothing before disconnecting",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 15,
+ desc = "Disconnect",
+ cmd = fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #command{id = 16,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 17,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+
+%% ------------------ errors ------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+socket_failure(suite) ->
+ [];
+socket_failure(Config) when is_list(Config) ->
+ put(sname, "socket_failure"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ socket_faulure().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+accept_process(suite) ->
+ [];
+accept_process(Config) when is_list(Config) ->
+ put(sname, "accept_process"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_accept_process().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+accept_supervisor(suite) ->
+ [];
+accept_supervisor(Config) when is_list(Config) ->
+ put(sname, "accept_supervisor"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_accept_supervisor().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+connection_supervisor(suite) ->
+ [];
+connection_supervisor(Config) when is_list(Config) ->
+ put(sname, "connection_supervisor"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_connection_supervisor().
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tcp_server(suite) ->
+ [];
+tcp_server(Config) when is_list(Config) ->
+ put(sname, "tcp_server"),
+ p("BEGIN TEST-CASE"),
+
+ %% process_flag(trap_exit, true),
+
+ failing_tcp_server().
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+start_case(Options, Expect) ->
+ p("start transport"),
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Pid} ->
+ p("create listen socket"),
+ case (catch megaco_tcp:listen(Pid, Options)) of
+ ok when Expect =:= ok ->
+ p("extected listen result [ok]"),
+ {ok, Pid};
+ ok ->
+ p("unextected listen result [ok] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ?ERROR(unexpected_start_sucesss);
+ {error, _Reason} when Expect =:= error ->
+ p("extected listen result [error] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ok;
+ {error, Reason} ->
+ p("unextected listen result [error] - stop transport"),
+ megaco_tcp:stop_transport(Pid),
+ ?ERROR({unexpected_start_failure, Reason});
+ Error ->
+ p("unextected listen result"),
+ ?ERROR({unexpected_result, Error})
+ end;
+ {error, Reason} ->
+ p("unextected start_transport result"),
+ ?ERROR({failed_starting_transport, Reason})
+ end.
+
+socket_faulure() ->
+ ?SKIP(not_yet_implemented).
+
+failing_accept_process() ->
+ ?SKIP(not_yet_implemented).
+
+failing_accept_supervisor() ->
+ ?SKIP(not_yet_implemented).
+
+failing_connection_supervisor() ->
+ ?SKIP(not_yet_implemented).
+
+failing_tcp_server() ->
+ ?SKIP(not_yet_implemented).
+
+
+%%----------------------------------------------------------------------
+%% Message Callback functions
+%%----------------------------------------------------------------------
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {receive_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {process_received_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% ------- Server command handler and utility functions ----------
+
+server_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #server{}, "server").
+
+server_start_transport(State) when is_record(State, server) ->
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#server{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+server_listen(#server{transport_ref = Ref} = State, Options)
+ when is_record(State, server) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_tcp:listen(Ref, Opts)) of
+ ok ->
+ {ok, State};
+ Error ->
+ Error
+ end.
+
+server_notify_listening(#server{parent = Parent} = State)
+ when is_record(State, server) ->
+ Parent ! {listening, self()},
+ {ok, State}.
+
+server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_await_initial_message(State, InitialMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {ControlPid, Handle, InitialMessage}} ->
+ NewState = State#server{control_pid = ControlPid,
+ handle = Handle},
+ {ok, NewState};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_send_message(#server{handle = Handle} = State, Message) ->
+ megaco_tcp:send_message(Handle, Message),
+ {ok, State}.
+
+server_await_nothing(State, Timeout)
+ when is_record(State, server) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {ok, State}
+ end.
+
+
+server_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_disconnect(#server{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:close(Handle),
+ {ok, State#server{handle = undefined}}.
+
+%% server_block(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_tcp:block(Handle),
+%% {ok, State}.
+
+%% server_unblock(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_tcp:unblock(Handle),
+%% {ok, State}.
+
+server_stop_transport(#server{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_tcp:stop_transport(Ref),
+ {ok, State}.
+
+
+%% ------- Client command handler and utility functions ----------
+
+client_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #client{}, "client").
+
+client_start_transport(State) when is_record(State, client) ->
+ case (catch megaco_tcp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#client{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+client_connect(#client{transport_ref = Ref} = State, Options)
+ when is_record(State, client) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_tcp:connect(Ref, Opts)) of
+ {ok, Handle, ControlPid} ->
+ {ok, State#client{control_pid = ControlPid,
+ handle = Handle}};
+ Error ->
+ Error
+ end.
+
+client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_notify_blocked(#client{parent = Parent} = State) ->
+ Parent ! {blocked, self()},
+ {ok, State}.
+
+client_await_nothing(State, Timeout)
+ when is_record(State, client) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+ after Timeout ->
+ {ok, State}
+ end.
+
+client_send_message(#client{handle = Handle} = State, Message) ->
+ megaco_tcp:send_message(Handle, Message),
+ {ok, State}.
+
+client_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, client) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_block(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:block(Handle),
+ {ok, State}.
+
+client_unblock(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:unblock(Handle),
+ {ok, State}.
+
+client_disconnect(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_tcp:close(Handle),
+ {ok, State#client{handle = undefined, control_pid = undefined}}.
+
+client_stop_transport(#client{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_tcp:stop_transport(Ref),
+ {ok, State}.
+
+
+%% -------- Command handler ---------
+
+start_command_handler(Node, Commands, State, ShortName) ->
+ Fun = fun() ->
+ put(sname, ShortName),
+ process_flag(trap_exit, true),
+ Result = (catch command_handler(Commands, State)),
+ p("command handler terminated with: "
+ "~n Result: ~p", [Result]),
+ exit(Result)
+ end,
+ erlang:spawn_link(Node, Fun).
+
+command_handler([], State) ->
+ p("command_handler -> entry when done with"
+ "~n State: ~p", [State]),
+ {ok, State};
+command_handler([#command{id = Id,
+ desc = Desc,
+ cmd = Cmd}|Commands], State) ->
+ p("command_handler -> entry with"
+ "~n Id: ~p"
+ "~n Desc: ~p", [Id, Desc]),
+ case (catch Cmd(State)) of
+ {ok, NewState} ->
+ p("command_handler -> cmd ~w ok", [Id]),
+ command_handler(Commands, NewState);
+ {error, Reason} ->
+ p("command_handler -> cmd ~w error: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_error, Reason}};
+ {'EXIT', Reason} ->
+ p("command_handler -> cmv ~w exit: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_exit, Reason}};
+ Error ->
+ p("command_handler -> cmd ~w failure: "
+ "~n Error: ~p", [Id, Error]),
+ {error, {cmd_failure, Error}}
+ end.
+
+
+await_command_handler_completion(Pids, Timeout) ->
+ await_command_handler_completion(Pids, [], [], Timeout).
+
+await_command_handler_completion([], [], _Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done"),
+ ok;
+await_command_handler_completion([], Bad, Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done with bad result: "
+ "~n Bad: ~p"
+ "~n Good: ~p", [Bad, Good]),
+ ok;
+await_command_handler_completion(Pids, Bad, Good, Timeout) ->
+ p("await_command_handler_completion -> entry when waiting for"
+ "~n Pids: ~p"
+ "~n Bad: ~p"
+ "~n Good: ~p"
+ "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
+ Begin = ms(),
+ receive
+ {'EXIT', Pid, {ok, FinalState}} ->
+ p("await_command_handler_completion -> "
+ "received ok EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done", [Pid]),
+ await_command_handler_completion(Pids2,
+ Bad,
+ [{Pid, FinalState}|Good],
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {error, Reason}} ->
+ p("await_command_handler_completion -> "
+ "received error EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done", [Pid]),
+ await_command_handler_completion(Pids2,
+ [{Pid, Reason}|Bad],
+ Good,
+ Timeout - (ms() - Begin))
+ end
+
+ after Timeout ->
+ p("await_command_handler_completion -> timeout"),
+ exit({timeout, Pids})
+ end.
+
+
+
+%% ------- Misc functions --------
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(sname), F, A).
+
+p(S, F, A) when is_list(S) ->
+ io:format("*** [~s] ~p ~s ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), S | A]);
+p(_S, F, A) ->
+ io:format("*** [~s] ~p ~s *** "
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), "undefined" | A]).
+
+
+ms() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
diff --git a/lib/megaco/test/megaco_test_deliver.erl b/lib/megaco/test/megaco_test_deliver.erl
new file mode 100644
index 0000000000..2d0f0c1cbe
--- /dev/null
+++ b/lib/megaco/test/megaco_test_deliver.erl
@@ -0,0 +1,188 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: This module takes the role of the main megaco module for
+%% the transport module. It is used when delivering
+%% received messages. The purpose is to be able to do
+%% various forms of filtering before passing the message
+%% the the megaco stack (by calling the megaco module).
+%% It can be controlled with the following flags:
+%% allow_recv_message - Shall the received message be
+%% delivered.
+%% extra_transport_info - Provide extra info from the transport
+%% module.
+%%----------------------------------------------------------------------
+-module(megaco_test_deliver).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+-include("megaco_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ process_received_message/4, process_received_message/5,
+ receive_message/4, receive_message/5
+ ]).
+
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ i("process_received_message -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n SendHandle: ~p",
+ [ReceiveHandle, ControlPid, SendHandle]),
+ case allow_recv_message() of
+ true ->
+ i("process_received_message -> allowed recv msg"),
+ case extra_transport_info() of
+ {value, Extra} ->
+ i("process_received_message -> extra_transport_info: "
+ "~n Extra: ~p", [Extra]),
+ megaco:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra);
+ _ ->
+ i("process_received_message -> no extra_transport_info"),
+ megaco:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg)
+ end;
+ false ->
+ i("process_received_message -> recv msg not allowed"),
+ ok;
+ {false, Reason} ->
+ i("process_received_message -> recv msg not allowed"
+ "~n Reason: ~p", [Reason]),
+ exit(Reason)
+ end.
+
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ i("process_received_message -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n SendHandle: ~p"
+ "~n Extra: ~p",
+ [ReceiveHandle, ControlPid, SendHandle, Extra]),
+ case allow_recv_message() of
+ true ->
+ i("process_received_message -> allowed recv msg"),
+ megaco:process_received_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra);
+ false ->
+ i("process_received_message -> recv msg not allowed"),
+ ok;
+ {false, Reason} ->
+ i("process_received_message -> recv msg not allowed"
+ "~n Reason: ~p", [Reason]),
+ exit(Reason)
+ end.
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) ->
+ i("receive_message -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n SendHandle: ~p",
+ [ReceiveHandle, ControlPid, SendHandle]),
+ case allow_recv_message() of
+ true ->
+ i("receive_message -> allowed recv msg"),
+ case extra_transport_info() of
+ {value, Extra} ->
+ i("receive_message -> extra_transport_info: "
+ "~n Extra: ~p", [Extra]),
+ megaco:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg, Extra);
+ _ ->
+ i("receive_message -> no extra_transport_info"),
+ megaco:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg)
+ end;
+ false ->
+ i("receive_message -> recv msg not allowed"),
+ ok;
+ {false, Reason} ->
+ i("receive_message -> recv msg not allowed"
+ "~n Reason: ~p", [Reason]),
+ exit(Reason)
+ end.
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg, Extra) ->
+ i("receive_message -> entry with"
+ "~n ReceiveHandle: ~p"
+ "~n ControlPid: ~p"
+ "~n SendHandle: ~p"
+ "~n Extra: ~p",
+ [ReceiveHandle, ControlPid, SendHandle, Extra]),
+ case allow_recv_message() of
+ true ->
+ i("receive_message -> allowed recv msg"),
+ megaco:receive_message(ReceiveHandle, ControlPid,
+ SendHandle, BinMsg,
+ Extra);
+ false ->
+ i("receive_message -> recv msg not allowed"),
+ ok;
+ {false, Reason} ->
+ i("receive_message -> recv msg not allowed"
+ "~n Reason: ~p", [Reason]),
+ exit(Reason)
+ end.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+allow_recv_message() ->
+ case megaco_tc_controller:lookup(allow_recv_message) of
+ {error, _} ->
+ true;
+ {value, Else} ->
+ Else;
+ false ->
+ true
+ end.
+
+extra_transport_info() ->
+ case megaco_tc_controller:lookup(extra_transport_info) of
+ {error, _} ->
+ false;
+ Else ->
+ Else
+ end.
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]).
diff --git a/lib/megaco/test/megaco_test_generator.erl b/lib/megaco/test/megaco_test_generator.erl
new file mode 100644
index 0000000000..8bbc60e6cd
--- /dev/null
+++ b/lib/megaco/test/megaco_test_generator.erl
@@ -0,0 +1,549 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Sequence generator for the megaco test suite
+%%----------------------------------------------------------------------
+
+-module(megaco_test_generator).
+
+-behaviour(gen_server).
+
+-export([
+ start_link/3,
+ start_link/4,
+ exec/2, exec/3,
+ stop/1
+ ]).
+
+%% Misc utility function for modules implementing this behaviour
+-export([
+ sleep/1,
+ sz/1,
+ debug/1, debug/2,
+ error/2,
+ print/3, print/4
+ ]).
+
+-export([behaviour_info/1]).
+
+%% Internal exports
+-export([start/4]).
+-export([handler_init/5]).
+
+%% Internal gen_server exports
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+
+-include_lib("megaco/include/megaco.hrl").
+
+
+%%----------------------------------------------------------------------
+
+-define(TIMEOUT, timer:minutes(5)).
+
+
+%%----------------------------------------------------------------------
+
+-record(state,
+ {
+ parent,
+ callback_module,
+ callback_state,
+ handler = {undefined, undefined},
+ timer,
+ name,
+ id
+ }).
+
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+behaviour_info(callbacks) ->
+ [
+ {init, 1},
+ {handle_parse, 2},
+ {handle_exec, 2},
+ {terminate, 2}
+ ];
+behaviour_info(_Other) ->
+ undefined.
+
+
+%%----------------------------------------------------------------------
+
+start_link(Mod, Args, Name)
+ when is_atom(Mod) andalso is_list(Name) ->
+ start(Mod, Args, Name, self()).
+
+start_link(Mod, Args, Name, Node)
+ when is_atom(Mod) andalso is_list(Name) andalso (Node =/= node()) ->
+ case rpc:call(Node, ?MODULE, start, [Mod, Args, Name, self()]) of
+ {ok, Pid} ->
+ link(Pid),
+ {ok, Pid};
+ Error ->
+ Error
+ end;
+start_link(Mod, Args, Name, Node)
+ when is_atom(Mod) andalso is_list(Name) andalso (Node =:= node()) ->
+ case start(Mod, Args, Name, self()) of
+ {ok, Pid} ->
+ link(Pid),
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+start(Mod, Args, Name, Pid) when is_pid(Pid) ->
+ gen_server:start({local, Mod}, ?MODULE, [Mod, Args, Name, Pid], []).
+
+
+exec(Server, Instructions) ->
+ exec(Server, Instructions, infinity).
+
+exec(Server, Instructions, Timeout)
+ when ((Timeout == infinity) orelse
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
+ call(Server, {exec, Instructions, Timeout}).
+
+
+stop(Server) ->
+ call(Server, stop).
+
+
+%%----------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+
+init([Mod, Args, Name, Parent]) ->
+ put(name, Name ++ "-CTRL"),
+ process_flag(trap_exit, true),
+ put(debug, true),
+ d("init -> entry with"
+ "~n Mod: ~p"
+ "~n Args: ~p"
+ "~n Name: ~p"
+ "~n Parent: ~p", [Mod, Args, Name, Parent]),
+ case (catch Mod:init(Args)) of
+ {ok, CallbackState} ->
+ d("init -> ~p initiated:"
+ "~n CallbackState: ~p", [Mod, CallbackState]),
+ State = #state{callback_module = Mod,
+ callback_state = CallbackState,
+ parent = Parent,
+ name = Name},
+ d("init -> initiated"),
+ {ok, State};
+ {error, Reason} ->
+ {stop, Reason}
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call({exec, Instructions, Timeout}, _From,
+ #state{callback_module = Mod,
+ callback_state = CallbackState,
+ name = Name} = State) ->
+ d("handle_call(exec) -> entry with"
+ "~n Timeout: ~p", [Timeout]),
+ case (catch handle_parse(Mod, CallbackState, Instructions)) of
+ {ok, NewCallbackState, NewInstructions} ->
+ d("handle_call(exec) -> parsed"
+ "~n NewCallbackState: ~p", [NewCallbackState]),
+ case handler_start(Name, Mod, NewCallbackState, NewInstructions) of
+ {ok, Pid} ->
+ d("handle_call(exec) -> handler started"
+ "~n Pid: ~p", [Pid]),
+ Timer = maybe_start_timer(Timeout),
+ Id = {node(), make_ref()},
+ Reply = {ok, Id},
+ {reply, Reply,
+ State#state{callback_state = NewCallbackState,
+ handler = {running, Pid},
+ timer = Timer,
+ id = Id}};
+ {error, Reason} ->
+ e("failed starting handler process"
+ "~n Reason: ~p", [Reason]),
+ Reply = {error, {failed_starting_handler, Reason}},
+ {stop, Reason, Reply, State}
+ end;
+ {error, Reason} ->
+ e("failed parsing instructions"
+ "~n Reason: ~p", [Reason]),
+ Reply = {error, {invalid_instruction, Reason}},
+ {stop, Reason, Reply, State}
+ end;
+
+handle_call(stop, _From, State) ->
+ Reply = ok,
+ {stop, normal, Reply, State};
+
+handle_call(Request, From, State) ->
+ e("unexpected request"
+ "~n Request: ~p"
+ "~n From: ~p", [Request, From]),
+ Reason = {error, {unknown_request, Request, From}},
+ Reply = {error, unknown_request},
+ {stop, Reason, Reply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ e("unexpected message"
+ "~n Msg: ~p", [Msg]),
+ Reason = {error, {unknown_message, Msg}},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({handler_result, Pid, Result},
+ #state{parent = Parent,
+ handler = {running, Pid},
+ timer = Timer,
+ id = Id} = State) ->
+ d("handle_info(handler_result) -> entry with"
+ "~n Result: ~p", [Result]),
+ maybe_stop_timer(Timer),
+ handler_stop(Pid),
+ deliver_exec_result(Parent, Id, Result),
+ NewState = State#state{handler = {stopping, Pid},
+ timer = undefined,
+ id = undefined},
+ {noreply, NewState};
+
+handle_info(handler_timeout, #state{handler = {running, Pid}} = State) ->
+ d("handle_info(handler_timeout) -> entry with"),
+ handler_stop(Pid),
+ {noreply, State#state{handler = {stopping, Pid}}};
+
+handle_info({'EXIT', Pid, {stopped, Result}},
+ #state{parent = Parent,
+ handler = {stopping, Pid},
+ id = Id} = State) ->
+ d("handle_info(handler stopped EXIT) -> entry with"
+ "~n Result: ~p", [Result]),
+ deliver_exec_result(Parent, Id, {error, {handler_timeout, Result}}),
+ {noreply, State#state{handler = {stopped, undefined},
+ timer = undefined,
+ id = undefined}};
+
+handle_info({'EXIT', Pid, normal},
+ #state{handler = {_, Pid},
+ timer = Timer} = State) ->
+ d("handle_info(handler normal EXIT) -> entry"),
+ maybe_stop_timer(Timer),
+ {noreply, State#state{handler = {stopped, undefined}, timer = undefined}};
+
+handle_info({'EXIT', Pid, Reason},
+ #state{parent = Parent,
+ handler = {_, Pid},
+ timer = Timer,
+ id = Id} = State) ->
+ d("handle_info(handler EXIT) -> entry with"
+ "~n Reason: ~p", [Reason]),
+ maybe_stop_timer(Timer),
+ deliver_exec_result(Parent, Id, {error, {handler_crashed, Reason}}),
+ {noreply, State#state{handler = {crashed, undefined},
+ timer = undefined,
+ id = undefined}};
+
+handle_info(Info, State) ->
+ e("unexpected info"
+ "~n Info: ~p"
+ "~n State: ~p", [Info, State]),
+ Reason = {error, {unknown_info, Info}},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(normal, #state{handler = {_HandlerState, Pid}} = _State) ->
+ d("terminate(normal) -> entry"),
+ handler_stop(Pid),
+ ok;
+
+terminate(Reason, #state{handler = {_HandlerState, Pid},
+ callback_module = Mod,
+ callback_state = CallbackState} = _State) ->
+ d("terminate -> entry with"
+ "~n Reason: ~p", [Reason]),
+ handler_kill(Pid),
+ (catch Mod:terminate(Reason, CallbackState)),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+deliver_exec_result(Parent, Id, {ok, Result}) ->
+ Parent ! {exec_complete, Id, ok, Result};
+deliver_exec_result(Parent, Id, {error, Reason}) ->
+ Parent ! {exec_complete, Id, error, Reason}.
+
+
+handle_parse(Mod, State, Instructions) ->
+ handle_parse(Mod, State, Instructions, []).
+
+handle_parse(_Mod, State, [], Acc) ->
+ {ok, State, lists:reverse(Acc)};
+
+handle_parse(Mod, State, [Instruction|Instructions], Acc) ->
+ case (catch Mod:handle_parse(Instruction, State)) of
+ {ok, NewInstruction, NewState} ->
+ handle_parse(Mod, NewState, Instructions, [NewInstruction|Acc]);
+ {error, Reason} ->
+ {error, {invalid_instruction, Instruction, Reason}};
+ {'EXIT', Reason} ->
+ {error, {exit, Instruction, Reason}}
+ end.
+
+
+%%%-------------------------------------------------------------------
+
+handler_kill(Pid) when is_pid(Pid) ->
+ erlang:exit(Pid, kill);
+handler_kill(_) ->
+ ok.
+
+handler_stop(Pid) when is_pid(Pid) ->
+ Pid ! {stop, self()};
+handler_stop(_) ->
+ ok.
+
+handler_start(Name, Mod, State, Instructions) ->
+ Args = [Name, self(), Mod, State, Instructions],
+ proc_lib:start_link(?MODULE, handler_init, Args).
+
+
+handler_init(Name, Parent, Mod, State, Instructions) ->
+ put(name, Name ++ "-HANDLER"),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ d("handler_init -> initiated"),
+ handler_main(Parent, Mod, State, Instructions).
+
+handler_main(Parent, Mod, State, []) ->
+ d("handler_main -> done when"
+ "~n State: ~p", [State]),
+ Result = (catch Mod:terminate(normal, State)),
+ Parent ! {handler_result, self(), {ok, Result}},
+ receive
+ {stop, Parent} ->
+ exit(normal);
+ {'EXIT', Parent, Reason} ->
+ exit({parent_died, Reason})
+ end;
+
+handler_main(Parent, Mod, State, [Instruction|Instructions]) ->
+ d("handler_main -> entry with"
+ "~n Instruction: ~p", [Instruction]),
+ receive
+ {stop, Parent} ->
+ d("handler_main -> premature stop requested"),
+ Result = (catch Mod:terminate(stopped, State)),
+ exit({stopped, Result});
+ {'EXIT', Parent, Reason} ->
+ d("handler_main -> parent exited"
+ "~n Reason: ~p", [Reason]),
+ Result = (catch Mod:terminate({parent_died, Reason}, State)),
+ exit({parent_died, Reason, Result})
+ after 0 ->
+ case (catch handler_callback_exec(Mod, State, Instruction)) of
+ {ok, NewState} ->
+ handler_main(Parent, Mod, NewState, Instructions);
+ {error, Reason} ->
+ d("handler_main -> exec failed"
+ "~n Reason: ~p", [Reason]),
+ case (catch Mod:terminate(normal, State)) of
+ {ok, Result} ->
+ Parent ! {handler_result, self(), {error, Result}};
+ Error ->
+ Result = {bad_terminate, Error},
+ Parent ! {handler_result, self(), {error, Result}}
+ end,
+ receive
+ {stop, Parent} ->
+ exit(normal);
+ {'EXIT', Parent, Reason} ->
+ exit({parent_died, Reason})
+ end;
+ {'EXIT', Reason} ->
+ d("handler_main -> exec EXIT"
+ "~n Reason: ~p", [Reason]),
+ exit({callback_exec_exit, Reason})
+
+ end
+ end.
+
+handler_callback_exec(Mod, State, Instruction) ->
+ Mod:handle_exec(Instruction, State).
+
+
+%%%-------------------------------------------------------------------
+
+maybe_start_timer(Timeout) when is_integer(Timeout) ->
+ erlang:send_after(Timeout, self(), handler_timeout);
+maybe_start_timer(_) ->
+ undefined.
+
+
+maybe_stop_timer(undefined) ->
+ ok;
+maybe_stop_timer(Timer) ->
+ (catch erlang:cancel_timer(Timer)).
+
+
+%%% ----------------------------------------------------------------
+
+call(Server, Request) ->
+ call(Server, Request, infinity).
+
+call(Server, Request, Timeout) ->
+ case (catch gen_server:call(Server, Request, Timeout)) of
+ {'EXIT', _} ->
+ {error, not_started};
+ Res ->
+ Res
+ end.
+
+%% cast(Server, Msg) ->
+%% case (catch gen_server:cast(Server, Msg)) of
+%% {'EXIT', _} ->
+%% {error, not_started};
+%% Res ->
+%% Res
+%% end.
+
+
+%%% ----------------------------------------------------------------
+
+sleep(X) when is_integer(X) andalso (X =< 0) -> ok;
+sleep(X) -> receive after X -> ok end.
+
+sz(Bin) when is_binary(Bin) ->
+ size(Bin);
+sz(L) when is_list(L) ->
+ length(L);
+sz(_) ->
+ -1.
+
+
+%%% ----------------------------------------------------------------
+
+d(F) -> debug(F).
+d(F, A) -> debug(F, A).
+
+e(F, A) -> error(F, A).
+
+%% p(P, F, A) -> print(P, F, A).
+%% p(P, N, F, A) -> print(P, N, F, A).
+
+
+%% -------------------------
+
+debug(F) ->
+ debug(F, []).
+
+debug(F, A) ->
+ debug(get(debug), F, A).
+
+debug(true, F, A) ->
+ print(" DBG", F, A);
+debug(_, _F, _A) ->
+ ok.
+
+
+error(F, A) ->
+ print(" ERROR", F, A).
+
+
+print(P, F, A) ->
+ print(P, get(name), F, A).
+
+print([], undefined, F, A) ->
+ io:format("*** [~s] ~p *** " ++
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()),self()|A]);
+print(P, undefined, F, A) ->
+ io:format("*** [~s] ~p ~s *** " ++
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()),self(),P|A]);
+print(P, N, F, A) ->
+ io:format("*** [~s] ~p ~s~s *** " ++
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()),self(),N,P|A]).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY, MM, DD} = Date,
+ {Hour, Min, Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY, MM, DD, Hour, Min, Sec, round(N3/1000)]),
+ lists:flatten(FormatDate).
diff --git a/lib/megaco/test/megaco_test_generator_lib.erl b/lib/megaco/test/megaco_test_generator_lib.erl
new file mode 100644
index 0000000000..cf0dcaf722
--- /dev/null
+++ b/lib/megaco/test/megaco_test_generator_lib.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility module for the generator users
+%%----------------------------------------------------------------------
+
+-module(megaco_test_generator_lib).
+
+-export([
+ await_completion/1, await_completion/2
+ ]).
+
+
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+await_completion(Tags) ->
+ await_completion(Tags, infinity).
+
+await_completion(Tags, Timeout) ->
+ TmrRef = start_timer(Timeout),
+ await_completion(TmrRef, Tags, [], []).
+
+await_completion(TmrRef, [], OK, []) ->
+ stop_timer(TmrRef),
+ {ok, OK};
+await_completion(TmrRef, [], OK, ERROR) ->
+ stop_timer(TmrRef),
+ {error, {OK, ERROR}};
+await_completion(TmrRef, Tags, OK, ERROR) ->
+ receive
+ exec_complete_timeout ->
+ {error, {timeout, Tags, OK, ERROR}};
+
+ {exec_complete, Tag, ok, Result} ->
+ case lists:delete(Tag, Tags) of
+ Tags ->
+ %% Unknown => ignore
+ await_completion(TmrRef, Tags, OK, ERROR);
+ Tags2 ->
+ await_completion(TmrRef, Tags2, [{Tag, Result}|OK], ERROR)
+ end;
+
+ {exec_complete, Tag, error, Reason} ->
+ case lists:delete(Tag, Tags) of
+ Tags ->
+ %% Unknown => ignore
+ await_completion(TmrRef, Tags, OK, ERROR);
+ Tags2 ->
+ await_completion(TmrRef, Tags2, OK, [{Tag, Reason}|ERROR])
+ end
+ end.
+
+start_timer(infinity) ->
+ undefined;
+start_timer(Timeout) when is_integer(Timeout) andalso (Timeout > 0) ->
+ Msg = exec_complete_timeout,
+ erlang:send_after(Timeout, self(), Msg).
+
+stop_timer(undefined) ->
+ ok;
+stop_timer(TmrRef) ->
+ erlang:cancel_timer(TmrRef).
diff --git a/lib/megaco/test/megaco_test_generic_transport.erl b/lib/megaco/test/megaco_test_generic_transport.erl
new file mode 100644
index 0000000000..10afa45baa
--- /dev/null
+++ b/lib/megaco/test/megaco_test_generic_transport.erl
@@ -0,0 +1,354 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Generic megaco transport simulator module
+%%----------------------------------------------------------------------
+
+-module(megaco_test_generic_transport).
+
+-behaviour(gen_server).
+-behaviour(megaco_transport).
+
+-export([
+ start_transport/0,
+ listen/2,
+ connect/2,
+ start/1,
+ stop/0,
+ incomming_message/2
+ ]).
+
+%% gen_server callbacks
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+%% megaco_transport callbacks
+-export([
+ send_message/2,
+ send_message/3,
+ resend_message/2
+ ]).
+
+-record(state, {parent,
+ controller,
+ receive_handle}).
+
+-include_lib("megaco/include/megaco.hrl").
+%% -include("megaco_test_lib.hrl").
+-define(SERVER, ?MODULE).
+
+
+%%-------------------------------------------------------------------
+%% API
+%%-------------------------------------------------------------------
+
+start(RH) ->
+ {ok, Pid} = start_transport(),
+ {ok, SendHandle, _} = connect(Pid, [{receive_handle, RH}]),
+ {ok, SendHandle}.
+
+start_transport() ->
+ %% GS_ARGS = [{debug,[trace]}],
+ GS_ARGS = [],
+ {ok, Pid} = gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], GS_ARGS),
+ unlink(Pid),
+ {ok, Pid}.
+
+connect(Sup, Opts) ->
+ call({connect, Sup, Opts}).
+
+listen(Sup, Opts) ->
+ call({listen, Sup, Opts}).
+
+stop() ->
+ call(stop).
+
+
+%%----------------------------------------------------------------------
+%% Megaco transport callback
+%%----------------------------------------------------------------------
+
+send_message(SendHandle, Bin) ->
+ call({transport, {send_message, SendHandle, Bin}}).
+
+send_message(SendHandle, Bin, Resend) ->
+ call({transport, {send_message, SendHandle, Bin, Resend}}).
+
+resend_message(SendHandle, Bin) ->
+ call({transport, {resend_message, SendHandle, Bin}}).
+
+incomming_message(Pid, Msg) ->
+ cast(Pid, {incomming_message, Msg}).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Parent]) ->
+ {ok, #state{parent = Parent}}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call({connect, _Sup, Opts}, _From, State) ->
+ d("handle_call(connect) -> entry with"
+ "~n Opts: ~p", [Opts]),
+ {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts),
+ {value, {_, Controller}} = lists:keysearch(port, 1, Opts),
+ SendHandle = self(),
+ ControlPid = self(),
+ Reply = {ok, SendHandle, ControlPid},
+ {reply, Reply, State#state{controller = Controller,
+ receive_handle = ReceiveHandle}};
+
+handle_call({listen, _Sup, Opts}, _From, State) ->
+ d("handle_call(listen) -> entry with"
+ "~n Opts: ~p", [Opts]),
+ {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts),
+ {value, {_, Controller}} = lists:keysearch(port, 1, Opts),
+ SendHandle = self(),
+ ControlPid = self(),
+ Reply = {ok, SendHandle, ControlPid},
+ Controller ! {listen, ReceiveHandle, SendHandle, ControlPid},
+ {reply, Reply, State#state{controller = Controller,
+ receive_handle = ReceiveHandle}};
+
+handle_call(stop, _From, State) ->
+ d("handle_call(stop) -> entry"),
+ Reply = ok,
+ Reason = normal,
+ {stop, Reason, Reply, State};
+
+handle_call({transport, Event}, _From,
+ #state{controller = Pid, receive_handle = RH} = State) ->
+ d("handle_call(transport) -> entry with"
+ "~n Event: ~p", [Event]),
+ Reply = handle_transport(Pid, RH, Event),
+ {reply, Reply, State};
+
+handle_call(Req, From, State) ->
+ d("handle_call -> entry with"
+ "~n Req: ~p", [Req]),
+ Reply = {error, {unknown_request, Req}},
+ Reason = {received_unexpected_request, Req, From},
+ {stop, Reason, Reply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast({incomming_message, Msg},
+ #state{receive_handle = RH} = State) ->
+ d("handle_cast(incomming_message) -> entry with"
+ "~n Msg: ~p", [Msg]),
+ handle_incomming_message(Msg, RH),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ d("handle_cast -> entry with"
+ "~n Msg: ~p", [Msg]),
+ Reason = {received_unexpected_message, Msg},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info(Info, State) ->
+ d("handle_info -> entry with"
+ "~n Info: ~p", [Info]),
+ Reason = {received_unexpected_info, Info},
+ {stop, Reason, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+handle_transport(Pid,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC},
+ {Event, SendHandle, Bin, Resend}) ->
+ Info =
+ case (catch EM:decode_message(EC, Bin)) of
+ {ok, MegMsg} ->
+ {message, MegMsg, Resend};
+ Error ->
+ d("handle_transport -> decode failed"
+ "~n Error: ~p", [Error]),
+ {bad_message, Error, Bin}
+ end,
+ handle_transport(Pid, Event, SendHandle, Info);
+handle_transport(Pid,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC},
+ {Event, SendHandle, Bin}) ->
+ Info =
+ case (catch EM:decode_message(EC, Bin)) of
+ {ok, MegMsg} ->
+ {message, MegMsg};
+ Error ->
+ d("handle_transport -> decode failed"
+ "~n Error: ~p", [Error]),
+ {bad_message, Error, Bin}
+ end,
+ handle_transport(Pid, Event, SendHandle, Info).
+
+handle_transport(Pid, Event, SendHandle, Info) ->
+ Pid ! {transport_event, {Event, SendHandle, Info}, self()},
+ receive
+ {transport_reply, Reply, Pid} ->
+ d("handle_transport -> received reply"
+ "~n Reply: ~p", [Reply]),
+ Reply
+ after 10000 ->
+ receive
+ Any ->
+ d("handle_transport -> received crap after timeout"
+ "~n Any: ~p", [Any]),
+ exit({timeout, Any})
+ after 0 ->
+ d("handle_transport -> timeout"),
+ exit(timeout)
+ end
+ end.
+
+
+%% This function is used to simulate incomming messages
+handle_incomming_message(Msg,
+ #megaco_receive_handle{encoding_mod = EM,
+ encoding_config = EC} = RH) ->
+ Self = self(),
+ case EM:encode_message(EC, Msg) of
+ {ok, Bin} ->
+ ProcessMessage =
+ fun() ->
+ megaco:process_received_message(RH, Self, Self, Bin)
+ end,
+ spawn(ProcessMessage),
+ ok;
+ Error ->
+ d("handle_incomming_message -> encode failed"
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end.
+
+
+%%-------------------------------------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ case (catch gen_server:call(?SERVER, Req, Timeout)) of
+ {'EXIT', _} ->
+ {error, not_started};
+ Res ->
+ Res
+ end.
+
+%% cast(Msg) ->
+%% cast(whereis(?SERVER), Msg).
+
+cast(Pid, Msg) ->
+ d("cast -> entry with"
+ "~n Pid: ~p"
+ "~n Msg: ~p", [Pid, Msg]),
+ case (catch gen_server:cast(Pid, Msg)) of
+ {'EXIT', Reason} ->
+ d("cast -> failed casting"
+ "~n Reason: ~p", [Reason]),
+ {error, not_started};
+ Res ->
+ Res
+ end.
+
+
+%%-------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(now(), F, A).
+
+
+print(Ts, F, A) ->
+ io:format("*** [~s] GENERIC TRANSPORT [~p] ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), self() | A]).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl
new file mode 100644
index 0000000000..03c04831e8
--- /dev/null
+++ b/lib/megaco/test/megaco_test_lib.erl
@@ -0,0 +1,841 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Lightweight test server
+%%----------------------------------------------------------------------
+
+-module(megaco_test_lib).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+
+
+%% ----------------------------------------------------------------
+%% Time related function
+%%
+
+sleep(infinity) ->
+ receive
+ after infinity ->
+ ok
+ end;
+sleep(MSecs) ->
+ receive
+ after trunc(MSecs) ->
+ ok
+ end,
+ ok.
+
+
+hours(N) -> trunc(N * 1000 * 60 * 60).
+minutes(N) -> trunc(N * 1000 * 60).
+seconds(N) -> trunc(N * 1000).
+
+
+%% ----------------------------------------------------------------
+%% Conditional skip of testcases
+%%
+
+non_pc_tc_maybe_skip(Config, Condition, File, Line)
+ when is_list(Config) andalso is_function(Condition) ->
+ %% Check if we shall skip the skip
+ case os:getenv("TS_OS_BASED_SKIP") of
+ "false" ->
+ ok;
+ _ ->
+ case lists:keysearch(ts, 1, Config) of
+ {value, {ts, megaco}} ->
+ %% Always run the testcase if we are using our own
+ %% test-server...
+ ok;
+ _ ->
+ case (catch Condition()) of
+ true ->
+ skip(non_pc_testcase, File, Line);
+ _ ->
+ ok
+ end
+ end
+ end.
+
+
+os_based_skip(any) ->
+ true;
+os_based_skip(Skippable) when is_list(Skippable) ->
+ {OsFam, OsName} =
+ case os:type() of
+ {_Fam, _Name} = FamAndName ->
+ FamAndName;
+ Fam ->
+ {Fam, undefined}
+ end,
+ case lists:member(OsFam, Skippable) of
+ true ->
+ true;
+ false ->
+ case lists:keysearch(OsFam, 1, Skippable) of
+ {value, {OsFam, OsName}} ->
+ true;
+ {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ lists:member(OsName, OsNames);
+ _ ->
+ false
+ end
+ end;
+os_based_skip(_) ->
+ false.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Evaluates a test case or test suite
+%% Returns a list of failing test cases:
+%%
+%% {Mod, Fun, ExpectedRes, ActualRes}
+%%----------------------------------------------------------------------
+
+tickets(Case) ->
+ Res = lists:flatten(tickets(Case, default_config())),
+ %% io:format("Res: ~p~n", [Res]),
+ display_result(Res),
+ Res.
+
+tickets(Cases, Config) when is_list(Cases) ->
+ [tickets(Case, Config) || Case <- Cases];
+tickets(Mod, Config) when is_atom(Mod) ->
+ Res = tickets(Mod, tickets, Config),
+ Res;
+tickets(Bad, _Config) ->
+ [{badarg, Bad, ok}].
+
+tickets(Mod, Func, Config) ->
+ case (catch Mod:Func(suite)) of
+ [] ->
+ io:format("Eval: ~p:", [{Mod, Func}]),
+ Res = eval(Mod, Func, Config),
+ {R, _, _} = Res,
+ io:format(" ~p~n", [R]),
+ Res;
+
+ Cases when is_list(Cases) ->
+ io:format("Expand: ~p:~p ... ~n"
+ " ~p~n", [Mod, Func, Cases]),
+ Map = fun({M,_}) when is_atom(M) ->
+ tickets(M, tickets, Config);
+ (F) when is_atom(F) ->
+ tickets(Mod, F, Config);
+ (Case) -> Case
+ end,
+ lists:map(Map, Cases);
+
+ {req, _, {conf, Init, Cases, Finish}} ->
+ case (catch Mod:Init(Config)) of
+ Conf when is_list(Conf) ->
+ io:format("Expand: ~p:~p ...~n", [Mod, Func]),
+ Map = fun({M,_}) when is_atom(M) ->
+ tickets(M, tickets, Config);
+ (F) when is_atom(F) ->
+ tickets(Mod, F, Config);
+ (Case) -> Case
+ end,
+ Res = lists:map(Map, Cases),
+ (catch Mod:Finish(Conf)),
+ Res;
+
+ {'EXIT', {skipped, Reason}} ->
+ io:format(" => skipping: ~p~n", [Reason]),
+ [{skipped, {Mod, Func}, Reason}];
+
+ Error ->
+ io:format(" => init failed: ~p~n", [Error]),
+ [{failed, {Mod, Func}, Error}]
+ end;
+
+ {'EXIT', {undef, _}} ->
+ io:format("Undefined: ~p~n", [{Mod, Func}]),
+ [{nyi, {Mod, Func}, ok}];
+
+ Error ->
+ io:format("Ignoring: ~p:~p: ~p~n", [Mod, Func, Error]),
+ [{failed, {Mod, Func}, Error}]
+ end.
+
+
+display_alloc_info() ->
+ io:format("Allocator memory information:~n", []),
+ AllocInfo = alloc_info(),
+ display_alloc_info(AllocInfo).
+
+display_alloc_info([]) ->
+ ok;
+display_alloc_info([{Alloc, Mem}|AllocInfo]) ->
+ io:format(" ~15w: ~10w~n", [Alloc, Mem]),
+ display_alloc_info(AllocInfo).
+
+alloc_info() ->
+ case erlang:system_info(allocator) of
+ {_Allocator, _Version, Features, _Settings} ->
+ alloc_info(Features);
+ _ ->
+ []
+ end.
+
+alloc_info(Allocators) ->
+ Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc,
+ ets_alloc, binary_alloc, driver_alloc],
+ alloc_info(Allocators, Allocs, []).
+
+alloc_info([], _, Acc) ->
+ lists:reverse(Acc);
+alloc_info([Allocator | Allocators], Allocs, Acc) ->
+ case lists:member(Allocator, Allocs) of
+ true ->
+ Instances0 = erlang:system_info({allocator, Allocator}),
+ Instances =
+ if
+ is_list(Instances0) ->
+ [Instance || Instance <- Instances0,
+ element(1, Instance) =:= instance];
+ true ->
+ []
+ end,
+ AllocatorMem = alloc_mem_info(Instances),
+ alloc_info(Allocators, Allocs, [{Allocator, AllocatorMem} | Acc]);
+
+ false ->
+ alloc_info(Allocators, Allocs, Acc)
+ end.
+
+alloc_mem_info(Instances) ->
+ alloc_mem_info(Instances, []).
+
+alloc_mem_info([], Acc) ->
+ lists:sum([Mem || {instance, _, Mem} <- Acc]);
+alloc_mem_info([{instance, N, Info}|Instances], Acc) ->
+ InstanceMemInfo = alloc_instance_mem_info(Info),
+ alloc_mem_info(Instances, [{instance, N, InstanceMemInfo} | Acc]).
+
+alloc_instance_mem_info(InstanceInfo) ->
+ MBCS = alloc_instance_mem_info(mbcs, InstanceInfo),
+ SBCS = alloc_instance_mem_info(sbcs, InstanceInfo),
+ MBCS + SBCS.
+
+alloc_instance_mem_info(Key, InstanceInfo) ->
+ case lists:keysearch(Key, 1, InstanceInfo) of
+ {value, {Key, Info}} ->
+ case lists:keysearch(blocks_size, 1, Info) of
+ {value, {blocks_size, Mem, _, _}} ->
+ Mem;
+ _ ->
+ 0
+ end;
+ _ ->
+ 0
+ end.
+
+
+t(Case) ->
+ process_flag(trap_exit, true),
+ MEM = fun() -> case (catch erlang:memory()) of
+ {'EXIT', _} ->
+ [];
+ Res ->
+ Res
+ end
+ end,
+ Alloc1 = alloc_info(),
+ Mem1 = MEM(),
+ Res = lists:flatten(t(Case, default_config())),
+ Alloc2 = alloc_info(),
+ Mem2 = MEM(),
+ %% io:format("Res: ~p~n", [Res]),
+ display_result(Res, Alloc1, Mem1, Alloc2, Mem2),
+ Res.
+
+t({Mod, Fun}, Config) when is_atom(Mod) andalso is_atom(Fun) ->
+ case catch apply(Mod, Fun, [suite]) of
+ [] ->
+ io:format("Eval: ~p:", [{Mod, Fun}]),
+ Res = eval(Mod, Fun, Config),
+ {R, _, _, _} = Res,
+ io:format(" ~p~n", [R]),
+ Res;
+
+ Cases when is_list(Cases) ->
+ io:format("Expand: ~p ...~n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case) -> {Mod, Case};
+ (Case) -> Case
+ end,
+ t(lists:map(Map, Cases), Config);
+
+ {req, _, {conf, Init, Cases, Finish}} ->
+ case (catch apply(Mod, Init, [Config])) of
+ Conf when is_list(Conf) ->
+ io:format("Expand: ~p ...~n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case) -> {Mod, Case};
+ (Case) -> Case
+ end,
+ Res = t(lists:map(Map, Cases), Conf),
+ (catch apply(Mod, Finish, [Conf])),
+ Res;
+
+ {'EXIT', {skipped, Reason}} ->
+ io:format(" => skipping: ~p~n", [Reason]),
+ [{skipped, {Mod, Fun}, Reason, 0}];
+
+ Error ->
+ io:format(" => failed: ~p~n", [Error]),
+ [{failed, {Mod, Fun}, Error, 0}]
+ end;
+
+ {'EXIT', {undef, _}} ->
+ io:format("Undefined: ~p~n", [{Mod, Fun}]),
+ [{nyi, {Mod, Fun}, ok, 0}];
+
+ Error ->
+ io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]),
+ [{failed, {Mod, Fun}, Error, 0}]
+ end;
+t(Mod, Config) when is_atom(Mod) ->
+ Res = t({Mod, all}, Config),
+ Res;
+t(Cases, Config) when is_list(Cases) ->
+ [t(Case, Config) || Case <- Cases];
+t(Bad, _Config) ->
+ [{badarg, Bad, ok, 0}].
+
+eval(Mod, Fun, Config) ->
+ TestCase = {?MODULE, Mod, Fun},
+ Label = lists:concat(["TEST CASE: ", Fun]),
+ megaco:report_event(40, ?MODULE, Mod, Label ++ " started",
+ [TestCase, Config]),
+ global:register_name(megaco_test_case_sup, self()),
+ Flag = process_flag(trap_exit, true),
+ put(megaco_test_server, true),
+ Config2 = Mod:init_per_testcase(Fun, Config),
+ Pid = spawn_link(?MODULE, do_eval, [self(), Mod, Fun, Config2]),
+ R = wait_for_evaluator(Pid, Mod, Fun, Config2, []),
+ Mod:fin_per_testcase(Fun, Config2),
+ erase(megaco_test_server),
+ global:unregister_name(megaco_test_case_sup),
+ process_flag(trap_exit, Flag),
+ R.
+
+-record('REASON', {mod, line, desc}).
+
+wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
+ wait_for_evaluator(Pid, Mod, Fun, Config, Errors, 0).
+wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) ->
+ TestCase = {?MODULE, Mod, Fun},
+ Label = lists:concat(["TEST CASE: ", Fun]),
+ receive
+ {done, Pid, ok, Time} when Errors =:= [] ->
+ megaco:report_event(40, Mod, ?MODULE, Label ++ " ok",
+ [TestCase, Config]),
+ {ok, {Mod, Fun}, Errors, Time};
+ {done, Pid, ok, Time} ->
+ megaco:report_event(40, Mod, ?MODULE, Label ++ " failed",
+ [TestCase, Config]),
+ {failed, {Mod, Fun}, Errors, Time};
+ {done, Pid, {ok, _}, Time} when Errors =:= [] ->
+ megaco:report_event(40, Mod, ?MODULE, Label ++ " ok",
+ [TestCase, Config]),
+ {ok, {Mod, Fun}, Errors, Time};
+ {done, Pid, {ok, _}, Time} ->
+ megaco:report_event(40, Mod, ?MODULE, Label ++ " failed",
+ [TestCase, Config]),
+ {failed, {Mod, Fun}, Errors, Time};
+ {done, Pid, Fail, Time} ->
+ megaco:report_event(20, Mod, ?MODULE, Label ++ " failed",
+ [TestCase, Config, {return, Fail}, Errors]),
+ {failed, {Mod,Fun}, Fail, Time};
+ {'EXIT', Pid, {skipped, Reason}, Time} ->
+ megaco:report_event(20, Mod, ?MODULE, Label ++ " skipped",
+ [TestCase, Config, {skipped, Reason}]),
+ {skipped, {Mod, Fun}, Errors, Time};
+ {'EXIT', Pid, Reason, Time} ->
+ megaco:report_event(20, Mod, ?MODULE, Label ++ " crashed",
+ [TestCase, Config, {'EXIT', Reason}]),
+ {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors], Time};
+ {fail, Pid, Reason, Time} ->
+ wait_for_evaluator(Pid, Mod, Fun, Config,
+ Errors ++ [Reason], AccTime + Time)
+ end.
+
+do_eval(ReplyTo, Mod, Fun, Config) ->
+ display_system_info("before", Mod, Fun),
+ case timer:tc(Mod, Fun, [Config]) of
+ {Time, {'EXIT', {skipped, Reason}}} ->
+ display_tc_time(Time),
+ display_system_info("after (skipped)", Mod, Fun),
+ ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time};
+ {Time, Other} ->
+ display_tc_time(Time),
+ display_system_info("after", Mod, Fun),
+ ReplyTo ! {done, self(), Other, Time}
+ end,
+ unlink(ReplyTo),
+ exit(shutdown).
+
+
+display_tc_time(Time) ->
+ io:format("~n"
+ "~n*********************************************"
+ "~n"
+ "~nTest case completion time: ~.3f sec (~w)"
+ "~n", [(Time / 1000000), Time]),
+ ok.
+
+display_system_info(WhenStr) ->
+ display_system_info(WhenStr, undefined, undefined).
+
+display_system_info(WhenStr, undefined, undefined) ->
+ display_system_info(WhenStr, "");
+display_system_info(WhenStr, Mod, Func) ->
+ ModFuncStr = lists:flatten(io_lib:format(" ~w:~w", [Mod, Func])),
+ display_system_info(WhenStr, ModFuncStr).
+
+display_system_info(WhenStr, ModFuncStr) ->
+ Fun = fun(F) -> case (catch F()) of
+ {'EXIT', _} ->
+ undefined;
+ Res ->
+ Res
+ end
+ end,
+ ProcCount = Fun(fun() -> erlang:system_info(process_count) end),
+ ProcLimit = Fun(fun() -> erlang:system_info(process_limit) end),
+ ProcMemAlloc = Fun(fun() -> erlang:memory(processes) end),
+ ProcMemUsed = Fun(fun() -> erlang:memory(processes_used) end),
+ ProcMemBin = Fun(fun() -> erlang:memory(binary) end),
+ ProcMemTot = Fun(fun() -> erlang:memory(total) end),
+ %% error_logger:info_msg(
+ io:format("~n"
+ "~n*********************************************"
+ "~n"
+ "System info ~s~s => "
+ "~n Process count: ~w"
+ "~n Process limit: ~w"
+ "~n Process memory alloc: ~w"
+ "~n Process memory used: ~w"
+ "~n Memory for binaries: ~w"
+ "~n Memory total: ~w"
+ "~n"
+ "~n*********************************************"
+ "~n"
+ "~n", [WhenStr, ModFuncStr,
+ ProcCount, ProcLimit, ProcMemAlloc, ProcMemUsed,
+ ProcMemBin, ProcMemTot]),
+ ok.
+
+display_result(Res, Alloc1, Mem1, Alloc2, Mem2) ->
+ io:format("~nAllocator info: ~n", []),
+ display_alloc(Alloc1, Alloc2),
+ io:format("~nMemory info: ~n", []),
+ display_memory(Mem1, Mem2),
+ display_result(Res).
+
+display_alloc([], []) ->
+ io:format("-~n", []),
+ ok;
+display_alloc(A1, A2) ->
+ do_display_alloc(A1, A2).
+
+do_display_alloc([], _) ->
+ ok;
+do_display_alloc([{Alloc, Mem1}|AllocInfo1], AllocInfo2) ->
+ Mem2 =
+ case lists:keysearch(Alloc, 1, AllocInfo2) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ undefined
+ end,
+ io:format("~15w: ~10w -> ~w~n", [Alloc, Mem1, Mem2]),
+ do_display_alloc(AllocInfo1, AllocInfo2).
+
+display_memory([], []) ->
+ io:format("-~n", []),
+ ok;
+display_memory(Mem1, Mem2) ->
+ do_display_memory(Mem1, Mem2).
+
+
+do_display_memory([], _) ->
+ ok;
+do_display_memory([{Key, Mem1}|MemInfo1], MemInfo2) ->
+ Mem2 =
+ case lists:keysearch(Key, 1, MemInfo2) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ undefined
+ end,
+ io:format("~15w: ~10w -> ~w~n", [Key, Mem1, Mem2]),
+ do_display_memory(MemInfo1, MemInfo2).
+
+display_result([]) ->
+ io:format("OK~n", []);
+display_result(Res) when is_list(Res) ->
+ Ok = [{MF, Time} || {ok, MF, _, Time} <- Res],
+ Nyi = [MF || {nyi, MF, _, _Time} <- Res],
+ Skipped = [{MF, Reason} || {skipped, MF, Reason, _Time} <- Res],
+ Failed = [{MF, Reason} || {failed, MF, Reason, _Time} <- Res],
+ Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res],
+ display_summery(Ok, Nyi, Skipped, Failed, Crashed),
+ display_ok(Ok),
+ display_skipped(Skipped),
+ display_failed(Failed),
+ display_crashed(Crashed).
+
+display_summery(Ok, Nyi, Skipped, Failed, Crashed) ->
+ io:format("~nTest case summery:~n", []),
+ display_summery(Ok, "successfull"),
+ display_summery(Nyi, "not yet implemented"),
+ display_summery(Skipped, "skipped"),
+ display_summery(Failed, "failed"),
+ display_summery(Crashed, "crashed"),
+ io:format("~n", []).
+
+display_summery(Res, Info) ->
+ io:format(" ~w test cases ~s~n", [length(Res), Info]).
+
+display_ok([]) ->
+ ok;
+display_ok(Ok) ->
+ io:format("Ok test cases:~n", []),
+ F = fun({{M, F}, Time}) ->
+ io:format(" ~w : ~w => ~.2f sec~n", [M, F, Time / 1000000])
+ end,
+ lists:foreach(F, Ok),
+ io:format("~n", []).
+
+display_skipped([]) ->
+ ok;
+display_skipped(Skipped) ->
+ io:format("Skipped test cases:~n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end,
+ lists:foreach(F, Skipped),
+ io:format("~n", []).
+
+
+display_failed([]) ->
+ ok;
+display_failed(Failed) ->
+ io:format("Failed test cases:~n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end,
+ lists:foreach(F, Failed),
+ io:format("~n", []).
+
+display_crashed([]) ->
+ ok;
+display_crashed(Crashed) ->
+ io:format("Crashed test cases:~n", []),
+ F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end,
+ lists:foreach(F, Crashed),
+ io:format("~n", []).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Verify that the actual result of a test case matches the exected one
+%% Returns the actual result
+%% Stores the result in the process dictionary if mismatch
+
+error(Actual, Mod, Line) ->
+ global:send(megaco_global_logger, {failed, Mod, Line}),
+ log("<ERROR> Bad result: ~p~n", [Actual], Mod, Line),
+ Label = lists:concat([Mod, "(", Line, ") unexpected result"]),
+ megaco:report_event(60, Mod, Mod, Label,
+ [{line, Mod, Line}, {error, Actual}]),
+ case global:whereis_name(megaco_test_case_sup) of
+ undefined ->
+ ignore;
+ Pid ->
+ Fail = #'REASON'{mod = Mod, line = Line, desc = Actual},
+ Pid ! {fail, self(), Fail}
+ end,
+ Actual.
+
+log(Format, Args, Mod, Line) ->
+ case global:whereis_name(megaco_global_logger) of
+ undefined ->
+ io:format(user, "~p~p(~p): " ++ Format,
+ [self(), Mod, Line] ++ Args);
+ Pid ->
+ io:format(Pid, "~p~p(~p): " ++ Format,
+ [self(), Mod, Line] ++ Args)
+ end.
+
+skip(Actual, File, Line) ->
+ log("Skipping test case~n", [], File, Line),
+ String = lists:flatten(io_lib:format("Skipping test case ~p(~p): ~p~n",
+ [File, Line, Actual])),
+ exit({skipped, String}).
+
+fatal_skip(Actual, File, Line) ->
+ error(Actual, File, Line),
+ exit(shutdown).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Flush the message queue and return its messages
+flush() ->
+ receive
+ Msg ->
+ [Msg | flush()]
+ after 1000 ->
+ []
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Check if process is alive and kicking
+still_alive(Pid) ->
+ case catch erlang:is_process_alive(Pid) of % New BIF in Erlang/OTP R5
+ true ->
+ true;
+ false ->
+ false;
+ {'EXIT', _} -> % Pre R5 backward compatibility
+ case process_info(Pid, message_queue_len) of
+ undefined -> false;
+ _ -> true
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% The proxy process
+
+proxy_start(ProxyId) ->
+ spawn_link(?MODULE, proxy_init, [ProxyId, self()]).
+
+proxy_start(Node, ProxyId) ->
+ spawn_link(Node, ?MODULE, proxy_init, [ProxyId, self()]).
+
+proxy_init(ProxyId, Controller) ->
+ process_flag(trap_exit, true),
+ ?LOG("[~p] proxy started by ~p~n",[ProxyId, Controller]),
+ proxy_loop(ProxyId, Controller).
+
+proxy_loop(OwnId, Controller) ->
+ receive
+ {'EXIT', Controller, Reason} ->
+ p("proxy_loop -> received exit from controller"
+ "~n Reason: ~p"
+ "~n", [Reason]),
+ exit(Reason);
+ {apply, Fun} ->
+ p("proxy_loop -> received apply request~n", []),
+ Res = Fun(),
+ p("proxy_loop -> apply result: "
+ "~n ~p"
+ "~n", [Res]),
+ Controller ! {res, OwnId, Res},
+ proxy_loop(OwnId, Controller);
+ OtherMsg ->
+ p("proxy_loop -> received unknown message: "
+ "~n OtherMsg: ~p"
+ "~n", [OtherMsg]),
+ Controller ! {msg, OwnId, OtherMsg},
+ proxy_loop(OwnId, Controller)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test server callbacks
+init_per_testcase(_Case, Config) ->
+ Pid = group_leader(),
+ Name = megaco_global_logger,
+ case global:whereis_name(Name) of
+ undefined ->
+ global:register_name(megaco_global_logger, Pid);
+ Pid ->
+ io:format("~w:init_per_testcase -> "
+ "already registered to ~p~n", [?MODULE, Pid]),
+ ok;
+ OtherPid when is_pid(OtherPid) ->
+ io:format("~w:init_per_testcase -> "
+ "already registered to other ~p (~p)~n",
+ [?MODULE, OtherPid, Pid]),
+ exit({already_registered, {megaco_global_logger, OtherPid, Pid}})
+ end,
+ set_kill_timer(Config).
+
+fin_per_testcase(_Case, Config) ->
+ Name = megaco_global_logger,
+ case global:whereis_name(Name) of
+ undefined ->
+ io:format("~w:fin_per_testcase -> already un-registered~n",
+ [?MODULE]),
+ ok;
+ Pid when is_pid(Pid) ->
+ global:unregister_name(megaco_global_logger),
+ ok
+ end,
+ reset_kill_timer(Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Set kill timer
+
+set_kill_timer(Config) ->
+ case init:get_argument(megaco_test_timeout) of
+ {ok, _} ->
+ Config;
+ _ ->
+ Time =
+ case lookup_config(tc_timeout, Config) of
+ [] ->
+ timer:minutes(5);
+ ConfigTime when is_integer(ConfigTime) ->
+ ConfigTime
+ end,
+ Dog =
+ case get(megaco_test_server) of
+ true ->
+ spawn_link(?MODULE, watchdog, [self(), Time]);
+ _ ->
+ test_server:timetrap(Time)
+ end,
+ [{kill_timer, Dog}|Config]
+
+
+ end.
+
+reset_kill_timer(Config) ->
+ DogKiller =
+ case get(megaco_test_server) of
+ true ->
+ fun(P) when is_pid(P) -> P ! stop;
+ (_) -> ok
+ end;
+ _ ->
+ fun(Ref) -> test_server:timetrap_cancel(Ref) end
+ end,
+ case lists:keysearch(kill_timer, 1, Config) of
+ {value, {kill_timer, Dog}} ->
+ DogKiller(Dog),
+ lists:keydelete(kill_timer, 1, Config);
+ _ ->
+ Config
+ end.
+
+watchdog(Pid, Time) ->
+ erlang:now(),
+ receive
+ stop ->
+ ok
+ after Time ->
+ case (catch process_info(Pid)) of
+ undefined ->
+ ok;
+ Info ->
+ ?LOG("<ERROR> Watchdog in test case timed out "
+ "for ~p after ~p min"
+ "~n~p"
+ "~n",
+ [Pid, Time div (1000*60), Info]),
+ exit(Pid, kill)
+ end
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+prepare_test_case(Actions, N, Config, File, Line) ->
+ OrigNodes = lookup_config(nodes, Config),
+ TestNodes = lookup_config(nodenames, Config), %% For testserver
+ This = node(),
+ SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes),
+ AllNodes = [This | (SomeNodes -- [This])],
+ Nodes = pick_n_nodes(N, AllNodes, File, Line),
+ start_nodes(Nodes, File, Line),
+ do_prepare_test_case(Actions, Nodes, Config, File, Line).
+
+do_prepare_test_case([init | Actions], Nodes, Config, File, Line) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:flush(),
+ do_prepare_test_case(Actions, Nodes, Config, File, Line);
+do_prepare_test_case([{stop_app, App} | Actions], Nodes, Config, File, Line) ->
+ _Res = rpc:multicall(Nodes, application, stop, [App]),
+ do_prepare_test_case(Actions, Nodes, Config, File, Line);
+do_prepare_test_case([], Nodes, _Config, _File, _Line) ->
+ Nodes.
+
+pick_n_nodes(all, AllNodes, _File, _Line) ->
+ AllNodes;
+pick_n_nodes(N, AllNodes, _File, _Line)
+ when is_integer(N) andalso (length(AllNodes) >= N) ->
+ AllNodes -- lists:nthtail(N, AllNodes);
+pick_n_nodes(N, AllNodes, File, Line) ->
+ fatal_skip({too_few_nodes, N, AllNodes}, File, Line).
+
+lookup_config(Key,Config) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value,{Key,Val}} ->
+ Val;
+ _ ->
+ []
+ end.
+
+default_config() ->
+ [{nodes, default_nodes()}, {ts, megaco}].
+
+default_nodes() ->
+ mk_nodes(2, []).
+
+mk_nodes(0, Nodes) ->
+ Nodes;
+mk_nodes(N, []) ->
+ mk_nodes(N - 1, [node()]);
+mk_nodes(N, Nodes) when N > 0 ->
+ Head = hd(Nodes),
+ [Name, Host] = node_to_name_and_host(Head),
+ Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)].
+
+mk_node(N, Name, Host) ->
+ list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])).
+
+%% Returns [Name, Host]
+node_to_name_and_host(Node) ->
+ string:tokens(atom_to_list(Node), [$@]).
+
+start_nodes([Node | Nodes], File, Line) ->
+ case net_adm:ping(Node) of
+ pong ->
+ start_nodes(Nodes, File, Line);
+ pang ->
+ [Name, Host] = node_to_name_and_host(Node),
+ case slave:start_link(Host, Name) of
+ {ok, NewNode} when NewNode =:= Node ->
+ Path = code:get_path(),
+ {ok, Cwd} = file:get_cwd(),
+ true = rpc:call(Node, code, set_path, [Path]),
+ ok = rpc:call(Node, file, set_cwd, [Cwd]),
+ true = rpc:call(Node, code, set_path, [Path]),
+ {_, []} = rpc:multicall(global, sync, []),
+ start_nodes(Nodes, File, Line);
+ Other ->
+ fatal_skip({cannot_start_node, Node, Other}, File, Line)
+ end
+ end;
+start_nodes([], _File, _Line) ->
+ ok.
+
+p(F,A) ->
+ io:format("~p" ++ F ++ "~n", [self()|A]).
diff --git a/lib/megaco/test/megaco_test_lib.hrl b/lib/megaco/test/megaco_test_lib.hrl
new file mode 100644
index 0000000000..b92474d7b8
--- /dev/null
+++ b/lib/megaco/test/megaco_test_lib.hrl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define common macros for testing
+%%----------------------------------------------------------------------
+
+-define(APPLY(Proxy, Fun),
+ Proxy ! {apply, Fun}).
+
+-define(LOG(Format, Args),
+ megaco_test_lib:log(Format, Args, ?MODULE, ?LINE)).
+
+-define(ERROR(Reason),
+ megaco_test_lib:error(Reason, ?MODULE, ?LINE)).
+
+-define(OS_BASED_SKIP(Skippable),
+ megaco_test_lib:os_based_skip(Skippable)).
+
+-define(NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ megaco_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)).
+
+-define(SKIP(Reason),
+ megaco_test_lib:skip(Reason, ?MODULE, ?LINE)).
+
+-define(VERIFYL(Expected, Expr),
+ fun(A,B) when list(A), list(B) ->
+ A1 = lists:sort(A),
+ B1 = lists:sort(B),
+ case A1 of
+ B1 -> ?LOG("Ok, ~p~n", [B]);
+ _ -> ?ERROR(B)
+ end,
+ B;
+ (A,A) ->
+ ?LOG("Ok, ~p~n", [A]),
+ A;
+ (A,B) ->
+ ?ERROR(B),
+ B
+ end(Expected, (catch Expr))).
+
+-define(VERIFY(Expected, Expr),
+ fun() ->
+ AcTuAlReS = (catch (Expr)),
+ case AcTuAlReS of
+ Expected -> ?LOG("Ok, ~p~n", [AcTuAlReS]);
+ _ -> ?ERROR(AcTuAlReS)
+ end,
+ AcTuAlReS
+ end()).
+
+-define(RECEIVE(Expected),
+ ?VERIFY(Expected, megaco_test_lib:flush())).
+
+-define(MULTI_RECEIVE(Expected),
+ ?VERIFY(lists:sort(Expected), lists:sort(megaco_test_lib:flush()))).
+
+-define(ACQUIRE_NODES(N, Config),
+ megaco_test_lib:prepare_test_case([init, {stop_app, megaco}],
+ N, Config, ?FILE, ?LINE)).
+
+
+-define(SLEEP(MSEC), megaco_test_lib:sleep(MSEC)).
+-define(M(), megaco_test_lib:millis()).
+-define(MDIFF(A,B), megaco_test_lib:millis_diff(A,B)).
+
+-define(HOURS(T), megaco_test_lib:hours(T)).
+-define(MINUTES(T), megaco_test_lib:minutes(T)).
+-define(SECONDS(T), megaco_test_lib:seconds(T)).
diff --git a/lib/megaco/test/megaco_test_megaco_generator.erl b/lib/megaco/test/megaco_test_megaco_generator.erl
new file mode 100644
index 0000000000..5ff7162223
--- /dev/null
+++ b/lib/megaco/test/megaco_test_megaco_generator.erl
@@ -0,0 +1,1120 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: megaco sequence generator for the megaco test suite
+%%----------------------------------------------------------------------
+
+-module(megaco_test_megaco_generator).
+
+-behaviour(megaco_test_generator).
+
+%% API
+-export([
+ start_link/1, start_link/2,
+ stop/1,
+ exec/2, exec/3
+ ]).
+
+%% genarator behaviour callback exports
+-export([
+ init/1,
+ handle_parse/2,
+ handle_exec/2,
+ terminate/2
+ ]).
+
+%% Megaco callback api
+-export([
+ handle_connect/3, handle_connect/4,
+ handle_disconnect/4,
+ handle_syntax_error/4, handle_syntax_error/5,
+ handle_message_error/4, handle_message_error/5,
+ handle_trans_request/4, handle_trans_request/5,
+ handle_trans_long_request/4, handle_trans_long_request/5,
+ handle_trans_reply/5, handle_trans_reply/6,
+ handle_trans_ack/5, handle_trans_ack/6,
+ handle_trans_request_abort/5, handle_trans_request_abort/6,
+ handle_unexpected_trans/4, handle_unexpected_trans/5
+ ]).
+
+
+%%----------------------------------------------------------------------
+
+-include_lib("megaco/include/megaco.hrl").
+
+
+%%----------------------------------------------------------------------
+
+-define(DELIVER_MOD, megaco_test_deliver).
+
+
+%%----------------------------------------------------------------------
+
+-record(state,
+ {
+ mid,
+ recv_handle,
+ port,
+ send_handle,
+ conn_handle,
+
+ transport_sup,
+ ctrl_pid,
+
+ result = [] % Accumulated results from verification
+ }).
+
+
+%%----------------------------------------------------------------------
+%% API
+%%----------------------------------------------------------------------
+
+start_link(Name) ->
+ megaco_test_generator:start_link(?MODULE, [], Name).
+
+start_link(Name, Node) ->
+ megaco_test_generator:start_link(?MODULE, [], Name, Node).
+
+stop(Server) ->
+ megaco_test_generator:stop(Server).
+
+exec(Server, Instructions) when is_list(Instructions) ->
+ megaco_test_generator:exec(Server, Instructions).
+
+exec(Server, Instructions, Timeout) when is_list(Instructions) ->
+ megaco_test_generator:exec(Server, Instructions, Timeout).
+
+
+%%----------------------------------------------------------------------
+%% generator callback functions
+%%----------------------------------------------------------------------
+
+init([]) ->
+ random_init(),
+ {ok, #state{}}.
+
+
+%% ----- instruction parser -----
+
+handle_parse({debug, Debug} = Instruction, State)
+ when (Debug == true) orelse (Debug == false) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_nothing, To} = Instruction, State)
+ when is_integer(To) andalso (To > 0) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_trace, Level} = Instruction, State)
+ when (Level == disable) orelse
+ (Level == max) orelse
+ (Level == min) orelse
+ is_integer(Level) ->
+ {ok, Instruction, State};
+
+handle_parse({sleep, To} = Instruction, State)
+ when is_integer(To) andalso (To > 0) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_start = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_stop = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_start_user, _Mid, _RecvInfo, Conf} = Instruction, State)
+ when is_list(Conf) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_stop_user = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_info = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_system_info, State) ->
+ Verify = fun(_) -> ok end,
+ Instruction = {megaco_system_info, internal_system_info_tag, Verify},
+ {ok, Instruction, State};
+
+handle_parse({megaco_system_info, Tag}, State)
+ when is_atom(Tag) ->
+ Verify = fun(_) -> ok end,
+ Instruction = {megaco_system_info, Tag, Verify},
+ {ok, Instruction, State};
+
+handle_parse({megaco_system_info, Tag, Verify} = Instruction, State)
+ when is_atom(Tag) andalso is_function(Verify) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_user_info, Tag} = Instruction, State)
+ when is_atom(Tag) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_update_user_info, Tag, _Val} = Instruction, State)
+ when is_atom(Tag) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_conn_info, Tag} = Instruction, State)
+ when is_atom(Tag) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_update_conn_info, Tag, _Val} = Instruction, State)
+ when is_atom(Tag) ->
+ {ok, Instruction, State};
+
+handle_parse(start_transport = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(listen = _Instruction, State) ->
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {listen, [], MeybeRetry},
+ {ok, Instruction, State};
+
+handle_parse({listen, Opts} = _Instruction, State)
+ when is_list(Opts) ->
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {listen, Opts, MeybeRetry},
+ {ok, Instruction, State};
+
+handle_parse({listen, Opts, MeybeRetry} = Instruction, State)
+ when is_list(Opts) andalso is_function(MeybeRetry) ->
+ {ok, Instruction, State};
+
+handle_parse(connect = _Instruction, State) ->
+ case inet:gethostname() of
+ {ok, LocalHost} ->
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {connect, LocalHost, [], MeybeRetry},
+ {ok, Instruction, State};
+ Error ->
+ Error
+ end;
+
+handle_parse({connect, Opts} = _Instruction, State)
+ when is_list(Opts) ->
+ verify_connect_opts(Opts),
+ case inet:gethostname() of
+ {ok, LocalHost} ->
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {connect, LocalHost, Opts, MeybeRetry},
+ {ok, Instruction, State};
+ Error ->
+ Error
+ end;
+
+handle_parse({connect, Host} = _Instruction, State)
+ when is_atom(Host) ->
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {connect, Host, [], MeybeRetry},
+ {ok, Instruction, State};
+
+handle_parse({connect, Host, Opts} = _Instruction, State)
+ when (is_atom(Host) orelse is_list(Host)) andalso is_list(Opts) ->
+ verify_connect_opts(Opts),
+ MeybeRetry = make_connect_retry_fun2(),
+ Instruction = {connect, Host, Opts, MeybeRetry},
+ {ok, Instruction, State};
+
+handle_parse({connect, Host, Opts, MeybeRetry} = Instruction, State)
+ when (is_atom(Host) orelse is_list(Host)) andalso
+ is_list(Opts) andalso
+ is_function(MeybeRetry) ->
+ verify_connect_opts(Opts),
+ {ok, Instruction, State};
+
+handle_parse(disconnect = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_connect = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_connect, _} = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse(megaco_disconnect = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_disconnect, _Reason} = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_call, ARs, Opts} = Instruction, State)
+ when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_call, _Mid, ARs, Opts} = Instruction, State)
+ when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_cast, ARs, Opts} = Instruction, State)
+ when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_cast, _Mid, ARs, Opts} = Instruction, State)
+ when (is_list(ARs) orelse is_binary(ARs)) andalso is_list(Opts) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_cancel, _Reason} = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_callback, Tag, TimeoutOrVerify} = Instruction, State)
+ when (is_atom(Tag) andalso
+ ((is_integer(TimeoutOrVerify) andalso
+ (TimeoutOrVerify > 0)) orelse
+ is_function(TimeoutOrVerify))) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_callback, Tag, Verify, Timeout} = Instruction, State)
+ when (is_atom(Tag) andalso
+ is_function(Verify) andalso
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
+ {ok, Instruction, State};
+
+handle_parse({megaco_callback, Tag, {VMod, VFunc, VArgs}} = _Instruction,
+ State)
+ when (is_atom(Tag) andalso
+ (is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs))) ->
+ Verify = fun(X) ->
+ io:format("[megaco_callback ~w] calling ~w:~w with"
+ "~n X: ~p"
+ "~n VArgs: ~w"
+ "~n", [Tag, VMod, VFunc, X, VArgs]),
+ (catch apply(VMod, VFunc, [X|VArgs]))
+ end,
+ Instruction = {megaco_callback, Tag, Verify},
+ {ok, Instruction, State};
+
+handle_parse({megaco_callback, Verifiers0} = _Instruction, State)
+ when is_list(Verifiers0) ->
+ Verifiers = [make_verifier(Verifier) || Verifier <- Verifiers0],
+ Instruction = {megaco_callback, Verifiers},
+ {ok, Instruction, State};
+
+handle_parse({trigger, Trigger} = Instruction, State)
+ when is_function(Trigger) ->
+ {ok, Instruction, State};
+
+handle_parse(Instruction, _State) ->
+ error({invalid_instruction, Instruction}).
+
+
+make_verifier({Tag, No, VerifyFunc} = Verify)
+ when is_atom(Tag) andalso is_integer(No) andalso is_function(VerifyFunc) ->
+ Verify;
+make_verifier({Tag, No, {VMod, VFunc, VArgs}})
+ when is_atom(Tag) andalso is_integer(No) andalso
+ (is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs)) ->
+ VerifyFunc = fun(X) ->
+ io:format("[megaco_callback ~w] calling ~w:~w with"
+ "~n X: ~p"
+ "~n VArgs: ~w"
+ "~n", [Tag, VMod, VFunc, X, VArgs]),
+ (catch apply(VMod, VFunc, [X|VArgs]))
+ end,
+ Verify = {Tag, No, VerifyFunc},
+ Verify;
+make_verifier(BadVerifier) ->
+ error({bad_verifier, BadVerifier}).
+
+
+verify_connect_opts([]) ->
+ ok;
+verify_connect_opts([{Key, _}|Opts]) when is_atom(Key) ->
+ verify_connect_opts(Opts);
+verify_connect_opts([H|_]) ->
+ error({bad_opts_list, H}).
+
+%% make_connect_retry_fun1() ->
+%% fun(Error, _) ->
+%% {false, Error}
+%% end.
+
+make_connect_retry_fun2() ->
+ fun(Error, noError) ->
+ Timeout = 250,
+ sleep(random(Timeout) + 100),
+ {true, {3, Timeout*2, Error}};
+ (_Error, {0, _Timeout, OriginalError}) ->
+ {false, OriginalError};
+ (_Error, {N, Timeout, OriginalError}) ->
+ sleep(random(Timeout) + 100),
+ {true, {N-1, Timeout*2, OriginalError}}
+ end.
+
+
+%% ----- instruction exececutor -----
+
+handle_exec({debug, Debug}, State) ->
+ p("debug: ~p", [Debug]),
+ put(debug, Debug),
+ {ok, State};
+
+handle_exec({expect_nothing, To}, State) ->
+ p("expect_nothing: ~p", [To]),
+ receive
+ Any ->
+ error({expect_nothing, Any})
+ after To ->
+ {ok, State}
+ end;
+
+handle_exec({megaco_trace, disable}, State) ->
+ p("megaco trace: disable"),
+ megaco:disable_trace(),
+ {ok, State};
+handle_exec({megaco_trace, Level}, State) ->
+ p("megaco trace: enable [~w]", [Level]),
+ megaco:enable_trace(Level, io),
+ {ok, State};
+
+handle_exec(megaco_start, State) ->
+ p("megaco_start"),
+ ok = megaco:start(),
+ {ok, State};
+
+handle_exec(megaco_stop, State) ->
+ p("megaco_stop"),
+ ok = megaco:stop(),
+ {ok, State};
+
+handle_exec({megaco_start_user, Mid, RecvInfo, Conf}, State) ->
+ p("megaco_start_user: ~p", [Mid]),
+
+ d("megaco_start_user -> start user"),
+ ok = megaco:start_user(Mid, Conf),
+
+ d("megaco_start_user -> update user info: user_mod"),
+ ok = megaco:update_user_info(Mid, user_mod, ?MODULE),
+
+ d("megaco_start_user -> update user info: user_args"),
+ ok = megaco:update_user_info(Mid, user_args, [self()]),
+
+ Port = get_config(port, RecvInfo),
+ EM = get_config(encoding_module, RecvInfo),
+ EC = get_config(encoding_config, RecvInfo),
+ TM = get_config(transport_module, RecvInfo),
+ RH0 = megaco:user_info(Mid, receive_handle),
+
+ RH1 = RH0#megaco_receive_handle{send_mod = TM,
+ encoding_mod = EM,
+ encoding_config = EC},
+
+ State1 = State#state{mid = Mid, recv_handle = RH1, port = Port},
+ {ok, State1};
+
+handle_exec(megaco_stop_user, #state{mid = Mid} = State)
+ when Mid /= undefined ->
+ megaco_cleanup(State),
+ ok = megaco:stop_user(Mid),
+ {ok, State#state{mid = undefined}};
+
+handle_exec(start_transport, #state{recv_handle = RH} = State) ->
+ p("start_transport"),
+ #megaco_receive_handle{send_mod = TM} = RH,
+ case (catch TM:start_transport()) of
+ {ok, Sup} ->
+ d("start_transport -> Sup: ~p", [Sup]),
+ {ok, State#state{transport_sup = Sup}};
+ {error, Reason} ->
+ e("failed starting transport (~w): "
+ "~n ~p", [TM, Reason]),
+ error({failed_starting_transport, TM, Reason});
+ Crap ->
+ e("failed starting transport (~w): "
+ "~n ~p", [TM, Crap]),
+ error({failed_starting_transport, TM, Crap})
+ end;
+
+handle_exec({listen, Opts0, MaybeRetry},
+ #state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_tcp ->
+ p("listen(tcp)", []),
+ Opts = [{module, ?DELIVER_MOD},
+ {port, Port},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]} | Opts0],
+ case (catch handle_exec_listen_tcp(Pid, Opts, MaybeRetry)) of
+ ok ->
+ {ok, State};
+ Else ->
+ error({tcp_listen_failed, Opts0, Else})
+ end;
+handle_exec({listen, Opts0, _MaybeRetry},
+ #state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_udp ->
+ p("listen(udp) - open"),
+ Opts = [{module, ?DELIVER_MOD}, {port, Port}, {receive_handle, RH}|Opts0],
+ case (catch megaco_udp:open(Pid, Opts)) of
+ {ok, _SH, _CtrlPid} ->
+ {ok, State};
+ Else ->
+ error({udp_open, Opts0, Else})
+ end;
+handle_exec({listen, Opts0, _MaybeRetry},
+ #state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport ->
+ p("listen(generic)"),
+ Opts = [{module, ?DELIVER_MOD}, {port, Port}, {receive_handle, RH}|Opts0],
+ case (catch megaco_test_generic_transport:listen(Pid, Opts)) of
+ {ok, _SH, _CtrlPid} ->
+ {ok, State};
+ Else ->
+ error({udp_open, Opts0, Else})
+ end;
+
+handle_exec({connect, Host, Opts0, MaybeRetry},
+ #state{transport_sup = Sup,
+ recv_handle = RH,
+ port = Port} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_tcp ->
+ p("connect[megaco_tcp] to ~p:~p", [Host, Port]),
+ PrelMid = preliminary_mid,
+ Opts = [{host, Host},
+ {port, Port},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]} | Opts0],
+ case (catch handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry)) of
+ {ok, SH, ControlPid} ->
+ d("tcp connected: ~p, ~p", [SH, ControlPid]),
+ megaco_connector_start(RH, PrelMid, SH, ControlPid),
+ {ok, State#state{send_handle = SH,
+ ctrl_pid = ControlPid}};
+ Error ->
+ error({tcp_connect_failed, Host, Opts0, Error})
+ end;
+
+handle_exec({connect, Host, Opts0, _MaybeRetry},
+ #state{transport_sup = Sup,
+ recv_handle = RH,
+ port = Port} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_udp ->
+ p("connect[megaco_udp] to ~p", [Host]),
+ PrelMid = preliminary_mid,
+ Opts = [{port, 0}, {receive_handle, RH}|Opts0],
+ d("udp open", []),
+ case (catch megaco_udp:open(Sup, Opts)) of
+ {ok, Handle, ControlPid} ->
+ d("udp opened: ~p, ~p", [Handle, ControlPid]),
+ SH = megaco_udp:create_send_handle(Handle, Host, Port),
+ megaco_connector_start(RH, PrelMid, SH, ControlPid),
+ {ok, State#state{send_handle = SH,
+ ctrl_pid = ControlPid}};
+ Error ->
+ error({udp_connect_failed, Host, Opts0, Error})
+ end;
+
+handle_exec({connect, Host, Opts0, _MaybeRetry},
+ #state{transport_sup = Sup,
+ recv_handle = RH,
+ port = Port} = State)
+ when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport ->
+ p("connect[megaco_test_generic_transport] to ~p", [Host]),
+ PrelMid = preliminary_mid,
+ Opts = [{host, Host}, {port, Port}, {receive_handle, RH}|Opts0],
+ case (catch megaco_test_generic_transport:connect(Sup, Opts)) of
+ {ok, SH, ControlPid} ->
+ d("generic connected: ~p, ~p", [SH, ControlPid]),
+ megaco_connector_start(RH, PrelMid, SH, ControlPid),
+ {ok, State#state{send_handle = SH,
+ ctrl_pid = ControlPid}};
+ Error ->
+ error({generic_connect_failed, Host, Opts0, Error})
+ end;
+
+handle_exec(megaco_connect, State) ->
+ p("megaco_connect"),
+ receive
+ {megaco_connect_result, {ok, CH}} ->
+ p("megaco connect succeeded: ~p", [CH]),
+ {ok, State#state{conn_handle = CH}};
+ {megaco_connect_result, Error} ->
+ p("megaco connect failed: ~p", [Error]),
+ #state{result = Res} = State,
+ {ok, State#state{result = [Error|Res]}}
+ end;
+
+handle_exec({megaco_connect, Mid},
+ #state{recv_handle = RH,
+ send_handle = SH,
+ ctrl_pid = ControlPid} = State) ->
+ p("megaco_connect: ~p", [Mid]),
+ megaco_connector_start(RH, Mid, SH, ControlPid),
+ {ok, State};
+
+handle_exec({megaco_user_info, Tag}, #state{mid = Mid, result = Res} = State)
+ when Mid /= undefined ->
+ p("megaco_user_info: ~w", [Tag]),
+ Val = (catch megaco:user_info(Mid, Tag)),
+ d("megaco_user_info: ~p", [Val]),
+ {ok, State#state{result = [Val|Res]}};
+
+handle_exec({megaco_update_user_info, Tag, Val}, #state{mid = Mid} = State)
+ when Mid /= undefined ->
+ p("megaco_update_user_info: ~w -> ~p", [Tag, Val]),
+ ok = megaco:update_user_info(Mid, Tag, Val),
+ {ok, State};
+
+handle_exec({megaco_conn_info, Tag},
+ #state{conn_handle = CH, result = Res} = State)
+ when CH /= undefined ->
+ p("megaco_conn_info: ~w", [Tag]),
+ Val = (catch megaco:conn_info(CH, Tag)),
+ d("megaco_conn_info: ~p", [Val]),
+ {ok, State#state{result = [Val|Res]}};
+
+handle_exec({megaco_update_conn_info, Tag, Val},
+ #state{conn_handle = CH} = State)
+ when CH /= undefined ->
+ p("megaco_update_conn_info: ~w -> ~p", [Tag, Val]),
+ case megaco:update_conn_info(CH, Tag, Val) of
+ ok ->
+ {ok, State};
+ Error ->
+ error({failed_updating_conn_info, Tag, Val, Error})
+ end;
+
+handle_exec(megaco_info, #state{result = Res} = State) ->
+ p("megaco_info", []),
+ Val = (catch megaco:info()),
+ d("megaco_info: ~p", [Val]),
+ {ok, State#state{result = [Val|Res]}};
+
+handle_exec({megaco_system_info, Tag, Verify}, #state{result = Res} = State) ->
+ p("megaco_system_info: ~w", [Tag]),
+ Val = (catch megaco:system_info(Tag)),
+ d("megaco_system_info: ~p", [Val]),
+ case Verify(Val) of
+ ok ->
+ {ok, State#state{result = [Val|Res]}};
+ Error ->
+ {error, State#state{result = [Error|Res]}}
+ end;
+
+%% This is either a MG or a MGC which is only connected to one MG
+handle_exec({megaco_call, ARs, Opts}, #state{conn_handle = CH} = State)
+ when CH /= undefined ->
+ p("megaco_call"),
+ {_PV, UserReply} = megaco:call(CH, ARs, Opts),
+ d("megaco_call -> UserReply: ~n~p", [UserReply]),
+ {ok, State};
+
+handle_exec({megaco_call, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) ->
+ p("megaco_call: ~p", [RemoteMid]),
+ %% First we have to find the CH for this Mid
+ Conns = megaco:user_info(Mid, connections),
+ {value, {_, CH}} =
+ lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns),
+ {_PV, UserReply} = megaco:call(CH, ARs, Opts),
+ d("megaco_call -> UserReply: ~n~p", [UserReply]),
+ {ok, State};
+
+%% This is either a MG or a MGC which is only connected to one MG
+handle_exec({megaco_cast, ARs, Opts}, #state{conn_handle = CH} = State)
+ when CH =/= undefined ->
+ p("megaco_cast"),
+ case megaco:cast(CH, ARs, Opts) of
+ ok ->
+ {ok, State};
+ Error ->
+ d("failed sending (cast) message: ~n~p", [Error]),
+ #state{result = Acc} = State,
+ {error, State#state{result = [Error|Acc]}}
+ end;
+
+handle_exec({megaco_cast, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) ->
+ p("megaco_cast: ~p", [RemoteMid]),
+ %% First we have to find the CH for this Mid
+ Conns = megaco:user_info(Mid, connections),
+ {value, {_, CH}} =
+ lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns),
+ case megaco:cast(CH, ARs, Opts) of
+ ok ->
+ {ok, State};
+ Error ->
+ d("failed sending (cast) message: ~n~p", [Error]),
+ #state{result = Acc} = State,
+ {error, State#state{result = [Error|Acc]}}
+ end;
+
+%% Nothing shall happen for atleast Timeout time
+handle_exec({megaco_callback, nocall, Timeout}, State) ->
+ p("megaco_callback [~w,~w]", [nocall, Timeout]),
+ receive
+ {handle_megaco_callback, Type, Msg, Pid} ->
+ d("received unexpected megaco callback: ~n~p", [Msg]),
+ #state{result = Res} = State,
+ Err = {unexpected_callback, Type, Msg, Pid},
+ {error, State#state{result = [Err|Res]}}
+ after Timeout ->
+ {ok, State}
+ end;
+
+handle_exec({megaco_callback, Tag, Verify}, State) when is_function(Verify) ->
+ p("megaco_callback [~w]", [Tag]),
+ receive
+ {handle_megaco_callback, Type, Msg, Pid} ->
+ d("received megaco callback: ~n~p", [Msg]),
+ case Verify(Msg) of
+ {VRes, Res, Reply} ->
+ d("megaco_callback [~w] ~w",[Tag, VRes]),
+ handle_megaco_callback_reply(Pid, Type, Reply),
+ validate(VRes, Tag, Res, State);
+ {VRes, Delay, Res, Reply} ->
+ d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]),
+ handle_megaco_callback_reply(Pid, Type, Delay, Reply),
+ validate(VRes, Tag, Res, State)
+ end
+ end;
+
+handle_exec({megaco_callback, Tag, {VMod, VFunc, VArgs}}, State)
+ when is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs) ->
+ p("megaco_callback [~w]", [Tag]),
+ receive
+ {handle_megaco_callback, Type, Msg, Pid} ->
+ d("received megaco callback: ~n~p"
+ "~n VMod: ~w"
+ "~n VFunc: ~w"
+ "~n VArgs: ~p", [Msg, VMod, VFunc, VArgs]),
+ case apply(VMod, VFunc, [Msg|VArgs]) of
+ {VRes, Res, Reply} ->
+ d("megaco_callback [~w] ~w",[Tag, VRes]),
+ handle_megaco_callback_reply(Pid, Type, Reply),
+ validate(VRes, Tag, Res, State);
+ {VRes, Delay, Res, Reply} ->
+ d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]),
+ handle_megaco_callback_reply(Pid, Type, Delay, Reply),
+ validate(VRes, Tag, Res, State)
+ end
+ end;
+
+handle_exec({megaco_callback, Tag, Verify, Timeout}, State)
+ when (is_function(Verify) andalso
+ (is_integer(Timeout) andalso (Timeout > 0))) ->
+ p("megaco_callback [~w]", [Tag]),
+ receive
+ {handle_megaco_callback, Type, Msg, Pid} ->
+ d("received megaco callback: ~n~p", [Msg]),
+ case Verify(Msg) of
+ {VRes, Res, Reply} ->
+ d("megaco_callback [~w] ~w",[Tag,VRes]),
+ handle_megaco_callback_reply(Pid, Type, Reply),
+ validate(VRes, Tag, Res, State);
+ {VRes, Delay, Res, Reply} ->
+ d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]),
+ handle_megaco_callback_reply(Pid, Type, Delay, Reply),
+ validate(VRes, Tag, Res, State)
+ end
+ after Timeout ->
+ #state{result = Res} = State,
+ Err = {callback_timeout, Tag, Timeout},
+ {error, State#state{result = [Err|Res]}}
+ end;
+
+handle_exec({megaco_callback, Verifiers}, State) ->
+ p("megaco_callback"),
+ megaco_callback_verify(Verifiers, State);
+
+handle_exec({megaco_cancel, Reason}, #state{conn_handle = CH} = State) ->
+ p("megaco_cancel [~w]", [Reason]),
+ case megaco:cancel(CH, Reason) of
+ ok ->
+ {ok, State};
+ Error ->
+ d("failed cancel: ~n~p", [Error]),
+ #state{result = Acc} = State,
+ {error, State#state{result = [Error|Acc]}}
+ end;
+
+handle_exec({trigger, Trigger}, State) when is_function(Trigger) ->
+ p("trigger"),
+ (catch Trigger()),
+ {ok, State};
+
+handle_exec({sleep, To}, State) ->
+ p("sleep ~p", [To]),
+ megaco_test_generator:sleep(To),
+ {ok, State};
+
+handle_exec(BadInstruction, _State) ->
+ error({invalid_instruction, BadInstruction}).
+
+
+%% --- cleanup ---
+
+megaco_cleanup(#state{mid = Mid}) ->
+ Close = fun(CH) -> do_megaco_cleanup(CH) end,
+ Conns =
+ case (catch megaco:user_info(Mid, connections)) of
+ Connections when is_list(Connections) ->
+ Connections;
+ _ ->
+ []
+ end,
+ lists:foreach(Close, Conns).
+
+do_megaco_cleanup(CH) ->
+ case (catch do_megaco_cleanup2(CH)) of
+ ok ->
+ ok;
+ {'EXIT', {no_such_connection, _}} ->
+ ok;
+ {'EXIT', Reason} ->
+ exit(Reason)
+ end.
+
+do_megaco_cleanup2(CH) ->
+ d("do_megaco_cleanup2 -> entry with"
+ "~n CH: ~p", [CH]),
+ Reason = {stopped_by_user,self()},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ d("do_megaco_cleanup2 -> disconnect"),
+ megaco:disconnect(CH, Reason),
+ d("do_megaco_cleanup2 -> disconnected, now cancel"),
+ megaco:cancel(CH, Reason),
+ d("do_megaco_cleanup2 -> canceled, now close"),
+ case SendMod of
+ megaco_tcp -> (catch megaco_tcp:close(SendHandle));
+ megaco_udp -> (catch megaco_udp:close(SendHandle));
+ SendMod -> exit(Pid, Reason)
+ end,
+ ok.
+
+
+%% --- connector ---
+
+megaco_connector_start(RH, PrelMid, SH, ControlPid) ->
+ Self = self(),
+ Fun = fun() -> megaco_connect(RH, PrelMid, SH, ControlPid, Self) end,
+ erlang:spawn_opt(Fun, [link]).
+
+megaco_connect(RH, PrelMid, SH, ControlPid, Parent) ->
+ Result = megaco:connect(RH, PrelMid, SH, ControlPid),
+ Parent ! {megaco_connect_result, Result},
+ exit(normal).
+
+
+%% --- megaco callback verify ---
+
+%% This is used when a number of callback's is expected, but where
+%% the specific order is unknown.
+megaco_callback_verify([], State) ->
+ d("megaco_callback_verify -> done"),
+ {ok, State};
+megaco_callback_verify(Verifiers0, State0) ->
+ d("megaco_callback_verify -> entry when"
+ "~n length(Verifiers0): ~w", [length(Verifiers0)]),
+ receive
+ {handle_megaco_callback, Type, Msg, Pid} ->
+ d("megaco_callback_verify -> received megaco callback: ~w"
+ "~n Msg: ~p", [Type, Msg]),
+ case megaco_callback_verify(Verifiers0, Type, Msg, Pid, State0) of
+ {ok, Verifiers, State} ->
+ megaco_callback_verify(Verifiers, State);
+ Error ->
+ Error
+ end
+ end.
+
+megaco_callback_verify(Verifiers0, Type, Msg, Pid, State0) ->
+ d("megaco_callback_verify -> entry"),
+ Tag = element(1, Msg),
+ d("megaco_callback_verify -> Tag: ~w", [Tag]),
+ case lists:keysearch(Tag, 1, Verifiers0) of
+ {value, {Tag, N, Verify}} when (N > 0) andalso is_function(Verify) ->
+ d("megaco_callback_verify -> N: ~w",[N]),
+ case Verify(Msg) of
+ {VRes, Res, Reply} ->
+ d("megaco_callback_verify -> VRes: ~w",[VRes]),
+ handle_megaco_callback_reply(Pid, Type, Reply),
+ case validate(VRes, Tag, Res, State0) of
+ {error, _} = EState ->
+ e("megaco_callback_verify -> (1) error", []),
+ throw(EState);
+ {ok, State} when N > 1 ->
+ d("megaco_callback_verify -> (1) validated"),
+ Rec = {Tag, N-1, Verify},
+ Verifiers =
+ lists:keyreplace(Tag, 1, Verifiers0, Rec),
+ {ok, Verifiers, State};
+ {ok, State} ->
+ d("megaco_callback_verify -> (2) validated"),
+ Verifiers = lists:keydelete(Tag, 1, Verifiers0),
+ {ok, Verifiers, State}
+ end;
+ {VRes, Delay, Res, Reply} ->
+ d("megaco_callback_verify -> Delay: ~w, VRes: ~w",
+ [Delay,VRes]),
+ handle_megaco_callback_reply(Pid, Type, Delay, Reply),
+ case validate(VRes, Tag, Res, State0) of
+ {error, _} = EState ->
+ e("megaco_callback_verify -> (2) error", []),
+ throw(EState);
+ {ok, State} when N > 1 ->
+ d("megaco_callback_verify -> (3) validated"),
+ Rec = {Tag, N-1, Verify},
+ Verifiers =
+ lists:keyreplace(Tag, 1, Verifiers0, Rec),
+ {ok, Verifiers, State};
+ {ok, State} ->
+ d("megaco_callback_verify -> (4) validated"),
+ Verifiers = lists:keydelete(Tag, 1, Verifiers0),
+ {ok, Verifiers, State}
+ end
+ end;
+ false ->
+ e("megaco_callback_verify -> no such tag ~w~n~p",
+ [Tag, Verifiers0]),
+ #state{result = Res} = State0,
+ State = State0#state{result = [{Type, error, Msg}|Res]},
+ error(State)
+ end.
+
+
+%% --- validate verify result ---
+
+validate(ok, handle_connect = Tag, CH, #state{result = Acc} = S) ->
+ {ok, S#state{conn_handle = CH, result = [{Tag, ok, CH}|Acc]}};
+validate(ok, Tag, Res, #state{result = Acc} = S) ->
+ {ok, S#state{result = [{Tag, ok, Res}|Acc]}};
+validate(error, Tag, Res, #state{result = Acc} = S) ->
+ {error, S#state{result = [{Tag, error, Res}|Acc]}}.
+
+
+%% ----- termination -----
+
+terminate(normal, #state{result = Result} = _State) ->
+ d("terminate -> entry when normal with"
+ "~n Result: ~p", [Result]),
+ %% megaco_cleanup(State),
+ {ok, Result};
+
+terminate(Reason, #state{result = Result} = State) ->
+ d("terminate -> entry with"
+ "~n Reason: ~p"
+ "~n Result: ~p", [Reason, Result]),
+ megaco_cleanup(State),
+ {error, {Reason, Result}}.
+
+
+%%----------------------------------------------------------------------
+
+handle_exec_listen_tcp(Sup, Opts, MaybeRetry) ->
+ handle_exec_listen_tcp(Sup, Opts, MaybeRetry, noError).
+
+handle_exec_listen_tcp(Sup, Opts, MaybeRetry, Error0) ->
+ case (catch megaco_tcp:listen(Sup, Opts)) of
+ ok ->
+ ok;
+ Error1 ->
+ case (catch MaybeRetry(Error1, Error0)) of
+ {true, Error2} ->
+ handle_exec_listen_tcp(Sup, Opts, MaybeRetry, Error2);
+ {false, Error3} ->
+ {error, Error3}
+ end
+ end.
+
+
+handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry)
+ when is_function(MaybeRetry) ->
+ handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry, noError).
+
+handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry, Error0) ->
+ case (catch megaco_tcp:connect(Sup, Opts)) of
+ {ok, SH, ControlPid} ->
+ d("tcp connected: ~p, ~p", [SH, ControlPid]),
+ {ok, SH, ControlPid};
+ Error1 ->
+ case (catch MaybeRetry(Error1, Error0)) of
+ {true, Error2} ->
+ handle_exec_connect_tcp(Host, Opts, Sup,
+ MaybeRetry, Error2);
+ {false, Error3} ->
+ {error, Error3}
+ end
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%% megaco_user callback functions
+%%----------------------------------------------------------------------
+
+handle_connect(CH, PV, P) ->
+ Req = {handle_connect, CH, PV},
+ handle_megaco_callback_call(P, Req).
+
+handle_connect(CH, PV, Extra, P) ->
+ Req = {handle_connect, CH, PV, Extra},
+ handle_megaco_callback_call(P, Req).
+
+handle_disconnect(CH, PV, R, P) ->
+ Msg = {handle_disconnect, CH, PV, R},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_syntax_error(RH, PV, ED, P) ->
+ Req = {handle_syntax_error, RH, PV, ED},
+ handle_megaco_callback_call(P, Req).
+
+handle_syntax_error(RH, PV, ED, Extra, P) ->
+ Req = {handle_syntax_error, RH, PV, ED, Extra},
+ handle_megaco_callback_call(P, Req).
+
+handle_message_error(CH, PV, ED, P) ->
+ Msg = {handle_message_error, CH, PV, ED},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_message_error(CH, PV, ED, Extra, P) ->
+ Msg = {handle_message_error, CH, PV, ED, Extra},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_request(CH, PV, AR, P) ->
+ Req = {handle_trans_request, CH, PV, AR},
+ handle_megaco_callback_call(P, Req).
+
+handle_trans_request(CH, PV, AR, Extra, P) ->
+ Req = {handle_trans_request, CH, PV, AR, Extra},
+ handle_megaco_callback_call(P, Req).
+
+handle_trans_long_request(CH, PV, RD, P) ->
+ Req = {handle_trans_long_request, CH, PV, RD},
+ handle_megaco_callback_call(P, Req).
+
+handle_trans_long_request(CH, PV, RD, Extra, P) ->
+ Req = {handle_trans_long_request, CH, PV, RD, Extra},
+ handle_megaco_callback_call(P, Req).
+
+handle_trans_reply(CH, PV, AR, RD, P) ->
+ Msg = {handle_trans_reply, CH, PV, AR, RD},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_reply(CH, PV, AR, RD, Extra, P) ->
+ Msg = {handle_trans_reply, CH, PV, AR, RD, Extra},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_ack(CH, PV, AS, AD, P) ->
+ Msg = {handle_trans_ack, CH, PV, AS, AD},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_ack(CH, PV, AS, AD, Extra, P) ->
+ Msg = {handle_trans_ack, CH, PV, AS, AD, Extra},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_unexpected_trans(CH, PV, T, P) ->
+ Msg = {handle_unexpected_trans, CH, PV, T},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_unexpected_trans(CH, PV, T, Extra, P) ->
+ Msg = {handle_unexpected_trans, CH, PV, T, Extra},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_request_abort(RH, PV, TransNo, Pid, P) ->
+ Msg = {handle_trans_request_abort, RH, PV, TransNo, Pid},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_trans_request_abort(RH, PV, TransNo, Pid, Extra, P) ->
+ Msg = {handle_trans_request_abort, RH, PV, TransNo, Pid, Extra},
+ Reply = ok,
+ handle_megaco_callback_cast(P, Msg, Reply).
+
+handle_megaco_callback_cast(P, Msg, Reply) ->
+ p("handle_megaco_callback_cast -> entry with Msg: ~n~p", [Msg]),
+ P ! {handle_megaco_callback, cast, Msg, self()},
+ Reply.
+
+handle_megaco_callback_call(P, Msg) ->
+ p("handle_megaco_callback_call -> entry with"
+ "~n P: ~p"
+ "~n Msg: ~p", [P, Msg]),
+ P ! {handle_megaco_callback, call, Msg, self()},
+ receive
+ {handle_megaco_callback_reply, Reply} ->
+ p("handle_megaco_callback_call -> received reply: ~n~p", [Reply]),
+ Reply;
+ {handle_megaco_callback_reply, Delay, Reply} when is_integer(Delay) ->
+ p("handle_megaco_callback_call -> "
+ "received reply [~w]: "
+ "~n ~p", [Delay, Reply]),
+ sleep(Delay),
+ p("handle_megaco_callback_call -> deliver reply after delay [~w]",
+ [Delay]),
+ Reply;
+ {'EXIT', SomePid, SomeReason} ->
+ p("handle_megaco_callback_call -> "
+ "received unexpected EXIT signal: "
+ "~n SomePid: ~p"
+ "~n SomeReason: ~p", [SomePid, SomeReason]),
+ exit({unexpected_EXIT_signal, SomePid, SomeReason})
+ end.
+
+
+handle_megaco_callback_reply(P, call, Reply) ->
+ P ! {handle_megaco_callback_reply, Reply};
+handle_megaco_callback_reply(_, _, _) ->
+ ok.
+
+handle_megaco_callback_reply(P, call, Delay, Reply) ->
+ P ! {handle_megaco_callback_reply, Delay, Reply};
+handle_megaco_callback_reply(_, _, _, _) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% internal utility functions
+%%----------------------------------------------------------------------
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random(N) ->
+ random:uniform(N).
+
+
+get_config(Key, Opts) ->
+ {value, {Key, Val}} = lists:keysearch(Key, 1, Opts),
+ Val.
+
+sleep(X) -> megaco_test_generator:sleep(X).
+
+d(F) -> megaco_test_generator:debug(F).
+d(F, A) -> megaco_test_generator:debug(F, A).
+
+e(F, A) -> megaco_test_generator:error(F, A).
+
+p(F ) -> p("", F, []).
+p(F, A) -> p("", F, A).
+p(P, F, A) -> megaco_test_generator:print(P, F, A).
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/megaco/test/megaco_test_mg.erl b/lib/megaco/test/megaco_test_mg.erl
new file mode 100644
index 0000000000..22b65a1ac6
--- /dev/null
+++ b/lib/megaco/test/megaco_test_mg.erl
@@ -0,0 +1,1585 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Implements an "MG" used by the test suite
+%%----------------------------------------------------------------------
+-module(megaco_test_mg).
+
+-export([start/5, start/6, stop/1,
+ get_stats/1, reset_stats/1,
+ user_info/1, user_info/2,
+ update_user_info/3,
+ conn_info/1, conn_info/2,
+ update_conn_info/3,
+ service_change/1,
+ ack_info/2, rep_info/2,
+ group_requests/2,
+ notify_request/1,
+ await_notify_reply/1,
+ notify_request_and_reply/1,
+ cancel_request/2,
+ apply_load/2,
+ apply_multi_load/3,
+ enable_test_code/4,
+ encode_ar_first/2,
+ verbosity/2]).
+
+-export([mg/3, notify_request_handler_main/5]).
+-export([loader_main/4]).
+
+%% Megaco callback api
+-export([
+ handle_connect/4,
+ handle_disconnect/5,
+ handle_syntax_error/5,
+ handle_message_error/5,
+ handle_trans_request/5,
+ handle_trans_long_request/5,
+ handle_trans_reply/6,
+ handle_trans_ack/6
+ ]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(A4444, tid(255*256*256) ).
+-define(A4445, tid(255*256*256 + 255) ).
+-define(A5555, tid(255*256*256 + 255*256) ).
+-define(A5556, tid(255*256*256 + 255*256 + 255) ).
+
+-record(mg, {mid = undefined,
+ state = initiated,
+ req_handler = undefined,
+ call_mode = async,
+ group_size = 1,
+ encode_ar_first = false,
+ ack_info = undefined,
+ rep_info = undefined,
+ load_counter = 0,
+ reply_counter = 0,
+ mload_info = undefined,
+ parent = undefined,
+ dsi_timer}).
+
+
+%%% --------------------------------------------------------------------
+
+start(Node, Mid, Encoding, Transport, Verbosity) ->
+ %% Conf = [{megaco_trace, io}],
+ %% Conf = [{megaco_trace, "megaco-mg.trace"}],
+ Conf = [{megaco_trace, false}],
+ start(Node, Mid, Encoding, Transport, Conf, Verbosity).
+
+start(Node, Mid, Encoding, Transport, Conf, Verbosity) ->
+ d("start mg[~p]: ~p"
+ "~n Encoding: ~p"
+ "~n Transport: ~p"
+ "~n Conf: ~p", [Node, Mid, Encoding, Transport, Conf]),
+ RI1 = encoding_config(Encoding),
+ RI2 = transport_config(Transport),
+ {RI3, Conf1} = transport_opts(Conf),
+ RI = {receive_info, RI1 ++ RI2 ++ RI3},
+ Config = [{local_mid, Mid}, RI] ++ Conf1,
+ Self = self(),
+ Fun =
+ fun() ->
+ io:format("LOADER(~p,~p) started~n", [self(),node()]),
+ case (catch mg(Self, Verbosity, Config)) of
+ {'EXIT', Reason} ->
+ io:format("LOADER(~p,~p) terminating with exit"
+ "~n~p"
+ "~n", [self(), node(), Reason]),
+ exit(Reason);
+ Else ->
+ io:format("LOADER(~p,~p) terminating with"
+ "~n~p"
+ "~n", [self(), node(), Else]),
+ Else
+ end
+ end,
+ true = erlang:monitor_node(Node, true),
+ Pid = spawn_link(Node, Fun),
+ %% Pid = spawn_link(Node, ?MODULE, mg, [self(), Verbosity, Config]),
+ MonRef = (catch erlang:monitor(process, Pid)),
+ NodePing = net_adm:ping(Node),
+ ProcInfo = (catch proc_info(Pid)),
+ i("start -> "
+ "~n self(): ~p"
+ "~n node(): ~p"
+ "~n net_adm:ping(~p): ~p"
+ "~n Loader: ~p"
+ "~n Monitor ref: ~p"
+ "~n Process info: ~p",
+ [self(), node(),
+ Node, NodePing,
+ Pid,
+ MonRef, ProcInfo]),
+ await_started(Node, MonRef, Pid).
+
+proc_info(Pid) ->
+ rpc:call(node(Pid), erlang, process_info, [Pid]).
+
+encoding_config({Encoding, EC}) when is_atom(Encoding) andalso is_list(EC) ->
+ {Mod, Port} = select_encoding(Encoding),
+ [{encoding_module, Mod},
+ {encoding_config, EC},
+ {port, Port}];
+encoding_config(Encoding) when is_atom(Encoding) ->
+ {Mod, Port} = select_encoding(Encoding),
+ [{encoding_module, Mod},
+ {encoding_config, []},
+ {port, Port}];
+encoding_config(Encoding) ->
+ throw({error, {invalid_encoding, Encoding}}).
+
+select_encoding(text) ->
+ {megaco_pretty_text_encoder, 2944};
+select_encoding(pretty_text) ->
+ {megaco_pretty_text_encoder, 2944};
+select_encoding(compact_text) ->
+ {megaco_compact_text_encoder, 2944};
+select_encoding(binary) ->
+ {megaco_ber_bin_encoder, 2945};
+select_encoding(erl_dist) ->
+ {megaco_erl_dist_encoder, 2946};
+select_encoding(Encoding) ->
+ throw({error, {invalid_encoding, Encoding}}).
+
+transport_config(tcp) ->
+ [{transport_module, megaco_tcp}];
+transport_config(udp) ->
+ [{transport_module, megaco_udp}];
+transport_config(TransportConfig) when is_list(TransportConfig) ->
+ {value, {transport, Trans}} =
+ lists:keysearch(transport, 1, TransportConfig),
+ transport_config(Trans) ++
+ case lists:keysearch(host, 1, TransportConfig) of
+ {value, Value} ->
+ [Value];
+ false ->
+ []
+ end.
+
+transport_opts(Config) ->
+ case lists:keysearch(transport_opts, 1, Config) of
+ {value, TO} ->
+ Config1 = lists:keydelete(transport_opts, 1, Config),
+ {[TO], Config1};
+ false ->
+ {[], Config}
+ end.
+
+
+await_started(Node, MonRef, Pid) ->
+ i("await_started -> entry with"
+ "~n MonRef: ~p"
+ "~n Pid: ~p", [MonRef, Pid]),
+ receive
+ {started, Pid} ->
+ d("await_started ~p - started"
+ "~n Process info: ~p", [Pid, (catch proc_info(Pid))]),
+ true = erlang:monitor_node(Node, false),
+ erlang:demonitor(MonRef),
+ {ok, Pid};
+
+ {nodedown, Node} ->
+ i("await_started ~p - received node down", [Pid]),
+ exit({node_down, Node});
+
+ {'DOWN', MonRef, process, Pid, Info} ->
+ i("await_started ~p - received down signal: ~p",
+ [Pid, Info]),
+ true = erlang:monitor_node(Node, false),
+ exit({failed_starting, Pid, Info});
+
+ {'EXIT', Pid, Reason} ->
+ i("await_started ~p - received exit signal: ~p", [Pid, Reason]),
+ true = erlang:monitor_node(Node, false),
+ exit({failed_starting, Pid, Reason})
+
+ %% This timeout was originally 10 secs, but on some debug compiled
+ %% platforms, it was simply not long enough
+ after 20000 ->
+ NodePing = net_adm:ping(Node),
+ ProcInfo = (catch proc_info(Pid)),
+ FlushQ = megaco_test_lib:flush(),
+ i("await_started ~p - timeout: "
+ "~n net_adm:ping(~p): ~p"
+ "~n Process info: ~p"
+ "~n Messages in my queue: ~p",
+ [Pid, Node, NodePing, ProcInfo, FlushQ]),
+ true = erlang:monitor_node(Node, false),
+ exit({error, timeout})
+ end.
+
+
+verbosity(Pid, V) ->
+ Pid ! {verbosity, V, self()}.
+
+
+stop(Pid) ->
+ server_request(Pid, stop, stopped).
+
+
+get_stats(Pid) ->
+ server_request(Pid, statistics, statistics_reply).
+
+reset_stats(Pid) ->
+ server_request(Pid, reset_stats, reset_stats_ack).
+
+
+user_info(Pid) ->
+ server_request(Pid, {user_info, all}, user_info_ack).
+
+user_info(Pid, Tag) when is_atom(Tag) ->
+ server_request(Pid, {user_info, Tag}, user_info_ack).
+
+
+update_user_info(Pid, Tag, Val) ->
+ server_request(Pid, {update_user_info, Tag, Val}, update_user_info_ack).
+
+
+conn_info(Pid) ->
+ server_request(Pid, {conn_info, all}, conn_info_ack).
+
+conn_info(Pid, Tag) when is_atom(Tag) ->
+ server_request(Pid, {conn_info, Tag}, conn_info_ack).
+
+
+update_conn_info(Pid, Tag, Val) ->
+ server_request(Pid, {update_conn_info, Tag, Val}, update_conn_info_ack).
+
+
+enable_test_code(Pid, Module, Where, Fun)
+ when is_atom(Module) andalso is_atom(Where) andalso is_function(Fun) ->
+ Tag = {Module, Where},
+ server_request(Pid, {enable_test_code, Tag, Fun}, enable_test_code_reply).
+
+encode_ar_first(Pid, New) when is_atom(New) ->
+ server_request(Pid, {encode_ar_first, New}, encode_ar_first_reply).
+
+service_change(Pid) ->
+ server_request(Pid, service_change, service_change_reply).
+
+
+group_requests(Pid, N) ->
+ server_request(Pid, {group_requests, N}, group_requests_reply).
+
+
+ack_info(Pid, InfoPid) ->
+ Pid ! {{ack_info, InfoPid}, self()}.
+
+rep_info(Pid, InfoPid) ->
+ Pid ! {{rep_info, InfoPid}, self()}.
+
+
+notify_request(Pid) ->
+ Pid ! {notify_request, self()}.
+
+
+await_notify_reply(Pid) ->
+ await_reply(Pid, notify_request_reply).
+
+
+notify_request_and_reply(Pid) ->
+ notify_request(Pid),
+ await_notify_reply(Pid).
+
+
+cancel_request(Pid, Reason) ->
+ server_request(Pid, cancel_request, Reason, cancel_request_reply).
+
+
+apply_load(Pid, CounterStart) ->
+ server_request(Pid, apply_load, CounterStart, apply_load_ack).
+
+
+apply_multi_load(Pid, NumLoaders, NumReq) ->
+ server_request(Pid, apply_multi_load, {NumLoaders, NumReq}, apply_multi_load_ack).
+
+
+server_request(Pid, Req, ReplyTag) ->
+ Pid ! {Req, self()},
+ await_reply(Pid, ReplyTag).
+
+server_request(Pid, Req, ReqData, ReplyTag) ->
+ Pid ! {Req, ReqData, self()},
+ await_reply(Pid, ReplyTag).
+
+await_reply(Pid, ReplyTag) ->
+ await_reply(Pid, ReplyTag, infinity).
+
+await_reply(Pid, ReplyTag, Timeout) ->
+ receive
+ {ReplyTag, Reply, Pid} ->
+ Reply;
+ {'EXIT', Pid, Reason} ->
+ exit({failed, ReplyTag, Pid, Reason})
+ after Timeout ->
+ exit({timeout, ReplyTag, Pid})
+ end.
+
+
+server_reply(Pid, ReplyTag, Reply) ->
+ Pid ! {ReplyTag, Reply, self()}.
+
+
+%%% --------------------------------------------------------------------
+
+
+mg(Parent, Verbosity, Config) ->
+ process_flag(trap_exit, true),
+ put(sname, "MG"),
+ %% put(verbosity, Verbosity),
+ put(verbosity, debug), % Enable debug printouts during init
+ i("mg -> starting"),
+ %% megaco:enable_trace(max, io),
+ case (catch init(Config)) of
+ {error, _} = Error ->
+ exit(Error);
+ {'EXIT', Reason} ->
+ exit({init_failed, Reason});
+ {ok, Mid, DSITimer} ->
+ notify_started(Parent),
+ MG = #mg{parent = Parent, mid = Mid, dsi_timer = DSITimer},
+ i("mg -> started"),
+ put(verbosity, Verbosity),
+ case (catch loop(MG)) of
+ {'EXIT', normal} ->
+ exit(normal);
+ {'EXIT', Reason} ->
+ i("mg failed with reason:~n ~p", [Reason]),
+ exit(Reason);
+ Else ->
+ i("mg terminated: ~n ~p", [Else]),
+ exit({unexpected, Else})
+ end
+ end.
+
+init(Config) ->
+ d("init -> entry with"
+ "~n Config: ~p", [Config]),
+ random_init(),
+ d("init -> random initiated", []),
+ Mid = get_conf(local_mid, Config),
+ d("init -> Mid: ~p", [Mid]),
+ RI = get_conf(receive_info, Config),
+ d("init -> RI: ~p", [RI]),
+
+ d("init -> maybe start the display system info timer"),
+ DSITimer =
+ case get_conf(display_system_info, Config, undefined) of
+ Time when is_integer(Time) ->
+ d("init -> creating display system info timer"),
+ create_timer(Time, display_system_info);
+ _ ->
+ undefined
+ end,
+ Conf0 = lists:keydelete(display_system_info, 1, Config),
+
+ d("init -> start megaco"),
+ application:start(megaco),
+
+
+ d("init -> possibly enable megaco trace"),
+ case lists:keysearch(megaco_trace, 1, Conf0) of
+ {value, {megaco_trace, true}} ->
+ megaco:enable_trace(max, io);
+ {value, {megaco_trace, io}} ->
+ megaco:enable_trace(max, io);
+ {value, {megaco_trace, File}} when is_list(File) ->
+ megaco:enable_trace(max, File);
+ _ ->
+ ok
+ end,
+ Conf1 = lists:keydelete(megaco_trace, 1, Conf0),
+
+ d("init -> start megaco user"),
+ Conf2 = lists:keydelete(local_mid, 1, Conf1),
+ Conf3 = lists:keydelete(receive_info, 1, Conf2),
+ ok = megaco:start_user(Mid, Conf3),
+ d("init -> update user info (user_mod)"),
+ ok = megaco:update_user_info(Mid, user_mod, ?MODULE),
+ d("init -> update user info (user_args)"),
+ ok = megaco:update_user_info(Mid, user_args, [self(), Mid]),
+
+ d("init -> get user info (receive_handle)"),
+ RH = megaco:user_info(Mid, receive_handle),
+ d("init -> parse receive info"),
+ {MgcPort, MgcHost, RH1, TO} = parse_receive_info(RI, RH),
+ d("init -> start transport (with ~p)", [TO]),
+ {ok, _CH} = start_transport(MgcPort, MgcHost, RH1, TO),
+ {ok, Mid, DSITimer}.
+
+
+loop(#mg{parent = Parent, mid = Mid} = S) ->
+ d("loop -> await request", []),
+ receive
+ {display_system_info, Time} ->
+ display_system_info(S#mg.mid),
+ NewTimer = create_timer(Time, display_system_info),
+ loop(S#mg{dsi_timer = NewTimer});
+
+ {verbosity, V, Parent} ->
+ i("loop -> received new verbosity: ~p", [V]),
+ put(verbosity,V),
+ loop(S);
+
+
+ {stop, Parent} ->
+ i("loop -> stopping", []),
+ display_system_info(S#mg.mid, "at finish "),
+ cancel_timer(S#mg.dsi_timer),
+ Res = do_stop(Mid),
+ d("loop -> stop result: ~p", [Res]),
+ server_reply(Parent, stopped, {ok, Res}),
+ exit(normal);
+
+ {{enable_test_code, Tag, Fun}, Parent} ->
+ i("loop -> enable_test_code: ~p, ~p", [Tag, Fun]),
+ Reply = (catch ets:insert(megaco_test_data, {Tag, Fun})),
+ d("loop -> enable_test_code -> "
+ "~n Reply: ~p"
+ "~n ets:tab2list(megaco_test_data): ~p",
+ [Reply,ets:tab2list(megaco_test_data)]),
+ server_reply(Parent, enable_test_code_reply, Reply),
+ loop(S);
+
+ {{encode_ar_first, EAF}, Parent} ->
+ i("loop -> encode_ar_first: ~p", [EAF]),
+ {Reply, S1} = handle_encode_ar_first(S, EAF),
+ server_reply(Parent, encode_ar_first_reply, Reply),
+ loop(S1#mg{encode_ar_first = EAF});
+
+ %% Give me statistics
+ {statistics, Parent} ->
+ i("loop -> got request for statistics", []),
+ Stats = do_get_statistics(Mid),
+ server_reply(Parent, statistics_reply, {ok, Stats}),
+ loop(S);
+
+ {reset_stats, Parent} ->
+ i("loop -> got request to reset stats counters", []),
+ do_reset_stats(Mid),
+ server_reply(Parent, reset_stats_ack, ok),
+ loop(S);
+
+ {{user_info, Tag}, Parent} ->
+ i("loop -> got user_info request for ~w", [Tag]),
+ Res = do_get_user_info(Mid, Tag),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, user_info_ack, Res),
+ loop(S);
+
+ {{update_user_info, Tag, Val}, Parent} ->
+ i("loop -> got update_user_info: ~w -> ~p", [Tag, Val]),
+ Res = do_update_user_info(Mid, Tag, Val),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, update_user_info_ack, Res),
+ loop(S);
+
+ {{conn_info, Tag}, Parent} ->
+ i("loop -> got conn_info request for ~w", [Tag]),
+ Res = do_get_conn_info(Mid, Tag),
+ server_reply(Parent, conn_info_ack, Res),
+ loop(S);
+
+ {{update_conn_info, Tag, Val}, Parent} ->
+ i("loop -> got update_conn_info: ~w -> ~p", [Tag, Val]),
+ Res = do_update_conn_info(Mid, Tag, Val),
+ server_reply(Parent, update_conn_info_ack, Res),
+ loop(S);
+
+
+ %% Do a service change
+ %% No server-reply here. Since the service change is
+ %% async, the reply (from the MGC) will come later.
+ {service_change, Parent} ->
+ i("loop -> received request to perform service change", []),
+ S1 =
+ case (catch do_service_change(S)) of
+ {ok, MG} ->
+ d("loop -> service change initiated", []),
+ MG;
+ Error ->
+ d("loop -> service change failed: ~p", [Error]),
+ server_reply(Parent, service_change_reply, Error),
+ S
+ end,
+ loop(S1);
+
+ {{group_requests, N}, Parent} when N > 0 ->
+ i("loop -> received group_requests ~p", [N]),
+ Reply = {ok, S#mg.group_size},
+ server_reply(Parent, group_requests_reply, Reply),
+ loop(S#mg{group_size = N});
+
+ {{ack_info, To}, Parent} ->
+ i("loop -> received request to inform about received ack's ", []),
+ loop(S#mg{ack_info = To});
+
+ {{rep_info, To}, Parent} ->
+ i("loop -> received request to inform about received rep's ", []),
+ loop(S#mg{rep_info = To});
+
+ %% Make a sync-call
+ {notify_request, Parent} ->
+ i("loop -> received request to send notify request ", []),
+ {Res, S1} = do_handle_notify_request(S),
+ d("loop -> notify request result: ~p", [Res]),
+ loop(S1);
+
+ %% sync-call complete
+ {notify_request_complete, NotifyReply, Pid} ->
+ i("loop -> received notify request complete from "
+ "~n ~p with"
+ "~n NotifyReply: ~p",
+ [Pid, NotifyReply]),
+ server_reply(Parent, notify_request_reply, NotifyReply),
+ loop(S#mg{req_handler = undefined});
+
+
+ %% cancel requests
+ {cancel_request, Reason, Parent} ->
+ i("loop -> received request to cancel (all) megaco requests ", []),
+ Res = do_cancel_requests(Mid, Reason),
+ server_reply(Parent, cancel_request_reply, Res),
+ loop(S);
+
+
+ %% Apply multi-load
+ {apply_multi_load, {NL, NR}, Parent} ->
+ i("loop -> received apply_multi_load request: ~w, ~w", [NL, NR]),
+ S1 = start_loaders(S, NL, NR),
+ loop(S1);
+
+
+ %% Apply some load
+ {apply_load, Times, Parent} ->
+ i("loop -> received apply_load request: ~w", [Times]),
+ S1 =
+ case update_load_times(S, Times) of
+ {ok, MG} ->
+ apply_load_timer(),
+ server_reply(Parent, apply_load_ack, ok),
+ MG;
+ Error ->
+ server_reply(Parent, apply_load_ack, Error),
+ S
+ end,
+ loop(S1);
+
+ {apply_load_timeout, _} ->
+ d("loop -> received apply_load timeout", []),
+ S1 = do_apply_load(S),
+ loop(S1);
+
+
+ %% Megaco callback messages
+ {request, Request, Mid, From} ->
+ d("loop -> received megaco request: ~n ~p"
+ "~n Mid: ~p"
+ "~n From: ~p",
+ [Request, Mid, From]),
+ {Reply, S1} = handle_megaco_request(S, Request),
+ d("loop -> send (megaco callback) request reply: ~n~p", [Reply]),
+ From ! {reply, Reply, self()},
+ loop(S1);
+
+
+ {'EXIT', Pid, Reason} ->
+ i("loop -> received exit signal from ~p: ~n~p", [Pid, Reason]),
+ S1 = handle_exit(S, Pid, Reason),
+ loop(S1);
+
+
+ Invalid ->
+ error_msg("received invalid request: ~n~p", [Invalid]),
+ loop(S)
+
+ end.
+
+
+handle_encode_ar_first(#mg{encode_ar_first = Old} = MG, New)
+ when (New =:= true) orelse (New =:= false) ->
+ {{ok, Old}, MG#mg{encode_ar_first = New}};
+handle_encode_ar_first(MG, New) ->
+ {{error, {invalid_value, New}}, MG}.
+
+
+%%
+%% Stop user
+%%
+do_stop(Mid) ->
+ d("do_stop -> stopping user ~p", [Mid]),
+ Disco = fun close_conn/1,
+ lists:map(Disco, megaco:user_info(Mid, connections)),
+ megaco:stop_user(Mid).
+
+close_conn(CH) ->
+ d("do_stop -> closing connection ~p", [CH]),
+ Reason = {stopped_by_user,self()},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ megaco:disconnect(CH, Reason),
+ megaco:cancel(CH, Reason),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end.
+
+
+
+%%
+%% Get statistics
+%%
+do_get_statistics(Mid) ->
+ case megaco:user_info(Mid, connections) of
+ [CH] ->
+ do_get_conn_statistics(CH);
+ [] ->
+ []
+ end.
+
+do_get_conn_statistics(CH) ->
+ {ok, Gen} = megaco:get_stats(),
+ %% Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ {ok, Trans} =
+ case SendMod of
+ megaco_tcp -> megaco_tcp:get_stats(SendHandle);
+ megaco_udp -> megaco_udp:get_stats(SendHandle)
+ end,
+ [{gen, Gen}, {trans, Trans}].
+
+
+%%
+%% reset user stats
+%%
+do_reset_stats(Mid) ->
+ %% We only have one connection
+ [CH] = megaco:user_info(Mid, connections),
+ do_reset_stats1(CH).
+
+do_reset_stats1(CH) ->
+ megaco:reset_stats(),
+ case (catch megaco:conn_info(CH, send_mod)) of
+ {error, Reason} ->
+ error_msg("unexpected result when retrieving send module for "
+ "own connection ~p: ~p. "
+ "~nexiting...", [CH, Reason]),
+ exit({invalid_connection, CH, Reason});
+ {'EXIT', Reason} ->
+ error_msg("exit signal when retrieving send module for "
+ "own connection ~p: ~p. "
+ "~nexiting...", [CH, Reason]),
+ exit({invalid_connection, CH, Reason});
+ SendMod when is_atom(SendMod) ->
+ SendMod:reset_stats()
+ end.
+
+
+%%
+%% Get user info for user
+%%
+do_get_user_info(Mid, all = Tag) ->
+ case (catch megaco:user_info(Mid, Tag)) of
+ L when is_list(L) ->
+ lists:sort(L);
+ Else ->
+ Else
+ end;
+do_get_user_info(Mid, Tag) ->
+ (catch megaco:user_info(Mid, Tag)).
+
+
+%%
+%% Update user info for user
+%%
+do_update_user_info(Mid, Tag, Val) ->
+ (catch megaco:update_user_info(Mid, Tag, Val)).
+
+
+%%
+%% Get conn info
+%%
+do_get_conn_info(CH, all = Tag) when is_record(CH, megaco_conn_handle) ->
+ case (catch megaco:conn_info(CH, Tag)) of
+ L when is_list(L) ->
+ lists:sort(L);
+ Else ->
+ Else
+ end;
+do_get_conn_info(CH, Tag) when is_record(CH, megaco_conn_handle) ->
+ (catch megaco:conn_info(CH, Tag));
+do_get_conn_info(Mid, Tag) ->
+ case megaco:user_info(Mid, connections) of
+ [CH|_] ->
+ do_get_conn_info(CH, Tag);
+ [] ->
+ []
+ end.
+
+%%
+%% Update conn info for user
+%%
+do_update_conn_info(Mid, Tag, Val) ->
+ %% We only have one connection
+ [CH] = megaco:user_info(Mid, connections),
+ (catch megaco:update_conn_info(CH, Tag, Val)).
+
+
+
+
+%%
+%% Perform service change
+%%
+do_service_change(#mg{mid = Mid,
+ state = initiated,
+ encode_ar_first = EAF} = MG) ->
+ %% We only have one connection
+ d("do service change for ~p", [Mid]),
+ [CH] = megaco:user_info(Mid, connections),
+ Method = restart,
+ Reason = ?megaco_cold_boot,
+ case do_service_change(CH, Method, EAF, Reason) of
+ ok ->
+ {ok, MG#mg{state = connecting}};
+ Error ->
+ d("service change for ~p failed: ~n~p", [Mid, Error]),
+ Error
+ end;
+do_service_change(#mg{state = State} = MG) ->
+ {{error, {invalid_state, State}}, MG}.
+
+do_service_change(ConnHandle, Method, EAF, Reason) ->
+ d("sending service change using:"
+ "~n ConnHandle: ~p"
+ "~n Method: ~p"
+ "~n EAF: ~p"
+ "~n Reason: ~p", [ConnHandle, Method, EAF, Reason]),
+ SCP = cre_serviceChangeParm(Method, [Reason]),
+ TermId = [?megaco_root_termination_id],
+ SCR = cre_serviceChangeReq(TermId, SCP),
+ CR = cre_commandReq({serviceChangeReq, SCR}),
+ AR = cre_actionReq(?megaco_null_context_id,[CR]),
+ send_async(EAF, ConnHandle, [AR], []).
+
+
+%% Make a sync call
+do_handle_notify_request(#mg{mid = Mid,
+ group_size = N,
+ encode_ar_first = EAF,
+ state = connected} = MG) ->
+ d("do_handle_notify_request -> entry"),
+ [CH] = megaco:user_info(Mid, connections),
+ Pid = start_notify_request_handler(EAF, CH, N),
+ {ok, MG#mg{req_handler = Pid}};
+do_handle_notify_request(#mg{state = State} = MG) ->
+ d("do_handle_notify_request -> entry with"
+ "~n State: ~p", [State]),
+ {{error, {invalid_state, State}}, MG}.
+
+
+
+%%
+%% Cancel requests
+%%
+do_cancel_requests(Mid, Reason) ->
+ [CH] = megaco:user_info(Mid, connections),
+ megaco:cancel(CH, Reason).
+
+
+%%
+%% Apply multi load
+%%
+start_loaders(#mg{mid = Mid, encode_ar_first = EAF} = MG, NumLoaders, Times) ->
+ [CH] = megaco:user_info(Mid, connections),
+ Env = get(),
+ Loaders = start_loaders1(NumLoaders, [], [Env, EAF, Times, CH]),
+ d("start_loaders -> Loaders: ~n~w", [Loaders]),
+ MG#mg{mload_info = {Loaders, 0, 0}}.
+
+start_loaders1(0, Acc, _) ->
+ Acc;
+start_loaders1(N, Acc, Args) ->
+ Pid = spawn_link(?MODULE, loader_main, Args),
+ start_loaders1(N-1, [Pid|Acc], Args).
+
+loader_main(Env, EAF, N, CH) ->
+ lists:foreach(fun({Tag,Val}) -> put(Tag,Val) end, Env),
+ loader_main(EAF, N, CH).
+
+loader_main(_EAF, 0, _) ->
+ d("loader_main -> done"),
+ exit(loader_done);
+loader_main(EAF, N, CH) ->
+ d("loader_main -> entry with: ~w", [N]),
+ {Act, _} = make_notify_request(),
+ _Res = send_sync(EAF, CH, Act, []),
+ loader_main(EAF, N-1, CH).
+
+
+
+handle_exit(#mg{parent = Pid}, Pid, Reason) ->
+ error_msg("received exit from the parent:"
+ "~n ~p", [Reason]),
+ exit({parent_terminated, Reason});
+
+handle_exit(#mg{parent = Parent, req_handler = Pid} = MG, Pid, Reason) ->
+ error_msg("received unexpected exit from the request handler:"
+ "~n ~p", [Reason]),
+ server_reply(Parent, notify_request_reply,
+ {error, {request_handler_exit, Reason}}),
+ MG#mg{req_handler = undefined};
+
+handle_exit(#mg{parent = Parent, mload_info = {Loaders0, Ok, Err}} = MG,
+ Pid, loader_done) ->
+ d("handle_exit(loader_done) -> entry when"
+ "~n Loaders0: ~p"
+ "~n Ok: ~p"
+ "~n Err: ~p", [Loaders0, Ok, Err]),
+ Loaders = lists:delete(Pid, Loaders0),
+ LoadInfo =
+ case Loaders of
+ [] ->
+ d("handle_exit -> multi load done", []),
+ server_reply(Parent, apply_multi_load_ack, {ok, Ok+1, Err}),
+ undefined;
+ _ ->
+ {Loaders, Ok+1, Err}
+ end,
+ MG#mg{mload_info = LoadInfo};
+
+
+handle_exit(#mg{parent = Parent, mload_info = {Loaders, Ok, Err}} = MG,
+ Pid, Reason)
+ when length(Loaders) > 0 ->
+ d("handle_exit -> entry when"
+ "~n Reason: ~p"
+ "~n Loaders: ~p"
+ "~n Ok: ~p"
+ "~n Err: ~p", [Reason, Loaders, Ok, Err]),
+ case lists:delete(Pid, Loaders) of
+ [] ->
+ %% since we cannot be empty prior the delete,
+ %% the last one exited...
+ server_reply(Parent, apply_multi_load, {ok, Ok, Err+1}),
+ MG#mg{mload_info = undefined};
+ Loaders ->
+ %% Could not be this MG, so go on to the next
+ error_msg("received unexpected exit signal from ~p:~n~p",
+ [Pid, Reason]);
+ Loaders1 ->
+ %% Not empty, but we removed one
+ MG#mg{mload_info = {Loaders1,Ok,Err+1}}
+ end;
+handle_exit(_MG, Pid, Reason) ->
+ error_msg("received unexpected exit signal from ~p:~n~p",
+ [Pid, Reason]).
+
+
+parse_receive_info(RI, RH) ->
+ d("parse_receive_info -> get encoding module"),
+ EM = get_encoding_module(RI),
+ d("parse_receive_info -> get encoding config"),
+ EC = get_encoding_config(RI, EM),
+ d("parse_receive_info -> get transport module"),
+ TM = get_transport_module(RI),
+ d("parse_receive_info -> get transport port"),
+ TP = get_transport_port(RI),
+ d("parse_receive_info -> get transport host"),
+ TH = get_transport_host(RI),
+ d("parse_receive_info -> get transport opts"),
+ TO = get_transport_opts(RI),
+ RH1 = RH#megaco_receive_handle{send_mod = TM,
+ encoding_mod = EM,
+ encoding_config = EC},
+ {TP, TH, RH1, TO}.
+
+
+start_transport(MgcPort, MgcHost,
+ #megaco_receive_handle{send_mod = megaco_tcp} = RH, TO) ->
+ start_tcp(MgcPort, MgcHost, RH, TO);
+start_transport(MgcPort, MgcHost,
+ #megaco_receive_handle{send_mod = megaco_udp} = RH, TO) ->
+ start_udp(MgcPort, MgcHost, RH, TO);
+start_transport(_, _, #megaco_receive_handle{send_mod = Mod}, _TO) ->
+ throw({error, {bad_send_mod, Mod}}).
+
+
+start_tcp(MgcPort, MgcHost, RH, TO) ->
+ d("start tcp transport: "
+ "~n MGC Port: ~p"
+ "~n MGC Host: ~p"
+ "~n Receive handle: ~p"
+ "~n Transport options: ~p", [MgcPort, MgcHost, RH, TO]),
+ case megaco_tcp:start_transport() of
+ {ok, Sup} ->
+ d("tcp transport started: ~p", [Sup]),
+ start_tcp_connect(TO, RH, MgcPort, MgcHost, Sup);
+ {error, Reason} ->
+ throw({error, {megaco_tcp_start_transport, Reason}})
+ end.
+
+start_tcp_connect(TO, RH, Port, Host, Sup) ->
+ d("try tcp connecting to: ~p:~p", [Host, Port]),
+ Opts = [{host, Host},
+ {port, Port},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]}] ++ TO,
+ try_start_tcp_connect(RH, Sup, Opts, 250, noError).
+
+try_start_tcp_connect(RH, Sup, Opts, Timeout, Error0) when (Timeout < 5000) ->
+ Sleep = random(Timeout) + 100,
+ d("try tcp connect (~p,~p)", [Timeout, Sleep]),
+ case megaco_tcp:connect(Sup, Opts) of
+ {ok, SendHandle, ControlPid} ->
+ d("tcp connected: ~p, ~p", [SendHandle, ControlPid]),
+ megaco_tcp_connect(RH, SendHandle, ControlPid);
+ Error1 when Error0 =:= noError -> % Keep the first error
+ d("failed connecting [1]: ~p", [Error1]),
+ sleep(Sleep),
+ try_start_tcp_connect(RH, Sup, Opts, Timeout*2, Error1);
+ Error2 ->
+ d("failed connecting [2]: ~p", [Error2]),
+ sleep(Sleep),
+ try_start_tcp_connect(RH, Sup, Opts, Timeout*2, Error0)
+ end;
+try_start_tcp_connect(_RH, Sup, _Opts, _Timeout, Error) ->
+ megaco_tcp:stop_transport(Sup),
+ throw({error, {megaco_tcp_connect, Error}}).
+
+megaco_tcp_connect(RH, SendHandle, ControlPid) ->
+ PrelMgcMid = preliminary_mid,
+ d("megaco connect", []),
+ {ok, CH} = megaco:connect(RH, PrelMgcMid, SendHandle, ControlPid),
+ d("megaco connected: ~p", [CH]),
+ {ok, CH}.
+
+start_udp(MgcPort, MgcHost, RH, TO) ->
+ d("start udp transport (~p)", [MgcPort]),
+ case megaco_udp:start_transport() of
+ {ok, Sup} ->
+ d("udp transport started: ~p", [Sup]),
+ Opts = [{port, 0}, {receive_handle, RH}] ++ TO,
+ d("udp open", []),
+ case megaco_udp:open(Sup, Opts) of
+ {ok, Handle, ControlPid} ->
+ d("udp opened: ~p, ~p", [Handle, ControlPid]),
+ megaco_udp_connect(MgcPort, MgcHost,
+ RH, Handle, ControlPid);
+ {error, Reason} ->
+ throw({error, {megaco_udp_open, Reason}})
+ end;
+ {error, Reason} ->
+ throw({error, {megaco_udp_start_transport, Reason}})
+ end.
+
+megaco_udp_connect(MgcPort, MgcHost, RH, Handle, ControlPid) ->
+ MgcMid = preliminary_mid,
+ SendHandle = megaco_udp:create_send_handle(Handle, MgcHost, MgcPort),
+ d("megaco connect", []),
+ {ok, CH} = megaco:connect(RH, MgcMid, SendHandle, ControlPid),
+ d("megaco connected: ~p", [CH]),
+ {ok, CH}.
+
+
+update_load_times(#mg{load_counter = 0} = MG, Times) ->
+ d("update_load_times(0) -> entry with"
+ "~n Times: ~p", [Times]),
+ {ok, MG#mg{load_counter = Times}};
+update_load_times(#mg{load_counter = N}, Times) ->
+ d("update_load_times(~p) -> entry with"
+ "~n Times: ~p", [N, Times]),
+ {error, {already_counting, N}}.
+
+
+do_apply_load(#mg{mid = Mid} = MG) ->
+ d("do_apply_load -> entry"),
+ case megaco:user_info(Mid, connections) of
+ [CH] ->
+ do_apply_load(MG, CH);
+ [] ->
+ i("failed to apply load: no connections for ~p", [Mid]),
+ MG
+ end.
+
+do_apply_load(#mg{parent = Parent,
+ encode_ar_first = EAF,
+ call_mode = Mode,
+ group_size = Sz,
+ load_counter = N0} = MG, CH) ->
+ d("do_apply_load -> entry with"
+ "~n Mode: ~p"
+ "~n Sz: ~p"
+ "~n N0: ~p", [Mode, Sz, N0]),
+ {NofSent, Actions, ReplyData} = make_notify_request(N0, Sz),
+ d("do_apply_load -> notifications constructed:"
+ "~n NofSent: ~p"
+ "~n Actions: ~p"
+ "~n ReplyData: ~p", [NofSent, Actions, ReplyData]),
+ N = N0 - NofSent,
+ case Mode of
+ sync ->
+ Result = send_sync(EAF, CH, Actions, []),
+ d("do_apply_load -> call result when N = ~p: ~n~p", [N,Result]),
+ case N of
+ 0 ->
+ d("do_apply_load -> load complete"),
+ Parent ! {load_complete, self()},
+ MG#mg{call_mode = async, load_counter = 0};
+ _ ->
+ d("do_apply_load -> make another round"),
+ apply_load_timer(),
+ MG#mg{call_mode = async, load_counter = N}
+ end;
+ async ->
+ Result = send_async(EAF, CH, Actions, [{reply_data, ReplyData}]),
+ d("do_apply_load -> cast result:~n ~p", [Result]),
+ MG#mg{call_mode = sync,
+ load_counter = N,
+ reply_counter = NofSent} % Outstanding replies
+ end.
+
+
+start_notify_request_handler(EAF, CH, N) ->
+ d("start_notify_request_handler -> entry with"
+ "~n EAF: ~p"
+ "~n CH: ~p"
+ "~n N: ~p", [EAF, CH, N]),
+ Env = get(),
+ spawn_link(?MODULE, notify_request_handler_main, [self(), Env, EAF, CH, N]).
+
+notify_request_handler_main(Parent, Env, EAF, CH, N) ->
+ F = fun({Tag, Val}) -> put(Tag, Val) end,
+ lists:foreach(F, Env),
+ d("notify_request_handler_main -> entry with"
+ "~n Parent: ~p"
+ "~n EAF: ~p"
+ "~n CH: ~p"
+ "~n N: ~p", [Parent, EAF, CH, N]),
+ Res = do_notify_request(EAF, CH, N),
+ d("notify_request_handler_main -> notify complete:"
+ "~n Res: ~p", [Res]),
+ Parent ! {notify_request_complete, {ok, Res}, self()},
+ unlink(Parent),
+ exit(normal).
+
+do_notify_request(_EAF, _CH, N) when N =< 0 ->
+ d("do_notify_request(~p) -> ignoring", [N]),
+ ignore;
+do_notify_request(EAF, CH, 1) ->
+ d("do_notify_request(1) -> entry with"),
+ {Action, _} = make_notify_request(),
+ send_sync(EAF, CH, Action, []);
+do_notify_request(EAF, CH, N) ->
+ d("do_notify_request(~p) -> entry with", [N]),
+ {N, Actions, _} = make_notify_request(N,N),
+ send_sync(EAF, CH, Actions, []).
+
+make_notify_request(N, Sz) when (N >= Sz) andalso (Sz > 0) ->
+ {Req, ReplyData} = make_notify_request(N, Sz, [], []),
+ {Sz, Req, ReplyData};
+make_notify_request(N, _Sz) when N > 0 ->
+ {Req, ReplyData} = make_notify_request(N, N, [], []),
+ {N, Req, ReplyData}.
+
+
+
+make_notify_request(_Offset, 0, Actions, ReplyDatas) ->
+ {lists:reverse(Actions), lists:reverse(ReplyDatas)};
+make_notify_request(Offset, N, Actions, ReplyDatas) when N > 0 ->
+ TimeStamp = cre_timeNotation(),
+ Event = cre_observedEvent("al/of", TimeStamp),
+ Desc = cre_observedEventsDesc(2000 + N, [Event]),
+ TidNum = 2#10000000 + Offset - N,
+ NotifyReq = cre_notifyReq([#megaco_term_id{id = tid(TidNum)}],Desc),
+ CmdReq = cre_commandReq({notifyReq, NotifyReq}),
+ ActReq = cre_actionReq(?megaco_null_context_id, [CmdReq]),
+ make_notify_request(Offset, N-1, [[ActReq]|Actions], [Desc|ReplyDatas]).
+
+make_notify_request() ->
+ TimeStamp = cre_timeNotation("19990729", "22000000"),
+ Event = cre_observedEvent("al/of", TimeStamp),
+ Desc1 = cre_observedEventsDesc(2221, [Event]),
+ Desc2 = cre_observedEventsDesc(2222, [Event]),
+ Desc3 = cre_observedEventsDesc(2223, [Event]),
+ Desc4 = cre_observedEventsDesc(2224, [Event]),
+ NotifyReq1 = cre_notifyReq([#megaco_term_id{id = ?A4444}], Desc1),
+ NotifyReq2 = cre_notifyReq([#megaco_term_id{id = ?A4445}], Desc2),
+ CmdReq1 = cre_commandReq({notifyReq, NotifyReq1}),
+ CmdReq2 = cre_commandReq({notifyReq, NotifyReq2}),
+ ActReq = cre_actionReq(?megaco_null_context_id, [CmdReq1,CmdReq2]),
+ {[ActReq], [Desc3,Desc4]}.
+
+
+cre_actionReq(Cid, Cmds) ->
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = Cmds}.
+
+cre_commandReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_serviceChangeReq(TermId, Parms) ->
+ #'ServiceChangeRequest'{terminationID = TermId,
+ serviceChangeParms = Parms}.
+
+cre_serviceChangeParm(Method, Reason) ->
+ #'ServiceChangeParm'{serviceChangeMethod = Method,
+ serviceChangeReason = Reason}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid, observedEventsDescriptor = EvsDesc}.
+
+% cre_notifyRep(Tid) ->
+% #'NotifyReply'{terminationID = [Tid]}.
+
+% cre_notifyRep(Tid,Err) ->
+% #'NotifyReply'{terminationID = [Tid], errorDescriptor = Err}.
+
+cre_observedEventsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id, observedEventLst = EvList}.
+
+cre_observedEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name, timeNotation = Not}.
+
+cre_timeNotation() ->
+ {{Year,Month,Day},{Hour,Min,Sec}} = calendar:universal_time(),
+ D = lists:flatten(io_lib:format("~4..0w~2..0w~2..0w", [Year,Month,Day])),
+ T = lists:flatten(io_lib:format("~2..0w~2..0w~4..0w", [Hour,Min,Sec])),
+ cre_timeNotation(D, T).
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_error_descr(Code,Text) ->
+ #'ErrorDescriptor'{errorCode = Code, errorText = Text}.
+
+% cre_error_descr(Code,FormatString,Args) ->
+% Text = lists:flatten(io_lib:format(FormatString,Args)),
+% cre_error_descr(Code,Text).
+
+
+%% -----------------------
+%% Handle megaco callbacks
+%%
+
+handle_megaco_request(#mg{state = connecting} = MG,
+ {handle_connect, _CH, _PV}) ->
+ d("handle_megaco_request(handle_connect,connecting) -> entry"),
+ {ok, MG};
+handle_megaco_request(#mg{state = S} = MG,
+ {handle_connect, _CH, _PV}) ->
+ d("handle_megaco_request(handle_connect) -> entry"),
+ Desc =
+ lists:flatten(io_lib:format("not ready for connect in state ~p", [S])),
+ ED = cre_error_descr(?megaco_internal_gateway_error, Desc),
+ {{discard_ack, ED}, MG};
+
+handle_megaco_request(#mg{req_handler = Pid} = MG,
+ {handle_disconnect, _CH, _PV, R})
+ when is_pid(Pid) ->
+ d("handle_megaco_request(handle_disconnect) -> entry with"
+ "~n Pid: ~p", [Pid]),
+ Error = {error, {disconnected, R}},
+ self() ! {notify_request_complete, Error, Pid},
+ unlink(Pid),
+ exit(Pid, kill),
+ {ok, MG#mg{req_handler = undefined, state = initiated}};
+handle_megaco_request(MG, {handle_disconnect, _CH, _PV, _R}) ->
+ d("handle_megaco_request(handle_disconnect) -> entry"),
+ {ok, MG#mg{state = initiated}};
+
+handle_megaco_request(MG,
+ {handle_syntax_error, _RH, _PV, _ED}) ->
+ {reply, MG};
+
+handle_megaco_request(#mg{req_handler = Pid} = MG,
+ {handle_message_error, CH, PV, ED})
+ when is_pid(Pid) ->
+ d("handle_megaco_request(handle_message_error) -> entry with"
+ "~n Pid: ~p"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n ED: ~p", [Pid, CH, PV, ED]),
+ self() ! {notify_request_complete, ED, Pid},
+ unlink(Pid),
+ exit(Pid, kill),
+ {no_reply, MG#mg{req_handler = undefined}};
+handle_megaco_request(MG, {handle_message_error, CH, PV, ED}) ->
+ d("handle_megaco_request(handle_message_error) -> entry with"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n ED: ~p", [CH, PV, ED]),
+ {no_reply, MG};
+
+handle_megaco_request(MG, {handle_trans_request, _CH, _PV, _AR}) ->
+ ED = cre_error_descr(?megaco_not_implemented,
+ "Transaction requests not handled"),
+ {{discard_ack, ED}, MG};
+
+handle_megaco_request(MG,
+ {handle_trans_long_request, _CH, _PV, _RD}) ->
+ ED = cre_error_descr(?megaco_not_implemented,
+ "Long transaction requests not handled"),
+ {{discard_ack, ED}, MG};
+
+handle_megaco_request(#mg{rep_info = P} = MG,
+ {handle_trans_reply, CH, PV, AR, RD}) when is_pid(P) ->
+ P ! {rep_received, self(), AR},
+ do_handle_trans_reply(MG, CH, PV, AR, RD);
+handle_megaco_request(MG, {handle_trans_reply, CH, PV, AR, RD}) ->
+ do_handle_trans_reply(MG, CH, PV, AR, RD);
+
+handle_megaco_request(#mg{ack_info = P} = MG,
+ {handle_trans_ack, _CH, _PV, AS, _AD}) when is_pid(P) ->
+ d("handle_megaco_request(handle_trans_ack,~p) -> entry",[P]),
+ P ! {ack_received, self(), AS},
+ {ok, MG};
+handle_megaco_request(MG, {handle_trans_ack, _CH, _PV, _AS, _AD}) ->
+ d("handle_megaco_request(handle_trans_ack) -> entry"),
+ {ok, MG}.
+
+do_handle_trans_reply(#mg{parent = Parent, state = connecting} = MG,
+ CH, _PV, {ok, Rep}, _RD) ->
+ d("do_handle_trans_reply(connecting) -> entry with"
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep]),
+ server_reply(Parent, service_change_reply, ok),
+ {ok, MG#mg{state = connected}};
+do_handle_trans_reply(#mg{parent = Parent, load_counter = 0} = MG,
+ CH, _PV, {ok, Rep}, _RD) ->
+ d("do_handle_trans_reply(load_counter = 0) -> entry with"
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep, Parent]),
+ handle_trans_reply_verify_act(Rep),
+ server_reply(Parent, load_complete, ok),
+ {ok, MG#mg{reply_counter = 0}};
+do_handle_trans_reply(#mg{reply_counter = 0} = MG,
+ CH, _PV, {ok, Rep}, _RD) ->
+ d("do_handle_trans_reply(reply_counter = 0) -> entry with"
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep]),
+ handle_trans_reply_verify_act(Rep),
+ apply_load_timer(),
+ {ok, MG};
+do_handle_trans_reply(#mg{reply_counter = N} = MG,
+ CH, _PV, {ok, Rep}, _RD) ->
+ d("do_handle_trans_reply(reply_counter = ~p) -> entry with"
+ "~n CH: ~p"
+ "~n Rep: ~p", [N, CH, Rep]),
+ handle_trans_reply_verify_act(Rep),
+ apply_load_timer(),
+ {ok, MG#mg{reply_counter = N-1}};
+do_handle_trans_reply(MG, _CH, _PV, {error, ED}, _RD) ->
+ i("unexpected error transaction: ~p", [ED]),
+ {ok, MG}.
+
+
+handle_trans_reply_verify_act([]) ->
+ ok;
+handle_trans_reply_verify_act([#'ActionReply'{commandReply = Rep}|Reps]) ->
+ handle_trans_reply_verify_cmd(Rep),
+ handle_trans_reply_verify_act(Reps);
+handle_trans_reply_verify_act([Rep|Reps]) ->
+ i("received 'propably' unexpected reply: ~n~p", [Rep]),
+ handle_trans_reply_verify_act(Reps).
+
+handle_trans_reply_verify_cmd([]) ->
+ ok;
+handle_trans_reply_verify_cmd([Cmd|Cmds]) ->
+ case Cmd of
+ {notifyReply, #'NotifyReply'{terminationID = [Tid]}} ->
+ d("received expected notification reply from ~n ~p", [Tid]);
+ Else ->
+ i("received unexpected notification reply ~n~p", [Else])
+ end,
+ handle_trans_reply_verify_cmd(Cmds).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+notify_started(Parent) ->
+ Parent ! {started, self()}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% The megaco user callback interface
+
+handle_connect(CH, PV, Pid, Mid) ->
+ case CH#megaco_conn_handle.remote_mid of
+ preliminary_mid ->
+ %% Avoids deadlock
+ ok;
+ _ ->
+ Reply = request(Pid, {handle_connect, CH, PV}, Mid),
+ Reply
+ end.
+
+handle_disconnect(_CH, _PV,
+ {user_disconnect, {stopped_by_user, Pid}},
+ Pid, _Mid) ->
+ ok;
+handle_disconnect(CH, PV, R, Pid, Mid) ->
+ request(Pid, {handle_disconnect, CH, PV, R}, Mid).
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Pid, Mid) ->
+ Req = {handle_syntax_error, ReceiveHandle, ProtocolVersion,
+ ErrorDescriptor},
+ request(Pid, Req, Mid).
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid, Mid) ->
+ Req = {handle_message_error, ConnHandle, ProtocolVersion, ErrorDescriptor},
+ request(Pid, Req, Mid).
+
+handle_trans_request(CH, PV, AR, Pid, Mid) ->
+ Reply = request(Pid, {handle_trans_request, CH, PV, AR}, Mid),
+ Reply.
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Pid, Mid) ->
+ Req = {handle_trans_long_request, ConnHandle, ProtocolVersion, ReqData},
+ request(Pid, Req, Mid).
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData, Pid, Mid) ->
+ Req = {handle_trans_reply, ConnHandle, ProtocolVersion,
+ ActualReply, ReplyData},
+ request(Pid, Req, Mid).
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Pid, Mid) ->
+ Req = {handle_trans_ack, ConnHandle, ProtocolVersion, AckStatus, AckData},
+ request(Pid, Req, Mid).
+
+
+request(Pid, Request, Mid) ->
+ Pid ! {request, Request, Mid, self()},
+ receive
+ {reply, {delay, To, ED}, Pid} ->
+ sleep(To),
+ {discard_ack, ED};
+ {reply, Reply, Pid} ->
+ Reply
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+send_async(true, CH, Actions, Opts) ->
+ d("send_async(true) -> encode actions first"),
+ case megaco:encode_actions(CH, Actions, Opts) of
+ {ok, BinOrBins} ->
+ d("send_async(true) -> send message"),
+ megaco:cast(CH, BinOrBins, Opts);
+ Error ->
+ d("send_async(true) -> encode failed: ~n~p", [Error]),
+ Error
+ end;
+send_async(_, CH, Actions, Opts) ->
+ d("send_async(true) -> send message"),
+ megaco:cast(CH, Actions, Opts).
+
+send_sync(true, CH, Actions, Opts) ->
+ d("send_sync(true) -> encode actions first"),
+ case megaco:encode_actions(CH, Actions, Opts) of
+ {ok, BinOrBins} ->
+ d("send_sync(true) -> send message"),
+ megaco:call(CH, BinOrBins, Opts);
+ Error ->
+ d("send_sync(true) -> encode failed: ~n~p", [Error]),
+ Error
+ end;
+send_sync(_, CH, Actions, Opts) ->
+ d("send_sync(false) -> send message"),
+ megaco:call(CH, Actions, Opts).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) ->
+ receive after X -> ok end.
+
+
+error_msg(F,A) -> error_logger:error_msg("MG: " ++ F ++ "~n",A).
+
+
+get_encoding_module(RI) ->
+ case (catch get_conf(encoding_module, RI)) of
+ {error, _} ->
+ undefined;
+ Val ->
+ Val
+ end.
+
+get_encoding_config(RI, EM) ->
+ case text_codec(EM) of
+ true ->
+ case megaco:system_info(text_config) of
+ [Conf] when is_list(Conf) ->
+ Conf;
+ _ ->
+ []
+ end;
+
+ false ->
+ get_conf(encoding_config, RI)
+ end.
+
+text_codec(megaco_compact_text_encoder) ->
+ true;
+text_codec(megaco_pretty_text_encoder) ->
+ true;
+text_codec(_) ->
+ false.
+
+
+get_transport_module(RI) ->
+ get_conf(transport_module, RI).
+
+get_transport_port(RI) ->
+ get_conf(port, RI).
+
+get_transport_host(RI) ->
+ {ok, LocalHost} = inet:gethostname(),
+ get_conf(host, RI, LocalHost).
+
+get_transport_opts(RI) ->
+ get_conf(transport_opts, RI, []).
+
+
+get_conf(Key, Config) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ exit({error, {not_found, Key, Config}})
+ end.
+
+get_conf(Key, Config, Default) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ Default
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tid(N) when N >= 0 ->
+ {Rem1, Val1} = num2str(N),
+ {Rem2, Val2} = num2str(Rem1),
+ {0, Val3} = num2str(Rem2),
+ [Val3, Val2, Val1].
+
+num2str(N) when N >= 0 ->
+ num2str(N, []).
+
+num2str(Rem, Val) when length(Val) == 8 ->
+ {Rem, Val};
+num2str(N, Val) ->
+ D = N div 2,
+ case N rem 2 of
+ 1 ->
+ num2str(D, [$1|Val]);
+ 0 ->
+ num2str(D, [$0|Val])
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), "", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), "DBG", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, P, F, A) ->
+ print(printable(Severity,Verbosity), P, F, A).
+
+print(true, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s ***"
+ "~n " ++ F ++ "~n~n",
+ [format_timestamp(now()), P, self(), get(sname) | A]);
+print(_, _, _, _) ->
+ ok.
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ random(50).
+random(N) ->
+ random:uniform(N).
+
+
+display_system_info(Mid) ->
+ display_system_info(Mid, "").
+
+display_system_info(Mid, Pre) ->
+ TimeStr = format_timestamp(now()),
+ MibStr = lists:flatten(io_lib:format("~p ", [Mid])),
+ megaco_test_lib:display_system_info(MibStr ++ Pre ++ TimeStr).
+
+
+create_timer(Time, Event) ->
+ erlang:send_after(Time, self(), {Event, Time}).
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Ref) ->
+ erlang:cancel_timer(Ref).
+
+
+apply_load_timer() ->
+ create_timer(random(), apply_load_timeout).
+
+
diff --git a/lib/megaco/test/megaco_test_mgc.erl b/lib/megaco/test/megaco_test_mgc.erl
new file mode 100644
index 0000000000..05c482f1af
--- /dev/null
+++ b/lib/megaco/test/megaco_test_mgc.erl
@@ -0,0 +1,1221 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Implements an "MGC" used by the test suite
+%%----------------------------------------------------------------------
+-module(megaco_test_mgc).
+
+-export([start/4, start/5, stop/1,
+ get_stats/2, reset_stats/1,
+ user_info/1, user_info/2, conn_info/1, conn_info/2,
+ update_user_info/3, update_conn_info/3,
+ request_ignore/1,
+ request_discard/1, request_discard/2,
+ request_pending/1, request_pending/2, request_pending_ignore/1,
+ request_handle/1, request_handle/2,
+ request_handle_pending/1, request_handle_pending/2,
+ request_handle_sloppy/1, request_handle_sloppy/2,
+ ack_info/2, abort_info/2, req_info/2,
+ disconnect/2,
+ verbosity/2]).
+-export([mgc/3]).
+
+%% Megaco callback api
+-export([
+ handle_connect/3,
+ handle_disconnect/4,
+ handle_syntax_error/4,
+ handle_message_error/4,
+ handle_trans_request/4,
+ handle_trans_long_request/4,
+ handle_trans_reply/5,
+ handle_trans_ack/5,
+ handle_unexpected_trans/4,
+ handle_trans_request_abort/5
+ ]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+-define(valid_actions,
+ [ignore, pending, pending_ignore, discard_ack, handle_ack, handle_pending_ack, handle_sloppy_ack]).
+
+-record(mgc, {parent = undefined,
+ tcp_sup = undefined,
+ udp_sup = undefined,
+ req_action = discard_ack,
+ req_timeout = 0,
+ mid = undefined,
+ ack_info = undefined,
+ abort_info = undefined,
+ req_info = undefined,
+ mg = [],
+ dsi_timer}).
+
+
+%%% ------------------------------------------------------------------
+
+start(Node, Mid, ET, Verbosity) ->
+ %% Conf = [{megaco_trace, io}],
+ %% Conf = [{megaco_trace, "megaco-mgc.trace"}],
+ Conf = [{megaco_trace, false}],
+ start(Node, Mid, ET, Conf, Verbosity).
+
+start(Node, Mid, ET, Conf, Verbosity) ->
+ d("start mgc[~p]: ~p", [Node, Mid]),
+ RI = {receive_info, mk_recv_info(ET)},
+ Config = [{local_mid, Mid}, RI] ++ Conf,
+ Pid = spawn_link(Node, ?MODULE, mgc, [self(), Verbosity, Config]),
+ await_started(Pid).
+
+mk_recv_info(ET) ->
+ mk_recv_info(ET, []).
+
+mk_recv_info([], Acc) ->
+ Acc;
+mk_recv_info([{Encoding, Transport}|ET], Acc)
+ when is_atom(Encoding) andalso is_atom(Transport) ->
+ {EMod, Port} = select_encoding(Encoding),
+ TMod = select_transport(Transport),
+ RI = [{encoding_module, EMod},
+ {encoding_config, []},
+ {transport_module, TMod},
+ {port, Port}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([{Encoding, Transport, TO}|ET], Acc)
+ when is_atom(Encoding) andalso is_atom(Transport) andalso is_list(TO) ->
+ {EMod, Port} = select_encoding(Encoding),
+ TMod = select_transport(Transport),
+ RI = [{encoding_module, EMod},
+ {encoding_config, []},
+ {transport_module, TMod},
+ {port, Port},
+ {transport_opts, TO}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([{Encoding, EC, Transport}|ET], Acc)
+ when is_atom(Encoding) andalso is_list(EC) andalso is_atom(Transport) ->
+ {EMod, Port} = select_encoding(Encoding),
+ TMod = select_transport(Transport),
+ RI = [{encoding_module, EMod},
+ {encoding_config, EC},
+ {transport_module, TMod},
+ {port, Port}],
+ mk_recv_info(ET, [RI|Acc]);
+mk_recv_info([ET|_], _) ->
+ throw({error, {invalid_encoding_transport, ET}}).
+
+select_encoding(text) ->
+ {megaco_pretty_text_encoder, 2944};
+select_encoding(pretty_text) ->
+ {megaco_pretty_text_encoder, 2944};
+select_encoding(compact_text) ->
+ {megaco_compact_text_encoder, 2944};
+select_encoding(binary) ->
+ {megaco_ber_bin_encoder, 2945};
+select_encoding(erl_dist) ->
+ {megaco_erl_dist_encoder, 2946};
+select_encoding(Encoding) ->
+ throw({error, {invalid_encoding, Encoding}}).
+
+select_transport(tcp) ->
+ megaco_tcp;
+select_transport(udp) ->
+ megaco_udp;
+select_transport(Transport) ->
+ throw({error, {invalid_transport, Transport}}).
+
+
+await_started(Pid) ->
+ receive
+ {started, Pid} ->
+ d("await_started ~p: ok", [Pid]),
+ {ok, Pid};
+ {'EXIT', Pid,
+ {failed_starting_tcp_listen, {could_not_start_listener, {gen_tcp_listen, eaddrinuse}}}} ->
+ i("await_started ~p: address already in use", [Pid]),
+ ?SKIP(eaddrinuse);
+ {'EXIT', Pid, Reason} ->
+ i("await_started ~p: received exit signal: ~p", [Pid, Reason]),
+ exit({failed_starting, Pid, Reason})
+ after 10000 ->
+ i("await_started ~p: timeout", [Pid]),
+ exit({error, timeout})
+ end.
+
+
+stop(Pid) ->
+ server_request(Pid, stop, stopped).
+
+get_stats(Pid, No) ->
+ server_request(Pid, {statistics, No}, {statistics_reply, No}).
+
+reset_stats(Pid) ->
+ server_request(Pid, reset_stats, reset_stats_ack).
+
+user_info(Pid) ->
+ server_request(Pid, {user_info, all}, user_info_ack).
+
+user_info(Pid, Tag) ->
+ server_request(Pid, {user_info, Tag}, user_info_ack).
+
+conn_info(Pid) ->
+ server_request(Pid, {conn_info, all}, conn_info_ack).
+
+conn_info(Pid, Tag) ->
+ server_request(Pid, {conn_info, Tag}, conn_info_ack).
+
+update_user_info(Pid, Tag, Val) ->
+ server_request(Pid, {update_user_info, Tag, Val}, update_user_info_ack).
+
+update_conn_info(Pid, Tag, Val) ->
+ server_request(Pid, {update_conn_info, Tag, Val}, update_conn_info_ack).
+
+disconnect(Pid, Reason) ->
+ server_request(Pid, {disconnect, Reason}, disconnected).
+
+ack_info(Pid, InfoPid) ->
+ Pid ! {ack_info, InfoPid, self()}.
+
+abort_info(Pid, InfoPid) ->
+ Pid ! {abort_info, InfoPid, self()}.
+
+req_info(Pid, InfoPid) ->
+ Pid ! {req_info, InfoPid, self()}.
+
+verbosity(Pid, V) ->
+ Pid ! {verbosity, V, self()}.
+
+request_ignore(Pid) ->
+ request_action(Pid, {ignore, infinity}).
+
+request_pending_ignore(Pid) ->
+ request_action(Pid, {pending_ignore, infinity}).
+
+request_discard(Pid) ->
+ request_discard(Pid,0).
+
+request_discard(Pid, To) ->
+ request_action(Pid, {discard_ack, To}).
+
+request_pending(Pid) ->
+ request_pending(Pid, 5000).
+
+request_pending(Pid, To) ->
+ request_action(Pid, {pending, To}).
+
+request_handle(Pid) ->
+ request_handle(Pid, 0).
+
+request_handle(Pid, To) ->
+ request_action(Pid, {handle_ack, To}).
+
+request_handle_pending(Pid) ->
+ request_handle_pending(Pid, 0).
+
+request_handle_pending(Pid, To) ->
+ request_action(Pid, {handle_pending_ack, To}).
+
+request_handle_sloppy(Pid) ->
+ request_handle_sloppy(Pid, 0).
+
+request_handle_sloppy(Pid, To) ->
+ request_action(Pid, {handle_sloppy_ack, To}).
+
+request_action(Pid, Action) ->
+ server_request(Pid, request_action, Action, request_action_ack).
+
+
+server_request(Pid, Req, ReplyTag) ->
+ Pid ! {Req, self()},
+ receive
+ {ReplyTag, Reply, Pid} ->
+ Reply;
+ {'EXIT', Pid, Reason} ->
+ exit({failed, Req, Pid, Reason})
+ after 10000 ->
+ exit({timeout, Req, Pid})
+ end.
+
+server_request(Pid, Req, ReqData, ReplyTag) ->
+ Pid ! {Req, ReqData, self()},
+ receive
+ {ReplyTag, Reply, Pid} ->
+ Reply;
+ {'EXIT', Pid, Reason} ->
+ exit({failed, Req, Pid, Reason})
+ after 10000 ->
+ exit({timeout, Req, Pid})
+ end.
+
+
+server_reply(Pid, ReplyTag, Reply) ->
+ Pid ! {ReplyTag, Reply, self()}.
+
+
+%%% ------------------------------------------------------------------
+
+
+mgc(Parent, Verbosity, Config) ->
+ process_flag(trap_exit, true),
+ put(verbosity, Verbosity),
+ put(sname, "MGC"),
+ i("mgc -> starting"),
+ case (catch init(Config)) of
+ {error, Reason} ->
+ exit(Reason);
+ {Mid, TcpSup, UdpSup, DSITimer} ->
+ notify_started(Parent),
+ S = #mgc{parent = Parent,
+ tcp_sup = TcpSup,
+ udp_sup = UdpSup,
+ mid = Mid,
+ dsi_timer = DSITimer},
+ i("mgc -> started"),
+ display_system_info("at start "),
+ loop(S)
+ end.
+
+init(Config) ->
+ d("init -> entry"),
+ random_init(),
+ Mid = get_conf(local_mid, Config),
+ RI = get_conf(receive_info, Config),
+
+ d("init -> maybe start the display system info timer"),
+ DSITimer =
+ case get_conf(display_system_info, Config, undefined) of
+ Time when is_integer(Time) ->
+ d("init -> creating display system info timer"),
+ create_timer(Time, display_system_info);
+ _ ->
+ undefined
+ end,
+ Conf0 = lists:keydelete(display_system_info, 1, Config),
+
+ d("init -> start megaco"),
+ application:start(megaco),
+
+ d("init -> possibly enable megaco trace"),
+ case lists:keysearch(megaco_trace, 1, Config) of
+ {value, {megaco_trace, true}} ->
+ megaco:enable_trace(max, io);
+ {value, {megaco_trace, io}} ->
+ megaco:enable_trace(max, io);
+ {value, {megaco_trace, File}} when is_list(File) ->
+ megaco:enable_trace(max, File);
+ _ ->
+ ok
+ end,
+ Conf1 = lists:keydelete(megaco_trace, 1, Conf0),
+
+ d("init -> start megaco user"),
+ Conf2 = lists:keydelete(local_mid, 1, Conf1),
+ Conf3 = lists:keydelete(receive_info, 1, Conf2),
+ ok = megaco:start_user(Mid, Conf3),
+
+ d("init -> update user info (user_mod)"),
+ ok = megaco:update_user_info(Mid, user_mod, ?MODULE),
+
+ d("init -> update user info (user_args)"),
+ ok = megaco:update_user_info(Mid, user_args, [self()]),
+
+ d("init -> get user info (receive_handle)"),
+ RH = megaco:user_info(Mid,receive_handle),
+ d("init -> parse receive info"),
+ Transports = parse_receive_info(RI, RH),
+
+ d("init -> start transports"),
+ {Tcp, Udp} = start_transports(Transports),
+ {Mid, Tcp, Udp, DSITimer}.
+
+loop(S) ->
+ d("loop -> await request"),
+ receive
+ {display_system_info, Time} ->
+ display_system_info(S#mgc.mid),
+ NewTimer = create_timer(Time, display_system_info),
+ loop(S#mgc{dsi_timer = NewTimer});
+
+ {stop, Parent} when S#mgc.parent =:= Parent ->
+ i("loop -> stopping", []),
+ display_system_info(S#mgc.mid, "at finish "),
+ cancel_timer(S#mgc.dsi_timer),
+ Mid = S#mgc.mid,
+ (catch close_conns(Mid)),
+ megaco:stop_user(Mid),
+ application:stop(megaco),
+ i("loop -> stopped", []),
+ server_reply(Parent, stopped, ok),
+ exit(normal);
+
+ {{disconnect, Reason}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> disconnecting", []),
+ Mid = S#mgc.mid,
+ [Conn|_] = megaco:user_info(Mid, connections),
+ Res = megaco:disconnect(Conn, {self(), Reason}),
+ server_reply(Parent, disconnected, Res),
+ loop(S);
+
+ {{update_user_info, Tag, Val}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got update_user_info: ~w -> ~p", [Tag, Val]),
+ Res = (catch megaco:update_user_info(S#mgc.mid, Tag, Val)),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, update_user_info_ack, Res),
+ loop(S);
+
+ {{user_info, Tag}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got user_info request for ~w", [Tag]),
+ Res = (catch megaco:user_info(S#mgc.mid, Tag)),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, user_info_ack, Res),
+ loop(S);
+
+ {{update_conn_info, Tag, Val}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got update_conn_info: ~w -> ~p", [Tag, Val]),
+ Conns = megaco:user_info(S#mgc.mid, connections),
+ Fun = fun(CH) ->
+ (catch megaco:update_conn_info(CH, Tag, Val))
+ end,
+ Res = lists:map(Fun, Conns),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, update_conn_info_ack, Res),
+ loop(S);
+
+ {{conn_info, Tag}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got conn_info request for ~w", [Tag]),
+ Conns = megaco:user_info(S#mgc.mid, connections),
+ Fun = fun(CH) ->
+ {CH, (catch megaco:conn_info(CH, Tag))}
+ end,
+ Res = lists:map(Fun, Conns),
+ d("loop -> Res: ~p", [Res]),
+ server_reply(Parent, conn_info_ack, Res),
+ loop(S);
+
+
+ %%
+ {request_action, {Action, To}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got new request_action: ~p:~w", [Action,To]),
+ {Reply, S1} =
+ case lists:member(Action, ?valid_actions) of
+ true when To >= 0; To == infinity ->
+ {{ok, S#mgc.req_action},
+ S#mgc{req_action = Action, req_timeout = To}};
+ true ->
+ {{error, {invalid_action_timeout, To}}, S};
+ false ->
+ {{error, {invalid_action, Action}}, S}
+ end,
+ server_reply(Parent, request_action_ack, Reply),
+ loop(S1);
+
+
+ %% Reset stats
+ {reset_stats, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got request to reset stats counters"),
+ do_reset_stats(S#mgc.mid),
+ server_reply(Parent, reset_stats_ack, ok),
+ loop(S);
+
+
+ %% Give me statistics
+ {{statistics, 1}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got request for statistics 1"),
+ {ok, Gen} = megaco:get_stats(),
+ GetTrans =
+ fun(CH) ->
+ Reason = {statistics, CH},
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ {ok, Stats} =
+ case SendMod of
+ megaco_tcp -> megaco_tcp:get_stats(SendHandle);
+ megaco_udp -> megaco_udp:get_stats(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end,
+ {SendHandle, Stats}
+ end,
+ Mid = S#mgc.mid,
+ Trans =
+ lists:map(GetTrans, megaco:user_info(Mid, connections)),
+ Reply = {ok, [{gen, Gen}, {trans, Trans}]},
+ server_reply(Parent, {statistics_reply, 1}, Reply),
+ loop(S);
+
+
+ {{statistics, 2}, Parent} when S#mgc.parent == Parent ->
+ i("loop -> got request for statistics 2"),
+ {ok, Gen} = megaco:get_stats(),
+ #mgc{tcp_sup = TcpSup, udp_sup = UdpSup} = S,
+ TcpStats = get_trans_stats(TcpSup, megaco_tcp),
+ UdpStats = get_trans_stats(UdpSup, megaco_udp),
+ Reply = {ok, [{gen, Gen}, {trans, [TcpStats, UdpStats]}]},
+ server_reply(Parent, {statistics_reply, 2}, Reply),
+ loop(S);
+
+
+ %% Megaco callback messages
+ {request, Request, From} ->
+ d("loop -> received megaco request from ~p:~n~p",
+ [From, Request]),
+ {Reply, S1} = handle_megaco_request(Request, S),
+ d("loop -> send request reply: ~n~p", [Reply]),
+ reply(From, Reply),
+ loop(S1);
+
+
+ {ack_info, To, Parent} when S#mgc.parent == Parent ->
+ i("loop -> received request to inform about received ack's ", []),
+ loop(S#mgc{ack_info = To});
+
+
+ {abort_info, To, Parent} when S#mgc.parent == Parent ->
+ i("loop -> received request to inform about received aborts ", []),
+ loop(S#mgc{abort_info = To});
+
+
+ {req_info, To, Parent} when S#mgc.parent == Parent ->
+ i("loop -> received request to inform about received req's ", []),
+ loop(S#mgc{req_info = To});
+
+
+ {verbosity, V, Parent} when S#mgc.parent == Parent ->
+ i("loop -> received new verbosity: ~p", [V]),
+ put(verbosity,V),
+ loop(S);
+
+
+ {'EXIT', Pid, Reason} when S#mgc.tcp_sup =:= Pid ->
+ error_msg("MGC received unexpected exit "
+ "from TCP transport supervisor (~p):~n~p",
+ [Pid, Reason]),
+ i("loop -> [tcp] exiting", []),
+ display_system_info(S#mgc.mid, "at bad finish (tcp) "),
+ cancel_timer(S#mgc.dsi_timer),
+ Mid = S#mgc.mid,
+ (catch close_conns(Mid)),
+ megaco:stop_user(Mid),
+ application:stop(megaco),
+ i("loop -> stopped", []),
+ StopReason = {error, {tcp_terminated, Pid, Reason}},
+ server_reply(S#mgc.parent, stopped, StopReason),
+ exit(StopReason);
+
+
+ {'EXIT', Pid, Reason} when S#mgc.udp_sup =:= Pid ->
+ error_msg("MGC received unexpected exit "
+ "from UDP transport supervisor (~p):~n~p",
+ [Pid, Reason]),
+ i("loop -> [udp] exiting", []),
+ display_system_info(S#mgc.mid, "at bad finish (udp) "),
+ cancel_timer(S#mgc.dsi_timer),
+ Mid = S#mgc.mid,
+ (catch close_conns(Mid)),
+ megaco:stop_user(Mid),
+ application:stop(megaco),
+ i("loop -> stopped", []),
+ StopReason = {error, {udp_terminated, Pid, Reason}},
+ server_reply(S#mgc.parent, stopped, StopReason),
+ exit(StopReason);
+
+
+ Invalid ->
+ i("loop -> received invalid request: ~p", [Invalid]),
+ loop(S)
+ end.
+
+
+do_reset_stats(Mid) ->
+ megaco:reset_stats(),
+ do_reset_trans_stats(megaco:user_info(Mid, connections), []).
+
+do_reset_trans_stats([], _Reset) ->
+ ok;
+do_reset_trans_stats([CH|CHs], Reset) ->
+ SendMod = megaco:conn_info(CH, send_mod),
+ case lists:member(SendMod, Reset) of
+ true ->
+ do_reset_trans_stats(CHs, Reset);
+ false ->
+ SendMod:reset_stats(),
+ do_reset_trans_stats(CHs, [SendMod|Reset])
+ end.
+
+
+close_conns(Mid) ->
+ Reason = {self(), ignore},
+ Disco = fun(CH) ->
+ (catch do_close_conn(CH, Reason))
+ end,
+ lists:map(Disco, megaco:user_info(Mid, connections)).
+
+do_close_conn(CH, Reason) ->
+ d("close connection to ~p", [CH#megaco_conn_handle.remote_mid]),
+ Pid = megaco:conn_info(CH, control_pid),
+ SendMod = megaco:conn_info(CH, send_mod),
+ SendHandle = megaco:conn_info(CH, send_handle),
+ megaco:disconnect(CH, Reason),
+ case SendMod of
+ megaco_tcp -> megaco_tcp:close(SendHandle);
+ megaco_udp -> megaco_udp:close(SendHandle);
+ SendMod -> exit(Pid, Reason)
+ end.
+
+get_trans_stats(P, SendMod) when is_pid(P) ->
+ case (catch SendMod:get_stats()) of
+ {ok, Stats} ->
+ {SendMod, Stats};
+ Else ->
+ {SendMod, Else}
+ end;
+get_trans_stats(_P, SendMod) ->
+ {SendMod, undefined}.
+
+parse_receive_info([], _RH) ->
+ throw({error, no_receive_info});
+parse_receive_info(RI, RH) ->
+ parse_receive_info(RI, RH, []).
+
+parse_receive_info([], _RH, Transports) ->
+ d("parse_receive_info -> done when"
+ "~n Transports: ~p", [Transports]),
+ Transports;
+parse_receive_info([RI|RIs], RH, Transports) ->
+ d("parse_receive_info -> parse receive info"),
+ case (catch parse_receive_info1(RI, RH)) of
+ {error, Reason} ->
+ i("failed parsing receive info: ~p~n~p", [RI, Reason]),
+ exit({failed_parsing_recv_info, RI, Reason});
+ RH1 ->
+ parse_receive_info(RIs, RH, [RH1|Transports])
+ end.
+
+parse_receive_info1(RI, RH) ->
+ d("parse_receive_info1 -> get encoding module"),
+ EM = get_encoding_module(RI),
+ d("parse_receive_info1 -> get encoding config"),
+ EC = get_encoding_config(RI, EM),
+ d("parse_receive_info1 -> get transport module"),
+ TM = get_transport_module(RI),
+ d("parse_receive_info1 -> get transport port"),
+ TP = get_transport_port(RI),
+ d("parse_receive_info1 -> get transport opts"),
+ TO = get_transport_opts(RI),
+ RH1 = RH#megaco_receive_handle{send_mod = TM,
+ encoding_mod = EM,
+ encoding_config = EC},
+ d("parse_receive_info1 -> "
+ "~n Transport Opts: ~p"
+ "~n Port: ~p"
+ "~n Receive handle: ~p", [TO, TP, RH1]),
+ {TO, TP, RH1}.
+
+
+
+%% --------------------------------------------------------
+%% On some platforms there seem to take some time before
+%% a port is released by the OS (after having been used,
+%% as is often the case in the test suites).
+%% So, starting the transports is done in two steps.
+%% First) Start the actual transport(s)
+%% Second) Create the listener (tcp) or open the
+%% send/receive port (udp).
+%% The second step *may* need to be repeated!
+%% --------------------------------------------------------
+start_transports([]) ->
+ throw({error, no_transport});
+start_transports(Transports) when is_list(Transports) ->
+ {Tcp, Udp} = start_transports1(Transports, undefined, undefined),
+ ok = start_transports2(Transports, Tcp, Udp),
+ {Tcp, Udp}.
+
+start_transports1([], Tcp, Udp) ->
+ {Tcp, Udp};
+start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp)
+ when ((RH#megaco_receive_handle.send_mod =:= megaco_tcp) andalso
+ (not is_pid(Tcp))) ->
+ case megaco_tcp:start_transport() of
+ {ok, Sup} ->
+ start_transports1(Transports, Sup, Udp);
+ Else ->
+ throw({error, {failed_starting_tcp_transport, Else}})
+ end;
+start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp)
+ when ((RH#megaco_receive_handle.send_mod =:= megaco_udp) andalso
+ (not is_pid(Udp))) ->
+ case megaco_udp:start_transport() of
+ {ok, Sup} ->
+ start_transports1(Transports, Tcp, Sup);
+ Else ->
+ throw({error, {failed_starting_udp_transport, Else}})
+ end;
+start_transports1([_|Transports], Tcp, Udp) ->
+ start_transports1(Transports, Tcp, Udp).
+
+start_transports2([], _, _) ->
+ ok;
+start_transports2([{TO, Port, RH}|Transports], Tcp, Udp)
+ when RH#megaco_receive_handle.send_mod =:= megaco_tcp ->
+ start_tcp(TO, RH, Port, Tcp),
+ start_transports2(Transports, Tcp, Udp);
+start_transports2([{TO, Port, RH}|Transports], Tcp, Udp)
+ when RH#megaco_receive_handle.send_mod =:= megaco_udp ->
+ start_udp(TO, RH, Port, Udp),
+ start_transports2(Transports, Tcp, Udp).
+
+start_tcp(TO, RH, Port, Sup) ->
+ d("start tcp transport"),
+ start_tcp(TO, RH, Port, Sup, 250).
+
+start_tcp(TO, RH, Port, Sup, Timeout)
+ when is_pid(Sup) andalso is_integer(Timeout) andalso (Timeout > 0) ->
+ d("tcp listen on ~p", [Port]),
+ Opts = [{port, Port},
+ {receive_handle, RH},
+ {tcp_options, [{nodelay, true}]}] ++ TO,
+ try_start_tcp(Sup, Opts, Timeout, noError).
+
+try_start_tcp(Sup, Opts, Timeout, Error0) when (Timeout < 5000) ->
+ Sleep = random(Timeout) + 100,
+ d("try create tcp listen socket (~p,~p)", [Timeout, Sleep]),
+ case megaco_tcp:listen(Sup, Opts) of
+ ok ->
+ d("listen socket created", []),
+ Sup;
+ Error1 when Error0 =:= noError -> % Keep the first error
+ d("failed creating listen socket [1]: ~p", [Error1]),
+ sleep(Sleep),
+ try_start_tcp(Sup, Opts, Timeout*2, Error1);
+ Error2 ->
+ d("failed creating listen socket [2]: ~p", [Error2]),
+ sleep(Sleep),
+ try_start_tcp(Sup, Opts, Timeout*2, Error0)
+ end;
+try_start_tcp(Sup, _Opts, _Timeout, Error) ->
+ megaco_tcp:stop_transport(Sup),
+ case Error of
+ {error, Reason} ->
+ throw({error, {failed_starting_tcp_listen, Reason}});
+ _ ->
+ throw({error, {failed_starting_tcp_listen, Error}})
+ end.
+
+
+start_udp(TO, RH, Port, Sup) ->
+ d("start udp transport"),
+ start_udp(TO, RH, Port, Sup, 250).
+
+start_udp(TO, RH, Port, Sup, Timeout) ->
+ d("udp open ~p", [Port]),
+ Opts = [{port, Port}, {receive_handle, RH}] ++ TO,
+ try_start_udp(Sup, Opts, Timeout, noError).
+
+try_start_udp(Sup, Opts, Timeout, Error0) when (Timeout < 5000) ->
+ d("try open udp socket (~p)", [Timeout]),
+ case megaco_udp:open(Sup, Opts) of
+ {ok, _SendHandle, _ControlPid} ->
+ d("port opened", []),
+ Sup;
+ Error1 when Error0 =:= noError -> % Keep the first error
+ d("failed open port [1]: ~p", [Error1]),
+ sleep(Timeout),
+ try_start_udp(Sup, Opts, Timeout*2, Error1);
+ Error2 ->
+ d("failed open port [2]: ~p", [Error2]),
+ sleep(Timeout),
+ try_start_udp(Sup, Opts, Timeout*2, Error0)
+ end;
+try_start_udp(Sup, _Opts, _Timeout, Error) ->
+ megaco_udp:stop_transport(Sup),
+ throw({error, {failed_starting_udp_open, Error}}).
+
+
+%% -----------------------
+%% Handle megaco callbacks
+%%
+
+handle_megaco_request({handle_connect, CH, _PV}, #mgc{mg = MGs} = S) ->
+ case lists:member(CH, MGs) of
+ true ->
+ i("MG already connected: ~n ~p", [CH]),
+ {error, S};
+ false ->
+ {ok, S#mgc{mg = [CH|MGs]}}
+ end;
+
+handle_megaco_request({handle_disconnect, CH, _PV, R}, S) ->
+ d("handle_megaco_request(handle_disconnect) -> entry with"
+ "~n CH: ~p"
+ "~n R: ~p", [CH, R]),
+ CancelRes = (catch megaco:cancel(CH, R)), % Cancel the outstanding messages
+ d("handle_megaco_request(handle_disconnect) -> megaco cancel result: ~p", [CancelRes]),
+ MGs = lists:delete(CH, S#mgc.mg),
+ d("handle_megaco_request(handle_disconnect) -> MGs: ~p", [MGs]),
+ {ok, S#mgc{mg = MGs}};
+
+handle_megaco_request({handle_syntax_error, _RH, _PV, _ED}, S) ->
+ {reply, S};
+
+handle_megaco_request({handle_message_error, _CH, _PV, _ED}, S) ->
+ {no_reply, S};
+
+handle_megaco_request({handle_trans_request, CH, PV, ARs},
+ #mgc{req_info = P} = S) when is_pid(P) ->
+ d("handle_megaco_request(handle_trans_request,~p) -> entry", [P]),
+ P ! {req_received, self(), ARs},
+ do_handle_trans_request(CH, PV, ARs, S);
+handle_megaco_request({handle_trans_request, CH, PV, ARs}, S) ->
+ d("handle_megaco_request(handle_trans_request) -> entry"),
+ do_handle_trans_request(CH, PV, ARs, S);
+
+handle_megaco_request({handle_trans_long_request, CH, PV, RD}, S) ->
+ d("handle_megaco_request(handle_long_trans_request) -> entry"),
+ Reply0 = handle_act_requests(CH, PV, RD, discard_ack),
+ Reply =
+ case S of
+ #mgc{req_action = ignore, req_timeout = To} ->
+ d("handle_megaco_request(handle_long_trans_request) -> "
+ "~n To: ~p", [To]),
+ {delay_reply, To, Reply0};
+ _ ->
+ d("handle_megaco_request(handle_long_trans_request) -> "
+ "~n S: ~p", [S]),
+ Reply0
+ end,
+ {Reply, S};
+
+handle_megaco_request({handle_trans_reply, _CH, _PV, _AR, _RD}, S) ->
+ {ok, S};
+
+handle_megaco_request({handle_trans_ack, CH, PV, AS, AD},
+ #mgc{ack_info = P} = S) when is_pid(P) ->
+ d("handle_megaco_request(handle_trans_ack,~p) -> entry when"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n AS: ~p"
+ "~n AD: ~p", [P, CH, PV, AS, AD]),
+ P ! {ack_received, self(), AS},
+ {ok, S};
+
+handle_megaco_request({handle_trans_ack, CH, PV, AS, AD}, S) ->
+ d("handle_megaco_request(handle_trans_ack) -> entry with"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n AS: ~p"
+ "~n AD: ~p", [CH, PV, AS, AD]),
+ {ok, S};
+
+handle_megaco_request({handle_unexpected_trans, CH, PV, TR}, S) ->
+ d("handle_megaco_request(handle_unexpected_trans) -> entry with"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n TR: ~p", [CH, PV, TR]),
+ {ok, S};
+
+handle_megaco_request({handle_trans_request_abort, CH, PV, TI, Handler}, S) ->
+ d("handle_megaco_request(handle_trans_request_abort) -> entry with"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n TI: ~p"
+ "~n Handler: ~p", [CH, PV, TI, Handler]),
+ Reply =
+ case S#mgc.abort_info of
+ P when is_pid(P) ->
+ P ! {abort_received, self(), TI},
+ ok;
+ _ ->
+ ok
+ end,
+ {Reply, S}.
+
+
+do_handle_trans_request(CH, PV, ARs,
+ #mgc{req_action = Action, req_timeout = To} = S) ->
+ d("do_handle_megaco_request(handle_trans_request) -> entry with"
+ "~n Action: ~p"
+ "~n To: ~p", [Action, To]),
+ case handle_act_requests(CH, PV, ARs, Action) of
+ {pending_ignore, ActReqs} ->
+ {{pending, ActReqs}, S#mgc{req_action = ignore}};
+ Reply ->
+ {{delay_reply, To, Reply}, S}
+ end.
+
+
+handle_act_requests(_CH, _PV, _ActReqs, ignore) ->
+ ignore;
+handle_act_requests(_CH, _PV, ActReqs, pending) ->
+ {pending, ActReqs};
+handle_act_requests(_CH, _PV, ActReqs, pending_ignore) ->
+ {pending_ignore, ActReqs};
+handle_act_requests(CH, PV, ActReqs, handle_ack) ->
+ Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])),
+ {{handle_ack, ActReqs}, Reply};
+handle_act_requests(CH, PV, ActReqs, handle_sloppy_ack) ->
+ Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])),
+ {{handle_sloppy_ack, ActReqs}, Reply};
+handle_act_requests(CH, PV, ActReqs, _) ->
+ Reply = (catch do_handle_act_requests(CH, PV, ActReqs, [])),
+ {discard_ack, Reply}.
+
+do_handle_act_requests(_CH, _PV, [], ActReplies) ->
+ lists:reverse(ActReplies);
+do_handle_act_requests(CH, PV, [ActReq|ActReqs], ActReplies) ->
+ ActReply = handle_act_request(CH, PV, ActReq),
+ do_handle_act_requests(CH, PV, ActReqs, [ActReply|ActReplies]).
+
+handle_act_request(CH, PV, ActReq) ->
+ #'ActionRequest'{contextId = CtxId, commandRequests = Cmds} = ActReq,
+ CmdReplies = handle_cmd_requests(CH, PV, CtxId, Cmds),
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdReplies}.
+
+handle_cmd_requests(CH, PV, ?megaco_null_context_id,
+ [#'CommandRequest'{command={serviceChangeReq,Req}}]) ->
+ Rep = service_change(CH, PV, Req),
+ [{serviceChangeReply, Rep}];
+handle_cmd_requests(CH, PV, CtxId, Cmds) ->
+ do_handle_cmd_requests(CH, PV, CtxId, Cmds, []).
+
+do_handle_cmd_requests(_CH, _PV, _CtxId, [], CmdReplies) ->
+ lists:reverse(CmdReplies);
+do_handle_cmd_requests(CH, PV, CtxId, [Cmd|Cmds], CmdReplies) ->
+ CmdReply = handle_cmd_request(CH, PV, CtxId, Cmd),
+ do_handle_cmd_requests(CH, PV, CtxId, Cmds, [CmdReply|CmdReplies]).
+
+handle_cmd_request(CH, PV, CtxId,
+ #'CommandRequest'{command = {Tag,Req}}) ->
+ case Tag of
+ notifyReq ->
+ (catch handle_notify_req(CH,PV,CtxId,Req));
+
+ serviceChangeReq ->
+ ED = cre_error_descr(?megaco_not_implemented,
+ "Service change only allowed "
+ "on null context handled"),
+ throw(ED);
+
+ _ ->
+ Code = ?megaco_not_implemented,
+ ED = cre_error_descr(Code,"Unknown command requst received:"
+ "~n Tag: ~p~n Req: ~p",[Tag,Req]),
+ throw(ED)
+ end.
+
+handle_notify_req(CH, PV, CtxId,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = EvDesc}) ->
+ handle_event(CH, PV, CtxId, Tid, EvDesc).
+
+handle_event(_CH, _PV, _Cid, Tid, EvDesc) ->
+ d("handle_event -> received"
+ "~n EvDesc: ~p"
+ "~n Tid: ~p", [EvDesc, Tid]),
+ {notifyReply, cre_notifyRep(Tid)}.
+
+
+service_change(CH, _PV, SCR) ->
+ SCP = SCR#'ServiceChangeRequest'.serviceChangeParms,
+ #'ServiceChangeParm'{serviceChangeAddress = Address,
+ serviceChangeProfile = Profile,
+ serviceChangeReason = [_Reason]} = SCP,
+ TermId = SCR#'ServiceChangeRequest'.terminationID,
+ if
+ TermId == [?megaco_root_termination_id] ->
+ MyMid = CH#megaco_conn_handle.local_mid,
+ Res = {serviceChangeResParms,
+ cre_serviceChangeResParms(MyMid, Address, Profile)},
+ cre_serviceChangeReply(TermId, Res);
+ true ->
+ Res = {errorDescriptor,
+ cre_error_descr(?megaco_not_implemented,
+ "Only handled for root")},
+ cre_serviceChangeReply(TermId, Res)
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_serviceChangeReply(TermId, Result) ->
+ #'ServiceChangeReply'{terminationID = TermId,
+ serviceChangeResult = Result}.
+
+cre_serviceChangeResParms(Mid, Addr, Prof) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeProfile = Prof}.
+
+
+cre_notifyRep(Tid) ->
+ #'NotifyReply'{terminationID = [Tid]}.
+
+% cre_notifyRep(Tid,Err) ->
+% #'NotifyReply'{terminationID = [Tid], errorDescriptor = Err}.
+
+cre_error_descr(Code,Text) ->
+ #'ErrorDescriptor'{errorCode = Code, errorText = Text}.
+
+cre_error_descr(Code,FormatString,Args) ->
+ Text = lists:flatten(io_lib:format(FormatString,Args)),
+ cre_error_descr(Code,Text).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+notify_started(Parent) ->
+ Parent ! {started, self()}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% The megaco user callback interface
+
+handle_connect(CH, PV, Pid) ->
+ case CH#megaco_conn_handle.remote_mid of
+ preliminary_mid ->
+ %% Avoids deadlock
+ ok;
+ _ ->
+ Reply = request(Pid, {handle_connect, CH, PV}),
+ Reply
+ end.
+
+handle_disconnect(_CH, _PV,
+ {user_disconnect, {Pid, ignore}},
+ Pid) ->
+ ok;
+handle_disconnect(CH, _PV,
+ {user_disconnect, {Pid, cancel}},
+ Pid) ->
+ megaco:cancel(CH, disconnected),
+ ok;
+handle_disconnect(CH, PV, R, Pid) ->
+ request(Pid, {handle_disconnect, CH, PV, R}).
+
+handle_syntax_error(ReceiveHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+ Req = {handle_syntax_error, ReceiveHandle, ProtocolVersion,
+ ErrorDescriptor},
+ request(Pid, Req).
+
+handle_message_error(ConnHandle, ProtocolVersion, ErrorDescriptor, Pid) ->
+ Req = {handle_message_error, ConnHandle, ProtocolVersion, ErrorDescriptor},
+ request(Pid, Req).
+
+handle_trans_request(CH, PV, AR, Pid) ->
+ Reply = request(Pid, {handle_trans_request, CH, PV, AR}),
+ Reply.
+
+handle_trans_long_request(ConnHandle, ProtocolVersion, ReqData, Pid) ->
+ Req = {handle_trans_long_request, ConnHandle, ProtocolVersion, ReqData},
+ request(Pid, Req).
+
+handle_trans_reply(ConnHandle, ProtocolVersion, ActualReply, ReplyData, Pid) ->
+ Req = {handle_trans_reply, ConnHandle, ProtocolVersion,
+ ActualReply, ReplyData},
+ request(Pid, Req).
+
+handle_trans_ack(ConnHandle, ProtocolVersion, AckStatus, AckData, Pid) ->
+ Req = {handle_trans_ack, ConnHandle, ProtocolVersion, AckStatus, AckData},
+ request(Pid, Req).
+
+handle_unexpected_trans(ConnHandle, ProtocolVersion, Trans, Pid) ->
+ Req = {handle_unexpected_trans, ConnHandle, ProtocolVersion, Trans},
+ request(Pid, Req).
+
+handle_trans_request_abort(ConnHandle, ProtocolVersion, TransId,
+ Handler, Pid) ->
+ Req = {handle_trans_request_abort,
+ ConnHandle, ProtocolVersion, TransId, Handler},
+ request(Pid, Req).
+
+
+request(Pid, Request) ->
+ Pid ! {request, Request, self()},
+ receive
+ {reply, {delay_reply, To, Reply}, Pid} ->
+ megaco:report_event(ignore, self(), Pid,
+ "reply: delay_reply", [To, Reply]),
+ sleep(To),
+ megaco:report_event(ignore, self(), Pid,
+ "reply: delay done now return", []),
+ Reply;
+ {reply, {exit, To, Reason}, Pid} ->
+ megaco:report_event(ignore, self(), Pid,
+ "reply: exit", [To, Reason]),
+ sleep(To),
+ megaco:report_event(ignore, self(), Pid,
+ "reply: sleep done now exit", []),
+ exit(Reason);
+ {reply, Reply, Pid} ->
+ megaco:report_event(ignore, self(), Pid, "reply", [Reply]),
+ Reply
+ end.
+
+
+reply(To, Reply) ->
+ To ! {reply, Reply, self()}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) ->
+ d("sleep -> ~w", [X]),
+ receive after X -> ok end.
+
+
+error_msg(F,A) -> error_logger:error_msg("MGC: " ++ F ++ "~n",A).
+
+
+get_encoding_module(RI) ->
+ case (catch get_conf(encoding_module, RI)) of
+ {error, _} ->
+ undefined;
+ Val ->
+ Val
+ end.
+
+get_encoding_config(RI, EM) ->
+ case text_codec(EM) of
+ true ->
+ case megaco:system_info(text_config) of
+ [Conf] when is_list(Conf) ->
+ Conf;
+ _ ->
+ []
+ end;
+
+ false ->
+ get_conf(encoding_config, RI)
+ end.
+
+text_codec(megaco_compact_text_encoder) ->
+ true;
+text_codec(megaco_pretty_text_encoder) ->
+ true;
+text_codec(_) ->
+ false.
+
+
+get_transport_module(RI) ->
+ get_conf(transport_module, RI).
+
+get_transport_port(RI) ->
+ get_conf(port, RI).
+
+get_transport_opts(RI) ->
+ get_conf(transport_opts, RI, []).
+
+
+get_conf(Key, Config) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ exit({error, {not_found, Key, Config}})
+ end.
+
+get_conf(Key, Config, Default) ->
+ case lists:keysearch(Key, 1, Config) of
+ {value, {Key, Val}} ->
+ Val;
+ _ ->
+ Default
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random(N) ->
+ random:uniform(N).
+
+
+display_system_info(Mid) ->
+ display_system_info(Mid, "").
+
+display_system_info(Mid, Pre) ->
+ TimeStr = format_timestamp(now()),
+ MibStr = lists:flatten(io_lib:format("~p ", [Mid])),
+ megaco_test_lib:display_system_info(MibStr ++ Pre ++ TimeStr).
+
+
+create_timer(Time, Event) ->
+ erlang:send_after(Time, self(), {Event, Time}).
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Ref) ->
+ erlang:cancel_timer(Ref).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), "", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), "DBG: ", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, P, F, A) ->
+ print(printable(Severity,Verbosity), P, F, A).
+
+print(true, P, F, A) ->
+ print(P, F, A);
+print(_, _, _, _) ->
+ ok.
+
+print(P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s ***"
+ "~n " ++ F ++ "~n~n",
+ [format_timestamp(now()), P, self(), get(sname) | A]).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
diff --git a/lib/megaco/test/megaco_test_msg_prev3a_lib.erl b/lib/megaco/test/megaco_test_msg_prev3a_lib.erl
new file mode 100644
index 0000000000..5ce2ec302b
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_prev3a_lib.erl
@@ -0,0 +1,7503 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_prev3a_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_prev3a.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([chk_MegacoMessage/2,
+ cre_MegacoMessage/1, cre_MegacoMessage/2,
+ cre_AuthenticationHeader/3,
+ cre_Message/3,
+ cre_ErrorDescriptor/1, cre_ErrorDescriptor/2,
+ cre_ErrorCode/1,
+ cre_ErrorText/1,
+ cre_ContextID/1,
+ cre_Transaction/1,
+ cre_TransactionId/1,
+ cre_TransactionRequest/2,
+ cre_TransactionPending/1,
+ cre_TransactionReply/2, cre_TransactionReply/3,
+ cre_TransactionAck/1, cre_TransactionAck/2,
+ cre_ActionRequest/2, cre_ActionRequest/3, cre_ActionRequest/4,
+ cre_ActionReply/2, cre_ActionReply/3, cre_ActionReply/4,
+ cre_ContextRequest/0, cre_ContextRequest/1, cre_ContextRequest/2,
+ cre_ContextRequest/3, cre_ContextRequest/4, cre_ContextRequest/5,
+ cre_ContextAttrAuditRequest/0, cre_ContextAttrAuditRequest/3,
+ cre_ContextAttrAuditRequest/4, cre_ContextAttrAuditRequest/5,
+ cre_CommandRequest/1, cre_CommandRequest/2, cre_CommandRequest/3,
+ cre_Command/2,
+ cre_CommandReply/2,
+ cre_TopologyRequest/3, cre_TopologyRequest/4,
+ cre_AmmRequest/2,
+ cre_AmmDescriptor/1,
+ cre_AmmsReply/1, cre_AmmsReply/2,
+ cre_SubtractRequest/1, cre_SubtractRequest/2,
+ cre_AuditRequest/2,
+ cre_AuditReply/1,
+ cre_AuditResult/2,
+ cre_AuditReturnParameter/1,
+ cre_AuditDescriptor/0, cre_AuditDescriptor/1, cre_AuditDescriptor/2,
+ cre_IndAuditParameter/1,
+ cre_IndAudMediaDescriptor/0, cre_IndAudMediaDescriptor/1,
+ cre_IndAudMediaDescriptor/2,
+ cre_IndAudStreamDescriptor/2,
+ cre_IndAudStreamParms/0, cre_IndAudStreamParms/1,
+ cre_IndAudStreamParms/3, cre_IndAudStreamParms/4,
+ cre_IndAudLocalControlDescriptor/0,
+ cre_IndAudLocalControlDescriptor/4,
+ cre_IndAudPropertyParm/1,
+ cre_IndAudLocalRemoteDescriptor/1,
+ cre_IndAudLocalRemoteDescriptor/2,
+ cre_IndAudPropertyGroup/1,
+ cre_IndAudTerminationStateDescriptor/1,
+ cre_IndAudTerminationStateDescriptor/3,
+ cre_IndAudEventsDescriptor/1, cre_IndAudEventsDescriptor/2,
+ cre_IndAudEventsDescriptor/3,
+ cre_IndAudEventBufferDescriptor/1,
+ cre_IndAudEventBufferDescriptor/2,
+ cre_IndAudSignalsDescriptor/1,
+ cre_IndAudSeqSigList/1,
+ cre_IndAudSeqSigList/2,
+ cre_IndAudSignal/1, cre_IndAudSignal/2,
+ cre_IndAudDigitMapDescriptor/0, cre_IndAudDigitMapDescriptor/1,
+ cre_IndAudStatisticsDescriptor/1,
+ cre_IndAudPackagesDescriptor/2,
+ cre_NotifyRequest/2, cre_NotifyRequest/3,
+ cre_NotifyReply/1, cre_NotifyReply/2,
+ cre_ObservedEventsDescriptor/2,
+ cre_ObservedEvent/2, cre_ObservedEvent/3, cre_ObservedEvent/4,
+ cre_EventName/1,
+ cre_EventParameter/2, cre_EventParameter/4,
+ cre_ServiceChangeRequest/2,
+ cre_ServiceChangeReply/2,
+ cre_ServiceChangeResult/1,
+ %% cre_WildcardField/1,
+ cre_TerminationAudit/1,
+ cre_TerminationID/2,
+ cre_TerminationIDList/1,
+ cre_MediaDescriptor/0, cre_MediaDescriptor/1, cre_MediaDescriptor/2,
+ cre_StreamDescriptor/2,
+ cre_StreamParms/0, cre_StreamParms/1, cre_StreamParms/2,
+ cre_StreamParms/3, cre_StreamParms/4,
+ cre_LocalControlDescriptor/1, cre_LocalControlDescriptor/2,
+ cre_LocalControlDescriptor/4,
+ cre_StreamMode/1,
+ cre_PropertyParm/2, cre_PropertyParm/4,
+ cre_Name/1,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+ cre_Relation/1,
+ cre_LocalRemoteDescriptor/1,
+ cre_PropertyGroup/1,
+ cre_TerminationStateDescriptor/1,
+ cre_TerminationStateDescriptor/2,
+ cre_TerminationStateDescriptor/3,
+ cre_EventBufferControl/1,
+ cre_ServiceState/1,
+ cre_MuxDescriptor/2, %% cre_MuxDescriptor/3,
+ cre_MuxType/1,
+ cre_StreamID/1,
+ cre_EventsDescriptor/0, cre_EventsDescriptor/2,
+ cre_RequestedEvent/1,
+ cre_RequestedEvent/2, cre_RequestedEvent/3, cre_RequestedEvent/4,
+ cre_RequestedActions/0,
+ cre_RequestedActions/1, cre_RequestedActions/4,
+ cre_EventDM/1,
+ cre_SecondEventsDescriptor/1, cre_SecondEventsDescriptor/2,
+ cre_SecondRequestedEvent/2, cre_SecondRequestedEvent/3,
+ cre_SecondRequestedEvent/4,
+ cre_SecondRequestedActions/0, cre_SecondRequestedActions/1,
+ cre_SecondRequestedActions/2, cre_SecondRequestedActions/3,
+ cre_EventBufferDescriptor/1,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+ cre_SignalsDescriptor/1,
+ cre_SignalRequest/1,
+ cre_SeqSigList/2,
+ cre_Signal/1, cre_Signal/2, cre_Signal/7, cre_Signal/9,
+ cre_SignalDirection/1,
+ cre_SignalType/1,
+ cre_SignalName/1,
+ cre_NotifyCompletion/1,
+ cre_SigParameter/2, cre_SigParameter/4,
+ cre_RequestID/1,
+ cre_ModemDescriptor/2, %% cre_ModemDescriptor/3,
+ cre_ModemType/1,
+ cre_DigitMapDescriptor/0, cre_DigitMapDescriptor/1,
+ cre_DigitMapDescriptor/2,
+ cre_DigitMapName/1,
+ cre_DigitMapValue/1, cre_DigitMapValue/4, cre_DigitMapValue/5,
+ cre_ServiceChangeParm/2, cre_ServiceChangeParm/4,
+ cre_ServiceChangeParm/9, cre_ServiceChangeParm/10,
+ cre_ServiceChangeAddress/2,
+ cre_ServiceChangeResParm/0, cre_ServiceChangeResParm/2,
+ cre_ServiceChangeResParm/5,
+ cre_ServiceChangeMethod/1,
+ cre_ServiceChangeProfile/1, cre_ServiceChangeProfile/2,
+ cre_PackagesDescriptor/1,
+ cre_PackagesItem/2,
+ cre_StatisticsDescriptor/1,
+ cre_StatisticsParameter/1, cre_StatisticsParameter/2,
+%% cre_NonStandardData/2,
+%% cre_NonStandardIdentifier/1,
+%% cre_H221NonStandard/4,
+ cre_TimeNotation/2,
+ cre_Value/1,
+ cre_BOOLEAN/1
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') andalso
+ is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+cre_AuthenticationHeader(SPI, SN, AD) ->
+ #'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+cre_ErrorDescriptor(EC) when is_integer(EC) ->
+ #'ErrorDescriptor'{errorCode = EC}.
+
+cre_ErrorDescriptor(EC, ET) when is_integer(EC) andalso is_list(ET) ->
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_ErrorCode(C) when is_integer(C) andalso (0 =< C) andalso (C =< 65535) ->
+ C;
+cre_ErrorCode(C) ->
+ exit({invalid_ErrorCode, C}).
+
+cre_ErrorText(T) when is_list(T) ->
+ T.
+
+cre_ContextID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA}.
+
+cre_TransactionId(Val) when (0 =< Val) andalso (Val =< 4294967295) ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs) when is_integer(TransID) andalso is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+cre_TransactionPending(TransID) when is_integer(TransID) ->
+ #'TransactionPending'{transactionId = TransID}.
+
+cre_TransactionReply(TransID, ED)
+ when is_integer(TransID) andalso is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, ARs)
+ when is_integer(TransID) andalso is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionReply(TransID, IAR, ED)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, IAR, ARs)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionAck(FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck}.
+
+cre_TransactionAck(FirstAck, FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck};
+cre_TransactionAck(FirstAck, LastAck) ->
+ #'TransactionAck'{firstAck = FirstAck,
+ lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) and is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ (is_record(CtxReq, 'ContextRequest') or
+ (CtxReq == asn1_NOVALUE)) and
+ (is_record(CAAR, 'ContextAttrAuditRequest') or
+ (CAAR == asn1_NOVALUE)) and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionReply(CtxID, CmdReps)
+ when is_integer(CtxID) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(ED, 'ErrorDescriptor') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ commandReply = CmdReps};
+cre_ActionReply(CtxID, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ (is_record(ED, 'ErrorDescriptor') orelse (ED =:= asn1_NOVALUE)) andalso
+ (is_record(CtxReq, 'ContextRequest') orelse (CtxReq =:= asn1_NOVALUE)) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ContextRequest() ->
+ strip_ContextRequest(#'ContextRequest'{}).
+
+cre_ContextRequest(Prio) when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) ->
+ strip_ContextRequest(#'ContextRequest'{priority = Prio});
+cre_ContextRequest(Em) when (Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE) ->
+ strip_ContextRequest(#'ContextRequest'{emergency = Em});
+cre_ContextRequest(Top) when is_list(Top) ->
+ strip_ContextRequest(#'ContextRequest'{topologyReq = Top}).
+
+cre_ContextRequest(Prio, Em)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Top)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) andalso is_list(Top) ->
+ CR = #'ContextRequest'{priority = Prio,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepsCallind = Ieps},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Em, Top, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ (is_list(Ctx)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextProp = Ctx},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepsCallind = Ieps,
+ contextProp = Ctx},
+ strip_ContextRequest(CR).
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = Top,
+ iepsCallind = Ieps,
+ contextProp = Prop} = CR) ->
+ case (((Top == []) or (Top == asn1_NOVALUE)) and
+ ((Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ ((Prop == []) or (Prop == asn1_NOVALUE))) of
+ true ->
+ asn1_NOVALUE;
+ false ->
+ CR
+ end;
+strip_ContextRequest(CR) ->
+ CR.
+
+cre_ContextAttrAuditRequest() ->
+ strip_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{}).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepsCallind = Ieps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepsCallind = Ieps,
+ contextPropAud = Ctx},
+ strip_ContextAttrAuditRequest(CAAR).
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepsCallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(CAAR) ->
+ CAAR.
+
+cre_CommandRequest(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_CommandRequest(Cmd, Opt)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt}.
+
+cre_CommandRequest(Cmd, Opt, WR)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+ ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}.
+
+cre_Command(addReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(moveReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(modReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(subtractReq = Tag, Req)
+ when is_record(Req, 'SubtractRequest') ->
+ {Tag, Req};
+cre_Command(auditCapRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(auditValueRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(notifyReq = Tag, Req)
+ when is_record(Req, 'NotifyRequest') ->
+ {Tag, Req};
+cre_Command(serviceChangeReq = Tag, Req)
+ when is_record(Req, 'ServiceChangeRequest') ->
+ {Tag, Req}.
+
+cre_CommandReply(addReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(moveReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(modReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(subtractReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(auditCapReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(auditValueReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(notifyReply = Tag, Rep)
+ when is_record(Rep, 'NotifyReply') ->
+ {Tag, Rep};
+cre_CommandReply(serviceChangeReply = Tag, Rep)
+ when is_record(Rep, 'ServiceChangeReply') ->
+ {Tag, Rep}.
+
+cre_TopologyRequest(From, To, Dir)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir}.
+
+cre_TopologyRequest(From, To, Dir, SID)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID}.
+
+cre_AmmRequest(TermIDs, Descs) ->
+ d("cre_AmmRequest -> entry with"
+ "~n TermIDs: ~p"
+ "~n Descs: ~p", [TermIDs, Descs]),
+ case is_TerminationIDList(TermIDs) andalso
+ is_AmmRequest_descriptors(Descs) of
+ true ->
+ #'AmmRequest'{terminationID = TermIDs,
+ descriptors = Descs};
+ false ->
+ error({invalid_AmmRequest, {TermIDs, Descs}})
+ end.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ case is_StatisticsDescriptor(D) of
+ true ->
+ {statisticsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end
+ end.
+
+cre_AmmsReply(TermIDs) when is_list(TermIDs) ->
+ #'AmmsReply'{terminationID = TermIDs}.
+
+cre_AmmsReply(TermIDs, TAs) when is_list(TermIDs) andalso is_list(TAs) ->
+ #'AmmsReply'{terminationID = TermIDs,
+ terminationAudit = TAs}.
+
+cre_SubtractRequest(TermIDs) when is_list(TermIDs) ->
+ #'SubtractRequest'{terminationID = TermIDs}.
+
+cre_SubtractRequest(TermIDs, Audit)
+ when is_list(TermIDs) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'SubtractRequest'{terminationID = TermIDs,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TermID, Audit)
+ when is_record(TermID, megaco_term_id) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TermID,
+ auditDescriptor = Audit}.
+
+cre_AuditReply(TermIDs) when is_list(TermIDs) ->
+ {contextAuditResult, TermIDs};
+cre_AuditReply(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {error, ED};
+cre_AuditReply(Audit) when is_record(Audit, 'AuditResult') ->
+ {auditResult, Audit}.
+
+cre_AuditResult(TermID, TAs)
+ when is_record(TermID, megaco_term_id) andalso is_list(TAs) ->
+ #'AuditResult'{terminationID = TermID,
+ terminationAuditResult = TAs}.
+
+cre_TerminationAudit(D) ->
+ true = is_TerminationAudit(D),
+ D.
+
+cre_AuditReturnParameter(D) when is_record(D, 'ErrorDescriptor') ->
+ {errorDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'EventSpec') ->
+ {eventBufferDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ObservedEventsDescriptor') ->
+ {observedEventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ {statisticsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'PackagesItem') ->
+ {packagesDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'AuditDescriptor') ->
+ {emptyDescriptors, D};
+cre_AuditReturnParameter([H|_] = D) when is_tuple(H) ->
+ {signalsDescriptor, D}.
+
+cre_AuditDescriptor() ->
+ #'AuditDescriptor'{}.
+
+cre_AuditDescriptor([H|_] = AT) when is_atom(H) ->
+ #'AuditDescriptor'{auditToken = AT};
+cre_AuditDescriptor(APT) ->
+ #'AuditDescriptor'{auditPropertyToken = APT}.
+
+cre_AuditDescriptor(AT, APT) ->
+ #'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}.
+
+cre_IndAuditParameter(D) when is_record(D, 'IndAudMediaDescriptor') ->
+ {indAudMediaDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventsDescriptor') ->
+ {indAudEventsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventBufferDescriptor') ->
+ {indAudEventBufferDescriptor, D};
+cre_IndAuditParameter({signal, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter({seqSigList, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudDigitMapDescriptor') ->
+ {indAudDigitMapDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudStatisticsDescriptor') ->
+ {indAudStatisticsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudPackagesDescriptor') ->
+ {indAudPackagesDescriptor, D}.
+
+cre_IndAudMediaDescriptor() ->
+ #'IndAudMediaDescriptor'{}.
+
+cre_IndAudMediaDescriptor(TSD)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudMediaDescriptor'{termStateDescr = TSD};
+cre_IndAudMediaDescriptor(Parms) when is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{streams = Streams};
+cre_IndAudMediaDescriptor(Descs) when is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{streams = Streams}.
+
+cre_IndAudMediaDescriptor(TSD, Parms)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso
+ is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_IndAudMediaDescriptor(TSD, Descs)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_IndAudStreamDescriptor(SID, Parms)
+ when is_integer(SID) andalso is_record(Parms, 'IndAudStreamParms') ->
+ #'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}.
+
+cre_IndAudStreamParms() ->
+ #'IndAudStreamParms'{}.
+
+cre_IndAudStreamParms(LCD) when is_record(LCD, 'IndAudLocalControlDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD};
+cre_IndAudStreamParms(SD) when is_record(SD, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{statisticsDescriptor = SD}.
+
+cre_IndAudStreamParms(LC, L, R)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R}.
+
+cre_IndAudStreamParms(LC, L, R, S)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(S, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R,
+ statisticsDescriptor = S}.
+
+cre_IndAudLocalControlDescriptor() ->
+ #'IndAudLocalControlDescriptor'{}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_IndAudPropertyParm(PkgdName) when is_list(PkgdName) ->
+ #'IndAudPropertyParm'{name = PkgdName}.
+
+cre_IndAudLocalRemoteDescriptor(Grps)
+ when is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+cre_IndAudLocalRemoteDescriptor(GrpID, Grps)
+ when is_integer(GrpID) andalso (0 =< GrpID) andalso (GrpID =< 65535) andalso is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = GrpID,
+ propGrps = Grps}.
+
+cre_IndAudPropertyGroup([]) ->
+ [];
+cre_IndAudPropertyGroup([H|_] = PG)
+ when is_record(H, 'IndAudPropertyParm') ->
+ PG.
+
+cre_IndAudTerminationStateDescriptor([] = PP) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+cre_IndAudTerminationStateDescriptor([H|_] = PP)
+ when is_record(H, 'IndAudPropertyParm') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}.
+
+cre_IndAudEventsDescriptor(PkgdName)
+ when is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName)
+ when is_integer(RID) andalso is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+cre_IndAudEventsDescriptor(PkgdName, SID)
+ when is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+ when is_integer(RID) andalso is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = PkgdName,
+ streamID = SID}.
+
+cre_IndAudEventBufferDescriptor(EventName) when is_list(EventName) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+cre_IndAudEventBufferDescriptor(EventName, SID)
+ when is_list(EventName) andalso is_integer(SID) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSignal') ->
+ {signal, S};
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSeqSigList') ->
+ {seqSigList, S}.
+
+cre_IndAudSeqSigList(ID) when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) ->
+ #'IndAudSeqSigList'{id = ID}.
+
+cre_IndAudSeqSigList(ID, S)
+ when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) andalso is_record(S, 'IndAudSignal') ->
+ #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+cre_IndAudSignal(SigName) when is_list(SigName) ->
+ #'IndAudSignal'{signalName = SigName}.
+
+cre_IndAudSignal(SigName, SID) when is_list(SigName) andalso is_integer(SID) ->
+ #'IndAudSignal'{signalName = SigName, streamID = SID}.
+
+cre_IndAudDigitMapDescriptor() ->
+ #'IndAudDigitMapDescriptor'{}.
+
+cre_IndAudDigitMapDescriptor(DMN) when is_list(DMN) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+cre_IndAudStatisticsDescriptor(StatName) when is_list(StatName) ->
+ #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+cre_IndAudPackagesDescriptor(N, V)
+ when is_list(N) andalso
+ is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+cre_NotifyRequest(TermIDs, D)
+ when is_list(TermIDs) andalso is_record(D, 'ObservedEventsDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D}.
+
+cre_NotifyRequest(TermIDs, D, ED)
+ when is_list(TermIDs) andalso
+ is_record(D, 'ObservedEventsDescriptor') andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D,
+ errorDescriptor = ED}.
+
+cre_NotifyReply(TermIDs) when is_list(TermIDs) ->
+ #'NotifyReply'{terminationID = TermIDs}.
+
+cre_NotifyReply(TermIDs, ED)
+ when is_list(TermIDs) andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyReply'{terminationID = TermIDs,
+ errorDescriptor = ED}.
+
+cre_ObservedEventsDescriptor(RID, [H|_] = L)
+ when is_integer(RID) andalso is_record(H, 'ObservedEvent') ->
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = L}.
+
+cre_ObservedEvent(EN, EPL) when is_list(EN) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL};
+cre_ObservedEvent(EN, TN) when is_list(EN) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL) when is_list(EN) andalso is_integer(SID) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL};
+cre_ObservedEvent(EN, EPL, TN)
+ when is_list(EN) andalso is_list(EPL) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL, TN)
+ when is_list(EN) andalso
+ is_integer(SID) andalso
+ is_list(EPL) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V)
+ when is_list(N) andalso
+ is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso
+ is_list(V) andalso
+ is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) andalso
+ is_list(V) andalso
+ is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso
+ is_list(V) andalso
+ is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+cre_ServiceChangeRequest(TermIDs, SCP)
+ when is_list(TermIDs) andalso
+ is_record(SCP, 'ServiceChangeParm') ->
+ #'ServiceChangeRequest'{terminationID = TermIDs,
+ serviceChangeParms = SCP}.
+
+cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+ when is_list(TermIDs) andalso
+ is_atom(Tag) andalso
+ is_tuple(R) ->
+ #'ServiceChangeReply'{terminationID = TermIDs,
+ serviceChangeResult = SCR}.
+
+cre_ServiceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED};
+cre_ServiceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP}.
+
+%% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+cre_TerminationID(W, ID)
+ when is_list(W) andalso
+ is_list(ID) andalso
+ (1 =< length(ID)) andalso
+ (length(ID) =< 8) ->
+ #'TerminationID'{wildcard = W,
+ id = ID}.
+
+cre_TerminationIDList(L) when is_list(L) ->
+ L.
+
+cre_MediaDescriptor() ->
+ #'MediaDescriptor'{}.
+
+cre_MediaDescriptor(TSD) when is_record(TSD, 'TerminationStateDescriptor') ->
+ #'MediaDescriptor'{termStateDescr = TSD};
+cre_MediaDescriptor(SP) when is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{streams = Streams};
+cre_MediaDescriptor([H|_] = SDs) when is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{streams = Streams}.
+
+cre_MediaDescriptor(TSD, SP)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_MediaDescriptor(TSD, [H|_] = SDs)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_StreamDescriptor(SID, SP) when is_integer(SID) andalso is_record(SP, 'StreamParms') ->
+ #'StreamDescriptor'{streamID = SID,
+ streamParms = SP}.
+
+cre_StreamParms() ->
+ #'StreamParms'{}.
+
+cre_StreamParms(LCD) when is_record(LCD, 'LocalControlDescriptor') ->
+ #'StreamParms'{localControlDescriptor = LCD};
+cre_StreamParms(LD) when is_record(LD, 'LocalRemoteDescriptor') ->
+ #'StreamParms'{localDescriptor = LD};
+cre_StreamParms(SD) when is_list(SD) ->
+ #'StreamParms'{statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD, RD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD};
+cre_StreamParms(LCD, LD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD, RD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}.
+
+cre_LocalControlDescriptor(SM) when is_atom(SM) ->
+ #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+cre_LocalControlDescriptor([H|_] = PP) when is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, [H|_] = PP)
+ when is_atom(SM) andalso is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+ when is_atom(SM) and
+ ((RV == true) or (RV == false) or (RV == asn1_NOVALUE)) and
+ ((RG == true) or (RG == false) or (RG == asn1_NOVALUE)) and
+ is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_StreamMode(sendOnly = M) ->
+ M;
+cre_StreamMode(recvOnly = M) ->
+ M;
+cre_StreamMode(sendRecv = M) ->
+ M;
+cre_StreamMode(inactive = M) ->
+ M;
+cre_StreamMode(loopBack = M) ->
+ M.
+
+cre_PropertyParm(N, [H|_] = V) when is_list(N) andalso is_list(H) ->
+ #'PropertyParm'{name = N, value = V}.
+
+cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+ when is_list(N) andalso is_list(H) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+cre_Name(N) when is_list(N) and (length(N) == 2) ->
+ N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) and (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) and (length(PackageName) =< 64)) and
+ (is_list(ItemID) and (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+cre_Relation(greaterThan = R) ->
+ R;
+cre_Relation(smallerThan = R) ->
+ R;
+cre_Relation(unequalTo = R) ->
+ R.
+
+cre_LocalRemoteDescriptor([H|_] = PGs) when is_list(H) ->
+ #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+cre_PropertyGroup([H|_] = PG) when is_record(H, 'PropertyParm') ->
+ PG.
+
+cre_TerminationStateDescriptor([H|_] = PPs) when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+ when is_record(H, 'PropertyParm') andalso
+ ((EMC == off) or (EMC == lockStep)) and
+ ((SS == test) or (SS == outOfSvc) or (SS == inSvc)) ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EMC,
+ serviceState = SS}.
+
+cre_EventBufferControl(off = EBC) ->
+ EBC;
+cre_EventBufferControl(lockStep = EBC) ->
+ EBC.
+
+cre_ServiceState(test = SS) ->
+ SS;
+cre_ServiceState(outOfSvc = SS) ->
+ SS;
+cre_ServiceState(inSvc = SS) ->
+ SS.
+
+cre_MuxDescriptor(MT, [H|_] = TL)
+ when is_atom(MT) andalso is_record(H, 'TerminationID') ->
+ #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+cre_MuxType(h221 = MT) ->
+ MT;
+cre_MuxType(h223 = MT) ->
+ MT;
+cre_MuxType(h226 = MT) ->
+ MT;
+cre_MuxType(v76 = MT) ->
+ MT;
+cre_MuxType(nx64k = MT) ->
+ MT.
+
+cre_StreamID(Val) when (0 =< Val) andalso (Val =< 65535) ->
+ Val;
+cre_StreamID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+%% RequestID must be present if eventList is non empty
+cre_EventsDescriptor() ->
+ #'EventsDescriptor'{eventList = []}.
+
+cre_EventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'RequestedEvent') ->
+ #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_RequestedEvent(N) ->
+ #'RequestedEvent'{pkgdName = N}.
+
+cre_RequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_RequestedEvent(N, EA)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions')->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA}.
+
+
+cre_RequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_RequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedActions() ->
+ #'RequestedActions'{}.
+
+cre_RequestedActions(KA)
+ when (KA == true) or (KA == true) or (KA == asn1_NOVALUE) ->
+ #'RequestedActions'{keepActive = KA};
+cre_RequestedActions(SE)
+ when is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE) ->
+ #'RequestedActions'{secondEvent = SE};
+cre_RequestedActions(SD)
+ when is_list(SD) or (SD == asn1_NOVALUE) ->
+ #'RequestedActions'{signalsDescriptor = SD};
+cre_RequestedActions({Tag, _} = EDM)
+ when is_atom(Tag) or (EDM == asn1_NOVALUE) ->
+ #'RequestedActions'{eventDM = EDM}.
+
+cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}.
+
+cre_EventDM(N) when is_list(N) ->
+ {digitMapName, N};
+cre_EventDM(V) when is_record(V, 'DigitMapValue') ->
+ {digitMapValue, V}.
+
+cre_SecondEventsDescriptor([H|_] = EL)
+ when is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{eventList = EL}.
+
+cre_SecondEventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_SecondRequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedActions() ->
+ #'SecondRequestedActions'{}.
+
+cre_SecondRequestedActions(KA)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA};
+cre_SecondRequestedActions(SD) when is_list(SD) ->
+ #'SecondRequestedActions'{signalsDescriptor = SD};
+cre_SecondRequestedActions({Tag, _} = EDM) when is_atom(Tag) ->
+ #'SecondRequestedActions'{eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, {Tag, _} = EDM)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) ->
+ #'SecondRequestedActions'{keepActive = KA, eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag),
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}.
+
+cre_EventBufferDescriptor([H|_] = D) when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL) when is_list(N) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+cre_SignalsDescriptor(D) ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ D;
+ false ->
+ error({invalid_SignalsDescriptor, D})
+ end.
+
+cre_SignalRequest(S) when is_record(S, 'Signal') ->
+ {signal, S};
+cre_SignalRequest(S) when is_record(S, 'SeqSigList') ->
+ {seqSigList, S}.
+
+cre_SeqSigList(ID, [H|_] = SL)
+ when is_integer(ID) andalso (0 =< ID) andalso (ID =< 65535) andalso is_record(H, 'Signal') ->
+ #'SeqSigList'{id = ID, signalList = SL}.
+
+cre_Signal(N) when is_list(N) ->
+ #'Signal'{signalName = N}.
+
+cre_Signal(N, SPL) when is_list(N) andalso is_list(SPL) ->
+ #'Signal'{signalName = N,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}.
+
+cre_SignalType(brief = ST) ->
+ ST;
+cre_SignalType(onOff = ST) ->
+ ST;
+cre_SignalType(timeOut = ST) ->
+ ST.
+
+cre_SignalDirection(internal = SD) ->
+ SD;
+cre_SignalDirection(external = SD) ->
+ SD;
+cre_SignalDirection(both = SD) ->
+ SD.
+
+cre_SignalName(N) ->
+ cre_PkgdName(N).
+
+cre_NotifyCompletion(L) when is_list(L) ->
+ Vals = [onTimeOut, onInterruptByEvent,
+ onInterruptByNewSignalDescr, otherReason],
+ F = fun(E) -> case lists:member(E, Vals) of
+ true ->
+ ok;
+ false ->
+ exit({invalid_NotifyCompletion, E})
+ end
+ end,
+ lists:foreach(F, L),
+ L.
+
+cre_SigParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'SigParameter'{sigParameterName = N, value = V}.
+
+cre_SigParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+cre_RequestID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_RequestID(Val) ->
+ exit({invalid_RequestID, Val}).
+
+cre_ModemDescriptor(MTL, MPL) when is_list(MTL) andalso is_list(MPL) ->
+ #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemDescriptor(MTL, MPL, NSD)
+%% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+cre_ModemType(v18 = MT) ->
+ MT;
+cre_ModemType(v22 = MT) ->
+ MT;
+cre_ModemType(v22bis = MT) ->
+ MT;
+cre_ModemType(v32 = MT) ->
+ MT;
+cre_ModemType(v32bis = MT) ->
+ MT;
+cre_ModemType(v34 = MT) ->
+ MT;
+cre_ModemType(v90 = MT) ->
+ MT;
+cre_ModemType(v91 = MT) ->
+ MT;
+cre_ModemType(synchISDN = MT) ->
+ MT.
+
+cre_DigitMapDescriptor() ->
+ #'DigitMapDescriptor'{}.
+
+cre_DigitMapDescriptor(N) when is_list(N) ->
+ #'DigitMapDescriptor'{digitMapName = N};
+cre_DigitMapDescriptor(V) when is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = V}.
+
+cre_DigitMapDescriptor(N, V) when is_list(N) andalso is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+cre_DigitMapName(N) ->
+ cre_Name(N).
+
+cre_DigitMapValue(DMB) when is_list(DMB) ->
+ #'DigitMapValue'{digitMapBody = DMB}.
+
+cre_DigitMapValue(Start, Short, Long, DMB) ->
+ cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+ when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+ (Start == asn1_NOVALUE)) and
+ ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+ (Short == asn1_NOVALUE)) and
+ ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+ (Long == asn1_NOVALUE)) and
+ is_list(DMB) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+ (Dur == asn1_NOVALUE)) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = DMB,
+ durationTimer = Dur}.
+
+cre_ServiceChangeParm(M, R) when is_atom(M) andalso is_list(R) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R}.
+
+cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+ cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE).
+
+%% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I) ->
+ cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, asn1_NOVALUE).
+
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, IF)
+ when is_atom(M) and
+ ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ is_list(R) and
+ ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+ (D == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+ (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) and
+ ((IF == 'NULL') or (IF == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Mid,
+ timeStamp = TS,
+ serviceChangeInfo = I,
+ serviceChangeIncompleteFlag = IF};
+ _ ->
+ exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeAddress(portNumber = Tag, P)
+ when is_integer(P) andalso (0 =< P) andalso (P =< 65535) ->
+ {Tag, P};
+cre_ServiceChangeAddress(ip4Address = Tag, A) when is_record(A, 'IP4Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(ip6Address = Tag, A) when is_record(A, 'IP6Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(domainName = Tag, N) when is_record(N, 'DomainName') ->
+ {Tag, N};
+cre_ServiceChangeAddress(deviceName = Tag, N) when is_list(N) ->
+ {Tag, N};
+cre_ServiceChangeAddress(mtpAddress = Tag, A) when is_list(A) ->
+ {Tag, A}.
+
+cre_ServiceChangeResParm() ->
+ #'ServiceChangeResParm'{}.
+cre_ServiceChangeResParm(Addr, Prof) ->
+ cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+ Prof, asn1_NOVALUE).
+cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+ when ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ timeStamp = TS};
+ _ ->
+ exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeMethod(failover = M) ->
+ M;
+cre_ServiceChangeMethod(forced = M) ->
+ M;
+cre_ServiceChangeMethod(graceful = M) ->
+ M;
+cre_ServiceChangeMethod(restart = M) ->
+ M;
+cre_ServiceChangeMethod(disconnected = M) ->
+ M;
+cre_ServiceChangeMethod(handOff = M) ->
+ M.
+
+%% The version field is added to make it look more like ABNF
+cre_ServiceChangeProfile(N) ->
+ cre_ServiceChangeProfile(N, 1).
+
+cre_ServiceChangeProfile(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'ServiceChangeProfile'{profileName = N, version = V}.
+
+cre_PackagesDescriptor([H|_] = D) when is_record(H, 'PackagesItem') ->
+ D.
+
+cre_PackagesItem(N, Ver)
+ when is_list(N) andalso is_integer(Ver) andalso (0 =< Ver) andalso (Ver =< 99) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = Ver}.
+
+cre_StatisticsDescriptor(D) ->
+ true = is_StatisticsDescriptor(D),
+ D.
+
+cre_StatisticsParameter(N) when is_list(N) ->
+ #'StatisticsParameter'{statName = N}.
+
+cre_StatisticsParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% {h221NonStandard, H221};
+%% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% {object, Obj};
+%% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% {experimental, Exp}.
+
+%% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}.
+
+cre_TimeNotation(D, T)
+ when is_list(D) andalso
+ (length(D) =:= 8) andalso
+ is_list(T), length(T) == 8 ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_Value([H|_] = V) when is_list(H) ->
+ V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% -- MegacoMessage --
+
+is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}) ->
+ d("is_MegacoMessage -> entry"),
+ is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+is_MegacoMessage(_) ->
+ false.
+
+
+chk_MegacoMessage(M, M) ->
+ d("chk_MegacoMessage -> entry (1)"),
+ chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ d("chk_MegacoMessage -> entry (2)"),
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type('MegacoMessage', M1, M2).
+
+
+%% -- AuthenticationHeader --
+
+is_opt_AuthenticationHeader(AH) ->
+ is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}) ->
+ is_SecurityParmIndex(SPI) andalso
+ is_SequenceNum(SN) andalso
+ is_AuthData(AD);
+is_AuthenticationHeader(_) ->
+ false.
+
+%% This stuff is not really used, so make it simple...
+chk_opt_AuthenticationHeader(A1, A2) ->
+ chk_OPTIONAL('AuthenticationHeader', A1, A2,
+ fun is_AuthenticationHeader/1,
+ fun chk_AuthenticationHeader/2).
+
+chk_AuthenticationHeader(A, A) ->
+ chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+chk_AuthenticationHeader(A1, A2) ->
+ case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+ true ->
+ not_equal('AuthenticationHeader', A1, A2);
+ false ->
+ wrong_type('AuthenticationHeader', A1, A2)
+ end.
+
+
+%% -- SecurityParmIndex --
+
+is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- SequenceNum --
+
+is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- AuthData --
+
+is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% -- Message --
+
+is_Message(#'Message'{version = V,
+ mId = MID,
+ messageBody = Body}) ->
+ d("is_Message -> entry"),
+ is_INTEGER(V, {range, 0, 99}) andalso
+ is_MId(MID) andalso
+ is_Message_messageBody(Body);
+is_Message(_) ->
+ false.
+
+chk_Message(M, M) ->
+ d("chk_Message -> entry (1)"),
+ chk_type(fun is_Message/1, 'Message', M);
+chk_Message(#'Message'{version = V1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = V2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ d("chk_Message -> entry with"
+ "~n V1: ~p"
+ "~n MID1: ~p"
+ "~n Body1: ~p"
+ "~n V2: ~p"
+ "~n MID2: ~p"
+ "~n Body2: ~p",
+ [V1, MID1, Body1, V2, MID2, Body2]),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'Message'),
+ validate(fun() -> chk_MId(MID1, MID2) end, 'Message'),
+ chk_Message_messageBody(Body1, Body2),
+ ok;
+chk_Message(M1, M2) ->
+ wrong_type('Message', M1, M2).
+
+
+is_Message_messageBody({Tag, Val}) ->
+ d("is_Message_messageBody -> entry"),
+ is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val);
+is_Message_messageBody(_) ->
+ false.
+
+is_Message_messageBody_tag(Tag) ->
+ Tags = [messageError, transactions],
+ lists:member(Tag, Tags).
+
+is_Message_messageBody_val(messageError, Val) ->
+ is_ErrorDescriptor(Val);
+is_Message_messageBody_val(transactions, Val) ->
+ is_Message_messageBody_transactions(Val).
+
+is_Message_messageBody_transactions([]) ->
+ d("is_Message_messageBody_transactions -> entry when done"),
+ true;
+is_Message_messageBody_transactions([H|T]) ->
+ d("is_Message_messageBody_transactions -> entry"),
+ is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+is_Message_messageBody_transactions(_) ->
+ false.
+
+chk_Message_messageBody(B, B) ->
+ d("chk_Message_messageBody -> entry (1)"),
+ chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (2)"),
+ case (is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val1) andalso
+ is_Message_messageBody_val(Tag, Val2)) of
+ true ->
+ chk_Message_messageBody_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (3)"),
+ case ((is_Message_messageBody_tag(Tag1) andalso
+ is_Message_messageBody_val(Tag1, Val1)) andalso
+ (is_Message_messageBody_tag(Tag2) andalso
+ is_Message_messageBody_val(Tag2, Val2))) of
+ true ->
+ not_equal('Message_messageBody', B1, B2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody(B1, B2) ->
+ wrong_type('Message_messageBody', B1, B2).
+
+chk_Message_messageBody_val(messageError, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'Message_messageBody');
+chk_Message_messageBody_val(transactions, Val1, Val2) ->
+ chk_Message_messageBody_transactions(lists:sort(Val1),
+ lists:sort(Val2)).
+
+chk_Message_messageBody_transactions([], []) ->
+ d("chk_Message_messageBody_transactions -> entry - ok (1)"),
+ ok;
+chk_Message_messageBody_transactions([] = T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (2)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions(T1, [] = T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (3)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (4)"),
+ case is_Transaction(H) of
+ true ->
+ chk_Message_messageBody_transactions(T1, T2);
+ false ->
+ wrong_type('Message_messageBody_transactions_val', H)
+ end;
+chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (5)"),
+ validate(fun() -> chk_Transaction(H1, H2) end,
+ 'Message_messageBody_transactions_val'),
+ chk_Message_messageBody_transactions(T1, T2);
+chk_Message_messageBody_transactions(T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - wrong-type (6)"),
+ wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% -- MId --
+
+is_opt_MId(M) ->
+ is_OPTIONAL(fun is_MId/1, M).
+
+is_MId({Tag, Val}) ->
+ is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+is_MId(_) ->
+ false.
+
+is_MId_tag(Tag) ->
+ Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+ lists:member(Tag, Tags).
+
+is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+is_MId_val(domainName, Val) -> is_DomainName(Val);
+is_MId_val(deviceName, Val) -> is_PathName(Val);
+is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+chk_opt_MId(M1, M2) ->
+ chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+chk_MId(M, M) ->
+ chk_type(fun is_MId/1, 'MId', M);
+chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+ case (is_MId_tag(Tag) andalso
+ is_MId_val(Tag, Val1) andalso
+ is_MId_val(Tag, Val2)) of
+ true ->
+ chk_MId_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+ case ((is_MId_tag(Tag1) andalso
+ is_MId_val(Tag1, Val1)) andalso
+ (is_MId_tag(Tag2) andalso
+ is_MId_val(Tag2, Val2))) of
+ true ->
+ not_equal('MId', M1, M2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId(M1, M2) ->
+ wrong_type('MId', M1, M2).
+
+chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% -- DomainName --
+
+is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+ is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+is_DomainName(_) ->
+ false.
+
+chk_DomainName(N, N) ->
+ ok;
+chk_DomainName(N1, N2) ->
+ not_equal('DomainName', N1, N2).
+
+
+%% -- IP4Address --
+
+is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 4}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP4Address(_) ->
+ false.
+
+chk_IP4Address(A, A) ->
+ ok;
+chk_IP4Address(A1, A2) ->
+ not_equal('IP4Address', A1, A2).
+
+
+%% -- IP6Address --
+
+is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 16}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP6Address(_) ->
+ false.
+
+chk_IP6Address(A, A) ->
+ ok;
+chk_IP6Address(A1, A2) ->
+ not_equal('IP6Address', A1, A2).
+
+
+%% -- PathName --
+
+is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+chk_PathName(N, N) ->
+ ok;
+chk_PathName(N1, N2) ->
+ not_equal('PathName', N1, N2).
+
+
+%% -- Transaction --
+
+is_Transaction({Tag, Val}) ->
+ d("is_Transaction -> entry"),
+ is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+is_Transaction(_) ->
+ false.
+
+is_Transaction_tag(Tag) ->
+ Tags = [transactionRequest,
+ transactionPending,
+ transactionReply,
+ transactionResponseAck],
+ lists:member(Tag, Tags).
+
+is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+chk_Transaction({Tag, Val} = Trans, Trans) ->
+ d("chk_Transaction -> entry (1)"),
+ case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Transaction', Trans, Trans)
+ end;
+chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (2)"),
+ case (is_Transaction_tag(Tag) and
+ is_Transaction_val(Tag, Val1) and
+ is_Transaction_val(Tag, Val2)) of
+ true ->
+ chk_Transaction_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (3)"),
+ case ((is_Transaction_tag(Tag1) andalso
+ is_Transaction_val(Tag1, Val1)) andalso
+ (is_Transaction_tag(Tag2) andalso
+ is_Transaction_val(Tag2, Val2))) of
+ true ->
+ not_equal('Transaction', Trans1, Trans2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction(Trans1, Trans2) ->
+ d("chk_Transaction -> entry - wrong-type - (4)"),
+ wrong_type('Transaction', Trans1, Trans2).
+
+chk_Transaction_val(transactionRequest, T1, T2) ->
+ chk_TransactionRequest(T1, T2);
+chk_Transaction_val(transactionPending, T1, T2) ->
+ chk_TransactionPending(T1, T2);
+chk_Transaction_val(transactionReply, T1, T2) ->
+ chk_TransactionReply(T1,T2);
+chk_Transaction_val(transactionResponseAck, T1, T2) ->
+ chk_TransactionResponseAck(T1, T2).
+
+
+%% -- TransactionId --
+
+is_opt_TransactionId(TID) ->
+ is_OPTIONAL(fun is_TransactionId/1, TID).
+
+is_TransactionId(TID) ->
+ d("is_TransactionId -> entry"),
+ is_INTEGER(TID, {range, 0, 4294967295}).
+
+chk_opt_TransactionId(TID1, TID2) ->
+ chk_OPTIONAL('TransactionId', TID1, TID2,
+ fun is_TransactionId/1, fun chk_TransactionId/2).
+
+chk_TransactionId(TID, TID) ->
+ chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+chk_TransactionId(TID1, TID2) ->
+ case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+ true ->
+ not_equal('TransactionId', TID1, TID2);
+ false ->
+ wrong_type('TransactionId', TID1, TID2)
+ end.
+
+
+%% -- TransactionRequest --
+
+is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+ actions = Acts}) ->
+ d("is_TransactionRequest -> entry"),
+ is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+is_TransactionRequest(_) ->
+ false.
+
+chk_TransactionRequest(T, T) ->
+ chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+ actions = Acts1},
+ #'TransactionRequest'{transactionId = TID2,
+ actions = Acts2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+ chk_TransactionRequest_actions(lists:sort(Acts1),
+ lists:sort(Acts2)),
+ ok;
+chk_TransactionRequest(T1, T2) ->
+ wrong_type('TransactionRequest', T1, T2).
+
+is_TransactionRequest_actions([]) ->
+ d("is_TransactionRequest_actions -> entry when done"),
+ true;
+is_TransactionRequest_actions([H|T]) ->
+ d("is_TransactionRequest_actions -> entry"),
+ is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+is_TransactionRequest_actions(_) ->
+ false.
+
+chk_TransactionRequest_actions([], []) ->
+ ok;
+chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+ case is_ActionRequest(H) of
+ true ->
+ chk_TransactionRequest_actions(T1, T2);
+ false ->
+ wrong_type('TransactionRequest_actions_val', H)
+ end;
+chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionRequest(H1, H2) end,
+ 'TransactionRequest_actions_val'),
+ chk_TransactionRequest_actions(T1, T2);
+chk_TransactionRequest_actions(Acts1, Acts2) ->
+ wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% -- TransactionPending --
+
+is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+ d("is_TransactionPending -> entry"),
+ is_TransactionId(TID);
+is_TransactionPending(_) ->
+ false.
+
+chk_TransactionPending(T, T) ->
+ chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+ #'TransactionPending'{transactionId = TID2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+ ok;
+chk_TransactionPending(T1, T2) ->
+ wrong_type('TransactionPending', T1, T2).
+
+
+%% -- TransactionReply --
+
+is_TransactionReply(#'TransactionReply'{transactionId = TID,
+ immAckRequired = IAR,
+ transactionResult = TR}) ->
+ d("is_TransactionReply -> entry"),
+ is_TransactionId(TID) andalso
+ is_opt_NULL(IAR) andalso
+ is_TransactionReply_transactionResult(TR);
+is_TransactionReply(_) ->
+ false.
+
+chk_TransactionReply(T, T) ->
+ chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+ immAckRequired = IAR1,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TID2,
+ immAckRequired = IAR2,
+ transactionResult = TR2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+ validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+ chk_TransactionReply_transactionResult(TR1, TR2),
+ ok;
+chk_TransactionReply(T1, T2) ->
+ wrong_type('TransactionReply', T1, T2).
+
+is_TransactionReply_transactionResult({Tag, Val}) ->
+ d("is_TransactionReply_transactionResult -> entry"),
+ is_TransactionReply_transactionResult_tag(Tag) andalso
+ is_TransactionReply_transactionResult_val(Tag, Val);
+is_TransactionReply_transactionResult(_) ->
+ false.
+
+is_TransactionReply_transactionResult_tag(T) ->
+ lists:member(T, [transactionError, actionReplies]).
+
+is_TransactionReply_transactionResult_val(transactionError, V) ->
+ is_ErrorDescriptor(V);
+is_TransactionReply_transactionResult_val(actionReplies, V) ->
+ is_TransactionReply_actionReplies(V).
+
+chk_TransactionReply_transactionResult(Res, Res) ->
+ chk_type(fun is_TransactionReply_transactionResult/1,
+ 'TransactionReply_transactionResult', Res);
+chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+ {Tag, Val2} = Res2) ->
+ case (is_TransactionReply_transactionResult_tag(Tag) and
+ is_TransactionReply_transactionResult_val(Tag, Val1) and
+ is_TransactionReply_transactionResult_val(Tag, Val2)) of
+ true ->
+ chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+ {Tag2, Val2} = Res2) ->
+ case ((is_TransactionReply_transactionResult_tag(Tag1) and
+ is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+ (is_TransactionReply_transactionResult_tag(Tag2) and
+ is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('TransactionReply_transactionResult', Res1, Res2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult(Res1, Res2) ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+ validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+ 'TransactionReply_transactionResult');
+chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+ validate(fun() ->
+ chk_TransactionReply_actionReplies(lists:sort(R1),
+ lists:sort(R2))
+ end,
+ 'TransactionReply_transactionResult').
+
+is_TransactionReply_actionReplies([]) ->
+ d("is_TransactionReply_actionReplies -> entry when done"),
+ true;
+is_TransactionReply_actionReplies([H|T]) ->
+ d("is_TransactionReply_actionReplies -> entry"),
+ is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+is_TransactionReply_actionReplies(_) ->
+ false.
+
+chk_TransactionReply_actionReplies([], []) ->
+ ok;
+chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+ case is_ActionReply(H) of
+ true ->
+ chk_TransactionReply_actionReplies(T1, T2);
+ false ->
+ wrong_type('TransactionReply_actionReplies_val', H)
+ end;
+chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionReply(H1, H2) end,
+ 'TransactionReply_actionReplies_val'),
+ chk_TransactionReply_actionReplies(T1, T2);
+chk_TransactionReply_actionReplies(AR1, AR2) ->
+ wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% -- TransactionResponseAck --
+
+is_TransactionResponseAck([]) ->
+ d("is_TransactionResponseAck -> entry when done"),
+ true;
+is_TransactionResponseAck([H|T]) ->
+ d("is_TransactionResponseAck -> entry"),
+ is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+is_TransactionResponseAck(_) ->
+ false.
+
+chk_TransactionResponseAck([], []) ->
+ ok;
+chk_TransactionResponseAck([] = AR1, AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck(AR1, [] = AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck([H|T1], [H|T2]) ->
+ case is_TransactionAck(H) of
+ true ->
+ chk_TransactionResponseAck(T1, T2);
+ false ->
+ wrong_type('TransactionResponseAck_val', H)
+ end;
+chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TransactionAck(H1, H2) end,
+ 'TransactionResponseAck'),
+ chk_TransactionResponseAck(T1, T2);
+chk_TransactionResponseAck(AR1, AR2) ->
+ wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% -- TransactionAck --
+
+is_TransactionAck(#'TransactionAck'{firstAck = F,
+ lastAck = L}) ->
+ d("is_TransactionAck -> entry"),
+ is_TransactionId(F) andalso is_opt_TransactionId(L);
+is_TransactionAck(_) ->
+ false.
+
+chk_TransactionAck(T, T) ->
+ chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+ validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+ ok;
+chk_TransactionAck(T1, T2) ->
+ wrong_type('TransactionAck', T1, T2).
+
+
+%% -- ErrorDescriptor --
+
+is_opt_ErrorDescriptor(V) ->
+ is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text}) ->
+ d("is_ErrorDescriptor -> entry"),
+ is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+is_ErrorDescriptor(_) ->
+ false.
+
+chk_opt_ErrorDescriptor(E1, E2) ->
+ chk_OPTIONAL('ErrorDescriptor', E1, E2,
+ fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+chk_ErrorDescriptor(E, E) ->
+ chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1},
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2}) ->
+ chk_ErrorCode(Code1, Code2),
+ chk_opt_ErrorText(Text1, Text2),
+ ok;
+chk_ErrorDescriptor(E1, E2) ->
+ wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% -- ErrorCode --
+
+is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+chk_ErrorCode(C, C) ->
+ case is_ErrorCode(C) of
+ true ->
+ ok;
+ false ->
+ wrong_type(errorCode, C, C)
+ end;
+chk_ErrorCode(C1, C2) ->
+ case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+ true ->
+ not_equal(errorCode, C1, C2);
+ false ->
+ wrong_type(errorCode, C1, C2)
+ end.
+
+
+%% -- ErrorText --
+
+is_opt_ErrorText(V) ->
+ is_OPTIONAL(fun is_ErrorText/1, V).
+
+is_ErrorText(V) -> is_IA5String(V).
+
+chk_opt_ErrorText(T1, T2) ->
+ chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+chk_ErrorText(T, T) ->
+ chk_type(fun is_ErrorText/1, 'ErrorText', T);
+chk_ErrorText(T1, T2) ->
+ case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+ true ->
+ case {to_lower(T1), to_lower(T2)} of
+ {T, T} ->
+ ok;
+ _ ->
+ not_equal('ErrorText', T1, T2)
+ end;
+ false ->
+ wrong_type('ErrorText', T1, T2)
+ end.
+
+
+%% -- ContextID --
+
+is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+chk_ContextID(Id, Id) ->
+ chk_type(fun is_ContextID/1, 'ContextID', Id);
+chk_ContextID(Id1, Id2) ->
+ case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+ true ->
+ not_equal('ContextID', Id1, Id2);
+ false ->
+ wrong_type('ContextID', Id1, Id2)
+ end.
+
+
+%% -- ActionRequest --
+
+is_ActionRequest(#'ActionRequest'{contextId = Id,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = AuditReq,
+ commandRequests = CmdReqs}) ->
+ d("is_ActionRequest -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ContextRequest(CtxReq) andalso
+ is_opt_ContextAttrAuditRequest(AuditReq) andalso
+ is_ActionRequest_commandRequests(CmdReqs);
+is_ActionRequest(_) ->
+ false.
+
+chk_ActionRequest(A, A) ->
+ chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+ validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+ validate(fun() ->
+ chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+ end,
+ 'ActionRequest'),
+ chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+ ok.
+
+
+is_ActionRequest_commandRequests([]) ->
+ d("is_ActionRequest_commandRequests -> entry when done"),
+ true;
+is_ActionRequest_commandRequests([H|T]) ->
+ d("is_ActionRequest_commandRequests -> entry"),
+ is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+is_ActionRequest_commandRequests(_) ->
+ false.
+
+chk_ActionRequest_commandRequests([], []) ->
+ ok;
+chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+ case is_CommandRequest(H) of
+ true ->
+ chk_ActionRequest_commandRequests(T1, T2);
+ false ->
+ wrong_type('ActionRequest_commandRequest_val', H)
+ end;
+chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandRequest(H1, H2) end,
+ 'ActionRequest_commandRequests_val'),
+ chk_ActionRequest_commandRequests(T1, T2);
+chk_ActionRequest_commandRequests(R1, R2) ->
+ wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% -- ActionReply --
+
+is_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep}) ->
+ d("is_ActionReply -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ErrorDescriptor(ED) andalso
+ is_opt_ContextRequest(CtxRep) andalso
+ is_ActionReply_commandReply(CmdRep);
+is_ActionReply(_) ->
+ false.
+
+is_ActionReply_commandReply([]) ->
+ d("is_ActionReply_commandReply -> entry when done"),
+ true;
+is_ActionReply_commandReply([H|T]) ->
+ d("is_ActionReply_commandReply -> entry"),
+ is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+is_ActionReply_commandReply(_) ->
+ false.
+
+chk_ActionReply(A, A) ->
+ chk_type(fun is_ActionReply/1, 'ActionReply', A);
+chk_ActionReply(#'ActionReply'{contextId = Id1,
+ errorDescriptor = ED1,
+ contextReply = CtxRep1,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = Id2,
+ errorDescriptor = ED2,
+ contextReply = CtxRep2,
+ commandReply = CmdRep2}) ->
+ chk_ContextID(Id1, Id2),
+ chk_opt_ErrorDescriptor(ED1, ED2),
+ chk_opt_ContextRequest(CtxRep1, CtxRep2),
+ chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+chk_ActionReply_commandReply([], []) ->
+ ok;
+chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+ case is_CommandReply(H) of
+ true ->
+ chk_ActionReply_commandReply(T1, T2);
+ false ->
+ wrong_type('ActionReply_commandReply_val', H)
+ end;
+chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandReply(H1, H2) end,
+ 'ActionReply_commandReply_val'),
+ chk_ActionReply_commandReply(T1, T2);
+chk_ActionReply_commandReply(R1, R2) ->
+ wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% -- ContextRequest --
+
+is_opt_ContextRequest(V) ->
+ is_OPTIONAL(fun is_ContextRequest/1, V).
+
+is_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReq,
+ iepsCallind = Ieps,
+ contextProp = Ctx}) ->
+ d("is_ContextRequest -> entry"),
+ is_ContextRequest_priority(Prio) andalso
+ is_ContextRequest_emergency(Em) andalso
+ is_ContextRequest_topologyReq(TopReq) andalso
+ is_ContextRequest_iepsCallind(Ieps) andalso
+ is_ContextRequest_contextProp(Ctx);
+is_ContextRequest(_) ->
+ false.
+
+is_ContextRequest_priority(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_priority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextRequest_emergency(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_emergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_topologyReq([]) ->
+ true;
+is_ContextRequest_topologyReq([H|T]) ->
+ is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+is_ContextRequest_topologyReq(_) ->
+ false.
+
+is_ContextRequest_iepsCallind(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_iepsCallind(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_contextProp(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextProp([]) ->
+ true;
+is_ContextRequest_contextProp([H|T]) ->
+ is_PropertyParm(H) andalso is_ContextRequest_contextProp(T);
+is_ContextRequest_contextProp(_) ->
+ false.
+
+chk_opt_ContextRequest(R1, R2) ->
+ chk_OPTIONAL('ContextRequest', R1, R2,
+ fun is_ContextRequest/1, fun chk_ContextRequest/2).
+
+chk_ContextRequest(R, R) ->
+ chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1,
+ iepsCallind = Ieps1,
+ contextProp = Ctx1},
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2,
+ iepsCallind = Ieps2,
+ contextProp = Ctx2}) ->
+ chk_ContextRequest_priority(Prio1, Prio2),
+ chk_ContextRequest_emergency(Em1, Em2),
+ chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+ chk_ContextRequest_iepsCallind(Ieps1, Ieps2),
+ chk_ContextRequest_contextProp(Ctx1, Ctx2),
+ ok;
+chk_ContextRequest(R1, R2) ->
+ wrong_type('ContextRequest', R1, R2).
+
+
+chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_priority(P, P) ->
+ chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+chk_ContextRequest_priority(P1, P2) ->
+ case (is_ContextRequest_priority(P1) andalso
+ is_ContextRequest_priority(P2)) of
+ true ->
+ not_equal('ContextRequest_priority', P1, P2);
+ false ->
+ wrong_type(contextRequest_priority, P1, P2)
+ end.
+
+
+chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_emergency(E, E) ->
+ chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+chk_ContextRequest_emergency(E1, E2) ->
+ case (is_ContextRequest_emergency(E1) andalso
+ is_ContextRequest_emergency(E2)) of
+ true ->
+ not_equal('ContextRequest_emergency', E1, E2);
+ false ->
+ wrong_type('ContextRequest_emergency', E1, E2)
+ end.
+
+chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_topologyReq([], []) ->
+ ok;
+chk_ContextRequest_topologyReq([] = T1, T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq(T1, [] = T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+ case is_TopologyRequest(H) of
+ true ->
+ chk_ContextRequest_topologyReq(T1, T2);
+ false ->
+ wrong_type('ContextRequest_topologyReq_val', H)
+ end;
+chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TopologyRequest(H1, H2) end,
+ 'ContextRequest_topologyReq_val'),
+ chk_ContextRequest_topologyReq(T1, T2);
+chk_ContextRequest_topologyReq(T1, T2) ->
+ wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+chk_ContextRequest_iepsCallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_iepsCallind(E, E) ->
+ chk_type(fun is_ContextRequest_iepsCallind/1,
+ 'ContextRequest_iepsCallind', E);
+chk_ContextRequest_iepsCallind(E1, E2) ->
+ case (is_ContextRequest_iepsCallind(E1) andalso
+ is_ContextRequest_iepsCallind(E2)) of
+ true ->
+ case (((E1 == false) and (E2 == asn1_NOVALUE)) or
+ ((E1 == asn1_NOVALUE) and (E2 == false))) of
+ true ->
+ ok;
+ false ->
+ not_equal('ContextRequest_iepsCallind', E1, E2)
+ end;
+
+ false ->
+ wrong_type('ContextRequest_iepsCallind', E1, E2)
+ end.
+
+chk_ContextRequest_contextProp(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextProp([], []) ->
+ ok;
+chk_ContextRequest_contextProp([] = T1, T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp(T1, [] = T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ContextRequest_contextProp(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextProp_val', H)
+ end;
+chk_ContextRequest_contextProp([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextRequest_contextProp_val'),
+ chk_ContextRequest_contextProp(T1, T2);
+chk_ContextRequest_contextProp(T1, T2) ->
+ wrong_type('ContextRequest_contextProp', T1, T2).
+
+
+%% -- ContextAttrAuditRequest --
+
+is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextAttrAuditRequest(V) ->
+ is_ContextAttrAuditRequest(V).
+
+is_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T,
+ emergency = E,
+ priority = P,
+ iepsCallind = I,
+ contextPropAud = A}) ->
+ d("is_ContextAttrAuditRequest -> entry"),
+ is_opt_NULL(T) andalso
+ is_opt_NULL(E) andalso
+ is_opt_NULL(P) andalso
+ is_opt_NULL(I) andalso
+ is_ContextAttrAuditRequest_contextPropAud(A);
+is_ContextAttrAuditRequest(_) ->
+ false.
+
+is_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([]) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([H|T]) ->
+ d("is_ContextAttrAuditRequest_contextPropAud -> entry"),
+ is_IndAudPropertyParm(H) andalso
+ is_ContextAttrAuditRequest_contextPropAud(T).
+
+chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextAttrAuditRequest(R1, R2) ->
+ chk_ContextAttrAuditRequest(R1, R2).
+
+chk_ContextAttrAuditRequest(R, R) ->
+ chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+chk_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1,
+ iepsCallind = I1,
+ contextPropAud = A1},
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2,
+ iepsCallind = I2,
+ contextPropAud = A2}) ->
+ validate(fun() -> chk_opt_NULL(T1, T2) end,
+ 'ContextAttrAuditRequest_topology'),
+ validate(fun() -> chk_opt_NULL(E1, E2) end,
+ 'ContextAttrAuditRequest_emergency'),
+ validate(fun() -> chk_opt_NULL(P1, P2) end,
+ 'ContextAttrAuditRequest_priority'),
+ validate(fun() -> chk_opt_NULL(I1, I2) end,
+ 'ContextAttrAuditRequest_iepsCallind'),
+ chk_ContextAttrAuditRequest_contextPropAud(lists:sort(A1),
+ lists:sort(A2)),
+ ok.
+
+chk_ContextAttrAuditRequest_contextPropAud(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_contextPropAud/1,
+ 'ContextAttrAuditRequest_contextPropAud', A);
+chk_ContextAttrAuditRequest_contextPropAud([], []) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud([] = T1, T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, [] = T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud_val', H)
+ end;
+chk_ContextAttrAuditRequest_contextPropAud([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextAttrAuditRequest_contextPropAud_val'),
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, T2) ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud', T1, T2).
+
+
+%% -- CommandRequest --
+
+is_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}) ->
+ d("is_CommandRequest -> entry"),
+ is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+is_CommandRequest(_) ->
+ false.
+
+chk_CommandRequest(C, C) ->
+ chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+ optional = Opt1,
+ wildcardReturn = WR1},
+ #'CommandRequest'{command = Cmd2,
+ optional = Opt2,
+ wildcardReturn = WR2}) ->
+ validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+ ok;
+chk_CommandRequest(R1, R2) ->
+ wrong_type('CommandRequest', R1, R2).
+
+
+%% -- Command --
+
+is_Command({Tag, Val}) ->
+ d("is_Command -> entry"),
+ is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+is_Command(_) ->
+ false.
+
+is_Command_tag(Tag) ->
+ Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+ auditValueRequest, notifyReq, serviceChangeReq],
+ lists:member(Tag, Tags).
+
+is_Command_val(addReq, V) -> is_AmmRequest(V);
+is_Command_val(moveReq, V) -> is_AmmRequest(V);
+is_Command_val(modReq, V) -> is_AmmRequest(V);
+is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+chk_Command(Cmd, Cmd) ->
+ chk_type(fun is_Command/1, 'Command', Cmd);
+chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_Command_tag(Tag) andalso
+ is_Command_val(Tag, Val1) andalso
+ is_Command_val(Tag, Val2)) of
+ true ->
+ chk_Command_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+ (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+ true ->
+ not_equal('Command', Cmd1, Cmd2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command(Cmd1, Cmd2) ->
+ wrong_type('Command', Cmd1, Cmd2).
+
+
+chk_Command_val(addReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+chk_Command_val(moveReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+chk_Command_val(modReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+chk_Command_val(subtractReq, R1, R2) ->
+ validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+chk_Command_val(auditCapRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+chk_Command_val(auditValueRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end,
+ 'Command_auditValueRequest');
+chk_Command_val(notifyReq, R1, R2) ->
+ validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+chk_Command_val(serviceChangeReq, R1, R2) ->
+ validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+ 'Command_serviceChangeReq').
+
+
+%% -- CommandReply --
+
+is_CommandReply({Tag, Val}) ->
+ d("is_CommandReply -> entry"),
+ is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+is_CommandReply(_) ->
+ false.
+
+is_CommandReply_tag(Tag) ->
+ Tags = [addReply, moveReply, modReply, subtractReply,
+ auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+ lists:member(Tag, Tags).
+
+is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+ case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('CommandReply', Cmd)
+ end;
+chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_CommandReply_tag(Tag) andalso
+ is_CommandReply_val(Tag, Val1) andalso
+ is_CommandReply_val(Tag, Val2)) of
+ true ->
+ chk_CommandReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_CommandReply_tag(Tag1) andalso
+ is_CommandReply_val(Tag1, Val1)) andalso
+ (is_CommandReply_tag(Tag2) andalso
+ is_CommandReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('CommandReply', Cmd1, Cmd2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply(Cmd1, Cmd2) ->
+ wrong_type('CommandReply', Cmd1, Cmd2).
+
+chk_CommandReply_val(addReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+chk_CommandReply_val(moveReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+chk_CommandReply_val(modReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+chk_CommandReply_val(subtractReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+chk_CommandReply_val(auditCapReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditCapReply');
+chk_CommandReply_val(auditValueReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditValueReply');
+chk_CommandReply_val(notifyReply, V1, V2) ->
+ validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+ validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+ 'CommandReply_serviceChangeReply').
+
+
+%% -- TopologyRequest --
+
+is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+ terminationTo = T,
+ topologyDirection = D,
+ streamID = S}) ->
+ d("is_TopologyRequest -> entry"),
+ is_TerminationID(F) andalso
+ is_TerminationID(T) andalso
+ is_TopologyRequest_topologyDirection(D) andalso
+ is_opt_StreamID(S);
+is_TopologyRequest(_) ->
+ false.
+
+is_TopologyRequest_topologyDirection(D) ->
+ lists:member(D, [bothway, isolate, oneway]).
+
+
+chk_TopologyRequest(T, T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = D1,
+ streamID = S1},
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = D2,
+ streamID = S2}) ->
+ validate(fun() -> chk_TerminationID(F1, F2) end,
+ 'TopologyRequest_terminationFrom'),
+ validate(fun() -> chk_TerminationID(T1, T2) end,
+ 'TopologyRequest_terminationTo'),
+ chk_TopologyRequest_topologyDirection(D1,D2),
+ validate(fun() -> chk_StreamID(S1, S2) end, 'TopologyRequest_streamID'),
+ ok.
+
+chk_TopologyRequest_topologyDirection(D, D) ->
+ case is_TopologyRequest_topologyDirection(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D)
+ end;
+chk_TopologyRequest_topologyDirection(D1, D2) ->
+ case (is_TopologyRequest_topologyDirection(D1) andalso
+ is_TopologyRequest_topologyDirection(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirection', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D1, D2)
+ end.
+
+
+%% -- AmmRequest --
+
+is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+ descriptors = Descs}) ->
+ d("is_AmmRequest -> entry with"
+ "~n Tids: ~p", [Tids]),
+ is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+is_AmmRequest(_) ->
+ false.
+
+is_AmmRequest_descriptors(Descs) ->
+ d("is_AmmRequest_descriptors -> entry"),
+ is_AmmRequest_descriptors(Descs, []).
+
+is_AmmRequest_descriptors([], _) ->
+ true;
+is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+ d("is_AmmRequest_descriptors -> entry with"
+ "~n Tag: ~p"
+ "~n FoundDescs: ~p", [Tag, FoundDescs]),
+ case lists:member(Tag, FoundDescs) of
+ true ->
+ atmost_once('AmmRequest_descriptors', Tag);
+ false ->
+ case is_AmmDescriptor(Desc) of
+ true ->
+ is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+ false ->
+ wrong_type('AmmRequest_descriptors', Desc)
+ end
+ end;
+is_AmmRequest_descriptors(Descs, _) ->
+ d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+ "~n Descs: ~p", [Descs]),
+ wrong_type('AmmRequest_descriptors', Descs).
+
+
+chk_AmmRequest(R, R) when is_record(R, 'AmmRequest') ->
+ d("chk_AmmRequest -> entry when equal"),
+ chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = Descs1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = Descs2}) ->
+ d("chk_AmmRequest -> entry with not equal"
+ "~n Tids1: ~p"
+ "~n Tids2: ~p", [Tids1, Tids2]),
+ validate(
+ fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'AmmRequest'),
+ validate(
+ fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+ 'AmmRequest'),
+ ok.
+
+
+chk_AmmRequest_descriptors([], []) ->
+ d("chk_AmmRequest_descriptors -> done when OK"),
+ ok;
+chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when equal"),
+ case is_AmmDescriptor(H) of
+ true ->
+ chk_AmmRequest_descriptors(T1, T2);
+ false ->
+ wrong_type('AmmRequest_descriptors_val', H)
+ end;
+chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when not equal"),
+ validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+ 'AmmRequest_descriptors_val'),
+ chk_AmmRequest_descriptors(T1, T2);
+chk_AmmRequest_descriptors(Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% -- AmmDescriptor --
+
+is_AmmDescriptor({Tag, Val}) ->
+ d("is_AmmDescriptor -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p",[Tag, Val]),
+ is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+is_AmmDescriptor(_) ->
+ false.
+
+is_AmmDescriptor_tag(Tag) ->
+ Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+ eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+ auditDescriptor, statisticsDescriptor],
+ lists:member(Tag, Tags).
+
+is_AmmDescriptor_val(mediaDescriptor, D) ->
+ is_MediaDescriptor(D);
+is_AmmDescriptor_val(modemDescriptor, D) ->
+ is_ModemDescriptor(D);
+is_AmmDescriptor_val(muxDescriptor, D) ->
+ is_MuxDescriptor(D);
+is_AmmDescriptor_val(eventsDescriptor, D) ->
+ is_EventsDescriptor(D);
+is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+ is_EventBufferDescriptor(D);
+is_AmmDescriptor_val(signalsDescriptor, D) ->
+ is_SignalsDescriptor(D);
+is_AmmDescriptor_val(digitMapDescriptor, D) ->
+ is_DigitMapDescriptor(D);
+is_AmmDescriptor_val(auditDescriptor, D) ->
+ is_AuditDescriptor(D);
+is_AmmDescriptor_val(statisticsDescriptor, D) ->
+ is_StatisticsDescriptor(D).
+
+chk_AmmDescriptor(D, D) ->
+ chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_AmmDescriptor_tag(Tag) andalso
+ is_AmmDescriptor_val(Tag, Val1) andalso
+ is_AmmDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_AmmDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_AmmDescriptor_tag(Tag1) andalso
+ is_AmmDescriptor_val(Tag1, Val1)) andalso
+ (is_AmmDescriptor_tag(Tag2) andalso
+ is_AmmDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('AmmDescriptor', Cmd1, Cmd2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor(Cmd1, Cmd2) ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+ validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+ validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+ validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+ validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+ validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+ validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% -- AmmsReply --
+
+is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+ terminationAudit = TA}) ->
+ is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+is_AmmsReply(_) ->
+ false.
+
+chk_AmmsReply(R, R) ->
+ is_AmmsReply(R);
+chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = TID2,
+ terminationAudit = TA2}) ->
+ validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+ validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+ ok;
+chk_AmmsReply(R1, R2) ->
+ wrong_type('AmmsReply', R1, R2).
+
+
+%% -- SubtractRequest --
+
+is_SubtractRequest(#'SubtractRequest'{terminationID = Tids,
+ auditDescriptor = AD}) ->
+ is_TerminationIDList(Tids) andalso is_opt_AuditDescriptor(AD);
+is_SubtractRequest(_) ->
+ false.
+
+chk_SubtractRequest(R, R) ->
+ chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'SubtractRequest'),
+ validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+ 'SubtractRequest'),
+ ok;
+chk_SubtractRequest(SR1, SR2) ->
+ wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% -- AuditRequest --
+
+is_AuditRequest(#'AuditRequest'{terminationID = Tid,
+ auditDescriptor = AD}) ->
+ is_TerminationID(Tid) andalso is_AuditDescriptor(AD);
+is_AuditRequest(_) ->
+ false.
+
+chk_AuditRequest(R, R) ->
+ chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+chk_AuditRequest(#'AuditRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'AuditRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationID(Tids1, Tids2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+ 'AuditRequest'),
+ ok;
+chk_AuditRequest(AR1, AR2) ->
+ wrong_type('AuditRequest', AR1, AR2).
+
+
+%% -- AuditReply --
+
+is_AuditReply({Tag, Val}) ->
+ is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+is_AuditReply(_) ->
+ false.
+
+is_AuditReply_tag(Tag) ->
+ Tags = [contextAuditResult, error, auditResult],
+ lists:member(Tag, Tags).
+
+is_AuditReply_val(contextAuditResult, Val) ->
+ is_TerminationIDList(Val);
+is_AuditReply_val(error, Val) ->
+ is_ErrorDescriptor(Val);
+is_AuditReply_val(auditResult, Val) ->
+ is_AuditResult(Val).
+
+chk_AuditReply(R, R) ->
+ chk_type(fun is_AuditReply/1, 'AuditReply', R);
+chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_AuditReply_tag(Tag) andalso
+ is_AuditReply_val(Tag, Val1)andalso
+ is_AuditReply_val(Tag, Val2)) of
+ true ->
+ chk_AuditReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_AuditReply_tag(Tag1) andalso
+ is_AuditReply_val(Tag1, Val1)) andalso
+ (is_AuditReply_tag(Tag2) andalso
+ is_AuditReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReply', R1, R2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply(AR1, AR2) ->
+ wrong_type('AuditReply', AR1, AR2).
+
+chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+ chk_TerminationIDList(Val1, Val2);
+chk_AuditReply_val(error, Val1, Val2) ->
+ chk_ErrorDescriptor(Val1, Val2);
+chk_AuditReply_val(auditResult, Val1, Val2) ->
+ chk_AuditResult(Val1, Val2).
+
+
+%% -- AuditResult --
+
+is_AuditResult(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}) ->
+ is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+is_AuditResult(_) ->
+ false.
+
+chk_AuditResult(R, R) ->
+ chk_type(fun is_AuditResult/1, 'AuditResult', R);
+chk_AuditResult(#'AuditResult'{terminationID = TID1,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = TID2,
+ terminationAuditResult = TAR2}) ->
+ validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+ ok;
+chk_AuditResult(AR1, AR2) ->
+ wrong_type('AuditResult', AR1, AR2).
+
+
+%% -- TerminationAudit --
+
+is_opt_TerminationAudit(TA) ->
+ is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+is_TerminationAudit([]) ->
+ true;
+is_TerminationAudit([H|T]) ->
+ is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+is_TerminationAudit(_) ->
+ false.
+
+chk_opt_TerminationAudit(TA1, TA2) ->
+ chk_OPTIONAL('TerminationAudit', TA1, TA2,
+ fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+chk_TerminationAudit([], []) ->
+ ok;
+chk_TerminationAudit([] = TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit(TA1, [] = TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit([H|T1], [H|T2]) ->
+ case is_AuditReturnParameter(H) of
+ true ->
+ chk_TerminationAudit(T1, T2);
+ false ->
+ wrong_type('TerminationAudit', H)
+ end;
+chk_TerminationAudit([H1|_], [H2|_]) ->
+ chk_AuditReturnParameter(H1, H2),
+ not_equal('TerminationAudit_val', H1, H2);
+chk_TerminationAudit(TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2).
+
+
+%% -- AuditReturnParameter --
+
+is_AuditReturnParameter({Tag, Val}) ->
+ is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val);
+is_AuditReturnParameter(_) ->
+ false.
+
+is_AuditReturnParameter_tag(Tag) ->
+ Tags = [errorDescriptor,
+ mediaDescriptor,
+ modemDescriptor,
+ muxDescriptor,
+ eventsDescriptor,
+ eventBufferDescriptor,
+ signalsDescriptor,
+ digitMapDescriptor,
+ observedEventsDescriptor,
+ statisticsDescriptor,
+ packagesDescriptor,
+ emptyDescriptors],
+ lists:member(Tag, Tags).
+
+is_AuditReturnParameter_val(errorDescriptor, V) ->
+ is_ErrorDescriptor(V);
+is_AuditReturnParameter_val(mediaDescriptor, V) ->
+ is_MediaDescriptor(V);
+is_AuditReturnParameter_val(modemDescriptor, V) ->
+ is_ModemDescriptor(V);
+is_AuditReturnParameter_val(muxDescriptor, V) ->
+ is_MuxDescriptor(V);
+is_AuditReturnParameter_val(eventsDescriptor, V) ->
+ is_EventsDescriptor(V);
+is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+ is_EventBufferDescriptor(V);
+is_AuditReturnParameter_val(signalsDescriptor, V) ->
+ is_SignalsDescriptor(V);
+is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+ is_DigitMapDescriptor(V);
+is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+ is_ObservedEventsDescriptor(V);
+is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+ is_StatisticsDescriptor(V);
+is_AuditReturnParameter_val(packagesDescriptor, V) ->
+ is_PackagesDescriptor(V);
+is_AuditReturnParameter_val(emptyDescriptors, V) ->
+ is_AuditDescriptor(V).
+
+chk_AuditReturnParameter(ARP, ARP) ->
+ chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+ case (is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val1) andalso
+ is_AuditReturnParameter_val(Tag, Val2)) of
+ true ->
+ chk_AuditReturnParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+ case ((is_AuditReturnParameter_tag(Tag1) andalso
+ is_AuditReturnParameter_val(Tag1, Val1)) andalso
+ (is_AuditReturnParameter_tag(Tag2) andalso
+ is_AuditReturnParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReturnParameter', ARP1, ARP2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter(ARP1, ARP2) ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+ validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+ validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+ validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+ validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+ validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+ validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+ validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+ validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+ validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+ 'AuditReturnParameter').
+
+
+%% -- AuditDescriptor --
+
+is_opt_AuditDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_AuditDescriptor(V) ->
+ is_AuditDescriptor(V).
+
+is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}) ->
+ is_AuditDescriptor_auditToken(AT) andalso
+ is_AuditDescriptor_auditPropertyToken(APT);
+is_AuditDescriptor(_) ->
+ false.
+
+is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditToken([]) ->
+ true;
+is_AuditDescriptor_auditToken([H|T]) ->
+ is_AuditDescriptor_auditToken_val(H) andalso
+ is_AuditDescriptor_auditToken(T);
+is_AuditDescriptor_auditToken(_) ->
+ false.
+
+is_AuditDescriptor_auditToken_val(V) ->
+ Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, observedEventsToken,
+ packagesToken, eventBufferToken],
+ lists:member(V, Toks).
+
+is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([]) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([H|T]) ->
+ is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+is_AuditDescriptor_auditPropertyToken(_) ->
+ false.
+
+chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(AD1, AD2) ->
+ chk_AuditDescriptor(AD1, AD2).
+
+chk_AuditDescriptor(AD, AD) ->
+ chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = AT2,
+ auditPropertyToken = APT2}) ->
+ chk_AuditDescriptor_auditToken(AT1, AT2),
+ chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+ ok;
+chk_AuditDescriptor(AD1, AD2) ->
+ wrong_type('AuditDescriptor', AD1, AD2).
+
+chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+ case is_AuditDescriptor_auditToken_val(H) of
+ true ->
+ chk_AuditDescriptor_auditToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H)
+ end;
+chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+ case (is_AuditDescriptor_auditToken_val(H1) andalso
+ is_AuditDescriptor_auditToken_val(H2)) of
+ true ->
+ not_equal('AuditDescriptor_auditToken_val', H1, H2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+ end;
+chk_AuditDescriptor_auditToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+ case is_IndAuditParameter(H) of
+ true ->
+ chk_AuditDescriptor_auditPropertyToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+ end;
+chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+ chk_IndAuditParameter(H1, H2),
+ not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% -- IndAuditParameter --
+
+is_IndAuditParameter({Tag, Val}) ->
+ is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+is_IndAuditParameter(_) ->
+ false.
+
+is_IndAuditParameter_tag(Tag) ->
+ Tags = [indAudMediaDescriptor,
+ indAudEventsDescriptor,
+ indAudEventBufferDescriptor,
+ indAudSignalsDescriptor,
+ indAudDigitMapDescriptor,
+ indAudStatisticsDescriptor,
+ indAudPackagesDescriptor],
+ lists:member(Tag, Tags).
+
+is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+ is_IndAudMediaDescriptor(Val);
+is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+ is_IndAudEventsDescriptor(Val);
+is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+ is_IndAudEventBufferDescriptor(Val);
+is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+ is_IndAudSignalsDescriptor(Val);
+is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+ is_IndAudDigitMapDescriptor(Val);
+is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+ is_IndAudStatisticsDescriptor(Val);
+is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+ is_IndAudPackagesDescriptor(Val).
+
+chk_IndAuditParameter(IAP, IAP) ->
+ chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+ case (is_IndAuditParameter_tag(Tag) andalso
+ is_IndAuditParameter_val(Tag, Val1) andalso
+ is_IndAuditParameter_val(Tag, Val2)) of
+ true ->
+ chk_IndAuditParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+ case ((is_IndAuditParameter_tag(Tag1) andalso
+ is_IndAuditParameter_val(Tag1, Val1)) andalso
+ (is_IndAuditParameter_tag(Tag2) andalso
+ is_IndAuditParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAuditParameter', IAP1, IAP2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter(IAP1, IAP2) ->
+ wrong_type('IndAuditParameter', IAP1, IAP2).
+
+chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+ 'IndAuditParameter').
+
+
+%% -- IndAudMediaDescriptor --
+
+is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+ is_IndAudMediaDescriptor_streams(S);
+is_IndAudMediaDescriptor(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+ is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val);
+is_IndAudMediaDescriptor_streams(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+ is_IndAudStreamParms(Val);
+is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+ is_IndAudMediaDescriptor_multiStream(Val).
+
+is_IndAudMediaDescriptor_multiStream([]) ->
+ true;
+is_IndAudMediaDescriptor_multiStream([H|T]) ->
+ is_IndAudStreamDescriptor(H) andalso
+ is_IndAudMediaDescriptor_multiStream(T);
+is_IndAudMediaDescriptor_multiStream(_) ->
+ false.
+
+chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+ chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+ 'IndAudMediaDescriptor'),
+ validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+ 'IndAudMediaDescriptor'),
+ ok;
+chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+ wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+ {Tag, Val2} = S2) ->
+ case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+ true ->
+ chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+ {Tag2, Val2} = S2) ->
+ case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+ (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudMediaDescriptor_streams', S1, S2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams(S1, S2) ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams');
+chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams').
+
+chk_IndAudMediaDescriptor_multiStream([], []) ->
+ ok;
+chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_IndAudStreamDescriptor(H) of
+ true ->
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+ end;
+chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+ 'IndAudMediaDescriptor_multiStream_val'),
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% -- IndAudStreamDescriptor --
+
+is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+is_IndAudStreamDescriptor(_) ->
+ false.
+
+chk_IndAudStreamDescriptor(D, D) ->
+ chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'IndAudStreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+ validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+ 'IndAudStreamDescriptor'),
+ ok;
+chk_IndAudStreamDescriptor(D1, D2) ->
+ wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% -- IndAudStreamParms --
+
+is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ is_opt_IndAudLocalControlDescriptor(LCD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(RD);
+is_IndAudStreamParms(_) ->
+ false.
+
+chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+ 'IndAudStreamParms'),
+ ok;
+chk_IndAudStreamParms(D1, D2) ->
+ wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% -- IndAudLocalControlDescriptor --
+
+is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalControlDescriptor(D) ->
+ is_IndAudLocalControlDescriptor(D).
+
+is_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}) ->
+ is_opt_NULL(SM) andalso is_opt_NULL(RV) andalso is_opt_NULL(RG) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(PPs);
+is_IndAudLocalControlDescriptor(_) ->
+ false.
+
+is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([]) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(T);
+is_IndAudLocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PPs1},
+ #'IndAudLocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PPs2}) ->
+ chk_opt_NULL(SM1, SM2),
+ chk_opt_NULL(RV1, RV2),
+ chk_opt_NULL(RG1, RG2),
+ chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+ ok;
+chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudLocalControlDescriptor_propertyParms_val'),
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+
+%% -- IndAudPropertyParm --
+
+is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name}) ->
+ d("is_IndAudPropertyParm -> entry"),
+ is_PkgdName(Name);
+is_IndAudPropertyParm(_) ->
+ false.
+
+chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1},
+ #'IndAudPropertyParm'{name = Name2}) ->
+ chk_PkgdName(Name1, Name2),
+ ok;
+chk_IndAudPropertyParm(P1, P2) ->
+ wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% -- IndAudLocalRemoteDescriptor --
+
+is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalRemoteDescriptor(D) ->
+ is_IndAudLocalRemoteDescriptor(D).
+
+is_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps}) ->
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+ is_IndAudPropertyGroup(Grps);
+is_IndAudLocalRemoteDescriptor(_) ->
+ false.
+
+is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+ chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+chk_IndAudLocalRemoteDescriptor(D, D) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+ 'IndAudLocalRemoteDescriptor', D);
+chk_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+ propGrps = Grps1},
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+ propGrps = Grps2}) ->
+ chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+ chk_IndAudPropertyGroup(Grps1, Grps2),
+ ok;
+chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+ 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+ case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+ true ->
+ not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+ false ->
+ wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+ end.
+
+
+%% -- IndAudPropertyGroup --
+
+is_IndAudPropertyGroup([]) ->
+ true;
+is_IndAudPropertyGroup([H|T]) ->
+ is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+is_IndAudPropertyGroup(_) ->
+ false.
+
+chk_IndAudPropertyGroup([], []) ->
+ ok;
+chk_IndAudPropertyGroup([] = PG1, PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudPropertyGroup(T1, T2);
+ false ->
+ wrong_type('IndAudPropertyGroup_val', H)
+ end;
+chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudPropertyGroup_val'),
+ chk_IndAudPropertyGroup(T1, T2);
+chk_IndAudPropertyGroup(P1, P2) ->
+ wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% -- IndAudTerminationStateDescriptor --
+
+is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudTerminationStateDescriptor(D) ->
+ is_IndAudTerminationStateDescriptor(D).
+
+is_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+ is_opt_NULL(EBC) andalso is_opt_NULL(SS);
+is_IndAudTerminationStateDescriptor(_) ->
+ false.
+
+is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudTerminationStateDescriptor_propertyParms(T);
+is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+ chk_IndAudTerminationStateDescriptor(D1, D2).
+
+chk_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+ validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+ 'IndAudTerminationStateDescriptor'),
+ validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+ 'IndAudTerminationStateDescriptor'),
+ ok;
+chk_IndAudTerminationStateDescriptor(D1, D2) ->
+ wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+ end;
+chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudTerminationStateDescriptor_propertyParms'),
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- IndAudEventsDescriptor --
+
+is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = SID}) ->
+ is_opt_RequestID(RID) andalso
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID);
+is_IndAudEventsDescriptor(_) ->
+ false.
+
+chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+ pkgdName = Name1,
+ streamID = SID1},
+ #'IndAudEventsDescriptor'{requestID = RID2,
+ pkgdName = Name2,
+ streamID = SID2}) ->
+ chk_opt_RequestID(RID1, RID2),
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventsDescriptor(D1, D2) ->
+ wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% -- IndAudEventBufferDescriptor --
+
+is_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudEventBufferDescriptor(_) ->
+ false.
+
+chk_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name1,
+ streamID = SID1},
+ #'IndAudEventBufferDescriptor'{eventName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventBufferDescriptor(D1, D2) ->
+ wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% -- IndAudSignalsDescriptor --
+
+is_IndAudSignalsDescriptor({Tag, Val}) ->
+ is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val);
+is_IndAudSignalsDescriptor(_) ->
+ false.
+
+is_IndAudSignalsDescriptor_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_IndAudSignalsDescriptor_val(signal, Val) ->
+ is_IndAudSignal(Val);
+is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+ is_IndAudSeqSigList(Val).
+
+chk_IndAudSignalsDescriptor(D, D) ->
+ chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+ case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+ case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+ is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+ (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+ is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudSignalsDescriptor', D1, D2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor(D1, D2) ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+ chk_IndAudSignal(Val1, Val2);
+chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+ chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% -- IndAudSeqSigList --
+
+is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+is_IndAudSeqSigList(_) ->
+ false.
+
+is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+chk_IndAudSeqSigList(L, L) ->
+ chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+ signalList = SL1},
+ #'IndAudSeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ chk_IndAudSeqSigList_id(ID1, ID2),
+ chk_opt_IndAudSignal(SL1, SL2),
+ ok;
+chk_IndAudSeqSigList(L1, L2) ->
+ wrong_type('IndAudSeqSigList', L1, L2).
+
+chk_IndAudSeqSigList_id(ID, ID) ->
+ chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+chk_IndAudSeqSigList_id(ID1, ID2) ->
+ case (is_IndAudSeqSigList_id(ID1) andalso
+ is_IndAudSeqSigList_id(ID2)) of
+ true ->
+ not_equal('IndAudSeqSigList_id', ID1, ID2);
+ false ->
+ wrong_type('IndAudSeqSigList_id', ID1, ID2)
+ end.
+
+
+%% -- IndAudSignal --
+
+is_opt_IndAudSignal(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudSignal(V) ->
+ is_IndAudSignal(V).
+
+is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudSignal(_) ->
+ false.
+
+chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudSignal(S1, S2) ->
+ chk_IndAudSignal(S1, S2).
+
+chk_IndAudSignal(S, S) ->
+ chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+ streamID = SID1},
+ #'IndAudSignal'{signalName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudSignal(S1, S2) ->
+ wrong_type('IndAudSignal', S1, S2).
+
+
+%% -- IndAudDigitMapDescriptor --
+
+is_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+ is_opt_DigitMapName(Name);
+is_IndAudDigitMapDescriptor(_) ->
+ false.
+
+chk_IndAudDigitMapDescriptor(D, D) ->
+ chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+chk_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+ #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'IndAudDigitMapDescriptor'),
+ ok;
+chk_IndAudDigitMapDescriptor(D1, D2) ->
+ wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% -- IndAudStatisticsDescriptor --
+
+is_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name}) ->
+ is_PkgdName(Name);
+is_IndAudStatisticsDescriptor(_) ->
+ false.
+
+chk_IndAudStatisticsDescriptor(D, D) ->
+ chk_type(fun is_IndAudStatisticsDescriptor/1,
+ 'IndAudStatisticsDescriptor', D);
+chk_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name1},
+ #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudStatisticsDescriptor'),
+ ok;
+chk_IndAudStatisticsDescriptor(D1, D2) ->
+ wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% -- IndAudPackagesDescriptor --
+
+is_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = Ver}) ->
+ is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+is_IndAudPackagesDescriptor(_) ->
+ false.
+
+is_IndAudPackagesDescriptor_packageVersion(V) ->
+ is_INTEGER(V, {range, 0, 99}).
+
+chk_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name1,
+ packageVersion = Ver1},
+ #'IndAudPackagesDescriptor'{packageName = Name2,
+ packageVersion = Ver2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+ chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+ ok;
+chk_IndAudPackagesDescriptor(D1, D2) ->
+ wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+ chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+ 'IndAudPackagesDescriptor_packageVersion', V);
+chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+ case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+ is_IndAudPackagesDescriptor_packageVersion(V2)) of
+ true ->
+ not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+ false ->
+ wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+ end.
+
+
+%% -- NotifyRequest --
+
+is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso
+ is_ObservedEventsDescriptor(OED) andalso
+ is_opt_ErrorDescriptor(ED);
+is_NotifyRequest(_) ->
+ false.
+
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = OED1,
+ errorDescriptor = ED1},
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = OED2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+ 'NotifyRequest'),
+ ok;
+chk_NotifyRequest(NR1, NR2) ->
+ wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% -- NotifyReply --
+
+is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+is_NotifyReply(_) ->
+ false.
+
+chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+ errorDescriptor = ED1},
+ #'NotifyReply'{terminationID = Tids2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+ ok;
+chk_NotifyReply(NR1, NR2) ->
+ wrong_type('NotifyReply', NR1, NR2).
+
+
+%% -- ObservedEventsDescriptor --
+
+is_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}) ->
+ is_RequestID(RID) andalso
+ is_ObservedEventsDescriptor_observedEventLst(OEL);
+is_ObservedEventsDescriptor(_) ->
+ false.
+
+is_ObservedEventsDescriptor_observedEventLst([]) ->
+ true;
+is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+ is_ObservedEvent(H) andalso
+ is_ObservedEventsDescriptor_observedEventLst(T);
+is_ObservedEventsDescriptor_observedEventLst(_) ->
+ false.
+
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID1,
+ observedEventLst = OEL1},
+ #'ObservedEventsDescriptor'{requestId = RID2,
+ observedEventLst = OEL2}) ->
+ validate(fun() -> chk_RequestID(RID1, RID2) end,
+ 'ObservedEventsDescriptor'),
+ validate(
+ fun() ->
+ chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+ end,
+ 'ObservedEventsDescriptor'),
+ ok;
+chk_ObservedEventsDescriptor(D1, D2) ->
+ wrong_type('ObservedEventsDescriptor', D1, D2).
+
+chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+ ok;
+chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+ case is_ObservedEvent(H) of
+ true ->
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+ false ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+ end;
+chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ObservedEvent(H1, H2) end,
+ 'ObservedEventsDescriptor_observedEventLst_val'),
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% -- ObservedEvent --
+
+is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}) ->
+ is_EventName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_ObservedEvent_eventParList(EPL) andalso
+ is_opt_TimeNotation(TN);
+is_ObservedEvent(_) ->
+ false.
+
+is_ObservedEvent_eventParList([]) ->
+ true;
+is_ObservedEvent_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+is_ObservedEvent_eventParList(_) ->
+ false.
+
+chk_ObservedEvent(E, E) ->
+ chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+ streamID = SID1,
+ eventParList = EPL1,
+ timeNotation = TN1},
+ #'ObservedEvent'{eventName = Name2,
+ streamID = SID2,
+ eventParList = EPL2,
+ timeNotation = TN2}) ->
+ validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+ chk_ObservedEvent_eventParList(EPL1, EPL2),
+ validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+ ok;
+chk_ObservedEvent(E1, E2) ->
+ wrong_type('ObservedEvent', E1, E2).
+
+chk_ObservedEvent_eventParList([], []) ->
+ ok;
+chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_ObservedEvent_eventParList(T1, T2);
+ false ->
+ wrong_type('ObservedEvent_eventParList_val', H)
+ end;
+chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'ObservedEvent_eventParList'),
+ chk_ObservedEvent_eventParList(T1, T2);
+chk_ObservedEvent_eventParList(L1, L2) ->
+ wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+chk_EventName(N, N) ->
+ chk_type(fun is_EventName/1, 'EventName', N);
+chk_EventName(N1, N2) ->
+ case (is_EventName(N1) andalso is_EventName(N2)) of
+ true ->
+ not_equal('EventName', N1, N2);
+ false ->
+ wrong_type('EventName', N1, N2)
+ end.
+
+
+%% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+ value = Val1,
+ extraInfo = EI1},
+ #'EventParameter'{eventParameterName = Name2,
+ value = Val2,
+ extraInfo = EI2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+ validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+ chk_EventParameter_extraInfo(EI1, EI2),
+ ok;
+chk_EventParameter(P1, P2) ->
+ wrong_type('EventParameter', P1, P2).
+
+chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_EventParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_EventParameter_extraInfo/1,
+ 'EventParameter_extraInfo', EI);
+chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val1) andalso
+ is_EventParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+ is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+ (is_EventParameter_extraInfo_tag(Tag2) andalso
+ is_EventParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo(EI1, EI2) ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val').
+
+
+%% -- ServiceChangeRequest --
+
+is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+ serviceChangeParms = Parms}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+is_ServiceChangeRequest(_) ->
+ false.
+
+chk_ServiceChangeRequest(R, R) ->
+ chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+chk_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = Parms1},
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = Parms2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeRequest'),
+ validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+ 'ServiceChangeRequest'),
+ ok;
+chk_ServiceChangeRequest(R1, R2) ->
+ wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% -- ServiceChangeReply --
+
+is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+ serviceChangeResult = Res}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+is_ServiceChangeReply(_) ->
+ false.
+
+chk_ServiceChangeReply(R, R) ->
+ chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+chk_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = Tids1,
+ serviceChangeResult = Res1},
+ #'ServiceChangeReply'{terminationID = Tids2,
+ serviceChangeResult = Res2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeReply'),
+ validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+ 'ServiceChangeReply'),
+ ok;
+chk_ServiceChangeReply(R1, R2) ->
+ wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% -- ServiceChangeResult --
+
+is_ServiceChangeResult({Tag, Val}) ->
+ is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val);
+is_ServiceChangeResult(_) ->
+ false.
+
+is_ServiceChangeResult_tag(Tag) ->
+ Tags = [errorDescriptor, serviceChangeResParms],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeResult_val(errorDescriptor, Val) ->
+ is_ErrorDescriptor(Val);
+is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+ is_ServiceChangeResParm(Val).
+
+chk_ServiceChangeResult(Res, Res) ->
+ chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+ case (is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val1) andalso
+ is_ServiceChangeResult_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+ case ((is_ServiceChangeResult_tag(Tag1) andalso
+ is_ServiceChangeResult_val(Tag1, Val1)) andalso
+ (is_ServiceChangeResult_tag(Tag2) andalso
+ is_ServiceChangeResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeResult', Res1, Res2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult(Res1, Res2) ->
+ wrong_type('ServiceChangeResult', Res1, Res2).
+
+chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'ServiceChangeResult');
+chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+ validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+ 'ServiceChangeResult').
+
+
+%% -- WildcardField --
+
+is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+chk_WildcardField(WF, WF) ->
+ case is_WildcardField(WF) of
+ true ->
+ ok;
+ false ->
+ wrong_type('WildcardField', WF)
+ end;
+chk_WildcardField(WF1, WF2) ->
+ case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+ true ->
+ not_equal('WildcardField', WF1, WF2);
+ false ->
+ wrong_type('WildcardField', WF1, WF2)
+ end.
+
+
+%% -- TerminationID --
+
+is_TerminationID(#'TerminationID'{wildcard = W,
+ id = ID}) ->
+ is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+ id = _ID}) ->
+ true; % What are the types?
+is_TerminationID(_) ->
+ false.
+
+is_TerminationID_wildcard([]) ->
+ true;
+is_TerminationID_wildcard([H|T]) ->
+ is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+is_TerminationID_wildcard(_) ->
+ false.
+
+is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+chk_TerminationID(Id,Id) ->
+ chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+chk_TerminationID(#'TerminationID'{wildcard = W1,
+ id = I1},
+ #'TerminationID'{wildcard = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+ id = I1},
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(Tid1, Tid2) ->
+ wrong_type('TerminationID', Tid1, Tid2).
+
+chk_TerminationID_wildcard([], []) ->
+ ok;
+chk_TerminationID_wildcard([] = WF1, WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard(WF1, [] = WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+ case is_WildcardField(H) of
+ true ->
+ chk_TerminationID_wildcard(T1, T2);
+ false ->
+ wrong_type('TerminationID_wildcard_val', H)
+ end;
+chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_WildcardField(H1, H2) end,
+ 'TerminationID_wildcard_val'),
+ chk_TerminationID_wildcard(T1, T2);
+chk_TerminationID_wildcard(WF1,WF2) ->
+ not_equal('TerminationId_wildcard', WF1, WF2).
+
+chk_TerminationID_id(Id, Id) ->
+ case is_OCTET_STRING(Id, {range, 1, 8}) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TerminationID_id', Id, Id)
+ end;
+chk_TerminationID_id(Id1, Id2) ->
+ not_equal(terminationId_id, Id1, Id2).
+
+
+%% -- TerminationIDList --
+
+is_TerminationIDList([]) ->
+ true;
+is_TerminationIDList([H|T]) ->
+ is_TerminationID(H) andalso is_TerminationIDList(T);
+is_TerminationIDList(_) ->
+ false.
+
+chk_TerminationIDList([], []) ->
+ ok;
+chk_TerminationIDList([] = L1, L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList(L1, [] = L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_TerminationIDList(T1, T2);
+ false ->
+ wrong_type('TerminationIDList', H)
+ end;
+chk_TerminationIDList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+ chk_TerminationIDList(T1, T2);
+chk_TerminationIDList(L1, L2) ->
+ wrong_type('TerminationIDList', L1, L2).
+
+
+%% -- MediaDescriptor --
+
+is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_MediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_TerminationStateDescriptor(TSD) andalso
+ is_MediaDescriptor_streams(S);
+is_MediaDescriptor(_) ->
+ false.
+
+is_MediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_MediaDescriptor_streams({Tag, Val}) ->
+ is_MediaDescriptor_streams_tag(Tag) andalso
+ is_MediaDescriptor_streams_val(Tag, Val);
+is_MediaDescriptor_streams(_) ->
+ false.
+
+is_MediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_MediaDescriptor_streams_val(oneStream, SP) ->
+ is_StreamParms(SP);
+is_MediaDescriptor_streams_val(multiStream, SDL) ->
+ is_MediaDescriptor_multiStream(SDL).
+
+is_MediaDescriptor_multiStream([]) ->
+ true;
+is_MediaDescriptor_multiStream([H|T]) ->
+ is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+is_MediaDescriptor_multiStream(_) ->
+ false.
+
+chk_MediaDescriptor(D, D) ->
+ chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'MediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(
+ fun() ->
+ chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+ end,
+ 'MediaDescriptor'),
+ validate(
+ fun() ->
+ chk_MediaDescriptor_streams(S1, S2)
+ end,
+ 'MediaDescriptor'),
+ ok;
+chk_MediaDescriptor(D1, D2) ->
+ wrong_type('MediaDescriptor', D1, D2).
+
+
+chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+ validate(fun() ->
+ chk_StreamParms(SP1, SP2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+ validate(fun() ->
+ chk_MediaDescriptor_multiStream(SDs1, SDs2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams(S1, S2) ->
+ wrong_type('MediaDescriptor_streams', S1, S2).
+
+chk_MediaDescriptor_multiStream([], []) ->
+ ok;
+chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_StreamDescriptor(H) of
+ true ->
+ chk_MediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('MediaDescriptor_multiStream_val', H)
+ end;
+chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+ 'MediaDescriptor_multiStream_val'),
+ chk_MediaDescriptor_multiStream(T1, T2);
+chk_MediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% -- StreamDescriptor --
+
+is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_StreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_StreamParms(Parms);
+is_StreamDescriptor(X) ->
+ d("is_StreamDescriptor -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamDescriptor(D, D) ->
+ chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+ validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+ ok;
+chk_StreamDescriptor(D1, D2) ->
+ wrong_type('StreamDescriptor', D1, D2).
+
+
+%% -- StreamParms --
+
+is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}) ->
+ d("is_StreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p"
+ "~n SD: ~p", [LCD, LD, RD, SD]),
+ is_opt_LocalControlDescriptor(LCD) andalso
+ is_opt_LocalRemoteDescriptor(LD) andalso
+ is_opt_LocalRemoteDescriptor(RD) andalso
+ is_opt_StatisticsDescriptor(SD);
+is_StreamParms(X) ->
+ d("is_StreamParms -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamParms(SP, SP) ->
+ chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1,
+ statisticsDescriptor = SD1},
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_LocalControlDescriptor(LCD1, LCD2) end,
+ 'StreamParms_localControlDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+ 'StreamParms_localDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+ 'StreamParms_remoteDescriptor'),
+ validate(fun() -> chk_opt_StatisticsDescriptor(SD1, SD2) end,
+ 'StreamParms_statisticsDescriptor'),
+ ok;
+chk_StreamParms(P1, P2) ->
+ wrong_type('StreamParms', P1, P2).
+
+
+%% -- LocalControlDescriptor --
+
+is_opt_LocalControlDescriptor(D) ->
+ d("is_opt_LocalControlDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalControlDescriptor/1, D).
+
+is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}) ->
+ d("is_LocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PP: ~p", [SM, RV, RG, PP]),
+ is_opt_StreamMode(SM) andalso
+ is_opt_BOOLEAN(RV) andalso
+ is_opt_BOOLEAN(RG) andalso
+ is_LocalControlDescriptor_propertyParms(PP);
+is_LocalControlDescriptor(_) ->
+ false.
+
+is_LocalControlDescriptor_propertyParms([]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry when done"),
+ true;
+is_LocalControlDescriptor_propertyParms([H|T]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry with"
+ "~n H: ~p"
+ "~n T: ~p", [H, T]),
+ is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+is_LocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+ chk_OPTIONAL('LocalControlDescriptor', LCD1, LCD2,
+ fun is_LocalControlDescriptor/1,
+ fun chk_LocalControlDescriptor/2).
+
+chk_LocalControlDescriptor(LCD, LCD) ->
+ chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PP1},
+ #'LocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PP2}) ->
+ validate(
+ fun() -> chk_opt_StreamMode(SM1, SM2) end,
+ 'LocalControlDescriptor'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+ 'LocalControlDescriptor_reserveValue'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+ 'LocalControlDescriptor_reserveGroup'),
+ chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+ ok;
+chk_LocalControlDescriptor(LCD1, LCD2) ->
+ wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+chk_LocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('LocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'LocalControlDescriptor_propertyParms_val'),
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- StreamMode --
+
+is_opt_StreamMode(asn1_NOVALUE) ->
+ true;
+is_opt_StreamMode(SM) ->
+ is_StreamMode(SM).
+
+is_StreamMode(SM) ->
+ lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamMode(SM1, SM2) ->
+ chk_StreamMode(SM1, SM2).
+
+chk_StreamMode(SM, SM) ->
+ chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+chk_StreamMode(SM1, SM2) ->
+ case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+ true ->
+ not_equal('StreamMode', SM1, SM2);
+ false ->
+ wrong_type('StreamMode', SM1, SM2)
+ end.
+
+
+%% -- PropertyParm --
+
+is_PropertyParm(#'PropertyParm'{name = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_PropertyParm -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_PkgdName(N) andalso
+ is_PropertyParm_value(V) andalso
+ is_PropertyParm_extraInfo(I);
+is_PropertyParm(_) ->
+ false.
+
+is_PropertyParm_value([]) ->
+ d("is_PropertyParm_value -> entry when done"),
+ true;
+is_PropertyParm_value([H|T]) ->
+ d("is_PropertyParm_value -> entry with"
+ "~n H: ~p", [H]),
+ is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+is_PropertyParm_value(_) ->
+ false.
+
+is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+ true;
+is_PropertyParm_extraInfo({Tag, Val}) ->
+ d("is_PropertyParm_extraInfo -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_PropertyParm_extraInfo_tag(Tag) andalso
+ is_PropertyParm_extraInfo_val(Tag, Val);
+is_PropertyParm_extraInfo(_) ->
+ false.
+
+is_PropertyParm_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_PropertyParm_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_PropertyParm_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_PropertyParm_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_PropertyParm(P, P) ->
+ chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+chk_PropertyParm(#'PropertyParm'{name = N1,
+ value = V1,
+ extraInfo = I1},
+ #'PropertyParm'{name = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+ chk_PropertyParm_value(V1, V2),
+ chk_PropertyParm_extraInfo(I1, I2),
+ ok;
+chk_PropertyParm(P1, P2) ->
+ wrong_type('PropertyParm', P1, P2).
+
+chk_PropertyParm_value([], []) ->
+ ok;
+chk_PropertyParm_value([] = V1, V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value(V1, [] = V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value([H|T1], [H|T2]) ->
+ case is_OCTET_STRING(H) of
+ true ->
+ chk_PropertyParm_value(T1, T2);
+ false ->
+ wrong_type('PropertyParm_value_val', H)
+ end;
+chk_PropertyParm_value([H1|_], [H2|_]) ->
+ case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+ true ->
+ not_equal('PropertyParm_value_val', H1, H2);
+ false ->
+ wrong_type('PropertyParm_value_val', H1, H2)
+ end;
+chk_PropertyParm_value(V1, V2) ->
+ wrong_type('PropertyParm_value', V1, V2).
+
+chk_PropertyParm_extraInfo(EI, EI) ->
+ chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_PropertyParm_extraInfo_tag(Tag) and
+ is_PropertyParm_extraInfo_val(Tag, Val1) and
+ is_PropertyParm_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_PropertyParm_extraInfo_tag(Tag1) and
+ is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+ (is_PropertyParm_extraInfo_tag(Tag2) and
+ is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('PropertyParm_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo(EI1, EI2) ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $9, $0 =< H ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+chk_Name(N, N) ->
+ chk_type(fun is_Name/1, 'Name', N);
+chk_Name(N1, N2) ->
+ case (is_Name(N1) andalso is_Name(N2)) of
+ true ->
+ not_equal('Name', N1, N2);
+ false ->
+ wrong_type('Name', N1, N2)
+ end.
+
+
+%% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+chk_PkgdName(N, N) ->
+ case is_PkgdName(N) of
+ true ->
+ ok;
+ false ->
+ wrong_type('PkgdName', N, N)
+ end;
+chk_PkgdName(N1, N2) ->
+ case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+ true ->
+ not_equal('PkgdName', N1, N2);
+ false ->
+ wrong_type('PkgdName', N1, N2)
+ end.
+
+
+%% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+chk_Relation(R, R) ->
+ chk_type(fun is_Relation/1, 'Relation', R);
+chk_Relation(R1, R2) ->
+ case (is_Relation(R1) andalso is_Relation(R2)) of
+ true ->
+ not_equal('Relation', R1, R2);
+ false ->
+ wrong_type('Relation', R1, R2)
+ end.
+
+
+%% -- LocalRemoteDescriptor --
+
+is_opt_LocalRemoteDescriptor(D) ->
+ d("is_LocalRemoteDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+ d("is_LocalRemoteDescriptor -> entry with"
+ "~n PGs: ~p", [PGs]),
+ is_LocalRemoteDescriptor_propGrps(PGs);
+is_LocalRemoteDescriptor(_) ->
+ false.
+
+is_LocalRemoteDescriptor_propGrps([]) ->
+ true;
+is_LocalRemoteDescriptor_propGrps([H|T]) ->
+ is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+is_LocalRemoteDescriptor_propGrps(_) ->
+ false.
+
+chk_opt_LocalRemoteDescriptor(D1, D2) ->
+ chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+ fun is_LocalRemoteDescriptor/1,
+ fun chk_LocalRemoteDescriptor/2).
+
+chk_LocalRemoteDescriptor(LRD, LRD) ->
+ chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+ #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+ chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+ ok;
+chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+ wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+chk_LocalRemoteDescriptor_propGrps([], []) ->
+ ok;
+chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+ case is_PropertyGroup(H) of
+ true ->
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+ false ->
+ wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+ end;
+chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyGroup(H1, H2) end,
+ 'LocalRemoteDescriptor_propGrps_val'),
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+ wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% -- PropertyGroup --
+
+is_PropertyGroup([]) ->
+ true;
+is_PropertyGroup([H|T]) ->
+ is_PropertyParm(H) andalso is_PropertyGroup(T);
+is_PropertyGroup(_) ->
+ false.
+
+chk_PropertyGroup([], []) ->
+ ok;
+chk_PropertyGroup([] = PG1, PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup(PG1, [] = PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_PropertyGroup(T1, T2);
+ false ->
+ wrong_type('PropertyGroup_val', H)
+ end;
+chk_PropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+ chk_PropertyGroup(T1, T2);
+chk_PropertyGroup(PG1, PG2) ->
+ wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% -- TerminationStateDescriptor --
+
+is_opt_TerminationStateDescriptor(D) ->
+ is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+is_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_TerminationStateDescriptor_propertyParms(PP) andalso
+ is_opt_EventBufferControl(EBC) andalso
+ is_opt_ServiceState(SS);
+is_TerminationStateDescriptor(_) ->
+ false.
+
+is_TerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_TerminationStateDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+is_TerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_TerminationStateDescriptor(D1, D2) ->
+ chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+ fun is_TerminationStateDescriptor/1,
+ fun chk_TerminationStateDescriptor/2).
+
+chk_TerminationStateDescriptor(D, D) ->
+ chk_type(fun is_TerminationStateDescriptor/1,
+ 'TerminationStateDescriptor', D);
+chk_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'TerminationStateDescriptor'{propertyParms = PP2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+ validate(
+ fun() ->
+ chk_opt_EventBufferControl(EBC1, EBC2)
+ end,
+ 'TerminationStateDescriptor'),
+ validate(
+ fun() ->
+ chk_opt_ServiceState(SS1, SS2)
+ end,
+ 'TerminationStateDescriptor'),
+ ok;
+chk_TerminationStateDescriptor(D1, D2) ->
+ wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+chk_TerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_TerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+ end;
+chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+ case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+ true ->
+ not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+ end;
+chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+ wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% -- EventBufferControl --
+
+is_opt_EventBufferControl(asn1_NOVALUE) ->
+ true;
+is_opt_EventBufferControl(EBC) ->
+ is_EventBufferControl(EBC).
+
+is_EventBufferControl(EBC) ->
+ lists:member(EBC, [off, lockStep]).
+
+chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_EventBufferControl(EBC1, EBC2) ->
+ chk_EventBufferControl(EBC1, EBC2).
+
+chk_EventBufferControl(EBC, EBC) ->
+ chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+chk_EventBufferControl(EBC1, EBC2) ->
+ case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+ true ->
+ not_equal('EventBufferControl', EBC1, EBC2);
+ false ->
+ wrong_type('EventBufferControl', EBC1, EBC2)
+ end.
+
+
+%% -- ServiceState --
+
+is_opt_ServiceState(asn1_NOVALUE) ->
+ true;
+is_opt_ServiceState(SS) ->
+ is_ServiceState(SS).
+
+is_ServiceState(SS) ->
+ lists:member(SS, [test, outOfSvc, inSvc]).
+
+chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ServiceState(SS1, SS2) ->
+ chk_ServiceState(SS1, SS2).
+
+chk_ServiceState(SS, SS) ->
+ chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+chk_ServiceState(SS1, SS2) ->
+ case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+ true ->
+ not_equal('ServiceState', SS1, SS2);
+ false ->
+ wrong_type('ServiceState', SS1, SS2)
+ end.
+
+
+%% -- MuxDescriptor --
+
+is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+ termList = TL,
+ nonStandardData = NSD}) ->
+ is_MuxType(MT) andalso
+ is_MuxDescriptor_termList(TL) andalso
+ is_NonStandardData(NSD);
+is_MuxDescriptor(_) ->
+ false.
+
+is_MuxDescriptor_termList([]) ->
+ true;
+is_MuxDescriptor_termList([H|T]) ->
+ is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+is_MuxDescriptor_termList(_) ->
+ false.
+
+chk_MuxDescriptor(D, D) ->
+ chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+ termList = TL1,
+ nonStandardData = NSD1},
+ #'MuxDescriptor'{muxType = MT2,
+ termList = TL2,
+ nonStandardData = NSD2}) ->
+ validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+ chk_MuxDescriptor_termList(TL1, TL2),
+ validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+ ok;
+chk_MuxDescriptor(D1, D2) ->
+ wrong_type('MuxDescriptor', D1, D2).
+
+chk_MuxDescriptor_termList([], []) ->
+ ok;
+chk_MuxDescriptor_termList([] = TL1, TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_MuxDescriptor_termList(T1, T2);
+ false ->
+ wrong_type('MuxDescriptor_termList_val', H)
+ end;
+chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end,
+ 'MuxDescriptor_termList_val'),
+ chk_MuxDescriptor_termList(T1, T2);
+chk_MuxDescriptor_termList(TL1, TL2) ->
+ wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% -- MuxType --
+
+is_MuxType(MT) ->
+ lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+chk_MuxType(MT, MT) ->
+ chk_type(fun is_MuxType/1, 'MuxType', MT);
+chk_MuxType(MT1, MT2) ->
+ case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+ true ->
+ not_equal('MuxType', MT1, MT2);
+ false ->
+ wrong_type('MuxType', MT1, MT2)
+ end.
+
+
+%% -- StreamID --
+
+is_opt_StreamID(V) ->
+ is_OPTIONAL(fun is_StreamID/1, V).
+
+is_StreamID(V) ->
+ d("is_StreamID -> entry with"
+ "~n V: ~p", [V]),
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_StreamID(V1, V2) ->
+ chk_OPTIONAL('StreamID', V1, V2, fun is_StreamID/1, fun chk_StreamID/2).
+
+chk_StreamID(ID, ID) ->
+ chk_type(fun is_StreamID/1, 'StreamID', ID);
+chk_StreamID(ID1, ID2) ->
+ case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+ true ->
+ not_equal('StreamID', ID1, ID2);
+ false ->
+ wrong_type('StreamID', ID1, ID2)
+ end.
+
+
+%% -- EventsDescriptor --
+
+is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = EVL}) ->
+ d("is_EventsDescriptor -> entry with"
+ "~n RID: ~p"
+ "~n EVL: ~p", [RID, EVL]),
+ is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+is_EventsDescriptor(_) ->
+ false.
+
+is_EventsDescriptor_eventList([]) ->
+ true;
+is_EventsDescriptor_eventList([H|T]) ->
+ is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+is_EventsDescriptor_eventList(_) ->
+ false.
+
+chk_EventsDescriptor(D, D) ->
+ chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+ eventList = EVL1},
+ #'EventsDescriptor'{requestID = RID2,
+ eventList = EVL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+ chk_EventsDescriptor_eventList(EVL1, EVL2),
+ ok;
+chk_EventsDescriptor(D1, D2) ->
+ wrong_type('EventsDescriptor', D1, D2).
+
+chk_EventsDescriptor_eventList([], []) ->
+ ok;
+chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_RequestedEvent(H) of
+ true ->
+ chk_EventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('EventsDescriptor_eventList_val', H)
+ end;
+chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_RequestedEvent(H1, H2) end,
+ 'EventsDescriptor_eventList_val'),
+ chk_EventsDescriptor_eventList(T1, T2);
+chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+ wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% -- RequestedEvent --
+
+is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ d("is_RequestedEvent -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n EA: ~p"
+ "~n EPL: ~p", [N, SID, EA, EPL]),
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestedActions(EA) andalso
+ is_RequestedEvent_evParList(EPL);
+is_RequestedEvent(_) ->
+ false.
+
+is_RequestedEvent_evParList([]) ->
+ true;
+is_RequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+is_RequestedEvent_evParList(_) ->
+ false.
+
+chk_RequestedEvent(RE, RE) ->
+ chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'RequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+ 'RequestedEvent'),
+ chk_RequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_RequestedEvent(RE1, RE2) ->
+ wrong_type('RequestedEvent', RE1, RE2).
+
+chk_RequestedEvent_evParList([], []) ->
+ ok;
+chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_RequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('RequestedEvent_evParList_val', H)
+ end;
+chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'RequestedEvent_evParList_val'),
+ chk_RequestedEvent_evParList(T1, T2);
+chk_RequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- RequestedActions --
+
+is_opt_RequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_RequestedActions(RA) ->
+ is_RequestedActions(RA).
+
+is_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ d("is_RequestedActions -> entry with"
+ "~n KA: ~p"
+ "~n EDM: ~p"
+ "~n SE: ~p"
+ "~n SD: ~p", [KA, EDM, SE, SD]),
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD);
+is_RequestedActions(_) ->
+ false.
+
+chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestedActions(RA1, RA2) ->
+ chk_RequestedActions(RA1, RA2).
+
+chk_RequestedActions(RA, RA) ->
+ chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ secondEvent = SA1,
+ signalsDescriptor = SD1},
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ secondEvent = SA2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_SecondEventsDescriptor(SA1, SA2) end,
+ 'RequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'RequestedActions'),
+ ok;
+chk_RequestedActions(RA1, RA2) ->
+ wrong_type('RequestedActions', RA1, RA2).
+
+
+%% -- EventDM --
+
+is_opt_EventDM(EDM) ->
+ is_OPTIONAL(fun is_EventDM/1, EDM).
+
+is_EventDM({Tag, Val}) ->
+ is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+is_EventDM(_) ->
+ false.
+
+is_EventDM_tag(Tag) ->
+ Tags = [digitMapName, digitMapValue],
+ lists:member(Tag, Tags).
+
+is_EventDM_val(digitMapName, Val) ->
+ is_DigitMapName(Val);
+is_EventDM_val(digitMapValue, Val) ->
+ is_DigitMapValue(Val).
+
+chk_opt_EventDM(EDM1, EDM2) ->
+ chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+chk_EventDM(EDM, EDM) ->
+ chk_type(fun is_EventDM/1, 'EventDM', EDM);
+chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+ case (is_EventDM_tag(Tag) andalso
+ is_EventDM_val(Tag, Val1) andalso
+ is_EventDM_val(Tag, Val2)) of
+ true ->
+ chk_EventDM_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+ case ((is_EventDM_tag(Tag1) andalso
+ is_EventDM_val(Tag1, Val1)) andalso
+ (is_EventDM_tag(Tag2) andalso
+ is_EventDM_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventDM', EDM1, EDM2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM(EDM1, EDM2) ->
+ wrong_type('EventDM', EDM1, EDM2).
+
+chk_EventDM_val(digitMapName, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+chk_EventDM_val(digitMapValue, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% -- SecondEventsDescriptor --
+
+is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SecondEventsDescriptor(D) ->
+ is_SecondEventsDescriptor(D).
+
+is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = EL}) ->
+ is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+is_SecondEventsDescriptor(_) ->
+ false.
+
+is_SecondEventsDescriptor_eventList([]) ->
+ true;
+is_SecondEventsDescriptor_eventList([H|T]) ->
+ is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+is_SecondEventsDescriptor_eventList(_) ->
+ false.
+
+chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondEventsDescriptor(D1, D2) ->
+ chk_SecondEventsDescriptor(D1, D2).
+
+chk_SecondEventsDescriptor(D, D) ->
+ chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+ eventList = EL1},
+ #'SecondEventsDescriptor'{requestID = RID2,
+ eventList = EL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+ 'SecondEventsDescriptor'),
+ chk_SecondEventsDescriptor_eventList(EL1, EL2),
+ ok;
+chk_SecondEventsDescriptor(D1, D2) ->
+ wrong_type('SecondEventsDescriptor', D1, D2).
+
+chk_SecondEventsDescriptor_eventList([], []) ->
+ ok;
+chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_SecondRequestedEvent(H) of
+ true ->
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('SecondEventsDescriptor_eventList_val', H)
+ end;
+chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+ 'SecondEventsDescriptor_eventList_val'),
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+chk_SecondEventsDescriptor_eventList(L1, L2) ->
+ wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% -- SecondRequestedEvent --
+
+is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SecondRequestedActions(EA) andalso
+ is_SecondRequestedEvent_evParList(EPL);
+is_SecondRequestedEvent(_) ->
+ false.
+
+is_SecondRequestedEvent_evParList([]) ->
+ true;
+is_SecondRequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+is_SecondRequestedEvent_evParList(_) ->
+ false.
+
+chk_SecondRequestedEvent(RE, RE) ->
+ chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'SecondRequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+ 'SecondRequestedEvent'),
+ chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_SecondRequestedEvent(RE1, RE2) ->
+ wrong_type('SecondRequestedEvent', RE1, RE2).
+
+chk_SecondRequestedEvent_evParList([], []) ->
+ ok;
+chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_SecondRequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('SecondRequestedEvent_evParList_val', H)
+ end;
+chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'SecondRequestedEvent_evParList_val'),
+ chk_SecondRequestedEvent_evParList(T1, T2);
+chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- SecondRequestedActions --
+
+is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_SecondRequestedActions(SRA) ->
+ is_SecondRequestedActions(SRA).
+
+is_SecondRequestedActions(#'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}) ->
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SignalsDescriptor(SD);
+is_SecondRequestedActions(_) ->
+ false.
+
+chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+ chk_SecondRequestedActions(SRA1, SRA2).
+
+chk_SecondRequestedActions(SRA, SRA) ->
+ chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+chk_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ signalsDescriptor = SD1},
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'SecondRequestedActions'),
+ ok;
+chk_SecondRequestedActions(SRA1, SRA2) ->
+ wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+
+%% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor([]) ->
+ true;
+is_EventBufferDescriptor([H|T]) ->
+ is_EventSpec(H) andalso is_EventBufferDescriptor(T);
+is_EventBufferDescriptor(_) ->
+ false.
+
+chk_EventBufferDescriptor([], []) ->
+ ok;
+chk_EventBufferDescriptor([] = D1, D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor(D1, [] = D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor([H|T1], [H|T2]) ->
+ case is_EventSpec(H) of
+ true ->
+ chk_EventBufferDescriptor(T1, T2);
+ false ->
+ wrong_type('EventBufferDescriptor_val', H)
+ end;
+chk_EventBufferDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventSpec(H1, H2) end,
+ 'EventBufferDescriptor_val'),
+ chk_EventBufferDescriptor(T1, T2);
+chk_EventBufferDescriptor(D1, D2) ->
+ wrong_type('EventBufferDescriptor_val', D1, D2).
+
+
+%% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+chk_EventSpec(ES, ES) ->
+ chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = SID1,
+ eventParList = EPL1},
+ #'EventSpec'{eventName = N2,
+ streamID = SID2,
+ eventParList = EPL2}) ->
+ validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+ chk_EventSpec_eventParList(EPL1, EPL2),
+ ok;
+chk_EventSpec(ES1, ES2) ->
+ wrong_type('EventSpec', ES1, ES2).
+
+chk_EventSpec_eventParList([], []) ->
+ ok;
+chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_EventSpec_eventParList(T1, T2);
+ false ->
+ wrong_type('EventSpec_eventParList_val', H)
+ end;
+chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'EventSpec_eventParList_val'),
+ chk_EventSpec_eventParList(T1, T2);
+chk_EventSpec_eventParList(EPL1, EPL2) ->
+ wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% -- SignalsDescriptor --
+
+is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SignalsDescriptor(D) ->
+ is_SignalsDescriptor(D).
+
+is_SignalsDescriptor([]) ->
+ true;
+is_SignalsDescriptor([H|T]) ->
+ is_SignalRequest(H) andalso is_SignalsDescriptor(T);
+is_SignalsDescriptor(_) ->
+ false.
+
+chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalsDescriptor(D1, D2) ->
+ chk_SignalsDescriptor(D1, D2).
+
+chk_SignalsDescriptor([], []) ->
+ ok;
+chk_SignalsDescriptor([] = D1, D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor(D1, [] = D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor([H|T1], [H|T2]) ->
+ case is_SignalRequest(H) of
+ true ->
+ chk_SignalsDescriptor(T1, T2);
+ false ->
+ wrong_type('SignalsDescriptor_val', H)
+ end;
+chk_SignalsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SignalRequest(H1, H2) end, 'SignalsDescriptor_val'),
+ chk_SignalsDescriptor(T1, T2);
+chk_SignalsDescriptor(D1, D2) ->
+ wrong_type('SignalsDescriptor', D1, D2).
+
+
+%% -- SignalRequest --
+
+is_SignalRequest({Tag, Val}) ->
+ is_SignalRequest_tag(Tag) andalso is_SignalRequest_val(Tag, Val);
+is_SignalRequest(_) ->
+ false.
+
+is_SignalRequest_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_SignalRequest_val(signal, Val) ->
+ is_Signal(Val);
+is_SignalRequest_val(seqSigList, Val) ->
+ is_SeqSigList(Val).
+
+chk_SignalRequest(R, R) ->
+ chk_type(fun is_SignalRequest/1, 'SignalRequest', R);
+chk_SignalRequest({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_SignalRequest_tag(Tag) andalso
+ is_SignalRequest_val(Tag, Val1) andalso
+ is_SignalRequest_val(Tag, Val2)) of
+ true ->
+ chk_SignalRequest_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_SignalRequest_tag(Tag1) andalso
+ is_SignalRequest_val(Tag1, Val1)) andalso
+ (is_SignalRequest_tag(Tag2) andalso
+ is_SignalRequest_val(Tag2, Val2))) of
+ true ->
+ not_equal('SignalRequest', R1, R2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest(R1, R2) ->
+ wrong_type('SignalRequest', R1, R2).
+
+chk_SignalRequest_val(signal, Val1, Val2) ->
+ validate(fun() -> chk_Signal(Val1, Val2) end, 'SignalRequest');
+chk_SignalRequest_val(seqSigList, Val1, Val2) ->
+ validate(fun() -> chk_SeqSigList(Val1, Val2) end, 'SignalRequest').
+
+
+%% -- SeqSigList --
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+chk_SeqSigList(L, L) ->
+ chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+chk_SeqSigList(#'SeqSigList'{id = ID1,
+ signalList = SL1},
+ #'SeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+ 'SeqSigList'),
+ chk_SeqSigList_signalList(SL1, SL2),
+ ok;
+chk_SeqSigList(L1, L2) ->
+ wrong_type('SeqSigList', L1, L2).
+
+chk_SeqSigList_signalList([], []) ->
+ ok;
+chk_SeqSigList_signalList([] = L1, L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList(L1, [] = L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+ case is_Signal(H) of
+ true ->
+ chk_SeqSigList_signalList(T1, T2);
+ false ->
+ wrong_type('SeqSigList_signalList_val', H)
+ end;
+chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Signal(H1, H2) end,
+ 'SeqSigList_signalList_val'),
+ chk_SeqSigList_signalList(T1, T2);
+chk_SeqSigList_signalList(L1, L2) ->
+ wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}) ->
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL) andalso
+ is_opt_SignalDirection(Dir) andalso
+ is_opt_RequestID(RID).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+chk_Signal(S, S) ->
+ chk_type(fun is_Signal/1, 'Signal', S);
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = SID1,
+ sigType = ST1,
+ duration = Dur1,
+ notifyCompletion = NC1,
+ keepActive = KA1,
+ sigParList = SPL1,
+ direction = Dir1,
+ requestID = RID1},
+ #'Signal'{signalName = N2,
+ streamID = SID2,
+ sigType = ST2,
+ duration = Dur2,
+ notifyCompletion = NC2,
+ keepActive = KA2,
+ sigParList = SPL2,
+ direction = Dir2,
+ requestID = RID2}) ->
+ validate(fun() -> chk_SignalName(N1, N2) end, 'Signal'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'Signal'),
+ validate(fun() -> chk_opt_SignalType(ST1, ST2) end, 'Signal'),
+ validate(fun() -> chk_opt_INTEGER(Dur1, Dur2, {range, 0, 65535}) end,
+ 'Signal'),
+ validate(fun() -> chk_opt_NotifyCompletion(NC1, NC2) end, 'Signal'),
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'Signal'),
+ chk_Signal_sigParList(SPL1, SPL2),
+ validate(fun() -> chk_opt_SignalDirection(Dir1, Dir2) end, 'Signal'),
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'Signal'),
+ ok;
+chk_Signal(S1, S2) ->
+ wrong_type('Signal', S1, S2).
+
+chk_Signal_sigParList([], []) ->
+ ok;
+chk_Signal_sigParList([] = L1, L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList(L1, [] = L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList([H|T1], [H|T2]) ->
+ case is_SigParameter(H) of
+ true ->
+ chk_Signal_sigParList(T1, T2);
+ false ->
+ wrong_type('Signal_sigParList_val', H)
+ end;
+chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SigParameter(H1, H2) end,
+ 'Signal_sigParList_val'),
+ chk_Signal_sigParList(T1, T2);
+chk_Signal_sigParList(L1, L2) ->
+ wrong_type('Signal_sigParList', L1, L2).
+
+
+%% -- SignalType --
+
+is_opt_SignalType(T) ->
+ is_OPTIONAL(fun is_SignalType/1, T).
+
+is_SignalType(T) ->
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+chk_opt_SignalType(T1, T2) ->
+ chk_OPTIONAL('SignalType', T1, T2,
+ fun is_SignalType/1, fun chk_SignalType/2).
+
+chk_SignalType(T, T) ->
+ chk_type(fun is_SignalType/1, 'SignalType', T);
+chk_SignalType(T1, T2) ->
+ case (is_SignalType(T1) andalso is_SignalType(T2)) of
+ true ->
+ not_equal('SignalType', T1, T2);
+ false ->
+ wrong_type('SignalType', T1, T2)
+ end.
+
+
+%% -- SignalDirection --
+
+is_opt_SignalDirection(T) ->
+ is_OPTIONAL(fun is_SignalDirection/1, T).
+
+is_SignalDirection(Dir) ->
+ Dirs = [internal, external, both],
+ lists:member(Dir, Dirs).
+
+chk_opt_SignalDirection(T1, T2) ->
+ chk_OPTIONAL('SignalDirection', T1, T2,
+ fun is_SignalDirection/1, fun chk_SignalDirection/2).
+
+chk_SignalDirection(Dir, Dir) ->
+ chk_type(fun is_SignalDirection/1, 'SignalDirection', Dir);
+chk_SignalDirection(Dir1, Dir2) ->
+ case (is_SignalDirection(Dir1) andalso is_SignalDirection(Dir2)) of
+ true ->
+ not_equal('SignalDirection', Dir1, Dir2);
+ false ->
+ wrong_type('SignalDirection', Dir1, Dir2)
+ end.
+
+
+%% -- SignalName --
+
+is_SignalName(N) -> is_PkgdName(N).
+
+chk_SignalName(N1, N2) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:all(fun(X) -> lists:member(X, Valids) end, NC).
+
+chk_opt_NotifyCompletion(NC1, NC2) ->
+ chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+ fun is_NotifyCompletion/1,
+ fun chk_NotifyCompletion/2).
+
+chk_NotifyCompletion(NC, NC) ->
+ chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+chk_NotifyCompletion(NC1, NC2) ->
+ case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+ true ->
+ not_equal('NotifyCompletion', NC1, NC2);
+ false ->
+ wrong_type('NotifyCompletion', NC1, NC2)
+ end.
+
+
+%% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_SigParameter(P, P) ->
+ chk_type(fun is_SigParameter/1, 'SigParameter', P);
+chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = I1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+ validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+ chk_SigParameter_extraInfo(I1, I2),
+ ok;
+chk_SigParameter(P1, P2) ->
+ wrong_type('SigParameter', P1, P2).
+
+chk_SigParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_SigParameter_extraInfo_tag(Tag) and
+ is_SigParameter_extraInfo_val(Tag, Val1) and
+ is_SigParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_SigParameter_extraInfo_tag(Tag1) and
+ is_SigParameter_extraInfo_val(Tag1, Val1)) and
+ (is_SigParameter_extraInfo_tag(Tag2) and
+ is_SigParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('SigParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo(EI1, EI2) ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% -- RequestID --
+
+is_opt_RequestID(asn1_NOVALUE) ->
+ true;
+is_opt_RequestID(V) ->
+ is_RequestID(V).
+
+is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestID(V1, V2) ->
+ chk_RequestID(V1, V2).
+
+chk_RequestID(ID, ID) ->
+ chk_type(fun is_RequestID/1, 'RequestID', ID);
+chk_RequestID(ID1, ID2) ->
+ case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+ true ->
+ not_equal('RequestID', ID1, ID2);
+ false ->
+ wrong_type('RequestID', ID1, ID2)
+ end.
+
+
+%% -- ModemDescriptor --
+
+is_ModemDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ true;
+is_ModemDescriptor(_) ->
+ false.
+
+chk_ModemDescriptor(D, D) when is_record(D, 'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+ mpl = MPL1,
+ nonStandardData = NSD1},
+ #'ModemDescriptor'{mtl = MTL2,
+ mpl = MPL2,
+ nonStandardData = NSD2}) ->
+ chk_ModemDescriptor_mtl(MTL1, MTL2),
+ chk_ModemDescriptor_mpl(MPL1, MPL2),
+ chk_opt_NonStandardData(NSD1, NSD2),
+ ok;
+chk_ModemDescriptor(D1, D2) ->
+ wrong_type('ModemDescriptor', D1, D2).
+
+chk_ModemDescriptor_mtl([], []) ->
+ ok;
+chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+ case is_ModemType(H) of
+ true ->
+ chk_ModemDescriptor_mtl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mtl_val', H)
+ end;
+chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+ chk_ModemDescriptor_mtl(T1, T2);
+chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+ wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+chk_ModemDescriptor_mpl([], []) ->
+ ok;
+chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ModemDescriptor_mpl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mpl_val', H)
+ end;
+chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+ chk_ModemDescriptor_mpl(T1, T2);
+chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+ wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% -- ModemType --
+
+chk_ModemType(MT, MT) ->
+ case is_ModemType(MT) of
+ true ->
+ ok;
+ false ->
+ wrong_type('ModemType', MT, MT)
+ end;
+chk_ModemType(MT1, MT2) ->
+ case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+ true ->
+ not_equal('ModemType', MT1, MT2);
+ false ->
+ wrong_type('ModemType', MT1, MT2)
+ end.
+
+is_ModemType(MT) ->
+ lists:member(MT,
+ [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% -- DigitMapDescriptor --
+
+is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Val}) ->
+ is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+is_DigitMapDescriptor(_) ->
+ false.
+
+chk_DigitMapDescriptor(D, D) ->
+ chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+ digitMapValue = Val1},
+ #'DigitMapDescriptor'{digitMapName = Name2,
+ digitMapValue = Val2}) ->
+ d("chk_DigitMapDescriptor -> entry with"
+ "~n Name1: ~p"
+ "~n Name2: ~p"
+ "~n Val1: ~p"
+ "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'DigitMapDescriptor'),
+ validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+ 'DigitMapDescriptor'),
+ ok;
+chk_DigitMapDescriptor(D1, D2) ->
+ wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% -- DigitMapName --
+
+is_opt_DigitMapName(asn1_NOVALUE) ->
+ true;
+is_opt_DigitMapName(N) ->
+ is_DigitMapName(N).
+
+is_DigitMapName(N) -> is_Name(N).
+
+chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_DigitMapName(N1, N2) ->
+ chk_DigitMapName(N1, N2).
+
+chk_DigitMapName(N, N) ->
+ chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+chk_DigitMapName(N1, N2) ->
+ case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+ true ->
+ not_equal('DigitMapName', N1, N2);
+ false ->
+ wrong_type('DigitMapName', N1, N2)
+ end.
+
+
+%% -- DigitMapValue --
+
+is_opt_DigitMapValue(V) ->
+ is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Dur}) ->
+ is_DigitMapValue_startTimer(Start) andalso
+ is_DigitMapValue_shortTimer(Short) andalso
+ is_DigitMapValue_longTimer(Long) andalso
+ is_IA5String(Body) andalso
+ is_DigitMapValue_durationTimer(Dur);
+is_DigitMapValue(_) ->
+ false.
+
+is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+chk_opt_DigitMapValue(V1, V2) ->
+ chk_OPTIONAL('DigitMapValue', V1, V2,
+ fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1,
+ digitMapBody = Body1,
+ durationTimer = Dur1},
+ #'DigitMapValue'{startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2,
+ digitMapBody = Body2,
+ durationTimer = Dur2}) ->
+ d("chk_DigitMapValue -> entry with"
+ "~n Start1: ~p"
+ "~n Start2: ~p"
+ "~n Short1: ~p"
+ "~n Short2: ~p"
+ "~n Long1: ~p"
+ "~n Long2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p"
+ "~n Dur1: ~p"
+ "~n Dur2: ~p", [Start1, Start2,
+ Short1, Short2,
+ Long1, Long2,
+ Body1, Body2,
+ Dur1, Dur2]),
+ chk_DigitMapValue_startTimer(Start1, Start2),
+ chk_DigitMapValue_shortTimer(Short1, Short2),
+ chk_DigitMapValue_longTimer(Long1, Long2),
+ chk_DigitMapValue_digitMapBody(Body1, Body2),
+ chk_DigitMapValue_durationTimer(Dur1, Dur2),
+ ok;
+chk_DigitMapValue(V1, V2) ->
+ wrong_type('DigitMapValue', V1, V2).
+
+chk_DigitMapValue_startTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+chk_DigitMapValue_startTimer(T1, T2) ->
+ case (is_DigitMapValue_startTimer(T1) andalso
+ is_DigitMapValue_startTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_startTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_startTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_shortTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+chk_DigitMapValue_shortTimer(T1, T2) ->
+ case (is_DigitMapValue_shortTimer(T1) andalso
+ is_DigitMapValue_shortTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_shortTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_shortTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_longTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+chk_DigitMapValue_longTimer(T1, T2) ->
+ case (is_DigitMapValue_longTimer(T1) andalso
+ is_DigitMapValue_longTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_longTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_longTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_durationTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_durationTimer/1,
+ 'DigitMapValue_durationTimer', T);
+chk_DigitMapValue_durationTimer(T1, T2) ->
+ case (is_DigitMapValue_durationTimer(T1) andalso
+ is_DigitMapValue_durationTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_durationTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_durationTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_digitMapBody(B, B) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B: ~p", [B]),
+ chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+chk_DigitMapValue_digitMapBody(B1, B2) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B1: ~p"
+ "~n B2: ~p", [B1, B2]),
+ case (is_IA5String(B1) andalso is_IA5String(B2)) of
+ true ->
+ %% If they are different it could be because
+ %% of trailing tab's and newline's.
+ case compare_strings(B1, B2) of
+ {[], []} ->
+ ok;
+ {Str1, []} ->
+ case strip_tab_and_newline(Str1) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ {[], Str2} ->
+ case strip_tab_and_newline(Str2) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ false ->
+ wrong_type('DigitMapValue_digitMapBody', B1, B2)
+ end.
+
+%% -- ServiceChangeParm --
+
+is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Id,
+ timeStamp = TS,
+ nonStandardData = NSD,
+ serviceChangeInfo = I}) ->
+ is_ServiceChangeMethod(M) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_Value(R) andalso
+ is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+ is_opt_MId(Id) andalso
+ is_opt_TimeNotation(TS) andalso
+ is_opt_NonStandardData(NSD) andalso
+ is_opt_AuditDescriptor(I);
+is_ServiceChangeParm(_) ->
+ false.
+
+chk_ServiceChangeParm(P, P) ->
+ chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Id1,
+ timeStamp = TS1,
+ nonStandardData = NSD1,
+ serviceChangeInfo = I1},
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Id2,
+ timeStamp = TS2,
+ nonStandardData = NSD2,
+ serviceChangeInfo = I2}) ->
+ validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_Value(R1, R2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_MId(Id1, Id2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+ 'ServiceChangeParm'),
+ ok;
+chk_ServiceChangeParm(P1, P2) ->
+ wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% -- ServiceChangeAddress --
+
+is_opt_ServiceChangeAddress(A) ->
+ is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+is_ServiceChangeAddress({Tag, Val}) ->
+ is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val);
+is_ServiceChangeAddress(_) ->
+ false.
+
+is_ServiceChangeAddress_tag(Tag) ->
+ Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+ mtpAddress],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeAddress_val(portNumber, Val) ->
+ is_INTEGER(Val, {range, 0, 65535});
+is_ServiceChangeAddress_val(ip4Address, Val) ->
+ is_IP4Address(Val);
+is_ServiceChangeAddress_val(ip6Address, Val) ->
+ is_IP6Address(Val);
+is_ServiceChangeAddress_val(domainName, Val) ->
+ is_DomainName(Val);
+is_ServiceChangeAddress_val(deviceName, Val) ->
+ is_PathName(Val);
+is_ServiceChangeAddress_val(mtpAddress, Val) ->
+ is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+chk_opt_ServiceChangeAddress(A1, A2) ->
+ chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+ fun is_ServiceChangeAddress/1,
+ fun chk_ServiceChangeAddress/2).
+
+chk_ServiceChangeAddress(A, A) ->
+ chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+ case (is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val1) andalso
+ is_ServiceChangeAddress_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+ case ((is_ServiceChangeAddress_tag(Tag1) andalso
+ is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+ (is_ServiceChangeAddress_tag(Tag2) andalso
+ is_ServiceChangeAddress_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeAddress', A1, A2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress(A1, A2) ->
+ wrong_type('ServiceChangeAddress', A1, A2).
+
+chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+ validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+ validate(fun() -> chk_IP4Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+ validate(fun() -> chk_IP6Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+ validate(fun() -> chk_DomainName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+ validate(fun() -> chk_PathName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+ validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+ 'ServiceChangeAddress').
+
+
+%% -- ServiceChangeResParm --
+
+is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ timeStamp = TS}) ->
+ is_opt_MId(Id) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_opt_TimeNotation(TS);
+is_ServiceChangeResParm(_) ->
+ false.
+
+chk_ServiceChangeResParm(P, P) ->
+ chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+chk_ServiceChangeResParm(
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ timeStamp = TS1},
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ timeStamp = TS2}) ->
+ validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeResParm'),
+ ok;
+chk_ServiceChangeResParm(P1, P2) ->
+ wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% -- ServiceChangeMethod --
+
+is_ServiceChangeMethod(M) ->
+ Methods = [failover, forced, graceful, restart, disconnected, handOff],
+ lists:member(M, Methods).
+
+chk_ServiceChangeMethod(M, M) ->
+ chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+chk_ServiceChangeMethod(M1, M2) ->
+ case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+ true ->
+ not_equal('ServiceChangeMethod', M1, M2);
+ false ->
+ wrong_type('ServiceChangeMethod', M1, M2)
+ end.
+
+
+%% -- ServiceChangeProfile --
+
+is_opt_ServiceChangeProfile(P) ->
+ is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+ is_IA5String(N, {range, 1, 67});
+is_ServiceChangeProfile(_) ->
+ false.
+
+chk_opt_ServiceChangeProfile(P1, P2) ->
+ chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+ fun is_ServiceChangeProfile/1,
+ fun chk_ServiceChangeProfile/2).
+
+chk_ServiceChangeProfile(P, P) ->
+ chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+ #'ServiceChangeProfile'{profileName = N2}) ->
+ validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+ 'ServiceChangeProfile'),
+ ok;
+chk_ServiceChangeProfile(P1, P2) ->
+ wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% -- PackagesDescriptor --
+
+is_PackagesDescriptor([]) ->
+ true;
+is_PackagesDescriptor([H|T]) ->
+ is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+is_PackagesDescriptor(_) ->
+ false.
+
+chk_PackagesDescriptor([], []) ->
+ ok;
+chk_PackagesDescriptor([] = D1, D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor(D1, [] = D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor([H|T1], [H|T2]) ->
+ case is_PackagesItem(H) of
+ true ->
+ chk_PackagesDescriptor(T1, T2);
+ false ->
+ wrong_type('PackagesDescriptor_val', H)
+ end;
+chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PackagesItem(H1, H2) end,
+ 'PackagesDescriptor_val'),
+ chk_PackagesDescriptor(T1, T2);
+chk_PackagesDescriptor(D1, D2) ->
+ wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% -- PackagesItem --
+
+is_PackagesItem(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+is_PackagesItem(_) ->
+ false.
+
+chk_PackagesItem(I, I) ->
+ chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+chk_PackagesItem(#'PackagesItem'{packageName = N1,
+ packageVersion = V1},
+ #'PackagesItem'{packageName = N2,
+ packageVersion = V2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+ ok;
+chk_PackagesItem(I1, I2) ->
+ wrong_type('PackagesItem', I1, I2).
+
+
+%% -- StatisticsDescriptor --
+
+is_opt_StatisticsDescriptor(D) ->
+ is_OPTIONAL(fun is_StatisticsDescriptor/1, D).
+
+is_StatisticsDescriptor([]) ->
+ true;
+is_StatisticsDescriptor([H|T]) ->
+ is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+is_StatisticsDescriptor(_) ->
+ false.
+
+chk_opt_StatisticsDescriptor(D1, D2) ->
+ chk_OPTIONAL('StatisticsDescriptor', D1, D2,
+ fun is_StatisticsDescriptor/1,
+ fun chk_StatisticsDescriptor/2).
+
+chk_StatisticsDescriptor([], []) ->
+ ok;
+chk_StatisticsDescriptor([] = D1, D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor(D1, [] = D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+ case is_StatisticsParameter(H) of
+ true ->
+ chk_StatisticsDescriptor(T1, T2);
+ false ->
+ wrong_type('StatisticsDescriptor_val', H)
+ end;
+chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+ 'StatisticsDescriptor_val'),
+ chk_StatisticsDescriptor(T1, T2);
+chk_StatisticsDescriptor(D1, D2) ->
+ wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% -- StatisticsParameter --
+
+is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+ statValue = V}) ->
+ is_PkgdName(N) andalso is_opt_Value(V);
+is_StatisticsParameter(_) ->
+ false.
+
+chk_StatisticsParameter(P, P) ->
+ chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+ statValue = V1},
+ #'StatisticsParameter'{statName = N2,
+ statValue = V2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+ validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+ ok;
+chk_StatisticsParameter(P1, P2) ->
+ wrong_type('StatisticsParameter', P1, P2).
+
+
+%% -- NonStandardData --
+
+is_opt_NonStandardData(asn1_NOVALUE) ->
+ true;
+is_opt_NonStandardData(NSD) ->
+ is_NonStandardData(NSD).
+
+%% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% data = D}) ->
+%% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% is_NonStandardData(_) ->
+%% false.
+
+is_NonStandardData(_) ->
+ true.
+
+chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+ true;
+chk_opt_NonStandardData(NSD1, NSD2) ->
+ chk_NonStandardData(NSD1, NSD2).
+
+chk_NonStandardData(NSD, NSD) ->
+ chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% data = D1},
+%% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% data = D2}) ->
+%% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% 'NonStandardData'),
+%% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% ok;
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% wrong_type('NonStandardData', NSD1, NSD2).
+chk_NonStandardData(NSD1, NSD2) ->
+ not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% -- NonStandardIdentifier --
+
+%% is_NonStandardIdentifier({Tag, Val}) ->
+%% is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val);
+%% is_NonStandardIdentifier(_) ->
+%% false.
+
+%% is_NonStandardIdentifier_tag(Tag) ->
+%% Tags = [object, h221NonStandard, experimental],
+%% lists:member(Tag, Tags).
+
+%% is_NonStandardIdentifier_val(object, Val) ->
+%% is_OBJECT_IDENTIFIER(Val);
+%% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% is_H221NonStandard(Val);
+%% is_NonStandardIdentifier_val(experimental, Val) ->
+%% is_IA5String(Val, {exact, 8}).
+
+%% chk_NonStandardIdentifier(Id, Id) ->
+%% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% true ->
+%% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% true ->
+%% not_equal('NonStandardIdentifier', Id1, Id2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier(Id1, Id2) ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% chk_H221NonStandard(Val1, Val2);
+%% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% -- H221NonStandard --
+
+%% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}) ->
+%% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 65535});
+%% is_H221NonStandard(_) ->
+%% false.
+
+%% chk_H221NonStandard(NS, NS) ->
+%% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% t35CountryCode2 = CC21,
+%% t35Extension = Ext1,
+%% manufacturerCode = MC1},
+%% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% t35CountryCode2 = CC22,
+%% t35Extension = Ext2,
+%% manufacturerCode = MC2}) ->
+%% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% 'H221NonStandard'),
+%% ok;
+%% chk_H221NonStandard(NS1, NS2) ->
+%% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% -- TimeNotation --
+
+is_opt_TimeNotation(asn1_NOVALUE) ->
+ true;
+is_opt_TimeNotation(TN) ->
+ is_TimeNotation(TN).
+
+is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+ is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+is_TimeNotation(_) ->
+ false.
+
+chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(TN1, TN2) ->
+ chk_TimeNotation(TN1, TN2).
+
+chk_TimeNotation(TN, TN) ->
+ chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+ #'TimeNotation'{date = D2, time = T2}) ->
+ validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+ validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+ ok;
+chk_TimeNotation(TN1, TN2) ->
+ wrong_type('TimeNotation', TN1, TN2).
+
+
+%% -- Value --
+
+is_opt_Value(V) ->
+ is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+chk_opt_Value(V1, V2) ->
+ chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+chk_Value(V, V) ->
+ case is_Value(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Value', V, V)
+ end;
+chk_Value(V1, V2) ->
+ case (is_Value(V1) andalso is_Value(V2)) of
+ true ->
+ not_equal('Value', V1, V2);
+ false ->
+ wrong_type('Value', V1, V2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Basic type check functions
+%% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ lists:member(B, [true, false]).
+
+chk_opt_BOOLEAN(B1, B2) ->
+ chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+chk_BOOLEAN(B, B) ->
+ chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+chk_BOOLEAN(B1, B2) ->
+ case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+ true ->
+ not_equal('BOOLEAN', B1, B2);
+ false ->
+ wrong_type('BOOLEAN', B1, B2)
+ end.
+
+
+is_IA5String(S) when is_list(S) ->
+ true;
+is_IA5String(_) ->
+ false.
+
+% chk_IA5String(S, S) ->
+% chk_type(fun is_IA5String/1, 'IA5String', S);
+% chk_IA5String(S1, S2) ->
+% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+% true ->
+% not_equal('IA5String', S1, S2);
+% false ->
+% wrong_type('IA5String', S1, S2)
+% end.
+
+is_IA5String(S, _) when is_list(S) ->
+ true;
+is_IA5String(_, _) ->
+ false.
+
+chk_IA5String(S, S, R) ->
+ chk_type(fun is_IA5String/2, 'IA5String', S, R);
+chk_IA5String(S1, S2, R) ->
+ case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+ true ->
+ not_equal('IA5String', S1, S2);
+ false ->
+ wrong_type('IA5String', S1, S2)
+ end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) andalso (length(L) =:= Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) andalso (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) andalso (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) andalso (Min =< length(L)) andalso (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% chk_OCTET_STRING(L1, L2) ->
+%% chk_OCTET_STRING(L1, L2, any).
+
+chk_OCTET_STRING(L, L, R) ->
+ chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+chk_OCTET_STRING(L1, L2, R) ->
+ case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+ true ->
+ not_equal('OCTET STRING', L1, L2);
+ false ->
+ wrong_type('OCTET STRING', L1, L2)
+ end.
+
+
+%% is_OBJECT_IDENTIFIER(_) ->
+%% true.
+
+%% chk_OBJECT_IDENTIFIER(X, X) ->
+%% ok;
+%% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+is_opt_NULL(N) ->
+ is_OPTIONAL(fun is_NULL/1, N).
+
+is_NULL('NULL') ->
+ true;
+is_NULL(_) ->
+ false.
+
+chk_opt_NULL(N1, N2) ->
+ chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+chk_NULL(N, N) ->
+ chk_type(fun is_NULL/1, 'NULL', N);
+chk_NULL(N1, N2) ->
+ case (is_NULL(N1) andalso is_NULL(N2)) of
+ true ->
+ not_equal('NULL', N1, N2);
+ false ->
+ wrong_type('NULL', N1, N2)
+ end.
+
+
+is_opt_INTEGER(I, R) ->
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max})
+ when is_integer(I) andalso
+ is_integer(Max) andalso
+ (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Min =< I) andalso
+ (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+chk_opt_INTEGER(I1, I2, R) ->
+ chk_OPTIONAL('INTEGER', I1, I2,
+ fun(X) -> is_INTEGER(X, R) end,
+ fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+chk_INTEGER(I, I, R) ->
+ chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+chk_INTEGER(I1, I2, R) ->
+ case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+ true ->
+ not_equal('INTEGER', I1, I2);
+ false ->
+ wrong_type('INTEGER', I1, I2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Various utility functions
+%% ----------------------------------------------------------------------
+
+
+to_lower([C|Cs]) when C >= $A, C =< $Z ->
+ [C+($a-$A)|to_lower(Cs)];
+to_lower([C|Cs]) ->
+ [C|to_lower(Cs)];
+to_lower([]) ->
+ [].
+
+
+validate(F, Type) when is_function(F) ->
+ case (catch F()) of
+ {error, Reason} ->
+ error({Type, Reason});
+ ok ->
+ ok
+ end.
+
+
+chk_type(F, T, V) when is_function(F) andalso is_atom(T) ->
+ case F(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V)
+ end.
+
+chk_type(F, T, V1, V2) when is_function(F) andalso is_atom(T) ->
+ case F(V1, V2) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V1)
+ end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+ ok;
+chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when is_function(IS) ->
+ case IS(V2) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when is_function(IS) ->
+ case IS(V1) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when is_function(CHK) ->
+ CHK(V1, V2).
+
+
+%% ----------------------------------------------------------------------
+
+compare_strings([] = L1, L2) ->
+ {L1, L2};
+compare_strings(L1, [] = L2) ->
+ {L1, L2};
+compare_strings([H|T1], [H|T2]) ->
+ compare_strings(T1, T2);
+compare_strings(L1, L2) ->
+ {L1, L2}.
+
+strip_tab_and_newline([]) ->
+ [];
+strip_tab_and_newline([$\n|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([$\t|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([H|T]) ->
+ [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+atmost_once(Type, Val) ->
+ error({atmost_once, {Type, Val}}).
+
+wrong_type(Type, Val) ->
+ error({wrong_type, {Type, Val}}).
+
+wrong_type(Type, Val1, Val2) ->
+ error({wrong_type, {Type, Val1, Val2}}).
+
+not_equal(What, Val1, Val2) ->
+ error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_msg_prev3b_lib.erl b/lib/megaco/test/megaco_test_msg_prev3b_lib.erl
new file mode 100644
index 0000000000..be87dc9a41
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_prev3b_lib.erl
@@ -0,0 +1,7489 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_prev3b_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_prev3b.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([chk_MegacoMessage/2,
+ cre_MegacoMessage/1, cre_MegacoMessage/2,
+ cre_AuthenticationHeader/3,
+ cre_Message/3,
+ cre_ErrorDescriptor/1, cre_ErrorDescriptor/2,
+ cre_ErrorCode/1,
+ cre_ErrorText/1,
+ cre_ContextID/1,
+ cre_Transaction/1,
+ cre_TransactionId/1,
+ cre_TransactionRequest/2,
+ cre_TransactionPending/1,
+ cre_TransactionReply/2, cre_TransactionReply/3,
+ cre_TransactionAck/1, cre_TransactionAck/2,
+ cre_ActionRequest/2, cre_ActionRequest/3, cre_ActionRequest/4,
+ cre_ActionReply/2, cre_ActionReply/3, cre_ActionReply/4,
+ cre_ContextRequest/0, cre_ContextRequest/1, cre_ContextRequest/2,
+ cre_ContextRequest/3, cre_ContextRequest/4, cre_ContextRequest/5,
+ cre_ContextAttrAuditRequest/0, cre_ContextAttrAuditRequest/3,
+ cre_ContextAttrAuditRequest/4, cre_ContextAttrAuditRequest/5,
+ cre_CommandRequest/1, cre_CommandRequest/2, cre_CommandRequest/3,
+ cre_Command/2,
+ cre_CommandReply/2,
+ cre_TopologyRequest/3, cre_TopologyRequest/4,
+ cre_AmmRequest/2,
+ cre_AmmDescriptor/1,
+ cre_AmmsReply/1, cre_AmmsReply/2,
+ cre_SubtractRequest/1, cre_SubtractRequest/2,
+ cre_AuditRequest/2,
+ cre_AuditReply/1,
+ cre_AuditResult/2,
+ cre_AuditReturnParameter/1,
+ cre_AuditDescriptor/0, cre_AuditDescriptor/1, cre_AuditDescriptor/2,
+ cre_IndAuditParameter/1,
+ cre_IndAudMediaDescriptor/0, cre_IndAudMediaDescriptor/1,
+ cre_IndAudMediaDescriptor/2,
+ cre_IndAudStreamDescriptor/2,
+ cre_IndAudStreamParms/0, cre_IndAudStreamParms/1,
+ cre_IndAudStreamParms/3, cre_IndAudStreamParms/4,
+ cre_IndAudLocalControlDescriptor/0,
+ cre_IndAudLocalControlDescriptor/4,
+ cre_IndAudPropertyParm/1,
+ cre_IndAudLocalRemoteDescriptor/1,
+ cre_IndAudLocalRemoteDescriptor/2,
+ cre_IndAudPropertyGroup/1,
+ cre_IndAudTerminationStateDescriptor/1,
+ cre_IndAudTerminationStateDescriptor/3,
+ cre_IndAudEventsDescriptor/1, cre_IndAudEventsDescriptor/2,
+ cre_IndAudEventsDescriptor/3,
+ cre_IndAudEventBufferDescriptor/1,
+ cre_IndAudEventBufferDescriptor/2,
+ cre_IndAudSignalsDescriptor/1,
+ cre_IndAudSeqSigList/1,
+ cre_IndAudSeqSigList/2,
+ cre_IndAudSignal/1, cre_IndAudSignal/2,
+ cre_IndAudDigitMapDescriptor/0, cre_IndAudDigitMapDescriptor/1,
+ cre_IndAudStatisticsDescriptor/1,
+ cre_IndAudPackagesDescriptor/2,
+ cre_NotifyRequest/2, cre_NotifyRequest/3,
+ cre_NotifyReply/1, cre_NotifyReply/2,
+ cre_ObservedEventsDescriptor/2,
+ cre_ObservedEvent/2, cre_ObservedEvent/3, cre_ObservedEvent/4,
+ cre_EventName/1,
+ cre_EventParameter/2, cre_EventParameter/4,
+ cre_ServiceChangeRequest/2,
+ cre_ServiceChangeReply/2,
+ cre_ServiceChangeResult/1,
+ %% cre_WildcardField/1,
+ cre_TerminationAudit/1,
+ cre_TerminationID/2,
+ cre_TerminationIDList/1,
+ cre_MediaDescriptor/0, cre_MediaDescriptor/1, cre_MediaDescriptor/2,
+ cre_StreamDescriptor/2,
+ cre_StreamParms/0, cre_StreamParms/1, cre_StreamParms/2,
+ cre_StreamParms/3, cre_StreamParms/4,
+ cre_LocalControlDescriptor/1, cre_LocalControlDescriptor/2,
+ cre_LocalControlDescriptor/4,
+ cre_StreamMode/1,
+ cre_PropertyParm/2, cre_PropertyParm/4,
+ cre_Name/1,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+ cre_Relation/1,
+ cre_LocalRemoteDescriptor/1,
+ cre_PropertyGroup/1,
+ cre_TerminationStateDescriptor/1,
+ cre_TerminationStateDescriptor/2,
+ cre_TerminationStateDescriptor/3,
+ cre_EventBufferControl/1,
+ cre_ServiceState/1,
+ cre_MuxDescriptor/2, %% cre_MuxDescriptor/3,
+ cre_MuxType/1,
+ cre_StreamID/1,
+ cre_EventsDescriptor/0, cre_EventsDescriptor/2,
+ cre_RequestedEvent/1,
+ cre_RequestedEvent/2, cre_RequestedEvent/3, cre_RequestedEvent/4,
+ cre_RequestedActions/0,
+ cre_RequestedActions/1, cre_RequestedActions/4,
+ cre_EventDM/1,
+ cre_SecondEventsDescriptor/1, cre_SecondEventsDescriptor/2,
+ cre_SecondRequestedEvent/2, cre_SecondRequestedEvent/3,
+ cre_SecondRequestedEvent/4,
+ cre_SecondRequestedActions/0, cre_SecondRequestedActions/1,
+ cre_SecondRequestedActions/2, cre_SecondRequestedActions/3,
+ cre_EventBufferDescriptor/1,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+ cre_SignalsDescriptor/1,
+ cre_SignalRequest/1,
+ cre_SeqSigList/2,
+ cre_Signal/1, cre_Signal/2, cre_Signal/7, cre_Signal/9,
+ cre_SignalDirection/1,
+ cre_SignalType/1,
+ cre_SignalName/1,
+ cre_NotifyCompletion/1,
+ cre_SigParameter/2, cre_SigParameter/4,
+ cre_RequestID/1,
+ cre_ModemDescriptor/2, %% cre_ModemDescriptor/3,
+ cre_ModemType/1,
+ cre_DigitMapDescriptor/0, cre_DigitMapDescriptor/1,
+ cre_DigitMapDescriptor/2,
+ cre_DigitMapName/1,
+ cre_DigitMapValue/1, cre_DigitMapValue/4, cre_DigitMapValue/5,
+ cre_ServiceChangeParm/2, cre_ServiceChangeParm/4,
+ cre_ServiceChangeParm/9, cre_ServiceChangeParm/10,
+ cre_ServiceChangeAddress/2,
+ cre_ServiceChangeResParm/0, cre_ServiceChangeResParm/2,
+ cre_ServiceChangeResParm/5,
+ cre_ServiceChangeMethod/1,
+ cre_ServiceChangeProfile/1, cre_ServiceChangeProfile/2,
+ cre_PackagesDescriptor/1,
+ cre_PackagesItem/2,
+ cre_StatisticsDescriptor/1,
+ cre_StatisticsParameter/1, cre_StatisticsParameter/2,
+%% cre_NonStandardData/2,
+%% cre_NonStandardIdentifier/1,
+%% cre_H221NonStandard/4,
+ cre_TimeNotation/2,
+ cre_Value/1,
+ cre_BOOLEAN/1
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') andalso
+ is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+cre_AuthenticationHeader(SPI, SN, AD) ->
+ #'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+cre_ErrorDescriptor(EC) when is_integer(EC) ->
+ #'ErrorDescriptor'{errorCode = EC}.
+
+cre_ErrorDescriptor(EC, ET) when is_integer(EC) andalso is_list(ET) ->
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_ErrorCode(C) when is_integer(C) andalso (0 =< C) andalso (C =< 65535) ->
+ C;
+cre_ErrorCode(C) ->
+ exit({invalid_ErrorCode, C}).
+
+cre_ErrorText(T) when is_list(T) ->
+ T.
+
+cre_ContextID(Val) when (0 =< Val) andalso (Val =< 4294967295) ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA}.
+
+cre_TransactionId(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs) when is_integer(TransID) andalso is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+cre_TransactionPending(TransID) when is_integer(TransID) ->
+ #'TransactionPending'{transactionId = TransID}.
+
+cre_TransactionReply(TransID, ED)
+ when is_integer(TransID) andalso is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, ARs)
+ when is_integer(TransID) andalso is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionReply(TransID, IAR, ED)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, IAR, ARs)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionAck(FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck}.
+
+cre_TransactionAck(FirstAck, FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck};
+cre_TransactionAck(FirstAck, LastAck) ->
+ #'TransactionAck'{firstAck = FirstAck,
+ lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) and is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ (is_record(CtxReq, 'ContextRequest') or
+ (CtxReq == asn1_NOVALUE)) and
+ (is_record(CAAR, 'ContextAttrAuditRequest') or
+ (CAAR == asn1_NOVALUE)) and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionReply(CtxID, CmdReps)
+ when is_integer(CtxID) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(ED, 'ErrorDescriptor') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ commandReply = CmdReps};
+cre_ActionReply(CtxID, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ (is_record(ED, 'ErrorDescriptor') orelse (ED =:= asn1_NOVALUE)) andalso
+ (is_record(CtxReq, 'ContextRequest') orelse (CtxReq =:= asn1_NOVALUE)) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ContextRequest() ->
+ strip_ContextRequest(#'ContextRequest'{}).
+
+cre_ContextRequest(Prio) when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) ->
+ strip_ContextRequest(#'ContextRequest'{priority = Prio});
+cre_ContextRequest(Em) when (Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE) ->
+ strip_ContextRequest(#'ContextRequest'{emergency = Em});
+cre_ContextRequest(Top) when is_list(Top) ->
+ strip_ContextRequest(#'ContextRequest'{topologyReq = Top}).
+
+cre_ContextRequest(Prio, Em)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Top)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) andalso is_list(Top) ->
+ CR = #'ContextRequest'{priority = Prio,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Em, Top, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ (is_list(Ctx)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextProp = Ctx},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Ctx},
+ strip_ContextRequest(CR).
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Prop} = CR) ->
+ case (((Top == []) or (Top == asn1_NOVALUE)) and
+ ((Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ ((Prop == []) or (Prop == asn1_NOVALUE))) of
+ true ->
+ asn1_NOVALUE;
+ false ->
+ CR
+ end;
+strip_ContextRequest(CR) ->
+ CR.
+
+cre_ContextAttrAuditRequest() ->
+ strip_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{}).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx},
+ strip_ContextAttrAuditRequest(CAAR).
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(CAAR) ->
+ CAAR.
+
+cre_CommandRequest(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_CommandRequest(Cmd, Opt)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt}.
+
+cre_CommandRequest(Cmd, Opt, WR)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+ ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}.
+
+cre_Command(addReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(moveReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(modReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(subtractReq = Tag, Req)
+ when is_record(Req, 'SubtractRequest') ->
+ {Tag, Req};
+cre_Command(auditCapRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(auditValueRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(notifyReq = Tag, Req)
+ when is_record(Req, 'NotifyRequest') ->
+ {Tag, Req};
+cre_Command(serviceChangeReq = Tag, Req)
+ when is_record(Req, 'ServiceChangeRequest') ->
+ {Tag, Req}.
+
+cre_CommandReply(addReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(moveReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(modReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(subtractReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(auditCapReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(auditValueReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(notifyReply = Tag, Rep)
+ when is_record(Rep, 'NotifyReply') ->
+ {Tag, Rep};
+cre_CommandReply(serviceChangeReply = Tag, Rep)
+ when is_record(Rep, 'ServiceChangeReply') ->
+ {Tag, Rep}.
+
+cre_TopologyRequest(From, To, Dir)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir}.
+
+cre_TopologyRequest(From, To, Dir, SID)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID}.
+
+cre_AmmRequest(TermIDs, Descs) ->
+ d("cre_AmmRequest -> entry with"
+ "~n TermIDs: ~p"
+ "~n Descs: ~p", [TermIDs, Descs]),
+ case is_TerminationIDList(TermIDs) andalso
+ is_AmmRequest_descriptors(Descs) of
+ true ->
+ #'AmmRequest'{terminationID = TermIDs,
+ descriptors = Descs};
+ false ->
+ error({invalid_AmmRequest, {TermIDs, Descs}})
+ end.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ case is_StatisticsDescriptor(D) of
+ true ->
+ {statisticsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end
+ end.
+
+cre_AmmsReply(TermIDs) when is_list(TermIDs) ->
+ #'AmmsReply'{terminationID = TermIDs}.
+
+cre_AmmsReply(TermIDs, TAs) when is_list(TermIDs) andalso is_list(TAs) ->
+ #'AmmsReply'{terminationID = TermIDs,
+ terminationAudit = TAs}.
+
+cre_SubtractRequest(TermIDs) when is_list(TermIDs) ->
+ #'SubtractRequest'{terminationID = TermIDs}.
+
+cre_SubtractRequest(TermIDs, Audit)
+ when is_list(TermIDs) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'SubtractRequest'{terminationID = TermIDs,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TermID, Audit)
+ when is_record(TermID, megaco_term_id) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TermID,
+ auditDescriptor = Audit}.
+
+cre_AuditReply(TermIDs) when is_list(TermIDs) ->
+ {contextAuditResult, TermIDs};
+cre_AuditReply(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {error, ED};
+cre_AuditReply(Audit) when is_record(Audit, 'AuditResult') ->
+ {auditResult, Audit}.
+
+cre_AuditResult(TermID, TAs)
+ when is_record(TermID, megaco_term_id) andalso is_list(TAs) ->
+ #'AuditResult'{terminationID = TermID,
+ terminationAuditResult = TAs}.
+
+cre_TerminationAudit(D) ->
+ true = is_TerminationAudit(D),
+ D.
+
+cre_AuditReturnParameter(D) when is_record(D, 'ErrorDescriptor') ->
+ {errorDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'EventSpec') ->
+ {eventBufferDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ObservedEventsDescriptor') ->
+ {observedEventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ {statisticsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'PackagesItem') ->
+ {packagesDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'AuditDescriptor') ->
+ {emptyDescriptors, D};
+cre_AuditReturnParameter([H|_] = D) when is_tuple(H) ->
+ {signalsDescriptor, D}.
+
+cre_AuditDescriptor() ->
+ #'AuditDescriptor'{}.
+
+cre_AuditDescriptor([H|_] = AT) when is_atom(H) ->
+ #'AuditDescriptor'{auditToken = AT};
+cre_AuditDescriptor(APT) ->
+ #'AuditDescriptor'{auditPropertyToken = APT}.
+
+cre_AuditDescriptor(AT, APT) ->
+ #'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}.
+
+cre_IndAuditParameter(D) when is_record(D, 'IndAudMediaDescriptor') ->
+ {indAudMediaDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventsDescriptor') ->
+ {indAudEventsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventBufferDescriptor') ->
+ {indAudEventBufferDescriptor, D};
+cre_IndAuditParameter({signal, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter({seqSigList, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudDigitMapDescriptor') ->
+ {indAudDigitMapDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudStatisticsDescriptor') ->
+ {indAudStatisticsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudPackagesDescriptor') ->
+ {indAudPackagesDescriptor, D}.
+
+cre_IndAudMediaDescriptor() ->
+ #'IndAudMediaDescriptor'{}.
+
+cre_IndAudMediaDescriptor(TSD)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudMediaDescriptor'{termStateDescr = TSD};
+cre_IndAudMediaDescriptor(Parms) when is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{streams = Streams};
+cre_IndAudMediaDescriptor(Descs) when is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{streams = Streams}.
+
+cre_IndAudMediaDescriptor(TSD, Parms)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso
+ is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_IndAudMediaDescriptor(TSD, Descs)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_IndAudStreamDescriptor(SID, Parms)
+ when is_integer(SID) andalso is_record(Parms, 'IndAudStreamParms') ->
+ #'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}.
+
+cre_IndAudStreamParms() ->
+ #'IndAudStreamParms'{}.
+
+cre_IndAudStreamParms(LCD) when is_record(LCD, 'IndAudLocalControlDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD};
+cre_IndAudStreamParms(SD) when is_record(SD, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{statisticsDescriptor = SD}.
+
+cre_IndAudStreamParms(LC, L, R)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R}.
+
+cre_IndAudStreamParms(LC, L, R, S)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(S, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R,
+ statisticsDescriptor = S}.
+
+cre_IndAudLocalControlDescriptor() ->
+ #'IndAudLocalControlDescriptor'{}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_IndAudPropertyParm(PkgdName) when is_list(PkgdName) ->
+ #'IndAudPropertyParm'{name = PkgdName}.
+
+cre_IndAudLocalRemoteDescriptor(Grps)
+ when is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+cre_IndAudLocalRemoteDescriptor(GrpID, Grps)
+ when is_integer(GrpID) andalso (0 =< GrpID) andalso (GrpID =< 65535) andalso is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = GrpID,
+ propGrps = Grps}.
+
+cre_IndAudPropertyGroup([]) ->
+ [];
+cre_IndAudPropertyGroup([H|_] = PG)
+ when is_record(H, 'IndAudPropertyParm') ->
+ PG.
+
+cre_IndAudTerminationStateDescriptor([] = PP) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+cre_IndAudTerminationStateDescriptor([H|_] = PP)
+ when is_record(H, 'IndAudPropertyParm') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}.
+
+cre_IndAudEventsDescriptor(PkgdName)
+ when is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName)
+ when is_integer(RID) andalso is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+cre_IndAudEventsDescriptor(PkgdName, SID)
+ when is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+ when is_integer(RID) andalso is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = PkgdName,
+ streamID = SID}.
+
+cre_IndAudEventBufferDescriptor(EventName) when is_list(EventName) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+cre_IndAudEventBufferDescriptor(EventName, SID)
+ when is_list(EventName) andalso is_integer(SID) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSignal') ->
+ {signal, S};
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSeqSigList') ->
+ {seqSigList, S}.
+
+cre_IndAudSeqSigList(ID) when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) ->
+ #'IndAudSeqSigList'{id = ID}.
+
+cre_IndAudSeqSigList(ID, S)
+ when is_integer(ID) andalso
+ (0=< ID) andalso
+ (ID =< 65535) andalso
+ is_record(S, 'IndAudSignal') ->
+ #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+cre_IndAudSignal(SigName)
+ when is_list(SigName) ->
+ #'IndAudSignal'{signalName = SigName}.
+
+cre_IndAudSignal(SigName, SID)
+ when is_list(SigName) andalso is_integer(SID) ->
+ #'IndAudSignal'{signalName = SigName, streamID = SID}.
+
+cre_IndAudDigitMapDescriptor() ->
+ #'IndAudDigitMapDescriptor'{}.
+
+cre_IndAudDigitMapDescriptor(DMN) when is_list(DMN) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+cre_IndAudStatisticsDescriptor(StatName) when is_list(StatName) ->
+ #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+cre_IndAudPackagesDescriptor(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+cre_NotifyRequest(TermIDs, D)
+ when is_list(TermIDs) andalso is_record(D, 'ObservedEventsDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D}.
+
+cre_NotifyRequest(TermIDs, D, ED)
+ when is_list(TermIDs) andalso
+ is_record(D, 'ObservedEventsDescriptor') andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D,
+ errorDescriptor = ED}.
+
+cre_NotifyReply(TermIDs) when is_list(TermIDs) ->
+ #'NotifyReply'{terminationID = TermIDs}.
+
+cre_NotifyReply(TermIDs, ED)
+ when is_list(TermIDs) andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyReply'{terminationID = TermIDs,
+ errorDescriptor = ED}.
+
+cre_ObservedEventsDescriptor(RID, [H|_] = L)
+ when is_integer(RID) andalso is_record(H, 'ObservedEvent') ->
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = L}.
+
+cre_ObservedEvent(EN, EPL) when is_list(EN) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL};
+cre_ObservedEvent(EN, TN) when is_list(EN) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL)
+ when is_list(EN) andalso is_integer(SID) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL};
+cre_ObservedEvent(EN, EPL, TN)
+ when is_list(EN) andalso
+ is_list(EPL) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL, TN)
+ when is_list(EN) andalso
+ is_integer(SID) andalso
+ is_list(EPL) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+cre_ServiceChangeRequest(TermIDs, SCP)
+ when is_list(TermIDs) andalso
+ is_record(SCP, 'ServiceChangeParm') ->
+ #'ServiceChangeRequest'{terminationID = TermIDs,
+ serviceChangeParms = SCP}.
+
+cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+ when is_list(TermIDs) andalso is_atom(Tag) andalso is_tuple(R) ->
+ #'ServiceChangeReply'{terminationID = TermIDs,
+ serviceChangeResult = SCR}.
+
+cre_ServiceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED};
+cre_ServiceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP}.
+
+%% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+cre_TerminationID(W, ID)
+ when is_list(W) andalso is_list(ID) andalso (1 =< length(ID)) andalso (length(ID) =< 8) ->
+ #'TerminationID'{wildcard = W,
+ id = ID}.
+
+cre_TerminationIDList(L) when is_list(L) ->
+ L.
+
+cre_MediaDescriptor() ->
+ #'MediaDescriptor'{}.
+
+cre_MediaDescriptor(TSD) when is_record(TSD, 'TerminationStateDescriptor') ->
+ #'MediaDescriptor'{termStateDescr = TSD};
+cre_MediaDescriptor(SP) when is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{streams = Streams};
+cre_MediaDescriptor([H|_] = SDs) when is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{streams = Streams}.
+
+cre_MediaDescriptor(TSD, SP)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_MediaDescriptor(TSD, [H|_] = SDs)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_StreamDescriptor(SID, SP) when is_integer(SID) andalso is_record(SP, 'StreamParms') ->
+ #'StreamDescriptor'{streamID = SID,
+ streamParms = SP}.
+
+cre_StreamParms() ->
+ #'StreamParms'{}.
+
+cre_StreamParms(LCD) when is_record(LCD, 'LocalControlDescriptor') ->
+ #'StreamParms'{localControlDescriptor = LCD};
+cre_StreamParms(LD) when is_record(LD, 'LocalRemoteDescriptor') ->
+ #'StreamParms'{localDescriptor = LD};
+cre_StreamParms(SD) when is_list(SD) ->
+ #'StreamParms'{statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD, RD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD};
+cre_StreamParms(LCD, LD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD, RD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}.
+
+cre_LocalControlDescriptor(SM) when is_atom(SM) ->
+ #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+cre_LocalControlDescriptor([H|_] = PP) when is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, [H|_] = PP)
+ when is_atom(SM) andalso is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+ when is_atom(SM) and
+ ((RV == true) or (RV == false) or (RV == asn1_NOVALUE)) and
+ ((RG == true) or (RG == false) or (RG == asn1_NOVALUE)) and
+ is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_StreamMode(sendOnly = M) ->
+ M;
+cre_StreamMode(recvOnly = M) ->
+ M;
+cre_StreamMode(sendRecv = M) ->
+ M;
+cre_StreamMode(inactive = M) ->
+ M;
+cre_StreamMode(loopBack = M) ->
+ M.
+
+cre_PropertyParm(N, [H|_] = V) when is_list(N) andalso is_list(H) ->
+ #'PropertyParm'{name = N, value = V}.
+
+cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+ when is_list(N) andalso is_list(H) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+cre_Name(N) when is_list(N) and (length(N) == 2) ->
+ N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) and (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) and (length(PackageName) =< 64)) and
+ (is_list(ItemID) and (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+cre_Relation(greaterThan = R) ->
+ R;
+cre_Relation(smallerThan = R) ->
+ R;
+cre_Relation(unequalTo = R) ->
+ R.
+
+cre_LocalRemoteDescriptor([H|_] = PGs) when is_list(H) ->
+ #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+cre_PropertyGroup([H|_] = PG) when is_record(H, 'PropertyParm') ->
+ PG.
+
+cre_TerminationStateDescriptor([H|_] = PPs) when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+ when is_record(H, 'PropertyParm') andalso
+ ((EMC =:= off) orelse (EMC =:= lockStep)) andalso
+ ((SS =:= test) orelse (SS =:= outOfSvc) orelse (SS =:= inSvc)) ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EMC,
+ serviceState = SS}.
+
+cre_EventBufferControl(off = EBC) ->
+ EBC;
+cre_EventBufferControl(lockStep = EBC) ->
+ EBC.
+
+cre_ServiceState(test = SS) ->
+ SS;
+cre_ServiceState(outOfSvc = SS) ->
+ SS;
+cre_ServiceState(inSvc = SS) ->
+ SS.
+
+cre_MuxDescriptor(MT, [H|_] = TL)
+ when is_atom(MT) andalso is_record(H, 'TerminationID') ->
+ #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+cre_MuxType(h221 = MT) ->
+ MT;
+cre_MuxType(h223 = MT) ->
+ MT;
+cre_MuxType(h226 = MT) ->
+ MT;
+cre_MuxType(v76 = MT) ->
+ MT;
+cre_MuxType(nx64k = MT) ->
+ MT.
+
+cre_StreamID(Val) when 0 =< Val, Val =< 65535 ->
+ Val;
+cre_StreamID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+%% RequestID must be present if eventList is non empty
+cre_EventsDescriptor() ->
+ #'EventsDescriptor'{eventList = []}.
+
+cre_EventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'RequestedEvent') ->
+ #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_RequestedEvent(N) ->
+ #'RequestedEvent'{pkgdName = N}.
+
+cre_RequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_RequestedEvent(N, EA)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions')->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA}.
+
+
+cre_RequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_RequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedActions() ->
+ #'RequestedActions'{}.
+
+cre_RequestedActions(KA)
+ when (KA == true) or (KA == true) or (KA == asn1_NOVALUE) ->
+ #'RequestedActions'{keepActive = KA};
+cre_RequestedActions(SE)
+ when is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE) ->
+ #'RequestedActions'{secondEvent = SE};
+cre_RequestedActions(SD)
+ when is_list(SD) or (SD == asn1_NOVALUE) ->
+ #'RequestedActions'{signalsDescriptor = SD};
+cre_RequestedActions({Tag, _} = EDM)
+ when is_atom(Tag) or (EDM == asn1_NOVALUE) ->
+ #'RequestedActions'{eventDM = EDM}.
+
+cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}.
+
+cre_EventDM(N) when is_list(N) ->
+ {digitMapName, N};
+cre_EventDM(V) when is_record(V, 'DigitMapValue') ->
+ {digitMapValue, V}.
+
+cre_SecondEventsDescriptor([H|_] = EL)
+ when is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{eventList = EL}.
+
+cre_SecondEventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_SecondRequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedActions() ->
+ #'SecondRequestedActions'{}.
+
+cre_SecondRequestedActions(KA)
+ when ((KA =:= true) orelse (KA =:= false) orelse (KA =:= asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA};
+cre_SecondRequestedActions(SD) when is_list(SD) ->
+ #'SecondRequestedActions'{signalsDescriptor = SD};
+cre_SecondRequestedActions({Tag, _} = EDM) when is_atom(Tag) ->
+ #'SecondRequestedActions'{eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, SD)
+ when ((KA =:= true) orelse (KA =:= false) orelse (KA =:= asn1_NOVALUE)) andalso
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, {Tag, _} = EDM)
+ when ((KA =:= true) orelse (KA =:= false) orelse (KA =:= asn1_NOVALUE)) andalso
+ is_atom(Tag) ->
+ #'SecondRequestedActions'{keepActive = KA, eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+ when ((KA =:= true) orelse (KA =:= false) orelse (KA =:= asn1_NOVALUE)) andalso
+ is_atom(Tag) andalso
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}.
+
+cre_EventBufferDescriptor([H|_] = D) when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL)
+ when is_list(N) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+cre_SignalsDescriptor(D) ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ D;
+ false ->
+ error({invalid_SignalsDescriptor, D})
+ end.
+
+cre_SignalRequest(S) when is_record(S, 'Signal') ->
+ {signal, S};
+cre_SignalRequest(S) when is_record(S, 'SeqSigList') ->
+ {seqSigList, S}.
+
+cre_SeqSigList(ID, [H|_] = SL)
+ when is_integer(ID) andalso (0 =< ID) andalso (ID =< 65535) andalso is_record(H, 'Signal') ->
+ #'SeqSigList'{id = ID, signalList = SL}.
+
+cre_Signal(N) when is_list(N) ->
+ #'Signal'{signalName = N}.
+
+cre_Signal(N, SPL) when is_list(N) andalso is_list(SPL) ->
+ #'Signal'{signalName = N,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}.
+
+cre_SignalType(brief = ST) ->
+ ST;
+cre_SignalType(onOff = ST) ->
+ ST;
+cre_SignalType(timeOut = ST) ->
+ ST.
+
+cre_SignalDirection(internal = SD) ->
+ SD;
+cre_SignalDirection(external = SD) ->
+ SD;
+cre_SignalDirection(both = SD) ->
+ SD.
+
+cre_SignalName(N) ->
+ cre_PkgdName(N).
+
+cre_NotifyCompletion(L) when is_list(L) ->
+ Vals = [onTimeOut, onInterruptByEvent,
+ onInterruptByNewSignalDescr, otherReason],
+ F = fun(E) -> case lists:member(E, Vals) of
+ true ->
+ ok;
+ false ->
+ exit({invalid_NotifyCompletion, E})
+ end
+ end,
+ lists:foreach(F, L),
+ L.
+
+cre_SigParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'SigParameter'{sigParameterName = N, value = V}.
+
+cre_SigParameter(N, V, relation = Tag, R)
+ when is_list(N) and is_list(V) and is_atom(R) ->
+ EI = {Tag, R},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, range = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, sublist = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+cre_RequestID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_RequestID(Val) ->
+ exit({invalid_RequestID, Val}).
+
+cre_ModemDescriptor(MTL, MPL) when is_list(MTL) andalso is_list(MPL) ->
+ #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemDescriptor(MTL, MPL, NSD)
+%% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+cre_ModemType(v18 = MT) ->
+ MT;
+cre_ModemType(v22 = MT) ->
+ MT;
+cre_ModemType(v22bis = MT) ->
+ MT;
+cre_ModemType(v32 = MT) ->
+ MT;
+cre_ModemType(v32bis = MT) ->
+ MT;
+cre_ModemType(v34 = MT) ->
+ MT;
+cre_ModemType(v90 = MT) ->
+ MT;
+cre_ModemType(v91 = MT) ->
+ MT;
+cre_ModemType(synchISDN = MT) ->
+ MT.
+
+cre_DigitMapDescriptor() ->
+ #'DigitMapDescriptor'{}.
+
+cre_DigitMapDescriptor(N) when is_list(N) ->
+ #'DigitMapDescriptor'{digitMapName = N};
+cre_DigitMapDescriptor(V) when is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = V}.
+
+cre_DigitMapDescriptor(N, V) when is_list(N) andalso is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+cre_DigitMapName(N) ->
+ cre_Name(N).
+
+cre_DigitMapValue(DMB) when is_list(DMB) ->
+ #'DigitMapValue'{digitMapBody = DMB}.
+
+cre_DigitMapValue(Start, Short, Long, DMB) ->
+ cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+ when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+ (Start == asn1_NOVALUE)) and
+ ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+ (Short == asn1_NOVALUE)) and
+ ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+ (Long == asn1_NOVALUE)) and
+ is_list(DMB) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+ (Dur == asn1_NOVALUE)) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = DMB,
+ durationTimer = Dur}.
+
+cre_ServiceChangeParm(M, R) when is_atom(M) andalso is_list(R) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R}.
+
+cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+ cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE).
+
+%% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I) ->
+ cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, asn1_NOVALUE).
+
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, IF)
+ when is_atom(M) and
+ ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ is_list(R) and
+ ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+ (D == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+ (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) and
+ ((IF == 'NULL') or (IF == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Mid,
+ timeStamp = TS,
+ serviceChangeInfo = I,
+ serviceChangeIncompleteFlag = IF};
+ _ ->
+ exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeAddress(portNumber = Tag, P)
+ when is_integer(P) andalso (0 =< P) andalso (P =< 65535) ->
+ {Tag, P};
+cre_ServiceChangeAddress(ip4Address = Tag, A) when is_record(A, 'IP4Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(ip6Address = Tag, A) when is_record(A, 'IP6Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(domainName = Tag, N) when is_record(N, 'DomainName') ->
+ {Tag, N};
+cre_ServiceChangeAddress(deviceName = Tag, N) when is_list(N) ->
+ {Tag, N};
+cre_ServiceChangeAddress(mtpAddress = Tag, A) when is_list(A) ->
+ {Tag, A}.
+
+cre_ServiceChangeResParm() ->
+ #'ServiceChangeResParm'{}.
+cre_ServiceChangeResParm(Addr, Prof) ->
+ cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+ Prof, asn1_NOVALUE).
+cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+ when ((is_integer(Ver) and (0 =< Ver) andalso (Ver =< 99)) orelse
+ (Ver =:= asn1_NOVALUE)) andalso
+ (is_record(Prof, 'ServiceChangeProfile') orelse (Prof =:= asn1_NOVALUE)) andalso
+ (is_record(TS, 'TimeNotation') orelse (TS =:= asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A =:= asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ timeStamp = TS};
+ _ ->
+ exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeMethod(failover = M) ->
+ M;
+cre_ServiceChangeMethod(forced = M) ->
+ M;
+cre_ServiceChangeMethod(graceful = M) ->
+ M;
+cre_ServiceChangeMethod(restart = M) ->
+ M;
+cre_ServiceChangeMethod(disconnected = M) ->
+ M;
+cre_ServiceChangeMethod(handOff = M) ->
+ M.
+
+%% The version field is added to make it look more like ABNF
+cre_ServiceChangeProfile(N) ->
+ cre_ServiceChangeProfile(N, 1).
+
+cre_ServiceChangeProfile(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'ServiceChangeProfile'{profileName = N, version = V}.
+
+cre_PackagesDescriptor([H|_] = D) when is_record(H, 'PackagesItem') ->
+ D.
+
+cre_PackagesItem(N, Ver)
+ when is_list(N) andalso is_integer(Ver) andalso (0 =< Ver) andalso (Ver =< 99) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = Ver}.
+
+cre_StatisticsDescriptor(D) ->
+ true = is_StatisticsDescriptor(D),
+ D.
+
+cre_StatisticsParameter(N) when is_list(N) ->
+ #'StatisticsParameter'{statName = N}.
+
+cre_StatisticsParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% {h221NonStandard, H221};
+%% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% {object, Obj};
+%% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% {experimental, Exp}.
+
+%% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}.
+
+cre_TimeNotation(D, T)
+ when is_list(D) andalso (length(D) =:= 8) andalso is_list(T) andalso (length(T) =:= 8) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_Value([H|_] = V) when is_list(H) ->
+ V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% -- MegacoMessage --
+
+is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}) ->
+ d("is_MegacoMessage -> entry"),
+ is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+is_MegacoMessage(_) ->
+ false.
+
+
+chk_MegacoMessage(M, M) ->
+ d("chk_MegacoMessage -> entry (1)"),
+ chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ d("chk_MegacoMessage -> entry (2)"),
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type('MegacoMessage', M1, M2).
+
+
+%% -- AuthenticationHeader --
+
+is_opt_AuthenticationHeader(AH) ->
+ is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}) ->
+ is_SecurityParmIndex(SPI) andalso
+ is_SequenceNum(SN) andalso
+ is_AuthData(AD);
+is_AuthenticationHeader(_) ->
+ false.
+
+%% This stuff is not really used, so make it simple...
+chk_opt_AuthenticationHeader(A1, A2) ->
+ chk_OPTIONAL('AuthenticationHeader', A1, A2,
+ fun is_AuthenticationHeader/1,
+ fun chk_AuthenticationHeader/2).
+
+chk_AuthenticationHeader(A, A) ->
+ chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+chk_AuthenticationHeader(A1, A2) ->
+ case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+ true ->
+ not_equal('AuthenticationHeader', A1, A2);
+ false ->
+ wrong_type('AuthenticationHeader', A1, A2)
+ end.
+
+
+%% -- SecurityParmIndex --
+
+is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- SequenceNum --
+
+is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- AuthData --
+
+is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% -- Message --
+
+is_Message(#'Message'{version = V,
+ mId = MID,
+ messageBody = Body}) ->
+ d("is_Message -> entry"),
+ is_INTEGER(V, {range, 0, 99}) andalso
+ is_MId(MID) andalso
+ is_Message_messageBody(Body);
+is_Message(_) ->
+ false.
+
+chk_Message(M, M) ->
+ d("chk_Message -> entry (1)"),
+ chk_type(fun is_Message/1, 'Message', M);
+chk_Message(#'Message'{version = V1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = V2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ d("chk_Message -> entry with"
+ "~n V1: ~p"
+ "~n MID1: ~p"
+ "~n Body1: ~p"
+ "~n V2: ~p"
+ "~n MID2: ~p"
+ "~n Body2: ~p",
+ [V1, MID1, Body1, V2, MID2, Body2]),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'Message'),
+ validate(fun() -> chk_MId(MID1, MID2) end, 'Message'),
+ chk_Message_messageBody(Body1, Body2),
+ ok;
+chk_Message(M1, M2) ->
+ wrong_type('Message', M1, M2).
+
+
+is_Message_messageBody({Tag, Val}) ->
+ d("is_Message_messageBody -> entry"),
+ is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val);
+is_Message_messageBody(_) ->
+ false.
+
+is_Message_messageBody_tag(Tag) ->
+ Tags = [messageError, transactions],
+ lists:member(Tag, Tags).
+
+is_Message_messageBody_val(messageError, Val) ->
+ is_ErrorDescriptor(Val);
+is_Message_messageBody_val(transactions, Val) ->
+ is_Message_messageBody_transactions(Val).
+
+is_Message_messageBody_transactions([]) ->
+ d("is_Message_messageBody_transactions -> entry when done"),
+ true;
+is_Message_messageBody_transactions([H|T]) ->
+ d("is_Message_messageBody_transactions -> entry"),
+ is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+is_Message_messageBody_transactions(_) ->
+ false.
+
+chk_Message_messageBody(B, B) ->
+ d("chk_Message_messageBody -> entry (1)"),
+ chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (2)"),
+ case (is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val1) andalso
+ is_Message_messageBody_val(Tag, Val2)) of
+ true ->
+ chk_Message_messageBody_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (3)"),
+ case ((is_Message_messageBody_tag(Tag1) andalso
+ is_Message_messageBody_val(Tag1, Val1)) andalso
+ (is_Message_messageBody_tag(Tag2) andalso
+ is_Message_messageBody_val(Tag2, Val2))) of
+ true ->
+ not_equal('Message_messageBody', B1, B2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody(B1, B2) ->
+ wrong_type('Message_messageBody', B1, B2).
+
+chk_Message_messageBody_val(messageError, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'Message_messageBody');
+chk_Message_messageBody_val(transactions, Val1, Val2) ->
+ chk_Message_messageBody_transactions(lists:sort(Val1),
+ lists:sort(Val2)).
+
+chk_Message_messageBody_transactions([], []) ->
+ d("chk_Message_messageBody_transactions -> entry - ok (1)"),
+ ok;
+chk_Message_messageBody_transactions([] = T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (2)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions(T1, [] = T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (3)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (4)"),
+ case is_Transaction(H) of
+ true ->
+ chk_Message_messageBody_transactions(T1, T2);
+ false ->
+ wrong_type('Message_messageBody_transactions_val', H)
+ end;
+chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (5)"),
+ validate(fun() -> chk_Transaction(H1, H2) end,
+ 'Message_messageBody_transactions_val'),
+ chk_Message_messageBody_transactions(T1, T2);
+chk_Message_messageBody_transactions(T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - wrong-type (6)"),
+ wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% -- MId --
+
+is_opt_MId(M) ->
+ is_OPTIONAL(fun is_MId/1, M).
+
+is_MId({Tag, Val}) ->
+ is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+is_MId(_) ->
+ false.
+
+is_MId_tag(Tag) ->
+ Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+ lists:member(Tag, Tags).
+
+is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+is_MId_val(domainName, Val) -> is_DomainName(Val);
+is_MId_val(deviceName, Val) -> is_PathName(Val);
+is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+chk_opt_MId(M1, M2) ->
+ chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+chk_MId(M, M) ->
+ chk_type(fun is_MId/1, 'MId', M);
+chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+ case (is_MId_tag(Tag) andalso
+ is_MId_val(Tag, Val1) andalso
+ is_MId_val(Tag, Val2)) of
+ true ->
+ chk_MId_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+ case ((is_MId_tag(Tag1) andalso
+ is_MId_val(Tag1, Val1)) andalso
+ (is_MId_tag(Tag2) andalso
+ is_MId_val(Tag2, Val2))) of
+ true ->
+ not_equal('MId', M1, M2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId(M1, M2) ->
+ wrong_type('MId', M1, M2).
+
+chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% -- DomainName --
+
+is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+ is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+is_DomainName(_) ->
+ false.
+
+chk_DomainName(N, N) ->
+ ok;
+chk_DomainName(N1, N2) ->
+ not_equal('DomainName', N1, N2).
+
+
+%% -- IP4Address --
+
+is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 4}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP4Address(_) ->
+ false.
+
+chk_IP4Address(A, A) ->
+ ok;
+chk_IP4Address(A1, A2) ->
+ not_equal('IP4Address', A1, A2).
+
+
+%% -- IP6Address --
+
+is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 16}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP6Address(_) ->
+ false.
+
+chk_IP6Address(A, A) ->
+ ok;
+chk_IP6Address(A1, A2) ->
+ not_equal('IP6Address', A1, A2).
+
+
+%% -- PathName --
+
+is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+chk_PathName(N, N) ->
+ ok;
+chk_PathName(N1, N2) ->
+ not_equal('PathName', N1, N2).
+
+
+%% -- Transaction --
+
+is_Transaction({Tag, Val}) ->
+ d("is_Transaction -> entry"),
+ is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+is_Transaction(_) ->
+ false.
+
+is_Transaction_tag(Tag) ->
+ Tags = [transactionRequest,
+ transactionPending,
+ transactionReply,
+ transactionResponseAck],
+ lists:member(Tag, Tags).
+
+is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+chk_Transaction({Tag, Val} = Trans, Trans) ->
+ d("chk_Transaction -> entry (1)"),
+ case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Transaction', Trans, Trans)
+ end;
+chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (2)"),
+ case (is_Transaction_tag(Tag) and
+ is_Transaction_val(Tag, Val1) and
+ is_Transaction_val(Tag, Val2)) of
+ true ->
+ chk_Transaction_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (3)"),
+ case ((is_Transaction_tag(Tag1) andalso
+ is_Transaction_val(Tag1, Val1)) andalso
+ (is_Transaction_tag(Tag2) andalso
+ is_Transaction_val(Tag2, Val2))) of
+ true ->
+ not_equal('Transaction', Trans1, Trans2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction(Trans1, Trans2) ->
+ d("chk_Transaction -> entry - wrong-type - (4)"),
+ wrong_type('Transaction', Trans1, Trans2).
+
+chk_Transaction_val(transactionRequest, T1, T2) ->
+ chk_TransactionRequest(T1, T2);
+chk_Transaction_val(transactionPending, T1, T2) ->
+ chk_TransactionPending(T1, T2);
+chk_Transaction_val(transactionReply, T1, T2) ->
+ chk_TransactionReply(T1,T2);
+chk_Transaction_val(transactionResponseAck, T1, T2) ->
+ chk_TransactionResponseAck(T1, T2).
+
+
+%% -- TransactionId --
+
+is_opt_TransactionId(TID) ->
+ is_OPTIONAL(fun is_TransactionId/1, TID).
+
+is_TransactionId(TID) ->
+ d("is_TransactionId -> entry"),
+ is_INTEGER(TID, {range, 0, 4294967295}).
+
+chk_opt_TransactionId(TID1, TID2) ->
+ chk_OPTIONAL('TransactionId', TID1, TID2,
+ fun is_TransactionId/1, fun chk_TransactionId/2).
+
+chk_TransactionId(TID, TID) ->
+ chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+chk_TransactionId(TID1, TID2) ->
+ case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+ true ->
+ not_equal('TransactionId', TID1, TID2);
+ false ->
+ wrong_type('TransactionId', TID1, TID2)
+ end.
+
+
+%% -- TransactionRequest --
+
+is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+ actions = Acts}) ->
+ d("is_TransactionRequest -> entry"),
+ is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+is_TransactionRequest(_) ->
+ false.
+
+chk_TransactionRequest(T, T) ->
+ chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+ actions = Acts1},
+ #'TransactionRequest'{transactionId = TID2,
+ actions = Acts2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+ chk_TransactionRequest_actions(lists:sort(Acts1),
+ lists:sort(Acts2)),
+ ok;
+chk_TransactionRequest(T1, T2) ->
+ wrong_type('TransactionRequest', T1, T2).
+
+is_TransactionRequest_actions([]) ->
+ d("is_TransactionRequest_actions -> entry when done"),
+ true;
+is_TransactionRequest_actions([H|T]) ->
+ d("is_TransactionRequest_actions -> entry"),
+ is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+is_TransactionRequest_actions(_) ->
+ false.
+
+chk_TransactionRequest_actions([], []) ->
+ ok;
+chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+ case is_ActionRequest(H) of
+ true ->
+ chk_TransactionRequest_actions(T1, T2);
+ false ->
+ wrong_type('TransactionRequest_actions_val', H)
+ end;
+chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionRequest(H1, H2) end,
+ 'TransactionRequest_actions_val'),
+ chk_TransactionRequest_actions(T1, T2);
+chk_TransactionRequest_actions(Acts1, Acts2) ->
+ wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% -- TransactionPending --
+
+is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+ d("is_TransactionPending -> entry"),
+ is_TransactionId(TID);
+is_TransactionPending(_) ->
+ false.
+
+chk_TransactionPending(T, T) ->
+ chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+ #'TransactionPending'{transactionId = TID2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+ ok;
+chk_TransactionPending(T1, T2) ->
+ wrong_type('TransactionPending', T1, T2).
+
+
+%% -- TransactionReply --
+
+is_TransactionReply(#'TransactionReply'{transactionId = TID,
+ immAckRequired = IAR,
+ transactionResult = TR}) ->
+ d("is_TransactionReply -> entry"),
+ is_TransactionId(TID) andalso
+ is_opt_NULL(IAR) andalso
+ is_TransactionReply_transactionResult(TR);
+is_TransactionReply(_) ->
+ false.
+
+chk_TransactionReply(T, T) ->
+ chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+ immAckRequired = IAR1,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TID2,
+ immAckRequired = IAR2,
+ transactionResult = TR2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+ validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+ chk_TransactionReply_transactionResult(TR1, TR2),
+ ok;
+chk_TransactionReply(T1, T2) ->
+ wrong_type('TransactionReply', T1, T2).
+
+is_TransactionReply_transactionResult({Tag, Val}) ->
+ d("is_TransactionReply_transactionResult -> entry"),
+ is_TransactionReply_transactionResult_tag(Tag) andalso
+ is_TransactionReply_transactionResult_val(Tag, Val);
+is_TransactionReply_transactionResult(_) ->
+ false.
+
+is_TransactionReply_transactionResult_tag(T) ->
+ lists:member(T, [transactionError, actionReplies]).
+
+is_TransactionReply_transactionResult_val(transactionError, V) ->
+ is_ErrorDescriptor(V);
+is_TransactionReply_transactionResult_val(actionReplies, V) ->
+ is_TransactionReply_actionReplies(V).
+
+chk_TransactionReply_transactionResult(Res, Res) ->
+ chk_type(fun is_TransactionReply_transactionResult/1,
+ 'TransactionReply_transactionResult', Res);
+chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+ {Tag, Val2} = Res2) ->
+ case (is_TransactionReply_transactionResult_tag(Tag) and
+ is_TransactionReply_transactionResult_val(Tag, Val1) and
+ is_TransactionReply_transactionResult_val(Tag, Val2)) of
+ true ->
+ chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+ {Tag2, Val2} = Res2) ->
+ case ((is_TransactionReply_transactionResult_tag(Tag1) and
+ is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+ (is_TransactionReply_transactionResult_tag(Tag2) and
+ is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('TransactionReply_transactionResult', Res1, Res2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult(Res1, Res2) ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+ validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+ 'TransactionReply_transactionResult');
+chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+ validate(fun() ->
+ chk_TransactionReply_actionReplies(lists:sort(R1),
+ lists:sort(R2))
+ end,
+ 'TransactionReply_transactionResult').
+
+is_TransactionReply_actionReplies([]) ->
+ d("is_TransactionReply_actionReplies -> entry when done"),
+ true;
+is_TransactionReply_actionReplies([H|T]) ->
+ d("is_TransactionReply_actionReplies -> entry"),
+ is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+is_TransactionReply_actionReplies(_) ->
+ false.
+
+chk_TransactionReply_actionReplies([], []) ->
+ ok;
+chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+ case is_ActionReply(H) of
+ true ->
+ chk_TransactionReply_actionReplies(T1, T2);
+ false ->
+ wrong_type('TransactionReply_actionReplies_val', H)
+ end;
+chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionReply(H1, H2) end,
+ 'TransactionReply_actionReplies_val'),
+ chk_TransactionReply_actionReplies(T1, T2);
+chk_TransactionReply_actionReplies(AR1, AR2) ->
+ wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% -- TransactionResponseAck --
+
+is_TransactionResponseAck([]) ->
+ d("is_TransactionResponseAck -> entry when done"),
+ true;
+is_TransactionResponseAck([H|T]) ->
+ d("is_TransactionResponseAck -> entry"),
+ is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+is_TransactionResponseAck(_) ->
+ false.
+
+chk_TransactionResponseAck([], []) ->
+ ok;
+chk_TransactionResponseAck([] = AR1, AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck(AR1, [] = AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck([H|T1], [H|T2]) ->
+ case is_TransactionAck(H) of
+ true ->
+ chk_TransactionResponseAck(T1, T2);
+ false ->
+ wrong_type('TransactionResponseAck_val', H)
+ end;
+chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TransactionAck(H1, H2) end,
+ 'TransactionResponseAck'),
+ chk_TransactionResponseAck(T1, T2);
+chk_TransactionResponseAck(AR1, AR2) ->
+ wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% -- TransactionAck --
+
+is_TransactionAck(#'TransactionAck'{firstAck = F,
+ lastAck = L}) ->
+ d("is_TransactionAck -> entry"),
+ is_TransactionId(F) andalso is_opt_TransactionId(L);
+is_TransactionAck(_) ->
+ false.
+
+chk_TransactionAck(T, T) ->
+ chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+ validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+ ok;
+chk_TransactionAck(T1, T2) ->
+ wrong_type('TransactionAck', T1, T2).
+
+
+%% -- ErrorDescriptor --
+
+is_opt_ErrorDescriptor(V) ->
+ is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text}) ->
+ d("is_ErrorDescriptor -> entry"),
+ is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+is_ErrorDescriptor(_) ->
+ false.
+
+chk_opt_ErrorDescriptor(E1, E2) ->
+ chk_OPTIONAL('ErrorDescriptor', E1, E2,
+ fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+chk_ErrorDescriptor(E, E) ->
+ chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1},
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2}) ->
+ chk_ErrorCode(Code1, Code2),
+ chk_opt_ErrorText(Text1, Text2),
+ ok;
+chk_ErrorDescriptor(E1, E2) ->
+ wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% -- ErrorCode --
+
+is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+chk_ErrorCode(C, C) ->
+ case is_ErrorCode(C) of
+ true ->
+ ok;
+ false ->
+ wrong_type(errorCode, C, C)
+ end;
+chk_ErrorCode(C1, C2) ->
+ case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+ true ->
+ not_equal(errorCode, C1, C2);
+ false ->
+ wrong_type(errorCode, C1, C2)
+ end.
+
+
+%% -- ErrorText --
+
+is_opt_ErrorText(V) ->
+ is_OPTIONAL(fun is_ErrorText/1, V).
+
+is_ErrorText(V) -> is_IA5String(V).
+
+chk_opt_ErrorText(T1, T2) ->
+ chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+chk_ErrorText(T, T) ->
+ chk_type(fun is_ErrorText/1, 'ErrorText', T);
+chk_ErrorText(T1, T2) ->
+ case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+ true ->
+ case {to_lower(T1), to_lower(T2)} of
+ {T, T} ->
+ ok;
+ _ ->
+ not_equal('ErrorText', T1, T2)
+ end;
+ false ->
+ wrong_type('ErrorText', T1, T2)
+ end.
+
+
+%% -- ContextID --
+
+is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+chk_ContextID(Id, Id) ->
+ chk_type(fun is_ContextID/1, 'ContextID', Id);
+chk_ContextID(Id1, Id2) ->
+ case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+ true ->
+ not_equal('ContextID', Id1, Id2);
+ false ->
+ wrong_type('ContextID', Id1, Id2)
+ end.
+
+
+%% -- ActionRequest --
+
+is_ActionRequest(#'ActionRequest'{contextId = Id,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = AuditReq,
+ commandRequests = CmdReqs}) ->
+ d("is_ActionRequest -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ContextRequest(CtxReq) andalso
+ is_opt_ContextAttrAuditRequest(AuditReq) andalso
+ is_ActionRequest_commandRequests(CmdReqs);
+is_ActionRequest(_) ->
+ false.
+
+chk_ActionRequest(A, A) ->
+ chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+ validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+ validate(fun() ->
+ chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+ end,
+ 'ActionRequest'),
+ chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+ ok.
+
+
+is_ActionRequest_commandRequests([]) ->
+ d("is_ActionRequest_commandRequests -> entry when done"),
+ true;
+is_ActionRequest_commandRequests([H|T]) ->
+ d("is_ActionRequest_commandRequests -> entry"),
+ is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+is_ActionRequest_commandRequests(_) ->
+ false.
+
+chk_ActionRequest_commandRequests([], []) ->
+ ok;
+chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+ case is_CommandRequest(H) of
+ true ->
+ chk_ActionRequest_commandRequests(T1, T2);
+ false ->
+ wrong_type('ActionRequest_commandRequest_val', H)
+ end;
+chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandRequest(H1, H2) end,
+ 'ActionRequest_commandRequests_val'),
+ chk_ActionRequest_commandRequests(T1, T2);
+chk_ActionRequest_commandRequests(R1, R2) ->
+ wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% -- ActionReply --
+
+is_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep}) ->
+ d("is_ActionReply -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ErrorDescriptor(ED) andalso
+ is_opt_ContextRequest(CtxRep) andalso
+ is_ActionReply_commandReply(CmdRep);
+is_ActionReply(_) ->
+ false.
+
+is_ActionReply_commandReply([]) ->
+ d("is_ActionReply_commandReply -> entry when done"),
+ true;
+is_ActionReply_commandReply([H|T]) ->
+ d("is_ActionReply_commandReply -> entry"),
+ is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+is_ActionReply_commandReply(_) ->
+ false.
+
+chk_ActionReply(A, A) ->
+ chk_type(fun is_ActionReply/1, 'ActionReply', A);
+chk_ActionReply(#'ActionReply'{contextId = Id1,
+ errorDescriptor = ED1,
+ contextReply = CtxRep1,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = Id2,
+ errorDescriptor = ED2,
+ contextReply = CtxRep2,
+ commandReply = CmdRep2}) ->
+ chk_ContextID(Id1, Id2),
+ chk_opt_ErrorDescriptor(ED1, ED2),
+ chk_opt_ContextRequest(CtxRep1, CtxRep2),
+ chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+chk_ActionReply_commandReply([], []) ->
+ ok;
+chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+ case is_CommandReply(H) of
+ true ->
+ chk_ActionReply_commandReply(T1, T2);
+ false ->
+ wrong_type('ActionReply_commandReply_val', H)
+ end;
+chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandReply(H1, H2) end,
+ 'ActionReply_commandReply_val'),
+ chk_ActionReply_commandReply(T1, T2);
+chk_ActionReply_commandReply(R1, R2) ->
+ wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% -- ContextRequest --
+
+is_opt_ContextRequest(V) ->
+ is_OPTIONAL(fun is_ContextRequest/1, V).
+
+is_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReq,
+ iepscallind = Ieps,
+ contextProp = Ctx}) ->
+ d("is_ContextRequest -> entry"),
+ is_ContextRequest_priority(Prio) andalso
+ is_ContextRequest_emergency(Em) andalso
+ is_ContextRequest_topologyReq(TopReq) andalso
+ is_ContextRequest_iepscallind(Ieps) andalso
+ is_ContextRequest_contextProp(Ctx);
+is_ContextRequest(_) ->
+ false.
+
+is_ContextRequest_priority(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_priority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextRequest_emergency(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_emergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_topologyReq([]) ->
+ true;
+is_ContextRequest_topologyReq([H|T]) ->
+ is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+is_ContextRequest_topologyReq(_) ->
+ false.
+
+is_ContextRequest_iepscallind(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_iepscallind(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_contextProp(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextProp([]) ->
+ true;
+is_ContextRequest_contextProp([H|T]) ->
+ is_PropertyParm(H) andalso is_ContextRequest_contextProp(T);
+is_ContextRequest_contextProp(_) ->
+ false.
+
+chk_opt_ContextRequest(R1, R2) ->
+ chk_OPTIONAL('ContextRequest', R1, R2,
+ fun is_ContextRequest/1, fun chk_ContextRequest/2).
+
+chk_ContextRequest(R, R) ->
+ chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1,
+ iepscallind = Ieps1,
+ contextProp = Ctx1},
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2,
+ iepscallind = Ieps2,
+ contextProp = Ctx2}) ->
+ chk_ContextRequest_priority(Prio1, Prio2),
+ chk_ContextRequest_emergency(Em1, Em2),
+ chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+ chk_ContextRequest_iepscallind(Ieps1, Ieps2),
+ chk_ContextRequest_contextProp(Ctx1, Ctx2),
+ ok;
+chk_ContextRequest(R1, R2) ->
+ wrong_type('ContextRequest', R1, R2).
+
+
+chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_priority(P, P) ->
+ chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+chk_ContextRequest_priority(P1, P2) ->
+ case (is_ContextRequest_priority(P1) andalso
+ is_ContextRequest_priority(P2)) of
+ true ->
+ not_equal('ContextRequest_priority', P1, P2);
+ false ->
+ wrong_type(contextRequest_priority, P1, P2)
+ end.
+
+
+chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_emergency(E, E) ->
+ chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+chk_ContextRequest_emergency(E1, E2) ->
+ case (is_ContextRequest_emergency(E1) andalso
+ is_ContextRequest_emergency(E2)) of
+ true ->
+ not_equal('ContextRequest_emergency', E1, E2);
+ false ->
+ wrong_type('ContextRequest_emergency', E1, E2)
+ end.
+
+chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_topologyReq([], []) ->
+ ok;
+chk_ContextRequest_topologyReq([] = T1, T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq(T1, [] = T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+ case is_TopologyRequest(H) of
+ true ->
+ chk_ContextRequest_topologyReq(T1, T2);
+ false ->
+ wrong_type('ContextRequest_topologyReq_val', H)
+ end;
+chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TopologyRequest(H1, H2) end,
+ 'ContextRequest_topologyReq_val'),
+ chk_ContextRequest_topologyReq(T1, T2);
+chk_ContextRequest_topologyReq(T1, T2) ->
+ wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+chk_ContextRequest_iepscallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_iepscallind(E, E) ->
+ chk_type(fun is_ContextRequest_iepscallind/1,
+ 'ContextRequest_iepscallind', E);
+chk_ContextRequest_iepscallind(E1, E2) ->
+ case (is_ContextRequest_iepscallind(E1) andalso
+ is_ContextRequest_iepscallind(E2)) of
+ true ->
+ case (((E1 == false) and (E2 == asn1_NOVALUE)) or
+ ((E1 == asn1_NOVALUE) and (E2 == false))) of
+ true ->
+ ok;
+ false ->
+ not_equal('ContextRequest_iepscallind', E1, E2)
+ end;
+
+ false ->
+ wrong_type('ContextRequest_iepscallind', E1, E2)
+ end.
+
+chk_ContextRequest_contextProp(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextProp([], []) ->
+ ok;
+chk_ContextRequest_contextProp([] = T1, T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp(T1, [] = T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ContextRequest_contextProp(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextProp_val', H)
+ end;
+chk_ContextRequest_contextProp([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextRequest_contextProp_val'),
+ chk_ContextRequest_contextProp(T1, T2);
+chk_ContextRequest_contextProp(T1, T2) ->
+ wrong_type('ContextRequest_contextProp', T1, T2).
+
+
+%% -- ContextAttrAuditRequest --
+
+is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextAttrAuditRequest(V) ->
+ is_ContextAttrAuditRequest(V).
+
+is_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T,
+ emergency = E,
+ priority = P,
+ iepscallind = I,
+ contextPropAud = A}) ->
+ d("is_ContextAttrAuditRequest -> entry"),
+ is_opt_NULL(T) andalso
+ is_opt_NULL(E) andalso
+ is_opt_NULL(P) andalso
+ is_opt_NULL(I) andalso
+ is_ContextAttrAuditRequest_contextPropAud(A);
+is_ContextAttrAuditRequest(_) ->
+ false.
+
+is_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([]) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([H|T]) ->
+ d("is_ContextAttrAuditRequest_contextPropAud -> entry"),
+ is_IndAudPropertyParm(H) andalso
+ is_ContextAttrAuditRequest_contextPropAud(T).
+
+chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextAttrAuditRequest(R1, R2) ->
+ chk_ContextAttrAuditRequest(R1, R2).
+
+chk_ContextAttrAuditRequest(R, R) ->
+ chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+chk_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1,
+ iepscallind = I1,
+ contextPropAud = A1},
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2,
+ iepscallind = I2,
+ contextPropAud = A2}) ->
+ validate(fun() -> chk_opt_NULL(T1, T2) end,
+ 'ContextAttrAuditRequest_topology'),
+ validate(fun() -> chk_opt_NULL(E1, E2) end,
+ 'ContextAttrAuditRequest_emergency'),
+ validate(fun() -> chk_opt_NULL(P1, P2) end,
+ 'ContextAttrAuditRequest_priority'),
+ validate(fun() -> chk_opt_NULL(I1, I2) end,
+ 'ContextAttrAuditRequest_iepscallind'),
+ chk_ContextAttrAuditRequest_contextPropAud(lists:sort(A1),
+ lists:sort(A2)),
+ ok.
+
+chk_ContextAttrAuditRequest_contextPropAud(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_contextPropAud/1,
+ 'ContextAttrAuditRequest_contextPropAud', A);
+chk_ContextAttrAuditRequest_contextPropAud([], []) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud([] = T1, T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, [] = T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud_val', H)
+ end;
+chk_ContextAttrAuditRequest_contextPropAud([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextAttrAuditRequest_contextPropAud_val'),
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, T2) ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud', T1, T2).
+
+
+%% -- CommandRequest --
+
+is_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}) ->
+ d("is_CommandRequest -> entry"),
+ is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+is_CommandRequest(_) ->
+ false.
+
+chk_CommandRequest(C, C) ->
+ chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+ optional = Opt1,
+ wildcardReturn = WR1},
+ #'CommandRequest'{command = Cmd2,
+ optional = Opt2,
+ wildcardReturn = WR2}) ->
+ validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+ ok;
+chk_CommandRequest(R1, R2) ->
+ wrong_type('CommandRequest', R1, R2).
+
+
+%% -- Command --
+
+is_Command({Tag, Val}) ->
+ d("is_Command -> entry"),
+ is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+is_Command(_) ->
+ false.
+
+is_Command_tag(Tag) ->
+ Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+ auditValueRequest, notifyReq, serviceChangeReq],
+ lists:member(Tag, Tags).
+
+is_Command_val(addReq, V) -> is_AmmRequest(V);
+is_Command_val(moveReq, V) -> is_AmmRequest(V);
+is_Command_val(modReq, V) -> is_AmmRequest(V);
+is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+chk_Command(Cmd, Cmd) ->
+ chk_type(fun is_Command/1, 'Command', Cmd);
+chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_Command_tag(Tag) andalso
+ is_Command_val(Tag, Val1) andalso
+ is_Command_val(Tag, Val2)) of
+ true ->
+ chk_Command_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+ (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+ true ->
+ not_equal('Command', Cmd1, Cmd2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command(Cmd1, Cmd2) ->
+ wrong_type('Command', Cmd1, Cmd2).
+
+
+chk_Command_val(addReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+chk_Command_val(moveReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+chk_Command_val(modReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+chk_Command_val(subtractReq, R1, R2) ->
+ validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+chk_Command_val(auditCapRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+chk_Command_val(auditValueRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end,
+ 'Command_auditValueRequest');
+chk_Command_val(notifyReq, R1, R2) ->
+ validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+chk_Command_val(serviceChangeReq, R1, R2) ->
+ validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+ 'Command_serviceChangeReq').
+
+
+%% -- CommandReply --
+
+is_CommandReply({Tag, Val}) ->
+ d("is_CommandReply -> entry"),
+ is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+is_CommandReply(_) ->
+ false.
+
+is_CommandReply_tag(Tag) ->
+ Tags = [addReply, moveReply, modReply, subtractReply,
+ auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+ lists:member(Tag, Tags).
+
+is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+ case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('CommandReply', Cmd)
+ end;
+chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_CommandReply_tag(Tag) andalso
+ is_CommandReply_val(Tag, Val1) andalso
+ is_CommandReply_val(Tag, Val2)) of
+ true ->
+ chk_CommandReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_CommandReply_tag(Tag1) andalso
+ is_CommandReply_val(Tag1, Val1)) andalso
+ (is_CommandReply_tag(Tag2) andalso
+ is_CommandReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('CommandReply', Cmd1, Cmd2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply(Cmd1, Cmd2) ->
+ wrong_type('CommandReply', Cmd1, Cmd2).
+
+chk_CommandReply_val(addReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+chk_CommandReply_val(moveReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+chk_CommandReply_val(modReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+chk_CommandReply_val(subtractReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+chk_CommandReply_val(auditCapReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditCapReply');
+chk_CommandReply_val(auditValueReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditValueReply');
+chk_CommandReply_val(notifyReply, V1, V2) ->
+ validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+ validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+ 'CommandReply_serviceChangeReply').
+
+
+%% -- TopologyRequest --
+
+is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+ terminationTo = T,
+ topologyDirection = D,
+ streamID = S}) ->
+ d("is_TopologyRequest -> entry"),
+ is_TerminationID(F) andalso
+ is_TerminationID(T) andalso
+ is_TopologyRequest_topologyDirection(D) andalso
+ is_opt_StreamID(S);
+is_TopologyRequest(_) ->
+ false.
+
+is_TopologyRequest_topologyDirection(D) ->
+ lists:member(D, [bothway, isolate, oneway]).
+
+
+chk_TopologyRequest(T, T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = D1,
+ streamID = S1},
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = D2,
+ streamID = S2}) ->
+ validate(fun() -> chk_TerminationID(F1, F2) end,
+ 'TopologyRequest_terminationFrom'),
+ validate(fun() -> chk_TerminationID(T1, T2) end,
+ 'TopologyRequest_terminationTo'),
+ chk_TopologyRequest_topologyDirection(D1,D2),
+ validate(fun() -> chk_StreamID(S1, S2) end, 'TopologyRequest_streamID'),
+ ok.
+
+chk_TopologyRequest_topologyDirection(D, D) ->
+ case is_TopologyRequest_topologyDirection(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D)
+ end;
+chk_TopologyRequest_topologyDirection(D1, D2) ->
+ case (is_TopologyRequest_topologyDirection(D1) andalso
+ is_TopologyRequest_topologyDirection(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirection', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D1, D2)
+ end.
+
+
+%% -- AmmRequest --
+
+is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+ descriptors = Descs}) ->
+ d("is_AmmRequest -> entry with"
+ "~n Tids: ~p", [Tids]),
+ is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+is_AmmRequest(_) ->
+ false.
+
+is_AmmRequest_descriptors(Descs) ->
+ d("is_AmmRequest_descriptors -> entry"),
+ is_AmmRequest_descriptors(Descs, []).
+
+is_AmmRequest_descriptors([], _) ->
+ true;
+is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+ d("is_AmmRequest_descriptors -> entry with"
+ "~n Tag: ~p"
+ "~n FoundDescs: ~p", [Tag, FoundDescs]),
+ case lists:member(Tag, FoundDescs) of
+ true ->
+ atmost_once('AmmRequest_descriptors', Tag);
+ false ->
+ case is_AmmDescriptor(Desc) of
+ true ->
+ is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+ false ->
+ wrong_type('AmmRequest_descriptors', Desc)
+ end
+ end;
+is_AmmRequest_descriptors(Descs, _) ->
+ d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+ "~n Descs: ~p", [Descs]),
+ wrong_type('AmmRequest_descriptors', Descs).
+
+
+chk_AmmRequest(R, R) when is_record(R, 'AmmRequest') ->
+ d("chk_AmmRequest -> entry when equal"),
+ chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = Descs1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = Descs2}) ->
+ d("chk_AmmRequest -> entry with not equal"
+ "~n Tids1: ~p"
+ "~n Tids2: ~p", [Tids1, Tids2]),
+ validate(
+ fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'AmmRequest'),
+ validate(
+ fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+ 'AmmRequest'),
+ ok.
+
+
+chk_AmmRequest_descriptors([], []) ->
+ d("chk_AmmRequest_descriptors -> done when OK"),
+ ok;
+chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when equal"),
+ case is_AmmDescriptor(H) of
+ true ->
+ chk_AmmRequest_descriptors(T1, T2);
+ false ->
+ wrong_type('AmmRequest_descriptors_val', H)
+ end;
+chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when not equal"),
+ validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+ 'AmmRequest_descriptors_val'),
+ chk_AmmRequest_descriptors(T1, T2);
+chk_AmmRequest_descriptors(Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% -- AmmDescriptor --
+
+is_AmmDescriptor({Tag, Val}) ->
+ d("is_AmmDescriptor -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p",[Tag, Val]),
+ is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+is_AmmDescriptor(_) ->
+ false.
+
+is_AmmDescriptor_tag(Tag) ->
+ Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+ eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+ auditDescriptor, statisticsDescriptor],
+ lists:member(Tag, Tags).
+
+is_AmmDescriptor_val(mediaDescriptor, D) ->
+ is_MediaDescriptor(D);
+is_AmmDescriptor_val(modemDescriptor, D) ->
+ is_ModemDescriptor(D);
+is_AmmDescriptor_val(muxDescriptor, D) ->
+ is_MuxDescriptor(D);
+is_AmmDescriptor_val(eventsDescriptor, D) ->
+ is_EventsDescriptor(D);
+is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+ is_EventBufferDescriptor(D);
+is_AmmDescriptor_val(signalsDescriptor, D) ->
+ is_SignalsDescriptor(D);
+is_AmmDescriptor_val(digitMapDescriptor, D) ->
+ is_DigitMapDescriptor(D);
+is_AmmDescriptor_val(auditDescriptor, D) ->
+ is_AuditDescriptor(D);
+is_AmmDescriptor_val(statisticsDescriptor, D) ->
+ is_StatisticsDescriptor(D).
+
+chk_AmmDescriptor(D, D) ->
+ chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_AmmDescriptor_tag(Tag) andalso
+ is_AmmDescriptor_val(Tag, Val1) andalso
+ is_AmmDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_AmmDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_AmmDescriptor_tag(Tag1) andalso
+ is_AmmDescriptor_val(Tag1, Val1)) andalso
+ (is_AmmDescriptor_tag(Tag2) andalso
+ is_AmmDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('AmmDescriptor', Cmd1, Cmd2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor(Cmd1, Cmd2) ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+ validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+ validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+ validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+ validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+ validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+ validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% -- AmmsReply --
+
+is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+ terminationAudit = TA}) ->
+ is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+is_AmmsReply(_) ->
+ false.
+
+chk_AmmsReply(R, R) ->
+ is_AmmsReply(R);
+chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = TID2,
+ terminationAudit = TA2}) ->
+ validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+ validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+ ok;
+chk_AmmsReply(R1, R2) ->
+ wrong_type('AmmsReply', R1, R2).
+
+
+%% -- SubtractRequest --
+
+is_SubtractRequest(#'SubtractRequest'{terminationID = Tids,
+ auditDescriptor = AD}) ->
+ is_TerminationIDList(Tids) andalso is_opt_AuditDescriptor(AD);
+is_SubtractRequest(_) ->
+ false.
+
+chk_SubtractRequest(R, R) ->
+ chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'SubtractRequest'),
+ validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+ 'SubtractRequest'),
+ ok;
+chk_SubtractRequest(SR1, SR2) ->
+ wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% -- AuditRequest --
+
+is_AuditRequest(#'AuditRequest'{terminationID = Tid,
+ auditDescriptor = AD}) ->
+ is_TerminationID(Tid) andalso is_AuditDescriptor(AD);
+is_AuditRequest(_) ->
+ false.
+
+chk_AuditRequest(R, R) ->
+ chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+chk_AuditRequest(#'AuditRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'AuditRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationID(Tids1, Tids2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+ 'AuditRequest'),
+ ok;
+chk_AuditRequest(AR1, AR2) ->
+ wrong_type('AuditRequest', AR1, AR2).
+
+
+%% -- AuditReply --
+
+is_AuditReply({Tag, Val}) ->
+ is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+is_AuditReply(_) ->
+ false.
+
+is_AuditReply_tag(Tag) ->
+ Tags = [contextAuditResult, error, auditResult],
+ lists:member(Tag, Tags).
+
+is_AuditReply_val(contextAuditResult, Val) ->
+ is_TerminationIDList(Val);
+is_AuditReply_val(error, Val) ->
+ is_ErrorDescriptor(Val);
+is_AuditReply_val(auditResult, Val) ->
+ is_AuditResult(Val).
+
+chk_AuditReply(R, R) ->
+ chk_type(fun is_AuditReply/1, 'AuditReply', R);
+chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_AuditReply_tag(Tag) andalso
+ is_AuditReply_val(Tag, Val1)andalso
+ is_AuditReply_val(Tag, Val2)) of
+ true ->
+ chk_AuditReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_AuditReply_tag(Tag1) andalso
+ is_AuditReply_val(Tag1, Val1)) andalso
+ (is_AuditReply_tag(Tag2) andalso
+ is_AuditReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReply', R1, R2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply(AR1, AR2) ->
+ wrong_type('AuditReply', AR1, AR2).
+
+chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+ chk_TerminationIDList(Val1, Val2);
+chk_AuditReply_val(error, Val1, Val2) ->
+ chk_ErrorDescriptor(Val1, Val2);
+chk_AuditReply_val(auditResult, Val1, Val2) ->
+ chk_AuditResult(Val1, Val2).
+
+
+%% -- AuditResult --
+
+is_AuditResult(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}) ->
+ is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+is_AuditResult(_) ->
+ false.
+
+chk_AuditResult(R, R) ->
+ chk_type(fun is_AuditResult/1, 'AuditResult', R);
+chk_AuditResult(#'AuditResult'{terminationID = TID1,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = TID2,
+ terminationAuditResult = TAR2}) ->
+ validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+ ok;
+chk_AuditResult(AR1, AR2) ->
+ wrong_type('AuditResult', AR1, AR2).
+
+
+%% -- TerminationAudit --
+
+is_opt_TerminationAudit(TA) ->
+ is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+is_TerminationAudit([]) ->
+ true;
+is_TerminationAudit([H|T]) ->
+ is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+is_TerminationAudit(_) ->
+ false.
+
+chk_opt_TerminationAudit(TA1, TA2) ->
+ chk_OPTIONAL('TerminationAudit', TA1, TA2,
+ fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+chk_TerminationAudit([], []) ->
+ ok;
+chk_TerminationAudit([] = TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit(TA1, [] = TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit([H|T1], [H|T2]) ->
+ case is_AuditReturnParameter(H) of
+ true ->
+ chk_TerminationAudit(T1, T2);
+ false ->
+ wrong_type('TerminationAudit', H)
+ end;
+chk_TerminationAudit([H1|_], [H2|_]) ->
+ chk_AuditReturnParameter(H1, H2),
+ not_equal('TerminationAudit_val', H1, H2);
+chk_TerminationAudit(TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2).
+
+
+%% -- AuditReturnParameter --
+
+is_AuditReturnParameter({Tag, Val}) ->
+ is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val);
+is_AuditReturnParameter(_) ->
+ false.
+
+is_AuditReturnParameter_tag(Tag) ->
+ Tags = [errorDescriptor,
+ mediaDescriptor,
+ modemDescriptor,
+ muxDescriptor,
+ eventsDescriptor,
+ eventBufferDescriptor,
+ signalsDescriptor,
+ digitMapDescriptor,
+ observedEventsDescriptor,
+ statisticsDescriptor,
+ packagesDescriptor,
+ emptyDescriptors],
+ lists:member(Tag, Tags).
+
+is_AuditReturnParameter_val(errorDescriptor, V) ->
+ is_ErrorDescriptor(V);
+is_AuditReturnParameter_val(mediaDescriptor, V) ->
+ is_MediaDescriptor(V);
+is_AuditReturnParameter_val(modemDescriptor, V) ->
+ is_ModemDescriptor(V);
+is_AuditReturnParameter_val(muxDescriptor, V) ->
+ is_MuxDescriptor(V);
+is_AuditReturnParameter_val(eventsDescriptor, V) ->
+ is_EventsDescriptor(V);
+is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+ is_EventBufferDescriptor(V);
+is_AuditReturnParameter_val(signalsDescriptor, V) ->
+ is_SignalsDescriptor(V);
+is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+ is_DigitMapDescriptor(V);
+is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+ is_ObservedEventsDescriptor(V);
+is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+ is_StatisticsDescriptor(V);
+is_AuditReturnParameter_val(packagesDescriptor, V) ->
+ is_PackagesDescriptor(V);
+is_AuditReturnParameter_val(emptyDescriptors, V) ->
+ is_AuditDescriptor(V).
+
+chk_AuditReturnParameter(ARP, ARP) ->
+ chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+ case (is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val1) andalso
+ is_AuditReturnParameter_val(Tag, Val2)) of
+ true ->
+ chk_AuditReturnParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+ case ((is_AuditReturnParameter_tag(Tag1) andalso
+ is_AuditReturnParameter_val(Tag1, Val1)) andalso
+ (is_AuditReturnParameter_tag(Tag2) andalso
+ is_AuditReturnParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReturnParameter', ARP1, ARP2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter(ARP1, ARP2) ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+ validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+ validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+ validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+ validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+ validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+ validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+ validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+ validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+ validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+ 'AuditReturnParameter').
+
+
+%% -- AuditDescriptor --
+
+is_opt_AuditDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_AuditDescriptor(V) ->
+ is_AuditDescriptor(V).
+
+is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}) ->
+ is_AuditDescriptor_auditToken(AT) andalso
+ is_AuditDescriptor_auditPropertyToken(APT);
+is_AuditDescriptor(_) ->
+ false.
+
+is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditToken([]) ->
+ true;
+is_AuditDescriptor_auditToken([H|T]) ->
+ is_AuditDescriptor_auditToken_val(H) andalso
+ is_AuditDescriptor_auditToken(T);
+is_AuditDescriptor_auditToken(_) ->
+ false.
+
+is_AuditDescriptor_auditToken_val(V) ->
+ Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, observedEventsToken,
+ packagesToken, eventBufferToken],
+ lists:member(V, Toks).
+
+is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([]) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([H|T]) ->
+ is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+is_AuditDescriptor_auditPropertyToken(_) ->
+ false.
+
+chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(AD1, AD2) ->
+ chk_AuditDescriptor(AD1, AD2).
+
+chk_AuditDescriptor(AD, AD) ->
+ chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = AT2,
+ auditPropertyToken = APT2}) ->
+ chk_AuditDescriptor_auditToken(AT1, AT2),
+ chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+ ok;
+chk_AuditDescriptor(AD1, AD2) ->
+ wrong_type('AuditDescriptor', AD1, AD2).
+
+chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+ case is_AuditDescriptor_auditToken_val(H) of
+ true ->
+ chk_AuditDescriptor_auditToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H)
+ end;
+chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+ case (is_AuditDescriptor_auditToken_val(H1) andalso
+ is_AuditDescriptor_auditToken_val(H2)) of
+ true ->
+ not_equal('AuditDescriptor_auditToken_val', H1, H2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+ end;
+chk_AuditDescriptor_auditToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+ case is_IndAuditParameter(H) of
+ true ->
+ chk_AuditDescriptor_auditPropertyToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+ end;
+chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+ chk_IndAuditParameter(H1, H2),
+ not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% -- IndAuditParameter --
+
+is_IndAuditParameter({Tag, Val}) ->
+ is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+is_IndAuditParameter(_) ->
+ false.
+
+is_IndAuditParameter_tag(Tag) ->
+ Tags = [indAudMediaDescriptor,
+ indAudEventsDescriptor,
+ indAudEventBufferDescriptor,
+ indAudSignalsDescriptor,
+ indAudDigitMapDescriptor,
+ indAudStatisticsDescriptor,
+ indAudPackagesDescriptor],
+ lists:member(Tag, Tags).
+
+is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+ is_IndAudMediaDescriptor(Val);
+is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+ is_IndAudEventsDescriptor(Val);
+is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+ is_IndAudEventBufferDescriptor(Val);
+is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+ is_IndAudSignalsDescriptor(Val);
+is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+ is_IndAudDigitMapDescriptor(Val);
+is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+ is_IndAudStatisticsDescriptor(Val);
+is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+ is_IndAudPackagesDescriptor(Val).
+
+chk_IndAuditParameter(IAP, IAP) ->
+ chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+ case (is_IndAuditParameter_tag(Tag) andalso
+ is_IndAuditParameter_val(Tag, Val1) andalso
+ is_IndAuditParameter_val(Tag, Val2)) of
+ true ->
+ chk_IndAuditParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+ case ((is_IndAuditParameter_tag(Tag1) andalso
+ is_IndAuditParameter_val(Tag1, Val1)) andalso
+ (is_IndAuditParameter_tag(Tag2) andalso
+ is_IndAuditParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAuditParameter', IAP1, IAP2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter(IAP1, IAP2) ->
+ wrong_type('IndAuditParameter', IAP1, IAP2).
+
+chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+ 'IndAuditParameter').
+
+
+%% -- IndAudMediaDescriptor --
+
+is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+ is_IndAudMediaDescriptor_streams(S);
+is_IndAudMediaDescriptor(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+ is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val);
+is_IndAudMediaDescriptor_streams(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+ is_IndAudStreamParms(Val);
+is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+ is_IndAudMediaDescriptor_multiStream(Val).
+
+is_IndAudMediaDescriptor_multiStream([]) ->
+ true;
+is_IndAudMediaDescriptor_multiStream([H|T]) ->
+ is_IndAudStreamDescriptor(H) andalso
+ is_IndAudMediaDescriptor_multiStream(T);
+is_IndAudMediaDescriptor_multiStream(_) ->
+ false.
+
+chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+ chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+ 'IndAudMediaDescriptor'),
+ validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+ 'IndAudMediaDescriptor'),
+ ok;
+chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+ wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+ {Tag, Val2} = S2) ->
+ case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+ true ->
+ chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+ {Tag2, Val2} = S2) ->
+ case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+ (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudMediaDescriptor_streams', S1, S2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams(S1, S2) ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams');
+chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams').
+
+chk_IndAudMediaDescriptor_multiStream([], []) ->
+ ok;
+chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_IndAudStreamDescriptor(H) of
+ true ->
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+ end;
+chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+ 'IndAudMediaDescriptor_multiStream_val'),
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% -- IndAudStreamDescriptor --
+
+is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+is_IndAudStreamDescriptor(_) ->
+ false.
+
+chk_IndAudStreamDescriptor(D, D) ->
+ chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'IndAudStreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+ validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+ 'IndAudStreamDescriptor'),
+ ok;
+chk_IndAudStreamDescriptor(D1, D2) ->
+ wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% -- IndAudStreamParms --
+
+is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ is_opt_IndAudLocalControlDescriptor(LCD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(RD);
+is_IndAudStreamParms(_) ->
+ false.
+
+chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+ 'IndAudStreamParms'),
+ ok;
+chk_IndAudStreamParms(D1, D2) ->
+ wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% -- IndAudLocalControlDescriptor --
+
+is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalControlDescriptor(D) ->
+ is_IndAudLocalControlDescriptor(D).
+
+is_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}) ->
+ is_opt_NULL(SM) andalso is_opt_NULL(RV) andalso is_opt_NULL(RG) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(PPs);
+is_IndAudLocalControlDescriptor(_) ->
+ false.
+
+is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([]) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(T);
+is_IndAudLocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PPs1},
+ #'IndAudLocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PPs2}) ->
+ chk_opt_NULL(SM1, SM2),
+ chk_opt_NULL(RV1, RV2),
+ chk_opt_NULL(RG1, RG2),
+ chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+ ok;
+chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudLocalControlDescriptor_propertyParms_val'),
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+
+%% -- IndAudPropertyParm --
+
+is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name}) ->
+ d("is_IndAudPropertyParm -> entry"),
+ is_PkgdName(Name);
+is_IndAudPropertyParm(_) ->
+ false.
+
+chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1},
+ #'IndAudPropertyParm'{name = Name2}) ->
+ chk_PkgdName(Name1, Name2),
+ ok;
+chk_IndAudPropertyParm(P1, P2) ->
+ wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% -- IndAudLocalRemoteDescriptor --
+
+is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalRemoteDescriptor(D) ->
+ is_IndAudLocalRemoteDescriptor(D).
+
+is_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps}) ->
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+ is_IndAudPropertyGroup(Grps);
+is_IndAudLocalRemoteDescriptor(_) ->
+ false.
+
+is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+ chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+chk_IndAudLocalRemoteDescriptor(D, D) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+ 'IndAudLocalRemoteDescriptor', D);
+chk_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+ propGrps = Grps1},
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+ propGrps = Grps2}) ->
+ chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+ chk_IndAudPropertyGroup(Grps1, Grps2),
+ ok;
+chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+ 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+ case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+ true ->
+ not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+ false ->
+ wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+ end.
+
+
+%% -- IndAudPropertyGroup --
+
+is_IndAudPropertyGroup([]) ->
+ true;
+is_IndAudPropertyGroup([H|T]) ->
+ is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+is_IndAudPropertyGroup(_) ->
+ false.
+
+chk_IndAudPropertyGroup([], []) ->
+ ok;
+chk_IndAudPropertyGroup([] = PG1, PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudPropertyGroup(T1, T2);
+ false ->
+ wrong_type('IndAudPropertyGroup_val', H)
+ end;
+chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudPropertyGroup_val'),
+ chk_IndAudPropertyGroup(T1, T2);
+chk_IndAudPropertyGroup(P1, P2) ->
+ wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% -- IndAudTerminationStateDescriptor --
+
+is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudTerminationStateDescriptor(D) ->
+ is_IndAudTerminationStateDescriptor(D).
+
+is_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+ is_opt_NULL(EBC) andalso is_opt_NULL(SS);
+is_IndAudTerminationStateDescriptor(_) ->
+ false.
+
+is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudTerminationStateDescriptor_propertyParms(T);
+is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+ chk_IndAudTerminationStateDescriptor(D1, D2).
+
+chk_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+ validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+ 'IndAudTerminationStateDescriptor'),
+ validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+ 'IndAudTerminationStateDescriptor'),
+ ok;
+chk_IndAudTerminationStateDescriptor(D1, D2) ->
+ wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+ end;
+chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudTerminationStateDescriptor_propertyParms'),
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- IndAudEventsDescriptor --
+
+is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = SID}) ->
+ is_opt_RequestID(RID) andalso
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID);
+is_IndAudEventsDescriptor(_) ->
+ false.
+
+chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+ pkgdName = Name1,
+ streamID = SID1},
+ #'IndAudEventsDescriptor'{requestID = RID2,
+ pkgdName = Name2,
+ streamID = SID2}) ->
+ chk_opt_RequestID(RID1, RID2),
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventsDescriptor(D1, D2) ->
+ wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% -- IndAudEventBufferDescriptor --
+
+is_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudEventBufferDescriptor(_) ->
+ false.
+
+chk_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name1,
+ streamID = SID1},
+ #'IndAudEventBufferDescriptor'{eventName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventBufferDescriptor(D1, D2) ->
+ wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% -- IndAudSignalsDescriptor --
+
+is_IndAudSignalsDescriptor({Tag, Val}) ->
+ is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val);
+is_IndAudSignalsDescriptor(_) ->
+ false.
+
+is_IndAudSignalsDescriptor_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_IndAudSignalsDescriptor_val(signal, Val) ->
+ is_IndAudSignal(Val);
+is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+ is_IndAudSeqSigList(Val).
+
+chk_IndAudSignalsDescriptor(D, D) ->
+ chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+ case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+ case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+ is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+ (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+ is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudSignalsDescriptor', D1, D2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor(D1, D2) ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+ chk_IndAudSignal(Val1, Val2);
+chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+ chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% -- IndAudSeqSigList --
+
+is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+is_IndAudSeqSigList(_) ->
+ false.
+
+is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+chk_IndAudSeqSigList(L, L) ->
+ chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+ signalList = SL1},
+ #'IndAudSeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ chk_IndAudSeqSigList_id(ID1, ID2),
+ chk_opt_IndAudSignal(SL1, SL2),
+ ok;
+chk_IndAudSeqSigList(L1, L2) ->
+ wrong_type('IndAudSeqSigList', L1, L2).
+
+chk_IndAudSeqSigList_id(ID, ID) ->
+ chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+chk_IndAudSeqSigList_id(ID1, ID2) ->
+ case (is_IndAudSeqSigList_id(ID1) andalso
+ is_IndAudSeqSigList_id(ID2)) of
+ true ->
+ not_equal('IndAudSeqSigList_id', ID1, ID2);
+ false ->
+ wrong_type('IndAudSeqSigList_id', ID1, ID2)
+ end.
+
+
+%% -- IndAudSignal --
+
+is_opt_IndAudSignal(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudSignal(V) ->
+ is_IndAudSignal(V).
+
+is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudSignal(_) ->
+ false.
+
+chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudSignal(S1, S2) ->
+ chk_IndAudSignal(S1, S2).
+
+chk_IndAudSignal(S, S) ->
+ chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+ streamID = SID1},
+ #'IndAudSignal'{signalName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudSignal(S1, S2) ->
+ wrong_type('IndAudSignal', S1, S2).
+
+
+%% -- IndAudDigitMapDescriptor --
+
+is_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+ is_opt_DigitMapName(Name);
+is_IndAudDigitMapDescriptor(_) ->
+ false.
+
+chk_IndAudDigitMapDescriptor(D, D) ->
+ chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+chk_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+ #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'IndAudDigitMapDescriptor'),
+ ok;
+chk_IndAudDigitMapDescriptor(D1, D2) ->
+ wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% -- IndAudStatisticsDescriptor --
+
+is_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name}) ->
+ is_PkgdName(Name);
+is_IndAudStatisticsDescriptor(_) ->
+ false.
+
+chk_IndAudStatisticsDescriptor(D, D) ->
+ chk_type(fun is_IndAudStatisticsDescriptor/1,
+ 'IndAudStatisticsDescriptor', D);
+chk_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name1},
+ #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudStatisticsDescriptor'),
+ ok;
+chk_IndAudStatisticsDescriptor(D1, D2) ->
+ wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% -- IndAudPackagesDescriptor --
+
+is_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = Ver}) ->
+ is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+is_IndAudPackagesDescriptor(_) ->
+ false.
+
+is_IndAudPackagesDescriptor_packageVersion(V) ->
+ is_INTEGER(V, {range, 0, 99}).
+
+chk_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name1,
+ packageVersion = Ver1},
+ #'IndAudPackagesDescriptor'{packageName = Name2,
+ packageVersion = Ver2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+ chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+ ok;
+chk_IndAudPackagesDescriptor(D1, D2) ->
+ wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+ chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+ 'IndAudPackagesDescriptor_packageVersion', V);
+chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+ case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+ is_IndAudPackagesDescriptor_packageVersion(V2)) of
+ true ->
+ not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+ false ->
+ wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+ end.
+
+
+%% -- NotifyRequest --
+
+is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso
+ is_ObservedEventsDescriptor(OED) andalso
+ is_opt_ErrorDescriptor(ED);
+is_NotifyRequest(_) ->
+ false.
+
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = OED1,
+ errorDescriptor = ED1},
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = OED2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+ 'NotifyRequest'),
+ ok;
+chk_NotifyRequest(NR1, NR2) ->
+ wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% -- NotifyReply --
+
+is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+is_NotifyReply(_) ->
+ false.
+
+chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+ errorDescriptor = ED1},
+ #'NotifyReply'{terminationID = Tids2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+ ok;
+chk_NotifyReply(NR1, NR2) ->
+ wrong_type('NotifyReply', NR1, NR2).
+
+
+%% -- ObservedEventsDescriptor --
+
+is_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}) ->
+ is_RequestID(RID) andalso
+ is_ObservedEventsDescriptor_observedEventLst(OEL);
+is_ObservedEventsDescriptor(_) ->
+ false.
+
+is_ObservedEventsDescriptor_observedEventLst([]) ->
+ true;
+is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+ is_ObservedEvent(H) andalso
+ is_ObservedEventsDescriptor_observedEventLst(T);
+is_ObservedEventsDescriptor_observedEventLst(_) ->
+ false.
+
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID1,
+ observedEventLst = OEL1},
+ #'ObservedEventsDescriptor'{requestId = RID2,
+ observedEventLst = OEL2}) ->
+ validate(fun() -> chk_RequestID(RID1, RID2) end,
+ 'ObservedEventsDescriptor'),
+ validate(
+ fun() ->
+ chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+ end,
+ 'ObservedEventsDescriptor'),
+ ok;
+chk_ObservedEventsDescriptor(D1, D2) ->
+ wrong_type('ObservedEventsDescriptor', D1, D2).
+
+chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+ ok;
+chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+ case is_ObservedEvent(H) of
+ true ->
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+ false ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+ end;
+chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ObservedEvent(H1, H2) end,
+ 'ObservedEventsDescriptor_observedEventLst_val'),
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% -- ObservedEvent --
+
+is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}) ->
+ is_EventName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_ObservedEvent_eventParList(EPL) andalso
+ is_opt_TimeNotation(TN);
+is_ObservedEvent(_) ->
+ false.
+
+is_ObservedEvent_eventParList([]) ->
+ true;
+is_ObservedEvent_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+is_ObservedEvent_eventParList(_) ->
+ false.
+
+chk_ObservedEvent(E, E) ->
+ chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+ streamID = SID1,
+ eventParList = EPL1,
+ timeNotation = TN1},
+ #'ObservedEvent'{eventName = Name2,
+ streamID = SID2,
+ eventParList = EPL2,
+ timeNotation = TN2}) ->
+ validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+ chk_ObservedEvent_eventParList(EPL1, EPL2),
+ validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+ ok;
+chk_ObservedEvent(E1, E2) ->
+ wrong_type('ObservedEvent', E1, E2).
+
+chk_ObservedEvent_eventParList([], []) ->
+ ok;
+chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_ObservedEvent_eventParList(T1, T2);
+ false ->
+ wrong_type('ObservedEvent_eventParList_val', H)
+ end;
+chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'ObservedEvent_eventParList'),
+ chk_ObservedEvent_eventParList(T1, T2);
+chk_ObservedEvent_eventParList(L1, L2) ->
+ wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+chk_EventName(N, N) ->
+ chk_type(fun is_EventName/1, 'EventName', N);
+chk_EventName(N1, N2) ->
+ case (is_EventName(N1) andalso is_EventName(N2)) of
+ true ->
+ not_equal('EventName', N1, N2);
+ false ->
+ wrong_type('EventName', N1, N2)
+ end.
+
+
+%% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+ value = Val1,
+ extraInfo = EI1},
+ #'EventParameter'{eventParameterName = Name2,
+ value = Val2,
+ extraInfo = EI2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+ validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+ chk_EventParameter_extraInfo(EI1, EI2),
+ ok;
+chk_EventParameter(P1, P2) ->
+ wrong_type('EventParameter', P1, P2).
+
+chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_EventParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_EventParameter_extraInfo/1,
+ 'EventParameter_extraInfo', EI);
+chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val1) andalso
+ is_EventParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+ is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+ (is_EventParameter_extraInfo_tag(Tag2) andalso
+ is_EventParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo(EI1, EI2) ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val').
+
+
+%% -- ServiceChangeRequest --
+
+is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+ serviceChangeParms = Parms}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+is_ServiceChangeRequest(_) ->
+ false.
+
+chk_ServiceChangeRequest(R, R) ->
+ chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+chk_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = Parms1},
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = Parms2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeRequest'),
+ validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+ 'ServiceChangeRequest'),
+ ok;
+chk_ServiceChangeRequest(R1, R2) ->
+ wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% -- ServiceChangeReply --
+
+is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+ serviceChangeResult = Res}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+is_ServiceChangeReply(_) ->
+ false.
+
+chk_ServiceChangeReply(R, R) ->
+ chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+chk_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = Tids1,
+ serviceChangeResult = Res1},
+ #'ServiceChangeReply'{terminationID = Tids2,
+ serviceChangeResult = Res2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeReply'),
+ validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+ 'ServiceChangeReply'),
+ ok;
+chk_ServiceChangeReply(R1, R2) ->
+ wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% -- ServiceChangeResult --
+
+is_ServiceChangeResult({Tag, Val}) ->
+ is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val);
+is_ServiceChangeResult(_) ->
+ false.
+
+is_ServiceChangeResult_tag(Tag) ->
+ Tags = [errorDescriptor, serviceChangeResParms],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeResult_val(errorDescriptor, Val) ->
+ is_ErrorDescriptor(Val);
+is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+ is_ServiceChangeResParm(Val).
+
+chk_ServiceChangeResult(Res, Res) ->
+ chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+ case (is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val1) andalso
+ is_ServiceChangeResult_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+ case ((is_ServiceChangeResult_tag(Tag1) andalso
+ is_ServiceChangeResult_val(Tag1, Val1)) andalso
+ (is_ServiceChangeResult_tag(Tag2) andalso
+ is_ServiceChangeResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeResult', Res1, Res2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult(Res1, Res2) ->
+ wrong_type('ServiceChangeResult', Res1, Res2).
+
+chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'ServiceChangeResult');
+chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+ validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+ 'ServiceChangeResult').
+
+
+%% -- WildcardField --
+
+is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+chk_WildcardField(WF, WF) ->
+ case is_WildcardField(WF) of
+ true ->
+ ok;
+ false ->
+ wrong_type('WildcardField', WF)
+ end;
+chk_WildcardField(WF1, WF2) ->
+ case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+ true ->
+ not_equal('WildcardField', WF1, WF2);
+ false ->
+ wrong_type('WildcardField', WF1, WF2)
+ end.
+
+
+%% -- TerminationID --
+
+is_TerminationID(#'TerminationID'{wildcard = W,
+ id = ID}) ->
+ is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+ id = _ID}) ->
+ true; % What are the types?
+is_TerminationID(_) ->
+ false.
+
+is_TerminationID_wildcard([]) ->
+ true;
+is_TerminationID_wildcard([H|T]) ->
+ is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+is_TerminationID_wildcard(_) ->
+ false.
+
+is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+chk_TerminationID(Id,Id) ->
+ chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+chk_TerminationID(#'TerminationID'{wildcard = W1,
+ id = I1},
+ #'TerminationID'{wildcard = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+ id = I1},
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(Tid1, Tid2) ->
+ wrong_type('TerminationID', Tid1, Tid2).
+
+chk_TerminationID_wildcard([], []) ->
+ ok;
+chk_TerminationID_wildcard([] = WF1, WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard(WF1, [] = WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+ case is_WildcardField(H) of
+ true ->
+ chk_TerminationID_wildcard(T1, T2);
+ false ->
+ wrong_type('TerminationID_wildcard_val', H)
+ end;
+chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_WildcardField(H1, H2) end,
+ 'TerminationID_wildcard_val'),
+ chk_TerminationID_wildcard(T1, T2);
+chk_TerminationID_wildcard(WF1,WF2) ->
+ not_equal('TerminationId_wildcard', WF1, WF2).
+
+chk_TerminationID_id(Id, Id) ->
+ case is_OCTET_STRING(Id, {range, 1, 8}) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TerminationID_id', Id, Id)
+ end;
+chk_TerminationID_id(Id1, Id2) ->
+ not_equal(terminationId_id, Id1, Id2).
+
+
+%% -- TerminationIDList --
+
+is_TerminationIDList([]) ->
+ true;
+is_TerminationIDList([H|T]) ->
+ is_TerminationID(H) andalso is_TerminationIDList(T);
+is_TerminationIDList(_) ->
+ false.
+
+chk_TerminationIDList([], []) ->
+ ok;
+chk_TerminationIDList([] = L1, L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList(L1, [] = L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_TerminationIDList(T1, T2);
+ false ->
+ wrong_type('TerminationIDList', H)
+ end;
+chk_TerminationIDList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+ chk_TerminationIDList(T1, T2);
+chk_TerminationIDList(L1, L2) ->
+ wrong_type('TerminationIDList', L1, L2).
+
+
+%% -- MediaDescriptor --
+
+is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_MediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_TerminationStateDescriptor(TSD) andalso
+ is_MediaDescriptor_streams(S);
+is_MediaDescriptor(_) ->
+ false.
+
+is_MediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_MediaDescriptor_streams({Tag, Val}) ->
+ is_MediaDescriptor_streams_tag(Tag) andalso
+ is_MediaDescriptor_streams_val(Tag, Val);
+is_MediaDescriptor_streams(_) ->
+ false.
+
+is_MediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_MediaDescriptor_streams_val(oneStream, SP) ->
+ is_StreamParms(SP);
+is_MediaDescriptor_streams_val(multiStream, SDL) ->
+ is_MediaDescriptor_multiStream(SDL).
+
+is_MediaDescriptor_multiStream([]) ->
+ true;
+is_MediaDescriptor_multiStream([H|T]) ->
+ is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+is_MediaDescriptor_multiStream(_) ->
+ false.
+
+chk_MediaDescriptor(D, D) ->
+ chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'MediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(
+ fun() ->
+ chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+ end,
+ 'MediaDescriptor'),
+ validate(
+ fun() ->
+ chk_MediaDescriptor_streams(S1, S2)
+ end,
+ 'MediaDescriptor'),
+ ok;
+chk_MediaDescriptor(D1, D2) ->
+ wrong_type('MediaDescriptor', D1, D2).
+
+
+chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+ validate(fun() ->
+ chk_StreamParms(SP1, SP2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+ validate(fun() ->
+ chk_MediaDescriptor_multiStream(SDs1, SDs2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams(S1, S2) ->
+ wrong_type('MediaDescriptor_streams', S1, S2).
+
+chk_MediaDescriptor_multiStream([], []) ->
+ ok;
+chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_StreamDescriptor(H) of
+ true ->
+ chk_MediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('MediaDescriptor_multiStream_val', H)
+ end;
+chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+ 'MediaDescriptor_multiStream_val'),
+ chk_MediaDescriptor_multiStream(T1, T2);
+chk_MediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% -- StreamDescriptor --
+
+is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_StreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_StreamParms(Parms);
+is_StreamDescriptor(X) ->
+ d("is_StreamDescriptor -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamDescriptor(D, D) ->
+ chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+ validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+ ok;
+chk_StreamDescriptor(D1, D2) ->
+ wrong_type('StreamDescriptor', D1, D2).
+
+
+%% -- StreamParms --
+
+is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}) ->
+ d("is_StreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p"
+ "~n SD: ~p", [LCD, LD, RD, SD]),
+ is_opt_LocalControlDescriptor(LCD) andalso
+ is_opt_LocalRemoteDescriptor(LD) andalso
+ is_opt_LocalRemoteDescriptor(RD) andalso
+ is_opt_StatisticsDescriptor(SD);
+is_StreamParms(X) ->
+ d("is_StreamParms -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamParms(SP, SP) ->
+ chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1,
+ statisticsDescriptor = SD1},
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_LocalControlDescriptor(LCD1, LCD2) end,
+ 'StreamParms_localControlDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+ 'StreamParms_localDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+ 'StreamParms_remoteDescriptor'),
+ validate(fun() -> chk_opt_StatisticsDescriptor(SD1, SD2) end,
+ 'StreamParms_statisticsDescriptor'),
+ ok;
+chk_StreamParms(P1, P2) ->
+ wrong_type('StreamParms', P1, P2).
+
+
+%% -- LocalControlDescriptor --
+
+is_opt_LocalControlDescriptor(D) ->
+ d("is_opt_LocalControlDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalControlDescriptor/1, D).
+
+is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}) ->
+ d("is_LocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PP: ~p", [SM, RV, RG, PP]),
+ is_opt_StreamMode(SM) andalso
+ is_opt_BOOLEAN(RV) andalso
+ is_opt_BOOLEAN(RG) andalso
+ is_LocalControlDescriptor_propertyParms(PP);
+is_LocalControlDescriptor(_) ->
+ false.
+
+is_LocalControlDescriptor_propertyParms([]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry when done"),
+ true;
+is_LocalControlDescriptor_propertyParms([H|T]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry with"
+ "~n H: ~p"
+ "~n T: ~p", [H, T]),
+ is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+is_LocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+ chk_OPTIONAL('LocalControlDescriptor', LCD1, LCD2,
+ fun is_LocalControlDescriptor/1,
+ fun chk_LocalControlDescriptor/2).
+
+chk_LocalControlDescriptor(LCD, LCD) ->
+ chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PP1},
+ #'LocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PP2}) ->
+ validate(
+ fun() -> chk_opt_StreamMode(SM1, SM2) end,
+ 'LocalControlDescriptor'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+ 'LocalControlDescriptor_reserveValue'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+ 'LocalControlDescriptor_reserveGroup'),
+ chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+ ok;
+chk_LocalControlDescriptor(LCD1, LCD2) ->
+ wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+chk_LocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('LocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'LocalControlDescriptor_propertyParms_val'),
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- StreamMode --
+
+is_opt_StreamMode(asn1_NOVALUE) ->
+ true;
+is_opt_StreamMode(SM) ->
+ is_StreamMode(SM).
+
+is_StreamMode(SM) ->
+ lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamMode(SM1, SM2) ->
+ chk_StreamMode(SM1, SM2).
+
+chk_StreamMode(SM, SM) ->
+ chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+chk_StreamMode(SM1, SM2) ->
+ case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+ true ->
+ not_equal('StreamMode', SM1, SM2);
+ false ->
+ wrong_type('StreamMode', SM1, SM2)
+ end.
+
+
+%% -- PropertyParm --
+
+is_PropertyParm(#'PropertyParm'{name = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_PropertyParm -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_PkgdName(N) andalso
+ is_PropertyParm_value(V) andalso
+ is_PropertyParm_extraInfo(I);
+is_PropertyParm(_) ->
+ false.
+
+is_PropertyParm_value([]) ->
+ d("is_PropertyParm_value -> entry when done"),
+ true;
+is_PropertyParm_value([H|T]) ->
+ d("is_PropertyParm_value -> entry with"
+ "~n H: ~p", [H]),
+ is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+is_PropertyParm_value(_) ->
+ false.
+
+is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+ true;
+is_PropertyParm_extraInfo({Tag, Val}) ->
+ d("is_PropertyParm_extraInfo -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_PropertyParm_extraInfo_tag(Tag) andalso
+ is_PropertyParm_extraInfo_val(Tag, Val);
+is_PropertyParm_extraInfo(_) ->
+ false.
+
+is_PropertyParm_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_PropertyParm_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_PropertyParm_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_PropertyParm_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_PropertyParm(P, P) ->
+ chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+chk_PropertyParm(#'PropertyParm'{name = N1,
+ value = V1,
+ extraInfo = I1},
+ #'PropertyParm'{name = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+ chk_PropertyParm_value(V1, V2),
+ chk_PropertyParm_extraInfo(I1, I2),
+ ok;
+chk_PropertyParm(P1, P2) ->
+ wrong_type('PropertyParm', P1, P2).
+
+chk_PropertyParm_value([], []) ->
+ ok;
+chk_PropertyParm_value([] = V1, V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value(V1, [] = V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value([H|T1], [H|T2]) ->
+ case is_OCTET_STRING(H) of
+ true ->
+ chk_PropertyParm_value(T1, T2);
+ false ->
+ wrong_type('PropertyParm_value_val', H)
+ end;
+chk_PropertyParm_value([H1|_], [H2|_]) ->
+ case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+ true ->
+ not_equal('PropertyParm_value_val', H1, H2);
+ false ->
+ wrong_type('PropertyParm_value_val', H1, H2)
+ end;
+chk_PropertyParm_value(V1, V2) ->
+ wrong_type('PropertyParm_value', V1, V2).
+
+chk_PropertyParm_extraInfo(EI, EI) ->
+ chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_PropertyParm_extraInfo_tag(Tag) and
+ is_PropertyParm_extraInfo_val(Tag, Val1) and
+ is_PropertyParm_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_PropertyParm_extraInfo_tag(Tag1) and
+ is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+ (is_PropertyParm_extraInfo_tag(Tag2) and
+ is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('PropertyParm_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo(EI1, EI2) ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $9, $0 =< H ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+chk_Name(N, N) ->
+ chk_type(fun is_Name/1, 'Name', N);
+chk_Name(N1, N2) ->
+ case (is_Name(N1) andalso is_Name(N2)) of
+ true ->
+ not_equal('Name', N1, N2);
+ false ->
+ wrong_type('Name', N1, N2)
+ end.
+
+
+%% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+chk_PkgdName(N, N) ->
+ case is_PkgdName(N) of
+ true ->
+ ok;
+ false ->
+ wrong_type('PkgdName', N, N)
+ end;
+chk_PkgdName(N1, N2) ->
+ case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+ true ->
+ not_equal('PkgdName', N1, N2);
+ false ->
+ wrong_type('PkgdName', N1, N2)
+ end.
+
+
+%% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+chk_Relation(R, R) ->
+ chk_type(fun is_Relation/1, 'Relation', R);
+chk_Relation(R1, R2) ->
+ case (is_Relation(R1) andalso is_Relation(R2)) of
+ true ->
+ not_equal('Relation', R1, R2);
+ false ->
+ wrong_type('Relation', R1, R2)
+ end.
+
+
+%% -- LocalRemoteDescriptor --
+
+is_opt_LocalRemoteDescriptor(D) ->
+ d("is_LocalRemoteDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+ d("is_LocalRemoteDescriptor -> entry with"
+ "~n PGs: ~p", [PGs]),
+ is_LocalRemoteDescriptor_propGrps(PGs);
+is_LocalRemoteDescriptor(_) ->
+ false.
+
+is_LocalRemoteDescriptor_propGrps([]) ->
+ true;
+is_LocalRemoteDescriptor_propGrps([H|T]) ->
+ is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+is_LocalRemoteDescriptor_propGrps(_) ->
+ false.
+
+chk_opt_LocalRemoteDescriptor(D1, D2) ->
+ chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+ fun is_LocalRemoteDescriptor/1,
+ fun chk_LocalRemoteDescriptor/2).
+
+chk_LocalRemoteDescriptor(LRD, LRD) ->
+ chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+ #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+ chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+ ok;
+chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+ wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+chk_LocalRemoteDescriptor_propGrps([], []) ->
+ ok;
+chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+ case is_PropertyGroup(H) of
+ true ->
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+ false ->
+ wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+ end;
+chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyGroup(H1, H2) end,
+ 'LocalRemoteDescriptor_propGrps_val'),
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+ wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% -- PropertyGroup --
+
+is_PropertyGroup([]) ->
+ true;
+is_PropertyGroup([H|T]) ->
+ is_PropertyParm(H) andalso is_PropertyGroup(T);
+is_PropertyGroup(_) ->
+ false.
+
+chk_PropertyGroup([], []) ->
+ ok;
+chk_PropertyGroup([] = PG1, PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup(PG1, [] = PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_PropertyGroup(T1, T2);
+ false ->
+ wrong_type('PropertyGroup_val', H)
+ end;
+chk_PropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+ chk_PropertyGroup(T1, T2);
+chk_PropertyGroup(PG1, PG2) ->
+ wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% -- TerminationStateDescriptor --
+
+is_opt_TerminationStateDescriptor(D) ->
+ is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+is_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_TerminationStateDescriptor_propertyParms(PP) andalso
+ is_opt_EventBufferControl(EBC) andalso
+ is_opt_ServiceState(SS);
+is_TerminationStateDescriptor(_) ->
+ false.
+
+is_TerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_TerminationStateDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+is_TerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_TerminationStateDescriptor(D1, D2) ->
+ chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+ fun is_TerminationStateDescriptor/1,
+ fun chk_TerminationStateDescriptor/2).
+
+chk_TerminationStateDescriptor(D, D) ->
+ chk_type(fun is_TerminationStateDescriptor/1,
+ 'TerminationStateDescriptor', D);
+chk_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'TerminationStateDescriptor'{propertyParms = PP2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+ validate(
+ fun() ->
+ chk_opt_EventBufferControl(EBC1, EBC2)
+ end,
+ 'TerminationStateDescriptor'),
+ validate(
+ fun() ->
+ chk_opt_ServiceState(SS1, SS2)
+ end,
+ 'TerminationStateDescriptor'),
+ ok;
+chk_TerminationStateDescriptor(D1, D2) ->
+ wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+chk_TerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_TerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+ end;
+chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+ case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+ true ->
+ not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+ end;
+chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+ wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% -- EventBufferControl --
+
+is_opt_EventBufferControl(asn1_NOVALUE) ->
+ true;
+is_opt_EventBufferControl(EBC) ->
+ is_EventBufferControl(EBC).
+
+is_EventBufferControl(EBC) ->
+ lists:member(EBC, [off, lockStep]).
+
+chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_EventBufferControl(EBC1, EBC2) ->
+ chk_EventBufferControl(EBC1, EBC2).
+
+chk_EventBufferControl(EBC, EBC) ->
+ chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+chk_EventBufferControl(EBC1, EBC2) ->
+ case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+ true ->
+ not_equal('EventBufferControl', EBC1, EBC2);
+ false ->
+ wrong_type('EventBufferControl', EBC1, EBC2)
+ end.
+
+
+%% -- ServiceState --
+
+is_opt_ServiceState(asn1_NOVALUE) ->
+ true;
+is_opt_ServiceState(SS) ->
+ is_ServiceState(SS).
+
+is_ServiceState(SS) ->
+ lists:member(SS, [test, outOfSvc, inSvc]).
+
+chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ServiceState(SS1, SS2) ->
+ chk_ServiceState(SS1, SS2).
+
+chk_ServiceState(SS, SS) ->
+ chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+chk_ServiceState(SS1, SS2) ->
+ case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+ true ->
+ not_equal('ServiceState', SS1, SS2);
+ false ->
+ wrong_type('ServiceState', SS1, SS2)
+ end.
+
+
+%% -- MuxDescriptor --
+
+is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+ termList = TL,
+ nonStandardData = NSD}) ->
+ is_MuxType(MT) andalso
+ is_MuxDescriptor_termList(TL) andalso
+ is_NonStandardData(NSD);
+is_MuxDescriptor(_) ->
+ false.
+
+is_MuxDescriptor_termList([]) ->
+ true;
+is_MuxDescriptor_termList([H|T]) ->
+ is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+is_MuxDescriptor_termList(_) ->
+ false.
+
+chk_MuxDescriptor(D, D) ->
+ chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+ termList = TL1,
+ nonStandardData = NSD1},
+ #'MuxDescriptor'{muxType = MT2,
+ termList = TL2,
+ nonStandardData = NSD2}) ->
+ validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+ chk_MuxDescriptor_termList(TL1, TL2),
+ validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+ ok;
+chk_MuxDescriptor(D1, D2) ->
+ wrong_type('MuxDescriptor', D1, D2).
+
+chk_MuxDescriptor_termList([], []) ->
+ ok;
+chk_MuxDescriptor_termList([] = TL1, TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_MuxDescriptor_termList(T1, T2);
+ false ->
+ wrong_type('MuxDescriptor_termList_val', H)
+ end;
+chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end,
+ 'MuxDescriptor_termList_val'),
+ chk_MuxDescriptor_termList(T1, T2);
+chk_MuxDescriptor_termList(TL1, TL2) ->
+ wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% -- MuxType --
+
+is_MuxType(MT) ->
+ lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+chk_MuxType(MT, MT) ->
+ chk_type(fun is_MuxType/1, 'MuxType', MT);
+chk_MuxType(MT1, MT2) ->
+ case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+ true ->
+ not_equal('MuxType', MT1, MT2);
+ false ->
+ wrong_type('MuxType', MT1, MT2)
+ end.
+
+
+%% -- StreamID --
+
+is_opt_StreamID(V) ->
+ is_OPTIONAL(fun is_StreamID/1, V).
+
+is_StreamID(V) ->
+ d("is_StreamID -> entry with"
+ "~n V: ~p", [V]),
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_StreamID(V1, V2) ->
+ chk_OPTIONAL('StreamID', V1, V2, fun is_StreamID/1, fun chk_StreamID/2).
+
+chk_StreamID(ID, ID) ->
+ chk_type(fun is_StreamID/1, 'StreamID', ID);
+chk_StreamID(ID1, ID2) ->
+ case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+ true ->
+ not_equal('StreamID', ID1, ID2);
+ false ->
+ wrong_type('StreamID', ID1, ID2)
+ end.
+
+
+%% -- EventsDescriptor --
+
+is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = EVL}) ->
+ d("is_EventsDescriptor -> entry with"
+ "~n RID: ~p"
+ "~n EVL: ~p", [RID, EVL]),
+ is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+is_EventsDescriptor(_) ->
+ false.
+
+is_EventsDescriptor_eventList([]) ->
+ true;
+is_EventsDescriptor_eventList([H|T]) ->
+ is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+is_EventsDescriptor_eventList(_) ->
+ false.
+
+chk_EventsDescriptor(D, D) ->
+ chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+ eventList = EVL1},
+ #'EventsDescriptor'{requestID = RID2,
+ eventList = EVL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+ chk_EventsDescriptor_eventList(EVL1, EVL2),
+ ok;
+chk_EventsDescriptor(D1, D2) ->
+ wrong_type('EventsDescriptor', D1, D2).
+
+chk_EventsDescriptor_eventList([], []) ->
+ ok;
+chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_RequestedEvent(H) of
+ true ->
+ chk_EventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('EventsDescriptor_eventList_val', H)
+ end;
+chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_RequestedEvent(H1, H2) end,
+ 'EventsDescriptor_eventList_val'),
+ chk_EventsDescriptor_eventList(T1, T2);
+chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+ wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% -- RequestedEvent --
+
+is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ d("is_RequestedEvent -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n EA: ~p"
+ "~n EPL: ~p", [N, SID, EA, EPL]),
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestedActions(EA) andalso
+ is_RequestedEvent_evParList(EPL);
+is_RequestedEvent(_) ->
+ false.
+
+is_RequestedEvent_evParList([]) ->
+ true;
+is_RequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+is_RequestedEvent_evParList(_) ->
+ false.
+
+chk_RequestedEvent(RE, RE) ->
+ chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'RequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+ 'RequestedEvent'),
+ chk_RequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_RequestedEvent(RE1, RE2) ->
+ wrong_type('RequestedEvent', RE1, RE2).
+
+chk_RequestedEvent_evParList([], []) ->
+ ok;
+chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_RequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('RequestedEvent_evParList_val', H)
+ end;
+chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'RequestedEvent_evParList_val'),
+ chk_RequestedEvent_evParList(T1, T2);
+chk_RequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- RequestedActions --
+
+is_opt_RequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_RequestedActions(RA) ->
+ is_RequestedActions(RA).
+
+is_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ d("is_RequestedActions -> entry with"
+ "~n KA: ~p"
+ "~n EDM: ~p"
+ "~n SE: ~p"
+ "~n SD: ~p", [KA, EDM, SE, SD]),
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD);
+is_RequestedActions(_) ->
+ false.
+
+chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestedActions(RA1, RA2) ->
+ chk_RequestedActions(RA1, RA2).
+
+chk_RequestedActions(RA, RA) ->
+ chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ secondEvent = SA1,
+ signalsDescriptor = SD1},
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ secondEvent = SA2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_SecondEventsDescriptor(SA1, SA2) end,
+ 'RequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'RequestedActions'),
+ ok;
+chk_RequestedActions(RA1, RA2) ->
+ wrong_type('RequestedActions', RA1, RA2).
+
+
+%% -- EventDM --
+
+is_opt_EventDM(EDM) ->
+ is_OPTIONAL(fun is_EventDM/1, EDM).
+
+is_EventDM({Tag, Val}) ->
+ is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+is_EventDM(_) ->
+ false.
+
+is_EventDM_tag(Tag) ->
+ Tags = [digitMapName, digitMapValue],
+ lists:member(Tag, Tags).
+
+is_EventDM_val(digitMapName, Val) ->
+ is_DigitMapName(Val);
+is_EventDM_val(digitMapValue, Val) ->
+ is_DigitMapValue(Val).
+
+chk_opt_EventDM(EDM1, EDM2) ->
+ chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+chk_EventDM(EDM, EDM) ->
+ chk_type(fun is_EventDM/1, 'EventDM', EDM);
+chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+ case (is_EventDM_tag(Tag) andalso
+ is_EventDM_val(Tag, Val1) andalso
+ is_EventDM_val(Tag, Val2)) of
+ true ->
+ chk_EventDM_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+ case ((is_EventDM_tag(Tag1) andalso
+ is_EventDM_val(Tag1, Val1)) andalso
+ (is_EventDM_tag(Tag2) andalso
+ is_EventDM_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventDM', EDM1, EDM2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM(EDM1, EDM2) ->
+ wrong_type('EventDM', EDM1, EDM2).
+
+chk_EventDM_val(digitMapName, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+chk_EventDM_val(digitMapValue, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% -- SecondEventsDescriptor --
+
+is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SecondEventsDescriptor(D) ->
+ is_SecondEventsDescriptor(D).
+
+is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = EL}) ->
+ is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+is_SecondEventsDescriptor(_) ->
+ false.
+
+is_SecondEventsDescriptor_eventList([]) ->
+ true;
+is_SecondEventsDescriptor_eventList([H|T]) ->
+ is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+is_SecondEventsDescriptor_eventList(_) ->
+ false.
+
+chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondEventsDescriptor(D1, D2) ->
+ chk_SecondEventsDescriptor(D1, D2).
+
+chk_SecondEventsDescriptor(D, D) ->
+ chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+ eventList = EL1},
+ #'SecondEventsDescriptor'{requestID = RID2,
+ eventList = EL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+ 'SecondEventsDescriptor'),
+ chk_SecondEventsDescriptor_eventList(EL1, EL2),
+ ok;
+chk_SecondEventsDescriptor(D1, D2) ->
+ wrong_type('SecondEventsDescriptor', D1, D2).
+
+chk_SecondEventsDescriptor_eventList([], []) ->
+ ok;
+chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_SecondRequestedEvent(H) of
+ true ->
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('SecondEventsDescriptor_eventList_val', H)
+ end;
+chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+ 'SecondEventsDescriptor_eventList_val'),
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+chk_SecondEventsDescriptor_eventList(L1, L2) ->
+ wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% -- SecondRequestedEvent --
+
+is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SecondRequestedActions(EA) andalso
+ is_SecondRequestedEvent_evParList(EPL);
+is_SecondRequestedEvent(_) ->
+ false.
+
+is_SecondRequestedEvent_evParList([]) ->
+ true;
+is_SecondRequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+is_SecondRequestedEvent_evParList(_) ->
+ false.
+
+chk_SecondRequestedEvent(RE, RE) ->
+ chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'SecondRequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+ 'SecondRequestedEvent'),
+ chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_SecondRequestedEvent(RE1, RE2) ->
+ wrong_type('SecondRequestedEvent', RE1, RE2).
+
+chk_SecondRequestedEvent_evParList([], []) ->
+ ok;
+chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_SecondRequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('SecondRequestedEvent_evParList_val', H)
+ end;
+chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'SecondRequestedEvent_evParList_val'),
+ chk_SecondRequestedEvent_evParList(T1, T2);
+chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- SecondRequestedActions --
+
+is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_SecondRequestedActions(SRA) ->
+ is_SecondRequestedActions(SRA).
+
+is_SecondRequestedActions(#'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}) ->
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SignalsDescriptor(SD);
+is_SecondRequestedActions(_) ->
+ false.
+
+chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+ chk_SecondRequestedActions(SRA1, SRA2).
+
+chk_SecondRequestedActions(SRA, SRA) ->
+ chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+chk_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ signalsDescriptor = SD1},
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'SecondRequestedActions'),
+ ok;
+chk_SecondRequestedActions(SRA1, SRA2) ->
+ wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+
+%% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor([]) ->
+ true;
+is_EventBufferDescriptor([H|T]) ->
+ is_EventSpec(H) andalso is_EventBufferDescriptor(T);
+is_EventBufferDescriptor(_) ->
+ false.
+
+chk_EventBufferDescriptor([], []) ->
+ ok;
+chk_EventBufferDescriptor([] = D1, D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor(D1, [] = D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor([H|T1], [H|T2]) ->
+ case is_EventSpec(H) of
+ true ->
+ chk_EventBufferDescriptor(T1, T2);
+ false ->
+ wrong_type('EventBufferDescriptor_val', H)
+ end;
+chk_EventBufferDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventSpec(H1, H2) end,
+ 'EventBufferDescriptor_val'),
+ chk_EventBufferDescriptor(T1, T2);
+chk_EventBufferDescriptor(D1, D2) ->
+ wrong_type('EventBufferDescriptor_val', D1, D2).
+
+
+%% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+chk_EventSpec(ES, ES) ->
+ chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = SID1,
+ eventParList = EPL1},
+ #'EventSpec'{eventName = N2,
+ streamID = SID2,
+ eventParList = EPL2}) ->
+ validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+ chk_EventSpec_eventParList(EPL1, EPL2),
+ ok;
+chk_EventSpec(ES1, ES2) ->
+ wrong_type('EventSpec', ES1, ES2).
+
+chk_EventSpec_eventParList([], []) ->
+ ok;
+chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_EventSpec_eventParList(T1, T2);
+ false ->
+ wrong_type('EventSpec_eventParList_val', H)
+ end;
+chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'EventSpec_eventParList_val'),
+ chk_EventSpec_eventParList(T1, T2);
+chk_EventSpec_eventParList(EPL1, EPL2) ->
+ wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% -- SignalsDescriptor --
+
+is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SignalsDescriptor(D) ->
+ is_SignalsDescriptor(D).
+
+is_SignalsDescriptor([]) ->
+ true;
+is_SignalsDescriptor([H|T]) ->
+ is_SignalRequest(H) andalso is_SignalsDescriptor(T);
+is_SignalsDescriptor(_) ->
+ false.
+
+chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalsDescriptor(D1, D2) ->
+ chk_SignalsDescriptor(D1, D2).
+
+chk_SignalsDescriptor([], []) ->
+ ok;
+chk_SignalsDescriptor([] = D1, D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor(D1, [] = D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor([H|T1], [H|T2]) ->
+ case is_SignalRequest(H) of
+ true ->
+ chk_SignalsDescriptor(T1, T2);
+ false ->
+ wrong_type('SignalsDescriptor_val', H)
+ end;
+chk_SignalsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SignalRequest(H1, H2) end, 'SignalsDescriptor_val'),
+ chk_SignalsDescriptor(T1, T2);
+chk_SignalsDescriptor(D1, D2) ->
+ wrong_type('SignalsDescriptor', D1, D2).
+
+
+%% -- SignalRequest --
+
+is_SignalRequest({Tag, Val}) ->
+ is_SignalRequest_tag(Tag) andalso is_SignalRequest_val(Tag, Val);
+is_SignalRequest(_) ->
+ false.
+
+is_SignalRequest_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_SignalRequest_val(signal, Val) ->
+ is_Signal(Val);
+is_SignalRequest_val(seqSigList, Val) ->
+ is_SeqSigList(Val).
+
+chk_SignalRequest(R, R) ->
+ chk_type(fun is_SignalRequest/1, 'SignalRequest', R);
+chk_SignalRequest({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_SignalRequest_tag(Tag) andalso
+ is_SignalRequest_val(Tag, Val1) andalso
+ is_SignalRequest_val(Tag, Val2)) of
+ true ->
+ chk_SignalRequest_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_SignalRequest_tag(Tag1) andalso
+ is_SignalRequest_val(Tag1, Val1)) andalso
+ (is_SignalRequest_tag(Tag2) andalso
+ is_SignalRequest_val(Tag2, Val2))) of
+ true ->
+ not_equal('SignalRequest', R1, R2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest(R1, R2) ->
+ wrong_type('SignalRequest', R1, R2).
+
+chk_SignalRequest_val(signal, Val1, Val2) ->
+ validate(fun() -> chk_Signal(Val1, Val2) end, 'SignalRequest');
+chk_SignalRequest_val(seqSigList, Val1, Val2) ->
+ validate(fun() -> chk_SeqSigList(Val1, Val2) end, 'SignalRequest').
+
+
+%% -- SeqSigList --
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+chk_SeqSigList(L, L) ->
+ chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+chk_SeqSigList(#'SeqSigList'{id = ID1,
+ signalList = SL1},
+ #'SeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+ 'SeqSigList'),
+ chk_SeqSigList_signalList(SL1, SL2),
+ ok;
+chk_SeqSigList(L1, L2) ->
+ wrong_type('SeqSigList', L1, L2).
+
+chk_SeqSigList_signalList([], []) ->
+ ok;
+chk_SeqSigList_signalList([] = L1, L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList(L1, [] = L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+ case is_Signal(H) of
+ true ->
+ chk_SeqSigList_signalList(T1, T2);
+ false ->
+ wrong_type('SeqSigList_signalList_val', H)
+ end;
+chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Signal(H1, H2) end,
+ 'SeqSigList_signalList_val'),
+ chk_SeqSigList_signalList(T1, T2);
+chk_SeqSigList_signalList(L1, L2) ->
+ wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}) ->
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL) andalso
+ is_opt_SignalDirection(Dir) andalso
+ is_opt_RequestID(RID).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+chk_Signal(S, S) ->
+ chk_type(fun is_Signal/1, 'Signal', S);
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = SID1,
+ sigType = ST1,
+ duration = Dur1,
+ notifyCompletion = NC1,
+ keepActive = KA1,
+ sigParList = SPL1,
+ direction = Dir1,
+ requestID = RID1},
+ #'Signal'{signalName = N2,
+ streamID = SID2,
+ sigType = ST2,
+ duration = Dur2,
+ notifyCompletion = NC2,
+ keepActive = KA2,
+ sigParList = SPL2,
+ direction = Dir2,
+ requestID = RID2}) ->
+ validate(fun() -> chk_SignalName(N1, N2) end, 'Signal'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'Signal'),
+ validate(fun() -> chk_opt_SignalType(ST1, ST2) end, 'Signal'),
+ validate(fun() -> chk_opt_INTEGER(Dur1, Dur2, {range, 0, 65535}) end,
+ 'Signal'),
+ validate(fun() -> chk_opt_NotifyCompletion(NC1, NC2) end, 'Signal'),
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'Signal'),
+ chk_Signal_sigParList(SPL1, SPL2),
+ validate(fun() -> chk_opt_SignalDirection(Dir1, Dir2) end, 'Signal'),
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'Signal'),
+ ok;
+chk_Signal(S1, S2) ->
+ wrong_type('Signal', S1, S2).
+
+chk_Signal_sigParList([], []) ->
+ ok;
+chk_Signal_sigParList([] = L1, L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList(L1, [] = L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList([H|T1], [H|T2]) ->
+ case is_SigParameter(H) of
+ true ->
+ chk_Signal_sigParList(T1, T2);
+ false ->
+ wrong_type('Signal_sigParList_val', H)
+ end;
+chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SigParameter(H1, H2) end,
+ 'Signal_sigParList_val'),
+ chk_Signal_sigParList(T1, T2);
+chk_Signal_sigParList(L1, L2) ->
+ wrong_type('Signal_sigParList', L1, L2).
+
+
+%% -- SignalType --
+
+is_opt_SignalType(T) ->
+ is_OPTIONAL(fun is_SignalType/1, T).
+
+is_SignalType(T) ->
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+chk_opt_SignalType(T1, T2) ->
+ chk_OPTIONAL('SignalType', T1, T2,
+ fun is_SignalType/1, fun chk_SignalType/2).
+
+chk_SignalType(T, T) ->
+ chk_type(fun is_SignalType/1, 'SignalType', T);
+chk_SignalType(T1, T2) ->
+ case (is_SignalType(T1) andalso is_SignalType(T2)) of
+ true ->
+ not_equal('SignalType', T1, T2);
+ false ->
+ wrong_type('SignalType', T1, T2)
+ end.
+
+
+%% -- SignalDirection --
+
+is_opt_SignalDirection(T) ->
+ is_OPTIONAL(fun is_SignalDirection/1, T).
+
+is_SignalDirection(Dir) ->
+ Dirs = [internal, external, both],
+ lists:member(Dir, Dirs).
+
+chk_opt_SignalDirection(T1, T2) ->
+ chk_OPTIONAL('SignalDirection', T1, T2,
+ fun is_SignalDirection/1, fun chk_SignalDirection/2).
+
+chk_SignalDirection(Dir, Dir) ->
+ chk_type(fun is_SignalDirection/1, 'SignalDirection', Dir);
+chk_SignalDirection(Dir1, Dir2) ->
+ case (is_SignalDirection(Dir1) andalso is_SignalDirection(Dir2)) of
+ true ->
+ not_equal('SignalDirection', Dir1, Dir2);
+ false ->
+ wrong_type('SignalDirection', Dir1, Dir2)
+ end.
+
+
+%% -- SignalName --
+
+is_SignalName(N) -> is_PkgdName(N).
+
+chk_SignalName(N1, N2) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:all(fun(X) -> lists:member(X, Valids) end, NC).
+
+chk_opt_NotifyCompletion(NC1, NC2) ->
+ chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+ fun is_NotifyCompletion/1,
+ fun chk_NotifyCompletion/2).
+
+chk_NotifyCompletion(NC, NC) ->
+ chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+chk_NotifyCompletion(NC1, NC2) ->
+ case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+ true ->
+ not_equal('NotifyCompletion', NC1, NC2);
+ false ->
+ wrong_type('NotifyCompletion', NC1, NC2)
+ end.
+
+
+%% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_SigParameter(P, P) ->
+ chk_type(fun is_SigParameter/1, 'SigParameter', P);
+chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = I1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+ validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+ chk_SigParameter_extraInfo(I1, I2),
+ ok;
+chk_SigParameter(P1, P2) ->
+ wrong_type('SigParameter', P1, P2).
+
+chk_SigParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_SigParameter_extraInfo_tag(Tag) and
+ is_SigParameter_extraInfo_val(Tag, Val1) and
+ is_SigParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_SigParameter_extraInfo_tag(Tag1) and
+ is_SigParameter_extraInfo_val(Tag1, Val1)) and
+ (is_SigParameter_extraInfo_tag(Tag2) and
+ is_SigParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('SigParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo(EI1, EI2) ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% -- RequestID --
+
+is_opt_RequestID(asn1_NOVALUE) ->
+ true;
+is_opt_RequestID(V) ->
+ is_RequestID(V).
+
+is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestID(V1, V2) ->
+ chk_RequestID(V1, V2).
+
+chk_RequestID(ID, ID) ->
+ chk_type(fun is_RequestID/1, 'RequestID', ID);
+chk_RequestID(ID1, ID2) ->
+ case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+ true ->
+ not_equal('RequestID', ID1, ID2);
+ false ->
+ wrong_type('RequestID', ID1, ID2)
+ end.
+
+
+%% -- ModemDescriptor --
+
+is_ModemDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ true;
+is_ModemDescriptor(_) ->
+ false.
+
+chk_ModemDescriptor(D, D) when is_record(D, 'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+ mpl = MPL1,
+ nonStandardData = NSD1},
+ #'ModemDescriptor'{mtl = MTL2,
+ mpl = MPL2,
+ nonStandardData = NSD2}) ->
+ chk_ModemDescriptor_mtl(MTL1, MTL2),
+ chk_ModemDescriptor_mpl(MPL1, MPL2),
+ chk_opt_NonStandardData(NSD1, NSD2),
+ ok;
+chk_ModemDescriptor(D1, D2) ->
+ wrong_type('ModemDescriptor', D1, D2).
+
+chk_ModemDescriptor_mtl([], []) ->
+ ok;
+chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+ case is_ModemType(H) of
+ true ->
+ chk_ModemDescriptor_mtl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mtl_val', H)
+ end;
+chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+ chk_ModemDescriptor_mtl(T1, T2);
+chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+ wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+chk_ModemDescriptor_mpl([], []) ->
+ ok;
+chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ModemDescriptor_mpl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mpl_val', H)
+ end;
+chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+ chk_ModemDescriptor_mpl(T1, T2);
+chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+ wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% -- ModemType --
+
+chk_ModemType(MT, MT) ->
+ case is_ModemType(MT) of
+ true ->
+ ok;
+ false ->
+ wrong_type('ModemType', MT, MT)
+ end;
+chk_ModemType(MT1, MT2) ->
+ case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+ true ->
+ not_equal('ModemType', MT1, MT2);
+ false ->
+ wrong_type('ModemType', MT1, MT2)
+ end.
+
+is_ModemType(MT) ->
+ lists:member(MT,
+ [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% -- DigitMapDescriptor --
+
+is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Val}) ->
+ is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+is_DigitMapDescriptor(_) ->
+ false.
+
+chk_DigitMapDescriptor(D, D) ->
+ chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+ digitMapValue = Val1},
+ #'DigitMapDescriptor'{digitMapName = Name2,
+ digitMapValue = Val2}) ->
+ d("chk_DigitMapDescriptor -> entry with"
+ "~n Name1: ~p"
+ "~n Name2: ~p"
+ "~n Val1: ~p"
+ "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'DigitMapDescriptor'),
+ validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+ 'DigitMapDescriptor'),
+ ok;
+chk_DigitMapDescriptor(D1, D2) ->
+ wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% -- DigitMapName --
+
+is_opt_DigitMapName(asn1_NOVALUE) ->
+ true;
+is_opt_DigitMapName(N) ->
+ is_DigitMapName(N).
+
+is_DigitMapName(N) -> is_Name(N).
+
+chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_DigitMapName(N1, N2) ->
+ chk_DigitMapName(N1, N2).
+
+chk_DigitMapName(N, N) ->
+ chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+chk_DigitMapName(N1, N2) ->
+ case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+ true ->
+ not_equal('DigitMapName', N1, N2);
+ false ->
+ wrong_type('DigitMapName', N1, N2)
+ end.
+
+
+%% -- DigitMapValue --
+
+is_opt_DigitMapValue(V) ->
+ is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Dur}) ->
+ is_DigitMapValue_startTimer(Start) andalso
+ is_DigitMapValue_shortTimer(Short) andalso
+ is_DigitMapValue_longTimer(Long) andalso
+ is_IA5String(Body) andalso
+ is_DigitMapValue_durationTimer(Dur);
+is_DigitMapValue(_) ->
+ false.
+
+is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+chk_opt_DigitMapValue(V1, V2) ->
+ chk_OPTIONAL('DigitMapValue', V1, V2,
+ fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1,
+ digitMapBody = Body1,
+ durationTimer = Dur1},
+ #'DigitMapValue'{startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2,
+ digitMapBody = Body2,
+ durationTimer = Dur2}) ->
+ d("chk_DigitMapValue -> entry with"
+ "~n Start1: ~p"
+ "~n Start2: ~p"
+ "~n Short1: ~p"
+ "~n Short2: ~p"
+ "~n Long1: ~p"
+ "~n Long2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p"
+ "~n Dur1: ~p"
+ "~n Dur2: ~p", [Start1, Start2,
+ Short1, Short2,
+ Long1, Long2,
+ Body1, Body2,
+ Dur1, Dur2]),
+ chk_DigitMapValue_startTimer(Start1, Start2),
+ chk_DigitMapValue_shortTimer(Short1, Short2),
+ chk_DigitMapValue_longTimer(Long1, Long2),
+ chk_DigitMapValue_digitMapBody(Body1, Body2),
+ chk_DigitMapValue_durationTimer(Dur1, Dur2),
+ ok;
+chk_DigitMapValue(V1, V2) ->
+ wrong_type('DigitMapValue', V1, V2).
+
+chk_DigitMapValue_startTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+chk_DigitMapValue_startTimer(T1, T2) ->
+ case (is_DigitMapValue_startTimer(T1) andalso
+ is_DigitMapValue_startTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_startTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_startTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_shortTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+chk_DigitMapValue_shortTimer(T1, T2) ->
+ case (is_DigitMapValue_shortTimer(T1) andalso
+ is_DigitMapValue_shortTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_shortTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_shortTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_longTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+chk_DigitMapValue_longTimer(T1, T2) ->
+ case (is_DigitMapValue_longTimer(T1) andalso
+ is_DigitMapValue_longTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_longTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_longTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_durationTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_durationTimer/1,
+ 'DigitMapValue_durationTimer', T);
+chk_DigitMapValue_durationTimer(T1, T2) ->
+ case (is_DigitMapValue_durationTimer(T1) andalso
+ is_DigitMapValue_durationTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_durationTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_durationTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_digitMapBody(B, B) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B: ~p", [B]),
+ chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+chk_DigitMapValue_digitMapBody(B1, B2) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B1: ~p"
+ "~n B2: ~p", [B1, B2]),
+ case (is_IA5String(B1) andalso is_IA5String(B2)) of
+ true ->
+ %% If they are different it could be because
+ %% of trailing tab's and newline's.
+ case compare_strings(B1, B2) of
+ {[], []} ->
+ ok;
+ {Str1, []} ->
+ case strip_tab_and_newline(Str1) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ {[], Str2} ->
+ case strip_tab_and_newline(Str2) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ false ->
+ wrong_type('DigitMapValue_digitMapBody', B1, B2)
+ end.
+
+%% -- ServiceChangeParm --
+
+is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Id,
+ timeStamp = TS,
+ nonStandardData = NSD,
+ serviceChangeInfo = I}) ->
+ is_ServiceChangeMethod(M) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_Value(R) andalso
+ is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+ is_opt_MId(Id) andalso
+ is_opt_TimeNotation(TS) andalso
+ is_opt_NonStandardData(NSD) andalso
+ is_opt_AuditDescriptor(I);
+is_ServiceChangeParm(_) ->
+ false.
+
+chk_ServiceChangeParm(P, P) ->
+ chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Id1,
+ timeStamp = TS1,
+ nonStandardData = NSD1,
+ serviceChangeInfo = I1},
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Id2,
+ timeStamp = TS2,
+ nonStandardData = NSD2,
+ serviceChangeInfo = I2}) ->
+ validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_Value(R1, R2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_MId(Id1, Id2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+ 'ServiceChangeParm'),
+ ok;
+chk_ServiceChangeParm(P1, P2) ->
+ wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% -- ServiceChangeAddress --
+
+is_opt_ServiceChangeAddress(A) ->
+ is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+is_ServiceChangeAddress({Tag, Val}) ->
+ is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val);
+is_ServiceChangeAddress(_) ->
+ false.
+
+is_ServiceChangeAddress_tag(Tag) ->
+ Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+ mtpAddress],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeAddress_val(portNumber, Val) ->
+ is_INTEGER(Val, {range, 0, 65535});
+is_ServiceChangeAddress_val(ip4Address, Val) ->
+ is_IP4Address(Val);
+is_ServiceChangeAddress_val(ip6Address, Val) ->
+ is_IP6Address(Val);
+is_ServiceChangeAddress_val(domainName, Val) ->
+ is_DomainName(Val);
+is_ServiceChangeAddress_val(deviceName, Val) ->
+ is_PathName(Val);
+is_ServiceChangeAddress_val(mtpAddress, Val) ->
+ is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+chk_opt_ServiceChangeAddress(A1, A2) ->
+ chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+ fun is_ServiceChangeAddress/1,
+ fun chk_ServiceChangeAddress/2).
+
+chk_ServiceChangeAddress(A, A) ->
+ chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+ case (is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val1) andalso
+ is_ServiceChangeAddress_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+ case ((is_ServiceChangeAddress_tag(Tag1) andalso
+ is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+ (is_ServiceChangeAddress_tag(Tag2) andalso
+ is_ServiceChangeAddress_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeAddress', A1, A2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress(A1, A2) ->
+ wrong_type('ServiceChangeAddress', A1, A2).
+
+chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+ validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+ validate(fun() -> chk_IP4Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+ validate(fun() -> chk_IP6Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+ validate(fun() -> chk_DomainName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+ validate(fun() -> chk_PathName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+ validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+ 'ServiceChangeAddress').
+
+
+%% -- ServiceChangeResParm --
+
+is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ timeStamp = TS}) ->
+ is_opt_MId(Id) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_opt_TimeNotation(TS);
+is_ServiceChangeResParm(_) ->
+ false.
+
+chk_ServiceChangeResParm(P, P) ->
+ chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+chk_ServiceChangeResParm(
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ timeStamp = TS1},
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ timeStamp = TS2}) ->
+ validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeResParm'),
+ ok;
+chk_ServiceChangeResParm(P1, P2) ->
+ wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% -- ServiceChangeMethod --
+
+is_ServiceChangeMethod(M) ->
+ Methods = [failover, forced, graceful, restart, disconnected, handOff],
+ lists:member(M, Methods).
+
+chk_ServiceChangeMethod(M, M) ->
+ chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+chk_ServiceChangeMethod(M1, M2) ->
+ case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+ true ->
+ not_equal('ServiceChangeMethod', M1, M2);
+ false ->
+ wrong_type('ServiceChangeMethod', M1, M2)
+ end.
+
+
+%% -- ServiceChangeProfile --
+
+is_opt_ServiceChangeProfile(P) ->
+ is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+ is_IA5String(N, {range, 1, 67});
+is_ServiceChangeProfile(_) ->
+ false.
+
+chk_opt_ServiceChangeProfile(P1, P2) ->
+ chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+ fun is_ServiceChangeProfile/1,
+ fun chk_ServiceChangeProfile/2).
+
+chk_ServiceChangeProfile(P, P) ->
+ chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+ #'ServiceChangeProfile'{profileName = N2}) ->
+ validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+ 'ServiceChangeProfile'),
+ ok;
+chk_ServiceChangeProfile(P1, P2) ->
+ wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% -- PackagesDescriptor --
+
+is_PackagesDescriptor([]) ->
+ true;
+is_PackagesDescriptor([H|T]) ->
+ is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+is_PackagesDescriptor(_) ->
+ false.
+
+chk_PackagesDescriptor([], []) ->
+ ok;
+chk_PackagesDescriptor([] = D1, D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor(D1, [] = D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor([H|T1], [H|T2]) ->
+ case is_PackagesItem(H) of
+ true ->
+ chk_PackagesDescriptor(T1, T2);
+ false ->
+ wrong_type('PackagesDescriptor_val', H)
+ end;
+chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PackagesItem(H1, H2) end,
+ 'PackagesDescriptor_val'),
+ chk_PackagesDescriptor(T1, T2);
+chk_PackagesDescriptor(D1, D2) ->
+ wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% -- PackagesItem --
+
+is_PackagesItem(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+is_PackagesItem(_) ->
+ false.
+
+chk_PackagesItem(I, I) ->
+ chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+chk_PackagesItem(#'PackagesItem'{packageName = N1,
+ packageVersion = V1},
+ #'PackagesItem'{packageName = N2,
+ packageVersion = V2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+ ok;
+chk_PackagesItem(I1, I2) ->
+ wrong_type('PackagesItem', I1, I2).
+
+
+%% -- StatisticsDescriptor --
+
+is_opt_StatisticsDescriptor(D) ->
+ is_OPTIONAL(fun is_StatisticsDescriptor/1, D).
+
+is_StatisticsDescriptor([]) ->
+ true;
+is_StatisticsDescriptor([H|T]) ->
+ is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+is_StatisticsDescriptor(_) ->
+ false.
+
+chk_opt_StatisticsDescriptor(D1, D2) ->
+ chk_OPTIONAL('StatisticsDescriptor', D1, D2,
+ fun is_StatisticsDescriptor/1,
+ fun chk_StatisticsDescriptor/2).
+
+chk_StatisticsDescriptor([], []) ->
+ ok;
+chk_StatisticsDescriptor([] = D1, D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor(D1, [] = D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+ case is_StatisticsParameter(H) of
+ true ->
+ chk_StatisticsDescriptor(T1, T2);
+ false ->
+ wrong_type('StatisticsDescriptor_val', H)
+ end;
+chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+ 'StatisticsDescriptor_val'),
+ chk_StatisticsDescriptor(T1, T2);
+chk_StatisticsDescriptor(D1, D2) ->
+ wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% -- StatisticsParameter --
+
+is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+ statValue = V}) ->
+ is_PkgdName(N) andalso is_opt_Value(V);
+is_StatisticsParameter(_) ->
+ false.
+
+chk_StatisticsParameter(P, P) ->
+ chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+ statValue = V1},
+ #'StatisticsParameter'{statName = N2,
+ statValue = V2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+ validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+ ok;
+chk_StatisticsParameter(P1, P2) ->
+ wrong_type('StatisticsParameter', P1, P2).
+
+
+%% -- NonStandardData --
+
+is_opt_NonStandardData(asn1_NOVALUE) ->
+ true;
+is_opt_NonStandardData(NSD) ->
+ is_NonStandardData(NSD).
+
+%% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% data = D}) ->
+%% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% is_NonStandardData(_) ->
+%% false.
+
+is_NonStandardData(_) ->
+ true.
+
+chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+ true;
+chk_opt_NonStandardData(NSD1, NSD2) ->
+ chk_NonStandardData(NSD1, NSD2).
+
+chk_NonStandardData(NSD, NSD) ->
+ chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% data = D1},
+%% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% data = D2}) ->
+%% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% 'NonStandardData'),
+%% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% ok;
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% wrong_type('NonStandardData', NSD1, NSD2).
+chk_NonStandardData(NSD1, NSD2) ->
+ not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% -- NonStandardIdentifier --
+
+%% is_NonStandardIdentifier({Tag, Val}) ->
+%% is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val);
+%% is_NonStandardIdentifier(_) ->
+%% false.
+
+%% is_NonStandardIdentifier_tag(Tag) ->
+%% Tags = [object, h221NonStandard, experimental],
+%% lists:member(Tag, Tags).
+
+%% is_NonStandardIdentifier_val(object, Val) ->
+%% is_OBJECT_IDENTIFIER(Val);
+%% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% is_H221NonStandard(Val);
+%% is_NonStandardIdentifier_val(experimental, Val) ->
+%% is_IA5String(Val, {exact, 8}).
+
+%% chk_NonStandardIdentifier(Id, Id) ->
+%% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% true ->
+%% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% true ->
+%% not_equal('NonStandardIdentifier', Id1, Id2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier(Id1, Id2) ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% chk_H221NonStandard(Val1, Val2);
+%% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% -- H221NonStandard --
+
+%% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}) ->
+%% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 65535});
+%% is_H221NonStandard(_) ->
+%% false.
+
+%% chk_H221NonStandard(NS, NS) ->
+%% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% t35CountryCode2 = CC21,
+%% t35Extension = Ext1,
+%% manufacturerCode = MC1},
+%% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% t35CountryCode2 = CC22,
+%% t35Extension = Ext2,
+%% manufacturerCode = MC2}) ->
+%% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% 'H221NonStandard'),
+%% ok;
+%% chk_H221NonStandard(NS1, NS2) ->
+%% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% -- TimeNotation --
+
+is_opt_TimeNotation(asn1_NOVALUE) ->
+ true;
+is_opt_TimeNotation(TN) ->
+ is_TimeNotation(TN).
+
+is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+ is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+is_TimeNotation(_) ->
+ false.
+
+chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(TN1, TN2) ->
+ chk_TimeNotation(TN1, TN2).
+
+chk_TimeNotation(TN, TN) ->
+ chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+ #'TimeNotation'{date = D2, time = T2}) ->
+ validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+ validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+ ok;
+chk_TimeNotation(TN1, TN2) ->
+ wrong_type('TimeNotation', TN1, TN2).
+
+
+%% -- Value --
+
+is_opt_Value(V) ->
+ is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+chk_opt_Value(V1, V2) ->
+ chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+chk_Value(V, V) ->
+ case is_Value(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Value', V, V)
+ end;
+chk_Value(V1, V2) ->
+ case (is_Value(V1) andalso is_Value(V2)) of
+ true ->
+ not_equal('Value', V1, V2);
+ false ->
+ wrong_type('Value', V1, V2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Basic type check functions
+%% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ lists:member(B, [true, false]).
+
+chk_opt_BOOLEAN(B1, B2) ->
+ chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+chk_BOOLEAN(B, B) ->
+ chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+chk_BOOLEAN(B1, B2) ->
+ case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+ true ->
+ not_equal('BOOLEAN', B1, B2);
+ false ->
+ wrong_type('BOOLEAN', B1, B2)
+ end.
+
+
+is_IA5String(S) when is_list(S) ->
+ true;
+is_IA5String(_) ->
+ false.
+
+% chk_IA5String(S, S) ->
+% chk_type(fun is_IA5String/1, 'IA5String', S);
+% chk_IA5String(S1, S2) ->
+% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+% true ->
+% not_equal('IA5String', S1, S2);
+% false ->
+% wrong_type('IA5String', S1, S2)
+% end.
+
+is_IA5String(S, _) when is_list(S) ->
+ true;
+is_IA5String(_, _) ->
+ false.
+
+chk_IA5String(S, S, R) ->
+ chk_type(fun is_IA5String/2, 'IA5String', S, R);
+chk_IA5String(S1, S2, R) ->
+ case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+ true ->
+ not_equal('IA5String', S1, S2);
+ false ->
+ wrong_type('IA5String', S1, S2)
+ end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) andalso (length(L) =:= Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) andalso (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) andalso (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) andalso (Min =< length(L)) andalso (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% chk_OCTET_STRING(L1, L2) ->
+%% chk_OCTET_STRING(L1, L2, any).
+
+chk_OCTET_STRING(L, L, R) ->
+ chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+chk_OCTET_STRING(L1, L2, R) ->
+ case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+ true ->
+ not_equal('OCTET STRING', L1, L2);
+ false ->
+ wrong_type('OCTET STRING', L1, L2)
+ end.
+
+
+%% is_OBJECT_IDENTIFIER(_) ->
+%% true.
+
+%% chk_OBJECT_IDENTIFIER(X, X) ->
+%% ok;
+%% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+is_opt_NULL(N) ->
+ is_OPTIONAL(fun is_NULL/1, N).
+
+is_NULL('NULL') ->
+ true;
+is_NULL(_) ->
+ false.
+
+chk_opt_NULL(N1, N2) ->
+ chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+chk_NULL(N, N) ->
+ chk_type(fun is_NULL/1, 'NULL', N);
+chk_NULL(N1, N2) ->
+ case (is_NULL(N1) andalso is_NULL(N2)) of
+ true ->
+ not_equal('NULL', N1, N2);
+ false ->
+ wrong_type('NULL', N1, N2)
+ end.
+
+
+is_opt_INTEGER(I, R) ->
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min}) when is_integer(I) andalso is_integer(Min) andalso (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max}) when is_integer(I) andalso is_integer(Max) andalso (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Min =< I) andalso (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+chk_opt_INTEGER(I1, I2, R) ->
+ chk_OPTIONAL('INTEGER', I1, I2,
+ fun(X) -> is_INTEGER(X, R) end,
+ fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+chk_INTEGER(I, I, R) ->
+ chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+chk_INTEGER(I1, I2, R) ->
+ case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+ true ->
+ not_equal('INTEGER', I1, I2);
+ false ->
+ wrong_type('INTEGER', I1, I2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Various utility functions
+%% ----------------------------------------------------------------------
+
+
+to_lower([C|Cs]) when (C >= $A) andalso (C =< $Z) ->
+ [C+($a-$A)|to_lower(Cs)];
+to_lower([C|Cs]) ->
+ [C|to_lower(Cs)];
+to_lower([]) ->
+ [].
+
+
+validate(F, Type) when is_function(F) ->
+ case (catch F()) of
+ {error, Reason} ->
+ error({Type, Reason});
+ ok ->
+ ok
+ end.
+
+
+chk_type(F, T, V) when is_function(F) andalso is_atom(T) ->
+ case F(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V)
+ end.
+
+chk_type(F, T, V1, V2) when is_function(F) andalso is_atom(T) ->
+ case F(V1, V2) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V1)
+ end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+ ok;
+chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when is_function(IS) ->
+ case IS(V2) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when is_function(IS) ->
+ case IS(V1) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when is_function(CHK) ->
+ CHK(V1, V2).
+
+
+%% ----------------------------------------------------------------------
+
+compare_strings([] = L1, L2) ->
+ {L1, L2};
+compare_strings(L1, [] = L2) ->
+ {L1, L2};
+compare_strings([H|T1], [H|T2]) ->
+ compare_strings(T1, T2);
+compare_strings(L1, L2) ->
+ {L1, L2}.
+
+strip_tab_and_newline([]) ->
+ [];
+strip_tab_and_newline([$\n|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([$\t|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([H|T]) ->
+ [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+atmost_once(Type, Val) ->
+ error({atmost_once, {Type, Val}}).
+
+wrong_type(Type, Val) ->
+ error({wrong_type, {Type, Val}}).
+
+wrong_type(Type, Val1, Val2) ->
+ error({wrong_type, {Type, Val1, Val2}}).
+
+not_equal(What, Val1, Val2) ->
+ error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_msg_prev3c_lib.erl b/lib/megaco/test/megaco_test_msg_prev3c_lib.erl
new file mode 100644
index 0000000000..74a05060d0
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_prev3c_lib.erl
@@ -0,0 +1,8643 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_prev3c_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_prev3c.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([chk_MegacoMessage/2,
+
+ cre_MegacoMessage/1,
+ cre_MegacoMessage/2,
+
+ cre_ActionReply/2,
+ cre_ActionReply/3,
+ cre_ActionReply/4,
+ cre_ActionRequest/2,
+ cre_ActionRequest/3,
+ cre_ActionRequest/4,
+ cre_AmmDescriptor/1,
+ cre_AmmRequest/2,
+ cre_AmmsReply/1,
+ cre_AmmsReply/2,
+ cre_AuditDescriptor/0,
+ cre_AuditDescriptor/1,
+ cre_AuditDescriptor/2,
+ cre_AuditReply/1,
+ cre_AuditRequest/2,
+ cre_AuditRequest/3,
+ cre_AuditResult/2,
+ cre_AuditReturnParameter/1,
+ cre_AuthenticationHeader/3,
+ cre_BOOLEAN/1,
+ cre_Command/2,
+ cre_CommandReply/2,
+ cre_CommandRequest/1,
+ cre_CommandRequest/2,
+ cre_CommandRequest/3,
+ cre_ContextAttrAuditRequest/0,
+ cre_ContextAttrAuditRequest/3,
+ cre_ContextAttrAuditRequest/4,
+ cre_ContextAttrAuditRequest/5,
+ cre_ContextAttrAuditRequest/6,
+ cre_ContextAttrAuditRequest/7,
+ cre_ContextAttrAuditRequest/8,
+ cre_ContextAttrAuditRequest/9,
+ cre_ContextID/1,
+ cre_ContextRequest/0,
+ cre_ContextRequest/1,
+ cre_ContextRequest/2,
+ cre_ContextRequest/3,
+ cre_ContextRequest/4,
+ cre_ContextRequest/5,
+ cre_ContextRequest/6,
+ cre_DigitMapDescriptor/0,
+ cre_DigitMapDescriptor/1,
+ cre_DigitMapDescriptor/2,
+ cre_DigitMapName/1,
+ cre_DigitMapValue/1,
+ cre_DigitMapValue/4,
+ cre_DigitMapValue/5,
+ cre_ErrorCode/1,
+ cre_ErrorDescriptor/1,
+ cre_ErrorDescriptor/2,
+ cre_ErrorText/1,
+ cre_EventBufferControl/1,
+ cre_EventBufferDescriptor/1,
+ cre_EventDM/1,
+ cre_EventName/1,
+ cre_EventParameter/2,
+ cre_EventParameter/4,
+ cre_EventsDescriptor/0,
+ cre_EventsDescriptor/2,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+ %% cre_H221NonStandard/4,
+ cre_IndAuditParameter/1,
+ cre_IndAudLocalControlDescriptor/0,
+ cre_IndAudLocalControlDescriptor/4,
+ cre_IndAudLocalControlDescriptor/5,
+ cre_IndAudLocalRemoteDescriptor/1,
+ cre_IndAudLocalRemoteDescriptor/2,
+ cre_IndAudMediaDescriptor/0,
+ cre_IndAudMediaDescriptor/1,
+ cre_IndAudMediaDescriptor/2,
+ cre_IndAudPropertyGroup/1,
+ cre_IndAudPropertyParm/1,
+ cre_IndAudPropertyParm/2,
+ cre_IndAudDigitMapDescriptor/0,
+ cre_IndAudDigitMapDescriptor/1,
+ cre_IndAudEventBufferDescriptor/1,
+ cre_IndAudEventBufferDescriptor/2,
+ cre_IndAudEventsDescriptor/1,
+ cre_IndAudEventsDescriptor/2,
+ cre_IndAudEventsDescriptor/3,
+ cre_IndAudPackagesDescriptor/2,
+ cre_IndAudSeqSigList/1,
+ cre_IndAudSeqSigList/2,
+ cre_IndAudSignal/1,
+ cre_IndAudSignal/2,
+ cre_IndAudSignalsDescriptor/1,
+ cre_IndAudStatisticsDescriptor/1,
+ cre_IndAudStreamDescriptor/2,
+ cre_IndAudStreamParms/0,
+ cre_IndAudStreamParms/1,
+ cre_IndAudStreamParms/3,
+ cre_IndAudStreamParms/4,
+ cre_IndAudTerminationStateDescriptor/1,
+ cre_IndAudTerminationStateDescriptor/3,
+ cre_IndAudTerminationStateDescriptor/4,
+ cre_LocalControlDescriptor/1,
+ cre_LocalControlDescriptor/2,
+ cre_LocalControlDescriptor/4,
+ cre_LocalRemoteDescriptor/1,
+ cre_MediaDescriptor/0,
+ cre_MediaDescriptor/1,
+ cre_MediaDescriptor/2,
+ cre_Message/3,
+ cre_ModemDescriptor/2,
+ %% cre_ModemDescriptor/3,
+ cre_ModemType/1,
+ cre_MuxDescriptor/2,
+ %% cre_MuxDescriptor/3,
+ cre_MuxType/1,
+ cre_Name/1,
+ %% cre_NonStandardData/2,
+ %% cre_NonStandardIdentifier/1,
+ cre_NotifyBehaviour/2,
+ cre_NotifyCompletion/1,
+ cre_NotifyReply/1,
+ cre_NotifyReply/2,
+ cre_NotifyRequest/2,
+ cre_NotifyRequest/3,
+ cre_ObservedEvent/2,
+ cre_ObservedEvent/3,
+ cre_ObservedEvent/4,
+ cre_ObservedEventsDescriptor/2,
+ cre_PackagesDescriptor/1,
+ cre_PackagesItem/2,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+ cre_PropertyGroup/1,
+ cre_PropertyParm/2,
+ cre_PropertyParm/4,
+ cre_RegulatedEmbeddedDescriptor/0,
+ cre_RegulatedEmbeddedDescriptor/1,
+ cre_RegulatedEmbeddedDescriptor/2,
+ cre_Relation/1,
+ cre_RequestedActions/0,
+ cre_RequestedActions/1,
+ cre_RequestedActions/4,
+ cre_RequestedActions/6,
+ cre_RequestedEvent/1,
+ cre_RequestedEvent/2,
+ cre_RequestedEvent/3,
+ cre_RequestedEvent/4,
+ cre_RequestID/1,
+ cre_SecondEventsDescriptor/1,
+ cre_SecondEventsDescriptor/2,
+ cre_SecondRequestedActions/0,
+ cre_SecondRequestedActions/1,
+ cre_SecondRequestedActions/2,
+ cre_SecondRequestedActions/3,
+ cre_SecondRequestedActions/5,
+ cre_SecondRequestedEvent/2,
+ cre_SecondRequestedEvent/3,
+ cre_SecondRequestedEvent/4,
+ cre_SelectLogic/1,
+ cre_SeqSigList/2,
+ cre_ServiceChangeAddress/2,
+ cre_ServiceChangeRequest/2,
+ cre_ServiceChangeMethod/1,
+ cre_ServiceChangeParm/2,
+ cre_ServiceChangeParm/4,
+ cre_ServiceChangeParm/9,
+ cre_ServiceChangeParm/10,
+ cre_ServiceChangeProfile/1,
+ cre_ServiceChangeProfile/2,
+ cre_ServiceChangeReply/2,
+ cre_ServiceChangeResParm/0,
+ cre_ServiceChangeResParm/2,
+ cre_ServiceChangeResParm/5,
+ cre_ServiceChangeResult/1,
+ cre_ServiceState/1,
+ cre_Signal/1,
+ cre_Signal/2,
+ cre_Signal/7,
+ cre_Signal/9,
+ cre_Signal/10,
+ cre_SignalDirection/1,
+ cre_SignalName/1,
+ cre_SignalRequest/1,
+ cre_SignalsDescriptor/1,
+ cre_SignalType/1,
+ cre_SigParameter/2,
+ cre_SigParameter/4,
+ cre_StatisticsDescriptor/1,
+ cre_StatisticsParameter/1,
+ cre_StatisticsParameter/2,
+ cre_StreamDescriptor/2,
+ cre_StreamID/1,
+ cre_StreamMode/1,
+ cre_StreamParms/0,
+ cre_StreamParms/1,
+ cre_StreamParms/2,
+ cre_StreamParms/3,
+ cre_StreamParms/4,
+ cre_SubtractRequest/1,
+ cre_SubtractRequest/2,
+ cre_TopologyRequest/3,
+ cre_TopologyRequest/4,
+ cre_TerminationAudit/1,
+ cre_TerminationID/2,
+ cre_TerminationIDList/1,
+ cre_TerminationStateDescriptor/1,
+ cre_TerminationStateDescriptor/2,
+ cre_TerminationStateDescriptor/3,
+ cre_TermListAuditResult/2,
+ cre_TimeNotation/2,
+ cre_Transaction/1,
+ cre_TransactionAck/1,
+ cre_TransactionAck/2,
+ cre_TransactionId/1,
+ cre_TransactionPending/1,
+ cre_TransactionReply/2,
+ cre_TransactionReply/3,
+ cre_TransactionRequest/2,
+ cre_Value/1
+ %% cre_WildcardField/1,
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') andalso is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+cre_AuthenticationHeader(SPI, SN, AD) ->
+ #'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+cre_ErrorDescriptor(EC) when is_integer(EC) ->
+ #'ErrorDescriptor'{errorCode = EC}.
+
+cre_ErrorDescriptor(EC, ET) when is_integer(EC) andalso is_list(ET) ->
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_ErrorCode(C) when is_integer(C) andalso (0 =< C) andalso (C =< 65535) ->
+ C;
+cre_ErrorCode(C) ->
+ exit({invalid_ErrorCode, C}).
+
+cre_ErrorText(T) when is_list(T) ->
+ T.
+
+cre_ContextID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA}.
+
+cre_TransactionId(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs) when is_integer(TransID) andalso is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+cre_TransactionPending(TransID) when is_integer(TransID) ->
+ #'TransactionPending'{transactionId = TransID}.
+
+cre_TransactionReply(TransID, ED)
+ when is_integer(TransID) andalso is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, ARs)
+ when is_integer(TransID) andalso is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionReply(TransID, IAR, ED)
+ when is_integer(TransID) andalso
+ ((IAR =:= 'NULL') orelse (IAR =:= asn1_NOVALUE)) andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, IAR, ARs)
+ when is_integer(TransID) andalso
+ ((IAR =:= 'NULL') orelse (IAR =:= asn1_NOVALUE)) andalso
+ is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionAck(FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck}.
+
+cre_TransactionAck(FirstAck, FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck};
+cre_TransactionAck(FirstAck, LastAck) ->
+ #'TransactionAck'{firstAck = FirstAck,
+ lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) andalso is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ (is_record(CtxReq, 'ContextRequest') or
+ (CtxReq == asn1_NOVALUE)) and
+ (is_record(CAAR, 'ContextAttrAuditRequest') or
+ (CAAR == asn1_NOVALUE)) and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionReply(CtxID, CmdReps)
+ when is_integer(CtxID) andalso is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CmdReps)
+ when is_integer(CtxID) andalso is_record(ED, 'ErrorDescriptor') andalso is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ commandReply = CmdReps};
+cre_ActionReply(CtxID, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ (is_record(ED, 'ErrorDescriptor') orelse (ED =:= asn1_NOVALUE)) andalso
+ (is_record(CtxReq, 'ContextRequest') orelse (CtxReq =:= asn1_NOVALUE)) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ContextRequest() ->
+ strip_ContextRequest(#'ContextRequest'{}).
+
+cre_ContextRequest(Prio) when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) ->
+ strip_ContextRequest(#'ContextRequest'{priority = Prio});
+cre_ContextRequest(Em) when (Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE) ->
+ strip_ContextRequest(#'ContextRequest'{emergency = Em});
+cre_ContextRequest(Top) when is_list(Top) ->
+ strip_ContextRequest(#'ContextRequest'{topologyReq = Top}).
+
+cre_ContextRequest(Prio, Em)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Top)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) andalso is_list(Top) ->
+ CR = #'ContextRequest'{priority = Prio,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Em, Top, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ (is_list(Ctx)) ->
+ CR =
+ case context_list_or_prop(Ctx) of
+ contextProp ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextProp = Ctx};
+ contextList ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextList = Ctx}
+ end,
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, Ctx)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx)) ->
+ CR =
+ case context_list_or_prop(Ctx) of
+ contextProp ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Ctx};
+ contextList ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextList = Ctx}
+ end,
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, CtxProp, CtxList)
+ when ((is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) or
+ (Prio == asn1_NOVALUE)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ (is_list(Top) or (Top == asn1_NOVALUE)) and
+ ((Ieps == true) or (Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ (is_list(CtxProp) or (CtxProp == asn1_NOVALUE)) and
+ (is_list(CtxList) or (CtxList == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = CtxProp,
+ contextList = CtxList},
+ strip_ContextRequest(CR).
+
+context_list_or_prop(asn1_NOVALUE) ->
+ contextProp;
+context_list_or_prop([]) ->
+ contextProp;
+context_list_or_prop([H|T]) ->
+ case is_ContextID(H) of
+ true ->
+ context_list_or_prop(T, contextList);
+ false ->
+ context_list_or_prop(T, contextProp)
+ end.
+
+context_list_or_prop([], What) ->
+ What;
+context_list_or_prop([H|T], What) ->
+ case is_ContextID(H) of
+ true when What == contextList ->
+ context_list_or_prop(T, What);
+ false when What == contextProp ->
+ context_list_or_prop(T, What);
+ _ ->
+ error({invalid_contextListOrProp, H, What})
+ end.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Prop} = CR) ->
+ case (((Top == []) or (Top == asn1_NOVALUE)) and
+ ((Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ ((Prop == []) or (Prop == asn1_NOVALUE))) of
+ true ->
+ asn1_NOVALUE;
+ false ->
+ CR
+ end;
+strip_ContextRequest(CR) ->
+ CR.
+
+cre_ContextAttrAuditRequest() ->
+ strip_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{}).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SelPrio)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SelPrio, SelLog)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) ->
+ case ((SelLog == asn1_NOVALUE) orelse is_SelectLogic(SelLog)) of
+ true ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectLogic = SelLog},
+ strip_ContextAttrAuditRequest(CAAR);
+ false ->
+ error({invalid_SelectLogic, SelLog,
+ ['ContextAttrAuditRequest',
+ Top, Em, Prio, Ieps, Ctx, SelPrio]})
+ end.
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SelPrio, SelEm, SelIeps)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) and
+ ((SelEm == true) or
+ (SelEm == false) or
+ (SelEm == asn1_NOVALUE)) and
+ ((SelIeps == true) or
+ (SelIeps == false) or
+ (SelIeps == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectemergency = SelEm,
+ selectiepscallind = SelIeps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SelPrio, SelEm, SelIeps, SelLog)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) and
+ ((SelEm == true) or
+ (SelEm == false) or
+ (SelEm == asn1_NOVALUE)) and
+ ((SelIeps == true) or
+ (SelIeps == false) or
+ (SelIeps == asn1_NOVALUE)) ->
+ case ((SelLog == asn1_NOVALUE) orelse is_SelectLogic(SelLog)) of
+ true ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectemergency = SelEm,
+ selectiepscallind = SelIeps,
+ selectLogic = SelLog},
+ strip_ContextAttrAuditRequest(CAAR);
+ false ->
+ error({invalid_SelectLogic, SelLog})
+ end.
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(CAAR) ->
+ CAAR.
+
+
+cre_SelectLogic(andAUDITSelect = SL) ->
+ {SL, 'NULL'};
+cre_SelectLogic(orAUDITSelect = SL) ->
+ {SL, 'NULL'};
+cre_SelectLogic(asn1_NOVALUE) ->
+ asn1_NOVALUE.
+
+
+cre_CommandRequest(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_CommandRequest(Cmd, Opt)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt}.
+
+cre_CommandRequest(Cmd, Opt, WR)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+ ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}.
+
+cre_Command(addReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(moveReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(modReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(subtractReq = Tag, Req)
+ when is_record(Req, 'SubtractRequest') ->
+ {Tag, Req};
+cre_Command(auditCapRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(auditValueRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(notifyReq = Tag, Req)
+ when is_record(Req, 'NotifyRequest') ->
+ {Tag, Req};
+cre_Command(serviceChangeReq = Tag, Req)
+ when is_record(Req, 'ServiceChangeRequest') ->
+ {Tag, Req}.
+
+cre_CommandReply(addReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(moveReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(modReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(subtractReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(auditCapReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(auditValueReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(notifyReply = Tag, Rep)
+ when is_record(Rep, 'NotifyReply') ->
+ {Tag, Rep};
+cre_CommandReply(serviceChangeReply = Tag, Rep)
+ when is_record(Rep, 'ServiceChangeReply') ->
+ {Tag, Rep}.
+
+
+%% -- TopologyRequest --
+
+cre_TopologyRequest(From, To, TD)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TD == bothway) or (TD == isolate) or (TD == oneway)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD};
+cre_TopologyRequest(From, To, TDE)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TDE == onewayexternal) or (TDE == onewayboth)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = oneway,
+ topologyDirectionExtension = TDE}.
+
+cre_TopologyRequest(From, To, TD, SID)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TD == bothway) or (TD == isolate) or (TD == oneway)) and
+ (is_integer(SID)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID};
+cre_TopologyRequest(From, To, SID, TDE)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ (is_integer(SID)) and
+ ((TDE == onewayexternal) or (TDE == onewayboth)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = oneway,
+ streamID = SID,
+ topologyDirectionExtension = TDE}.
+
+cre_AmmRequest(TermIDs, Descs) ->
+ d("cre_AmmRequest -> entry with"
+ "~n TermIDs: ~p"
+ "~n Descs: ~p", [TermIDs, Descs]),
+ case is_TerminationIDList(TermIDs) andalso
+ is_AmmRequest_descriptors(Descs) of
+ true ->
+ #'AmmRequest'{terminationID = TermIDs,
+ descriptors = Descs};
+ false ->
+ error({invalid_AmmRequest, {TermIDs, Descs}})
+ end.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ case is_StatisticsDescriptor(D) of
+ true ->
+ {statisticsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end
+ end.
+
+cre_AmmsReply(TermIDs) when is_list(TermIDs) ->
+ #'AmmsReply'{terminationID = TermIDs}.
+
+cre_AmmsReply(TermIDs, TAs) when is_list(TermIDs) andalso is_list(TAs) ->
+ #'AmmsReply'{terminationID = TermIDs,
+ terminationAudit = TAs}.
+
+cre_SubtractRequest(TermIDs) when is_list(TermIDs) ->
+ #'SubtractRequest'{terminationID = TermIDs}.
+
+cre_SubtractRequest(TermIDs, Audit)
+ when is_list(TermIDs) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'SubtractRequest'{terminationID = TermIDs,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TermID, Audit)
+ when is_record(TermID, megaco_term_id) andalso
+ is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TermID,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TID, Audit, [TID|_] = TIDs)
+ when is_record(TID, megaco_term_id) and
+ is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = Audit,
+ terminationIDList = TIDs}.
+
+cre_AuditReply(TermIDs) when is_list(TermIDs) ->
+ {contextAuditResult, TermIDs};
+cre_AuditReply(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {error, ED};
+cre_AuditReply(Audit) when is_record(Audit, 'AuditResult') ->
+ {auditResult, Audit};
+cre_AuditReply(ARTL) when is_record(ARTL, 'TermListAuditResult') ->
+ {auditResultTermList, ARTL}.
+
+cre_AuditResult(TID, TAs)
+ when is_record(TID, megaco_term_id) andalso is_list(TAs) ->
+ #'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAs}.
+
+cre_TermListAuditResult(TIDs, TA)
+ when is_list(TIDs) andalso is_list(TA) ->
+ #'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TA}.
+
+cre_TerminationAudit(D) ->
+ true = is_TerminationAudit(D),
+ D.
+
+cre_AuditReturnParameter(D) when is_record(D, 'ErrorDescriptor') ->
+ {errorDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'EventSpec') ->
+ {eventBufferDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ObservedEventsDescriptor') ->
+ {observedEventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ {statisticsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'PackagesItem') ->
+ {packagesDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'AuditDescriptor') ->
+ {emptyDescriptors, D};
+cre_AuditReturnParameter([H|_] = D) when is_tuple(H) ->
+ {signalsDescriptor, D}.
+
+cre_AuditDescriptor() ->
+ #'AuditDescriptor'{}.
+
+cre_AuditDescriptor([H|_] = AT) when is_atom(H) ->
+ #'AuditDescriptor'{auditToken = AT};
+cre_AuditDescriptor(APT) ->
+ #'AuditDescriptor'{auditPropertyToken = APT}.
+
+cre_AuditDescriptor(AT, APT) ->
+ #'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}.
+
+cre_IndAuditParameter(D) when is_record(D, 'IndAudMediaDescriptor') ->
+ {indAudMediaDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventsDescriptor') ->
+ {indAudEventsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventBufferDescriptor') ->
+ {indAudEventBufferDescriptor, D};
+cre_IndAuditParameter({signal, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter({seqSigList, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudDigitMapDescriptor') ->
+ {indAudDigitMapDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudStatisticsDescriptor') ->
+ {indAudStatisticsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudPackagesDescriptor') ->
+ {indAudPackagesDescriptor, D}.
+
+cre_IndAudMediaDescriptor() ->
+ #'IndAudMediaDescriptor'{}.
+
+cre_IndAudMediaDescriptor(TSD)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudMediaDescriptor'{termStateDescr = TSD};
+cre_IndAudMediaDescriptor(Parms) when is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{streams = Streams};
+cre_IndAudMediaDescriptor(Descs) when is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{streams = Streams}.
+
+cre_IndAudMediaDescriptor(TSD, Parms)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso
+ is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_IndAudMediaDescriptor(TSD, Descs)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_IndAudStreamDescriptor(SID, Parms)
+ when is_integer(SID) andalso is_record(Parms, 'IndAudStreamParms') ->
+ #'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms};
+cre_IndAudStreamDescriptor(SID, Parms) ->
+ error({invalid_IndAudStreamDescriptor, [SID, Parms]}).
+
+cre_IndAudStreamParms() ->
+ #'IndAudStreamParms'{}.
+
+cre_IndAudStreamParms(LCD) when is_record(LCD, 'IndAudLocalControlDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD};
+cre_IndAudStreamParms(SD) when is_record(SD, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{statisticsDescriptor = SD}.
+
+cre_IndAudStreamParms(LC, L, R)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R}.
+
+cre_IndAudStreamParms(LC, L, R, S)
+ when is_record(LC, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(S, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R,
+ statisticsDescriptor = S}.
+
+cre_IndAudLocalControlDescriptor() ->
+ #'IndAudLocalControlDescriptor'{}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP};
+cre_IndAudLocalControlDescriptor(RV, RG, PP, SMS)
+ when ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) and
+ is_atom(SMS) ->
+ #'IndAudLocalControlDescriptor'{reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS)
+ when (SM == 'NULL') and
+ (is_atom(SMS) and (SMS =/= asn1_NOVALUE)) ->
+ error({invalid_IndAudLocalControlDescriptor, [SM, RV, RG, PP, SMS]});
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) and
+ is_atom(SMS) ->
+ case is_StreamMode(SMS) of
+ true ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS};
+ false ->
+ error({invalid_IndAudLocalControlDescriptor, SMS})
+ end.
+
+cre_IndAudPropertyParm(PkgdName) when is_list(PkgdName) ->
+ #'IndAudPropertyParm'{name = PkgdName}.
+
+cre_IndAudPropertyParm(PkgdName, PP)
+ when is_list(PkgdName) andalso is_record(PP, 'PropertyParm') ->
+ #'IndAudPropertyParm'{name = PkgdName, propertyParms = PP}.
+
+cre_IndAudLocalRemoteDescriptor(Grps)
+ when is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+cre_IndAudLocalRemoteDescriptor(GID, Grps)
+ when is_integer(GID) andalso (0 =< GID) andalso (GID =< 65535) andalso is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = GID,
+ propGrps = Grps}.
+
+cre_IndAudPropertyGroup([]) ->
+ [];
+cre_IndAudPropertyGroup([H|_] = PG)
+ when is_record(H, 'IndAudPropertyParm') ->
+ PG.
+
+cre_IndAudTerminationStateDescriptor([] = PP) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+cre_IndAudTerminationStateDescriptor([H|_] = PP)
+ when is_record(H, 'IndAudPropertyParm') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+ when is_record(H, 'IndAudPropertyParm') andalso
+ ((EBC =:= 'NULL') orelse (EBC =:= asn1_NOVALUE)) andalso
+ ((SS =:= 'NULL') orelse (SS =:= asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}.
+
+cre_IndAudTerminationStateDescriptor(PP, EBC, SS, SSS)
+ when (SS =:= 'NULL') andalso
+ ((is_atom(SSS) andalso (SSS =/= asn1_NOVALUE))) ->
+ error({invalid_IndAudTerminationStateDescriptor, [PP, EBC, SS, SSS]});
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS, SSS)
+ when ((EBC =:= 'NULL') orelse (EBC =:= asn1_NOVALUE)) andalso
+ ((SS =:= 'NULL') orelse (SS =:= asn1_NOVALUE)) andalso
+ is_atom(SSS) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS, SSS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC =:= 'NULL') orelse (EBC =:= asn1_NOVALUE)) andalso
+ ((SS =:= 'NULL') orelse (SS =:= asn1_NOVALUE)) andalso
+ is_atom(SSS) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS}.
+
+cre_IndAudEventsDescriptor(PkgdName)
+ when is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName)
+ when is_integer(RID) andalso is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+cre_IndAudEventsDescriptor(PkgdName, SID)
+ when is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+ when is_integer(RID) andalso is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = PkgdName,
+ streamID = SID}.
+
+cre_IndAudEventBufferDescriptor(EventName) when is_list(EventName) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+cre_IndAudEventBufferDescriptor(EventName, SID)
+ when is_list(EventName) andalso is_integer(SID) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSignal') ->
+ {signal, S};
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSeqSigList') ->
+ {seqSigList, S}.
+
+cre_IndAudSeqSigList(ID) when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) ->
+ #'IndAudSeqSigList'{id = ID}.
+
+cre_IndAudSeqSigList(ID, S)
+ when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) andalso is_record(S, 'IndAudSignal') ->
+ #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+cre_IndAudSignal(SigName) when is_list(SigName) ->
+ #'IndAudSignal'{signalName = SigName}.
+
+cre_IndAudSignal(SigName, RID)
+ when is_list(SigName) andalso is_integer(RID) ->
+ #'IndAudSignal'{signalName = SigName,
+ signalRequestID = RID}.
+
+cre_IndAudDigitMapDescriptor() ->
+ #'IndAudDigitMapDescriptor'{}.
+
+cre_IndAudDigitMapDescriptor(DMN) when is_list(DMN) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+cre_IndAudStatisticsDescriptor(StatName) when is_list(StatName) ->
+ #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+cre_IndAudPackagesDescriptor(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+cre_NotifyRequest(TermIDs, D)
+ when is_list(TermIDs) andalso is_record(D, 'ObservedEventsDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D}.
+
+cre_NotifyRequest(TermIDs, D, ED)
+ when is_list(TermIDs) andalso is_record(D, 'ObservedEventsDescriptor') andalso is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D,
+ errorDescriptor = ED}.
+
+cre_NotifyReply(TermIDs) when is_list(TermIDs) ->
+ #'NotifyReply'{terminationID = TermIDs}.
+
+cre_NotifyReply(TermIDs, ED)
+ when is_list(TermIDs) andalso is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyReply'{terminationID = TermIDs,
+ errorDescriptor = ED}.
+
+cre_ObservedEventsDescriptor(RID, [H|_] = L)
+ when is_integer(RID) andalso is_record(H, 'ObservedEvent') ->
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = L}.
+
+cre_ObservedEvent(EN, EPL) when is_list(EN) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL};
+cre_ObservedEvent(EN, TN) when is_list(EN) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL) when is_list(EN) andalso is_integer(SID) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL};
+cre_ObservedEvent(EN, EPL, TN)
+ when is_list(EN) andalso is_list(EPL) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL, TN)
+ when is_list(EN) andalso is_integer(SID) andalso is_list(EPL) andalso is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+cre_ServiceChangeRequest(TermIDs, SCP)
+ when is_list(TermIDs) andalso is_record(SCP, 'ServiceChangeParm') ->
+ #'ServiceChangeRequest'{terminationID = TermIDs,
+ serviceChangeParms = SCP}.
+
+cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+ when is_list(TermIDs) andalso is_atom(Tag) andalso is_tuple(R) ->
+ #'ServiceChangeReply'{terminationID = TermIDs,
+ serviceChangeResult = SCR}.
+
+cre_ServiceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED};
+cre_ServiceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP}.
+
+%% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+cre_TerminationID(W, ID)
+ when is_list(W) andalso is_list(ID) andalso (1 =< length(ID)) andalso (length(ID) =< 8) ->
+ #'TerminationID'{wildcard = W,
+ id = ID}.
+
+cre_TerminationIDList(L) when is_list(L) ->
+ L.
+
+cre_MediaDescriptor() ->
+ #'MediaDescriptor'{}.
+
+cre_MediaDescriptor(TSD) when is_record(TSD, 'TerminationStateDescriptor') ->
+ #'MediaDescriptor'{termStateDescr = TSD};
+cre_MediaDescriptor(SP) when is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{streams = Streams};
+cre_MediaDescriptor([H|_] = SDs) when is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{streams = Streams}.
+
+cre_MediaDescriptor(TSD, SP)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_MediaDescriptor(TSD, [H|_] = SDs)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_StreamDescriptor(SID, SP) when is_integer(SID) andalso is_record(SP, 'StreamParms') ->
+ #'StreamDescriptor'{streamID = SID,
+ streamParms = SP}.
+
+cre_StreamParms() ->
+ #'StreamParms'{}.
+
+cre_StreamParms(LCD) when is_record(LCD, 'LocalControlDescriptor') ->
+ #'StreamParms'{localControlDescriptor = LCD};
+cre_StreamParms(LD) when is_record(LD, 'LocalRemoteDescriptor') ->
+ #'StreamParms'{localDescriptor = LD};
+cre_StreamParms(SD) when is_list(SD) ->
+ #'StreamParms'{statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD, RD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD};
+cre_StreamParms(LCD, LD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD, RD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}.
+
+cre_LocalControlDescriptor(SM) when is_atom(SM) ->
+ #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+cre_LocalControlDescriptor([H|_] = PP) when is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, [H|_] = PP)
+ when is_atom(SM) andalso is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+ when is_atom(SM) andalso
+ ((RV =:= true) orelse (RV =:= false) orelse (RV =:= asn1_NOVALUE)) andalso
+ ((RG =:= true) orelse (RG =:= false) orelse (RG =:= asn1_NOVALUE)) andalso
+ is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_StreamMode(sendOnly = M) ->
+ M;
+cre_StreamMode(recvOnly = M) ->
+ M;
+cre_StreamMode(sendRecv = M) ->
+ M;
+cre_StreamMode(inactive = M) ->
+ M;
+cre_StreamMode(loopBack = M) ->
+ M.
+
+cre_PropertyParm(N, [H|_] = V) when is_list(N) andalso is_list(H) ->
+ #'PropertyParm'{name = N, value = V}.
+
+cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+ when is_list(N) andalso is_list(H) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+cre_Name(N) when is_list(N) andalso (length(N) == 2) ->
+ N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) andalso (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) andalso (length(PackageName) =< 64)) andalso
+ (is_list(ItemID) andalso (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+cre_Relation(greaterThan = R) ->
+ R;
+cre_Relation(smallerThan = R) ->
+ R;
+cre_Relation(unequalTo = R) ->
+ R.
+
+cre_LocalRemoteDescriptor([H|_] = PGs) when is_list(H) ->
+ #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+cre_PropertyGroup([H|_] = PG) when is_record(H, 'PropertyParm') ->
+ PG.
+
+cre_TerminationStateDescriptor([H|_] = PPs) when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+ when is_record(H, 'PropertyParm') andalso
+ ((EMC =:= off) orelse (EMC =:= lockStep)) andalso
+ ((SS =:= test) orelse (SS =:= outOfSvc) orelse (SS =:= inSvc)) ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EMC,
+ serviceState = SS}.
+
+cre_EventBufferControl(off = EBC) ->
+ EBC;
+cre_EventBufferControl(lockStep = EBC) ->
+ EBC.
+
+cre_ServiceState(test = SS) ->
+ SS;
+cre_ServiceState(outOfSvc = SS) ->
+ SS;
+cre_ServiceState(inSvc = SS) ->
+ SS.
+
+cre_MuxDescriptor(MT, [H|_] = TL)
+ when is_atom(MT) andalso is_record(H, 'TerminationID') ->
+ #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+cre_MuxType(h221 = MT) ->
+ MT;
+cre_MuxType(h223 = MT) ->
+ MT;
+cre_MuxType(h226 = MT) ->
+ MT;
+cre_MuxType(v76 = MT) ->
+ MT;
+cre_MuxType(nx64k = MT) ->
+ MT.
+
+cre_StreamID(Val) when 0 =< Val, Val =< 65535 ->
+ Val;
+cre_StreamID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+%% RequestID must be present if eventList is non empty
+cre_EventsDescriptor() ->
+ #'EventsDescriptor'{eventList = []}.
+
+cre_EventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'RequestedEvent') ->
+ #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_RequestedEvent(N) ->
+ #'RequestedEvent'{pkgdName = N}.
+
+cre_RequestedEvent(N, EPL)
+ when is_list(N) andalso is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_RequestedEvent(N, EA)
+ when is_list(N) andalso is_record(EA, 'RequestedActions')->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA}.
+
+
+cre_RequestedEvent(N, SID, EPL)
+ when is_list(N) and is_integer(SID) and is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_RequestedEvent(N, EA, EPL)
+ when is_list(N) and is_record(EA, 'RequestedActions') and is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedEvent(N, SID, EA, EPL)
+ when is_list(N) and
+ is_integer(SID) and
+ is_record(EA, 'RequestedActions') and
+ is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RegulatedEmbeddedDescriptor() ->
+ #'RegulatedEmbeddedDescriptor'{}.
+
+cre_RegulatedEmbeddedDescriptor(D) ->
+ case is_SecondEventsDescriptor(D) of
+ true ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ #'RegulatedEmbeddedDescriptor'{signalsDescriptor = D};
+ false ->
+ error({invalid_RegulatedEmbeddedDescriptor, D})
+ end
+ end.
+
+cre_RegulatedEmbeddedDescriptor(SED, SD)
+ when ((SED == asn1_NOVALUE) or is_record(SED, 'SecondEventsDescriptor')) and
+ ((SD == asn1_NOVALUE) or is_list(SD)) ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SED,
+ signalsDescriptor = SD}.
+
+cre_NotifyBehaviour(notifyImmediate = Tag, 'NULL' = Val) ->
+ {Tag, Val};
+cre_NotifyBehaviour(notifyRegulated = Tag, Val)
+ when is_record(Val, 'RegulatedEmbeddedDescriptor') ->
+ {Tag, Val};
+cre_NotifyBehaviour(neverNotify = Tag, 'NULL' = Val) ->
+ {Tag, Val};
+cre_NotifyBehaviour(Tag, Val) ->
+ error({invalid_NotifyBehaviour, [Tag, Val]}).
+
+cre_RequestedActions() ->
+ #'RequestedActions'{}.
+
+cre_RequestedActions(KA)
+ when (KA == true) or (KA == true) ->
+ #'RequestedActions'{keepActive = KA};
+cre_RequestedActions(SE)
+ when is_record(SE, 'SecondEventsDescriptor') ->
+ #'RequestedActions'{secondEvent = SE};
+cre_RequestedActions(SD)
+ when is_list(SD) ->
+ #'RequestedActions'{signalsDescriptor = SD};
+cre_RequestedActions({Tag, _} = EDM)
+ when is_atom(Tag) ->
+ #'RequestedActions'{eventDM = EDM}.
+
+cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}.
+
+cre_RequestedActions(KA, {EDMTag, _} = EDM, SE, SD, {NBTag, _} = NB, RED)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(EDMTag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) and
+ (is_atom(NBTag) or (NB == asn1_NOVALUE)) and
+ ((RED == 'NULL') or (RED == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}.
+
+cre_EventDM(N) when is_list(N) ->
+ {digitMapName, N};
+cre_EventDM(V) when is_record(V, 'DigitMapValue') ->
+ {digitMapValue, V}.
+
+cre_SecondEventsDescriptor([H|_] = EL)
+ when is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{eventList = EL}.
+
+cre_SecondEventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_SecondRequestedEvent(N, EPL)
+ when is_list(N) andalso is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EPL) ->
+ error({invalid_SecondRequestedEvent, [N, EPL]}).
+
+cre_SecondRequestedEvent(N, SID, EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EA, EPL)
+ when is_list(N) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, EA, EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedActions() ->
+ #'SecondRequestedActions'{}.
+
+cre_SecondRequestedActions(KA)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA};
+cre_SecondRequestedActions(SD) when is_list(SD) ->
+ #'SecondRequestedActions'{signalsDescriptor = SD};
+cre_SecondRequestedActions({Tag, _} = Val) when is_atom(Tag) ->
+ case is_EventDM(Val) of
+ true ->
+ #'SecondRequestedActions'{eventDM = Val};
+ false ->
+ case is_NotifyBehaviour(Val) of
+ true ->
+ #'SecondRequestedActions'{notifyBehaviour = Val};
+ false ->
+ error({invalid_SecondRequestedActions, Val})
+ end
+ end;
+cre_SecondRequestedActions('NULL' = RED) ->
+ #'SecondRequestedActions'{resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, {Tag, _} = Val)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) ->
+ case is_EventDM(Val) of
+ true ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = Val};
+ false ->
+ case is_NotifyBehaviour(Val) of
+ true ->
+ #'SecondRequestedActions'{keepActive = KA,
+ notifyBehaviour = Val};
+ false ->
+ error({invalid_SecondRequestedActions, Val})
+ end
+ end;
+cre_SecondRequestedActions(KA, 'NULL' = RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, SD, {Tag, _} = NB)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) and
+ is_atom(Tag) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB};
+cre_SecondRequestedActions(KA, SD, 'NULL' = RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ signalsDescriptor = SD,
+ resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, {EDMTag, _} = EDM, SD,
+ {NBTag, _} = NB, RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ (is_atom(EDMTag) or (EDM == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) and
+ (is_atom(NBTag) or (NB == asn1_NOVALUE)) and
+ ((RED == 'NULL') or (RED == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}.
+
+cre_EventBufferDescriptor([H|_] = D) when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL) when is_list(N) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+cre_SignalsDescriptor(D) ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ D;
+ false ->
+ error({invalid_SignalsDescriptor, D})
+ end.
+
+cre_SignalRequest(S) when is_record(S, 'Signal') ->
+ {signal, S};
+cre_SignalRequest(S) when is_record(S, 'SeqSigList') ->
+ {seqSigList, S}.
+
+cre_SeqSigList(ID, [H|_] = SL)
+ when is_integer(ID) andalso (0 =< ID) andalso (ID =< 65535) andalso is_record(H, 'Signal') ->
+ #'SeqSigList'{id = ID, signalList = SL}.
+
+cre_Signal(N) when is_list(N) ->
+ #'Signal'{signalName = N}.
+
+cre_Signal(N, SPL) when is_list(N) andalso is_list(SPL) ->
+ #'Signal'{signalName = N,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISIG)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) and
+ (is_integer(ISIG) or (ISIG == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ISIG}.
+
+cre_SignalType(brief = ST) ->
+ ST;
+cre_SignalType(onOff = ST) ->
+ ST;
+cre_SignalType(timeOut = ST) ->
+ ST.
+
+cre_SignalDirection(internal = SD) ->
+ SD;
+cre_SignalDirection(external = SD) ->
+ SD;
+cre_SignalDirection(both = SD) ->
+ SD.
+
+cre_SignalName(N) ->
+ cre_PkgdName(N).
+
+cre_NotifyCompletion(L) when is_list(L) ->
+ Vals = [onTimeOut, onInterruptByEvent,
+ onInterruptByNewSignalDescr, otherReason],
+ F = fun(E) -> case lists:member(E, Vals) of
+ true ->
+ ok;
+ false ->
+ exit({invalid_NotifyCompletion, E})
+ end
+ end,
+ lists:foreach(F, L),
+ L.
+
+cre_SigParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'SigParameter'{sigParameterName = N, value = V}.
+
+cre_SigParameter(N, V, relation = Tag, R)
+ when is_list(N) and is_list(V) and is_atom(R) ->
+ EI = {Tag, R},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, range = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, sublist = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+cre_RequestID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_RequestID(Val) ->
+ exit({invalid_RequestID, Val}).
+
+cre_ModemDescriptor(MTL, MPL) when is_list(MTL) andalso is_list(MPL) ->
+ #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemDescriptor(MTL, MPL, NSD)
+%% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+cre_ModemType(v18 = MT) ->
+ MT;
+cre_ModemType(v22 = MT) ->
+ MT;
+cre_ModemType(v22bis = MT) ->
+ MT;
+cre_ModemType(v32 = MT) ->
+ MT;
+cre_ModemType(v32bis = MT) ->
+ MT;
+cre_ModemType(v34 = MT) ->
+ MT;
+cre_ModemType(v90 = MT) ->
+ MT;
+cre_ModemType(v91 = MT) ->
+ MT;
+cre_ModemType(synchISDN = MT) ->
+ MT.
+
+cre_DigitMapDescriptor() ->
+ #'DigitMapDescriptor'{}.
+
+cre_DigitMapDescriptor(N) when is_list(N) ->
+ #'DigitMapDescriptor'{digitMapName = N};
+cre_DigitMapDescriptor(V) when is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = V}.
+
+cre_DigitMapDescriptor(N, V) when is_list(N) andalso is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+cre_DigitMapName(N) ->
+ cre_Name(N).
+
+cre_DigitMapValue(DMB) when is_list(DMB) ->
+ #'DigitMapValue'{digitMapBody = DMB}.
+
+cre_DigitMapValue(Start, Short, Long, DMB) ->
+ cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+ when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+ (Start == asn1_NOVALUE)) and
+ ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+ (Short == asn1_NOVALUE)) and
+ ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+ (Long == asn1_NOVALUE)) and
+ is_list(DMB) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+ (Dur == asn1_NOVALUE)) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = DMB,
+ durationTimer = Dur}.
+
+cre_ServiceChangeParm(M, R) when is_atom(M) andalso is_list(R) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R}.
+
+cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+ cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE).
+
+%% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I) ->
+ cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, asn1_NOVALUE).
+
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, IF)
+ when is_atom(M) and
+ ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ is_list(R) and
+ ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+ (D == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+ (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) and
+ ((IF == 'NULL') or (IF == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Mid,
+ timeStamp = TS,
+ serviceChangeInfo = I,
+ serviceChangeIncompleteFlag = IF};
+ _ ->
+ exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeAddress(portNumber = Tag, P)
+ when is_integer(P) andalso (0 =< P) andalso (P =< 65535) ->
+ {Tag, P};
+cre_ServiceChangeAddress(ip4Address = Tag, A) when is_record(A, 'IP4Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(ip6Address = Tag, A) when is_record(A, 'IP6Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(domainName = Tag, N) when is_record(N, 'DomainName') ->
+ {Tag, N};
+cre_ServiceChangeAddress(deviceName = Tag, N) when is_list(N) ->
+ {Tag, N};
+cre_ServiceChangeAddress(mtpAddress = Tag, A) when is_list(A) ->
+ {Tag, A}.
+
+cre_ServiceChangeResParm() ->
+ #'ServiceChangeResParm'{}.
+cre_ServiceChangeResParm(Addr, Prof) ->
+ cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+ Prof, asn1_NOVALUE).
+cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+ when ((is_integer(Ver) andalso (0 =< Ver) andalso (Ver =< 99)) orelse
+ (Ver =:= asn1_NOVALUE)) andalso
+ (is_record(Prof, 'ServiceChangeProfile') orelse (Prof =:= asn1_NOVALUE)) andalso
+ (is_record(TS, 'TimeNotation') orelse (TS =:= asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ timeStamp = TS};
+ _ ->
+ exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeMethod(failover = M) ->
+ M;
+cre_ServiceChangeMethod(forced = M) ->
+ M;
+cre_ServiceChangeMethod(graceful = M) ->
+ M;
+cre_ServiceChangeMethod(restart = M) ->
+ M;
+cre_ServiceChangeMethod(disconnected = M) ->
+ M;
+cre_ServiceChangeMethod(handOff = M) ->
+ M.
+
+%% The version field is added to make it look more like ABNF
+cre_ServiceChangeProfile(N) ->
+ cre_ServiceChangeProfile(N, 1).
+
+cre_ServiceChangeProfile(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'ServiceChangeProfile'{profileName = N, version = V}.
+
+cre_PackagesDescriptor([H|_] = D) when is_record(H, 'PackagesItem') ->
+ D.
+
+cre_PackagesItem(N, Ver) when is_list(N) andalso is_integer(Ver) andalso (0 =< Ver) andalso (Ver =< 99) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = Ver}.
+
+cre_StatisticsDescriptor(D) ->
+ true = is_StatisticsDescriptor(D),
+ D.
+
+cre_StatisticsParameter(N) when is_list(N) ->
+ #'StatisticsParameter'{statName = N}.
+
+cre_StatisticsParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% {h221NonStandard, H221};
+%% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% {object, Obj};
+%% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% {experimental, Exp}.
+
+%% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}.
+
+cre_TimeNotation(D, T)
+ when is_list(D) andalso (length(D) =:= 8) andalso is_list(T) andalso (length(T) =:= 8) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_Value([H|_] = V) when is_list(H) ->
+ V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% -- MegacoMessage --
+
+is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}) ->
+ d("is_MegacoMessage -> entry"),
+ is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+is_MegacoMessage(_) ->
+ false.
+
+
+chk_MegacoMessage(M, M) ->
+ d("chk_MegacoMessage -> entry (1)"),
+ chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ d("chk_MegacoMessage -> entry (2)"),
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type('MegacoMessage', M1, M2).
+
+
+%% -- AuthenticationHeader --
+
+is_opt_AuthenticationHeader(AH) ->
+ is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}) ->
+ is_SecurityParmIndex(SPI) andalso
+ is_SequenceNum(SN) andalso
+ is_AuthData(AD);
+is_AuthenticationHeader(_) ->
+ false.
+
+%% This stuff is not really used, so make it simple...
+chk_opt_AuthenticationHeader(A1, A2) ->
+ chk_OPTIONAL('AuthenticationHeader', A1, A2,
+ fun is_AuthenticationHeader/1,
+ fun chk_AuthenticationHeader/2).
+
+chk_AuthenticationHeader(A, A) ->
+ chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+chk_AuthenticationHeader(A1, A2) ->
+ case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+ true ->
+ not_equal('AuthenticationHeader', A1, A2);
+ false ->
+ wrong_type('AuthenticationHeader', A1, A2)
+ end.
+
+
+%% -- SecurityParmIndex --
+
+is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- SequenceNum --
+
+is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- AuthData --
+
+is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% -- Message --
+
+is_Message(#'Message'{version = V,
+ mId = MID,
+ messageBody = Body}) ->
+ d("is_Message -> entry"),
+ is_INTEGER(V, {range, 0, 99}) andalso
+ is_MId(MID) andalso
+ is_Message_messageBody(Body);
+is_Message(_) ->
+ false.
+
+chk_Message(M, M) ->
+ d("chk_Message -> entry (1)"),
+ chk_type(fun is_Message/1, 'Message', M);
+chk_Message(#'Message'{version = V1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = V2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ d("chk_Message -> entry with"
+ "~n V1: ~p"
+ "~n V2: ~p"
+ "~n MID1: ~p"
+ "~n MID2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p",
+ [V1, V2, MID1, MID2, Body1, Body2]),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'Message_version'),
+ validate(fun() -> chk_MId(MID1, MID2) end, 'Message_mId'),
+ chk_Message_messageBody(Body1, Body2),
+ ok;
+chk_Message(M1, M2) ->
+ wrong_type('Message', M1, M2).
+
+
+is_Message_messageBody({Tag, Val}) ->
+ d("is_Message_messageBody -> entry"),
+ is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val);
+is_Message_messageBody(_) ->
+ false.
+
+is_Message_messageBody_tag(Tag) ->
+ Tags = [messageError, transactions],
+ lists:member(Tag, Tags).
+
+is_Message_messageBody_val(messageError, Val) ->
+ is_ErrorDescriptor(Val);
+is_Message_messageBody_val(transactions, Val) ->
+ is_Message_messageBody_transactions(Val).
+
+is_Message_messageBody_transactions([]) ->
+ d("is_Message_messageBody_transactions -> entry when done"),
+ true;
+is_Message_messageBody_transactions([H|T]) ->
+ d("is_Message_messageBody_transactions -> entry"),
+ is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+is_Message_messageBody_transactions(_) ->
+ false.
+
+chk_Message_messageBody(B, B) ->
+ d("chk_Message_messageBody -> entry (1)"),
+ chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (2)"),
+ case (is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val1) andalso
+ is_Message_messageBody_val(Tag, Val2)) of
+ true ->
+ chk_Message_messageBody_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (3)"),
+ case ((is_Message_messageBody_tag(Tag1) andalso
+ is_Message_messageBody_val(Tag1, Val1)) andalso
+ (is_Message_messageBody_tag(Tag2) andalso
+ is_Message_messageBody_val(Tag2, Val2))) of
+ true ->
+ not_equal('Message_messageBody', B1, B2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody(B1, B2) ->
+ wrong_type('Message_messageBody', B1, B2).
+
+chk_Message_messageBody_val(messageError, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'Message_messageBody');
+chk_Message_messageBody_val(transactions, Val1, Val2) ->
+ chk_Message_messageBody_transactions(lists:sort(Val1),
+ lists:sort(Val2)).
+
+chk_Message_messageBody_transactions([], []) ->
+ d("chk_Message_messageBody_transactions -> entry - ok (1)"),
+ ok;
+chk_Message_messageBody_transactions([] = T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (2)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions(T1, [] = T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (3)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (4)"),
+ case is_Transaction(H) of
+ true ->
+ chk_Message_messageBody_transactions(T1, T2);
+ false ->
+ wrong_type('Message_messageBody_transactions_val', H)
+ end;
+chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (5)"),
+ validate(fun() -> chk_Transaction(H1, H2) end,
+ 'Message_messageBody_transactions_val'),
+ chk_Message_messageBody_transactions(T1, T2);
+chk_Message_messageBody_transactions(T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - wrong-type (6)"),
+ wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% -- MId --
+
+is_opt_MId(M) ->
+ is_OPTIONAL(fun is_MId/1, M).
+
+is_MId({Tag, Val}) ->
+ is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+is_MId(_) ->
+ false.
+
+is_MId_tag(Tag) ->
+ Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+ lists:member(Tag, Tags).
+
+is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+is_MId_val(domainName, Val) -> is_DomainName(Val);
+is_MId_val(deviceName, Val) -> is_PathName(Val);
+is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+chk_opt_MId(M1, M2) ->
+ chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+chk_MId(M, M) ->
+ chk_type(fun is_MId/1, 'MId', M);
+chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+ case (is_MId_tag(Tag) andalso
+ is_MId_val(Tag, Val1) andalso
+ is_MId_val(Tag, Val2)) of
+ true ->
+ chk_MId_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+ case ((is_MId_tag(Tag1) andalso
+ is_MId_val(Tag1, Val1)) andalso
+ (is_MId_tag(Tag2) andalso
+ is_MId_val(Tag2, Val2))) of
+ true ->
+ not_equal('MId', M1, M2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId(M1, M2) ->
+ wrong_type('MId', M1, M2).
+
+chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% -- DomainName --
+
+is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+ is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+is_DomainName(_) ->
+ false.
+
+chk_DomainName(N, N) ->
+ ok;
+chk_DomainName(N1, N2) ->
+ not_equal('DomainName', N1, N2).
+
+
+%% -- IP4Address --
+
+is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 4}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP4Address(_) ->
+ false.
+
+chk_IP4Address(A, A) ->
+ ok;
+chk_IP4Address(A1, A2) ->
+ not_equal('IP4Address', A1, A2).
+
+
+%% -- IP6Address --
+
+is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 16}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP6Address(_) ->
+ false.
+
+chk_IP6Address(A, A) ->
+ ok;
+chk_IP6Address(A1, A2) ->
+ not_equal('IP6Address', A1, A2).
+
+
+%% -- PathName --
+
+is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+chk_PathName(N, N) ->
+ ok;
+chk_PathName(N1, N2) ->
+ not_equal('PathName', N1, N2).
+
+
+%% -- Transaction --
+
+is_Transaction({Tag, Val}) ->
+ d("is_Transaction -> entry"),
+ is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+is_Transaction(_) ->
+ false.
+
+is_Transaction_tag(Tag) ->
+ Tags = [transactionRequest,
+ transactionPending,
+ transactionReply,
+ transactionResponseAck],
+ lists:member(Tag, Tags).
+
+is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+chk_Transaction({Tag, Val} = Trans, Trans) ->
+ d("chk_Transaction -> entry (1)"),
+ case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Transaction', Trans, Trans)
+ end;
+chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (2)"),
+ case (is_Transaction_tag(Tag) and
+ is_Transaction_val(Tag, Val1) and
+ is_Transaction_val(Tag, Val2)) of
+ true ->
+ chk_Transaction_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (3)"),
+ case ((is_Transaction_tag(Tag1) andalso
+ is_Transaction_val(Tag1, Val1)) andalso
+ (is_Transaction_tag(Tag2) andalso
+ is_Transaction_val(Tag2, Val2))) of
+ true ->
+ not_equal('Transaction', Trans1, Trans2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction(Trans1, Trans2) ->
+ d("chk_Transaction -> entry - wrong-type - (4)"),
+ wrong_type('Transaction', Trans1, Trans2).
+
+chk_Transaction_val(transactionRequest, T1, T2) ->
+ chk_TransactionRequest(T1, T2);
+chk_Transaction_val(transactionPending, T1, T2) ->
+ chk_TransactionPending(T1, T2);
+chk_Transaction_val(transactionReply, T1, T2) ->
+ chk_TransactionReply(T1,T2);
+chk_Transaction_val(transactionResponseAck, T1, T2) ->
+ chk_TransactionResponseAck(T1, T2).
+
+
+%% -- TransactionId --
+
+is_opt_TransactionId(TID) ->
+ is_OPTIONAL(fun is_TransactionId/1, TID).
+
+is_TransactionId(TID) ->
+ d("is_TransactionId -> entry"),
+ is_INTEGER(TID, {range, 0, 4294967295}).
+
+chk_opt_TransactionId(TID1, TID2) ->
+ chk_OPTIONAL('TransactionId', TID1, TID2,
+ fun is_TransactionId/1, fun chk_TransactionId/2).
+
+chk_TransactionId(TID, TID) ->
+ chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+chk_TransactionId(TID1, TID2) ->
+ case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+ true ->
+ not_equal('TransactionId', TID1, TID2);
+ false ->
+ wrong_type('TransactionId', TID1, TID2)
+ end.
+
+
+%% -- TransactionRequest --
+
+is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+ actions = Acts}) ->
+ d("is_TransactionRequest -> entry"),
+ is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+is_TransactionRequest(_) ->
+ false.
+
+chk_TransactionRequest(T, T) ->
+ chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+ actions = Acts1},
+ #'TransactionRequest'{transactionId = TID2,
+ actions = Acts2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+ chk_TransactionRequest_actions(lists:sort(Acts1),
+ lists:sort(Acts2)),
+ ok;
+chk_TransactionRequest(T1, T2) ->
+ wrong_type('TransactionRequest', T1, T2).
+
+is_TransactionRequest_actions([]) ->
+ d("is_TransactionRequest_actions -> entry when done"),
+ true;
+is_TransactionRequest_actions([H|T]) ->
+ d("is_TransactionRequest_actions -> entry"),
+ is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+is_TransactionRequest_actions(_) ->
+ false.
+
+chk_TransactionRequest_actions([], []) ->
+ ok;
+chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+ case is_ActionRequest(H) of
+ true ->
+ chk_TransactionRequest_actions(T1, T2);
+ false ->
+ wrong_type('TransactionRequest_actions_val', H)
+ end;
+chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionRequest(H1, H2) end,
+ 'TransactionRequest_actions_val'),
+ chk_TransactionRequest_actions(T1, T2);
+chk_TransactionRequest_actions(Acts1, Acts2) ->
+ wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% -- TransactionPending --
+
+is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+ d("is_TransactionPending -> entry"),
+ is_TransactionId(TID);
+is_TransactionPending(_) ->
+ false.
+
+chk_TransactionPending(T, T) ->
+ chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+ #'TransactionPending'{transactionId = TID2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+ ok;
+chk_TransactionPending(T1, T2) ->
+ wrong_type('TransactionPending', T1, T2).
+
+
+%% -- TransactionReply --
+
+is_TransactionReply(#'TransactionReply'{transactionId = TID,
+ immAckRequired = IAR,
+ transactionResult = TR}) ->
+ d("is_TransactionReply -> entry"),
+ is_TransactionId(TID) andalso
+ is_opt_NULL(IAR) andalso
+ is_TransactionReply_transactionResult(TR);
+is_TransactionReply(_) ->
+ false.
+
+chk_TransactionReply(T, T) ->
+ d("chk_TransactionReply -> entry (2)"),
+ chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+ immAckRequired = IAR1,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TID2,
+ immAckRequired = IAR2,
+ transactionResult = TR2}) ->
+ d("chk_TransactionReply -> entry (2)"),
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+ validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+ chk_TransactionReply_transactionResult(TR1, TR2),
+ ok;
+chk_TransactionReply(T1, T2) ->
+ d("chk_TransactionReply -> entry (3)"),
+ wrong_type('TransactionReply', T1, T2).
+
+is_TransactionReply_transactionResult({Tag, Val}) ->
+ d("is_TransactionReply_transactionResult -> entry"),
+ is_TransactionReply_transactionResult_tag(Tag) andalso
+ is_TransactionReply_transactionResult_val(Tag, Val);
+is_TransactionReply_transactionResult(_) ->
+ false.
+
+is_TransactionReply_transactionResult_tag(T) ->
+ lists:member(T, [transactionError, actionReplies]).
+
+is_TransactionReply_transactionResult_val(transactionError, V) ->
+ is_ErrorDescriptor(V);
+is_TransactionReply_transactionResult_val(actionReplies, V) ->
+ is_TransactionReply_actionReplies(V).
+
+chk_TransactionReply_transactionResult(Res, Res) ->
+ chk_type(fun is_TransactionReply_transactionResult/1,
+ 'TransactionReply_transactionResult', Res);
+chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+ {Tag, Val2} = Res2) ->
+ case (is_TransactionReply_transactionResult_tag(Tag) and
+ is_TransactionReply_transactionResult_val(Tag, Val1) and
+ is_TransactionReply_transactionResult_val(Tag, Val2)) of
+ true ->
+ chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+ {Tag2, Val2} = Res2) ->
+ case ((is_TransactionReply_transactionResult_tag(Tag1) and
+ is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+ (is_TransactionReply_transactionResult_tag(Tag2) and
+ is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('TransactionReply_transactionResult', Res1, Res2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult(Res1, Res2) ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+ validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+ 'TransactionReply_transactionResult');
+chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+ validate(fun() ->
+ chk_TransactionReply_actionReplies(lists:sort(R1),
+ lists:sort(R2))
+ end,
+ 'TransactionReply_transactionResult').
+
+is_TransactionReply_actionReplies([]) ->
+ d("is_TransactionReply_actionReplies -> entry when done"),
+ true;
+is_TransactionReply_actionReplies([H|T]) ->
+ d("is_TransactionReply_actionReplies -> entry"),
+ is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+is_TransactionReply_actionReplies(_) ->
+ false.
+
+chk_TransactionReply_actionReplies([], []) ->
+ ok;
+chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+ case is_ActionReply(H) of
+ true ->
+ chk_TransactionReply_actionReplies(T1, T2);
+ false ->
+ wrong_type('TransactionReply_actionReplies_val', H)
+ end;
+chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionReply(H1, H2) end,
+ 'TransactionReply_actionReplies_val'),
+ chk_TransactionReply_actionReplies(T1, T2);
+chk_TransactionReply_actionReplies(AR1, AR2) ->
+ wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% -- TransactionResponseAck --
+
+is_TransactionResponseAck([]) ->
+ d("is_TransactionResponseAck -> entry when done"),
+ true;
+is_TransactionResponseAck([H|T]) ->
+ d("is_TransactionResponseAck -> entry"),
+ is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+is_TransactionResponseAck(_) ->
+ false.
+
+chk_TransactionResponseAck([], []) ->
+ ok;
+chk_TransactionResponseAck([] = AR1, AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck(AR1, [] = AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck([H|T1], [H|T2]) ->
+ case is_TransactionAck(H) of
+ true ->
+ chk_TransactionResponseAck(T1, T2);
+ false ->
+ wrong_type('TransactionResponseAck_val', H)
+ end;
+chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TransactionAck(H1, H2) end,
+ 'TransactionResponseAck'),
+ chk_TransactionResponseAck(T1, T2);
+chk_TransactionResponseAck(AR1, AR2) ->
+ wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% -- TransactionAck --
+
+is_TransactionAck(#'TransactionAck'{firstAck = F,
+ lastAck = L}) ->
+ d("is_TransactionAck -> entry"),
+ is_TransactionId(F) andalso is_opt_TransactionId(L);
+is_TransactionAck(_) ->
+ false.
+
+chk_TransactionAck(T, T) ->
+ chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+ validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+ ok;
+chk_TransactionAck(T1, T2) ->
+ wrong_type('TransactionAck', T1, T2).
+
+
+%% -- ErrorDescriptor --
+
+is_opt_ErrorDescriptor(V) ->
+ is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text}) ->
+ d("is_ErrorDescriptor -> entry"),
+ is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+is_ErrorDescriptor(_) ->
+ false.
+
+chk_opt_ErrorDescriptor(E1, E2) ->
+ chk_OPTIONAL('ErrorDescriptor', E1, E2,
+ fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+chk_ErrorDescriptor(E, E) ->
+ chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1},
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2}) ->
+ chk_ErrorCode(Code1, Code2),
+ chk_opt_ErrorText(Text1, Text2),
+ ok;
+chk_ErrorDescriptor(E1, E2) ->
+ wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% -- ErrorCode --
+
+is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+chk_ErrorCode(C, C) ->
+ case is_ErrorCode(C) of
+ true ->
+ ok;
+ false ->
+ wrong_type(errorCode, C, C)
+ end;
+chk_ErrorCode(C1, C2) ->
+ case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+ true ->
+ not_equal(errorCode, C1, C2);
+ false ->
+ wrong_type(errorCode, C1, C2)
+ end.
+
+
+%% -- ErrorText --
+
+is_opt_ErrorText(V) ->
+ is_OPTIONAL(fun is_ErrorText/1, V).
+
+is_ErrorText(V) -> is_IA5String(V).
+
+chk_opt_ErrorText(T1, T2) ->
+ chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+chk_ErrorText(T, T) ->
+ chk_type(fun is_ErrorText/1, 'ErrorText', T);
+chk_ErrorText(T1, T2) ->
+ case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+ true ->
+ case {to_lower(T1), to_lower(T2)} of
+ {T, T} ->
+ ok;
+ _ ->
+ not_equal('ErrorText', T1, T2)
+ end;
+ false ->
+ wrong_type('ErrorText', T1, T2)
+ end.
+
+
+%% -- ContextID --
+
+is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+chk_ContextID(Id, Id) ->
+ chk_type(fun is_ContextID/1, 'ContextID', Id);
+chk_ContextID(Id1, Id2) ->
+ case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+ true ->
+ not_equal('ContextID', Id1, Id2);
+ false ->
+ wrong_type('ContextID', Id1, Id2)
+ end.
+
+
+%% -- ActionRequest --
+
+is_ActionRequest(#'ActionRequest'{contextId = Id,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = AuditReq,
+ commandRequests = CmdReqs}) ->
+ d("is_ActionRequest -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ContextRequest(CtxReq) andalso
+ is_opt_ContextAttrAuditRequest(AuditReq) andalso
+ is_ActionRequest_commandRequests(CmdReqs);
+is_ActionRequest(_) ->
+ false.
+
+chk_ActionRequest(A, A) ->
+ chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+ validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+ validate(fun() ->
+ chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+ end,
+ 'ActionRequest'),
+ chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+ ok.
+
+
+is_ActionRequest_commandRequests([]) ->
+ d("is_ActionRequest_commandRequests -> entry when done"),
+ true;
+is_ActionRequest_commandRequests([H|T]) ->
+ d("is_ActionRequest_commandRequests -> entry"),
+ is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+is_ActionRequest_commandRequests(_) ->
+ false.
+
+chk_ActionRequest_commandRequests([], []) ->
+ ok;
+chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+ case is_CommandRequest(H) of
+ true ->
+ chk_ActionRequest_commandRequests(T1, T2);
+ false ->
+ wrong_type('ActionRequest_commandRequest_val', H)
+ end;
+chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandRequest(H1, H2) end,
+ 'ActionRequest_commandRequests_val'),
+ chk_ActionRequest_commandRequests(T1, T2);
+chk_ActionRequest_commandRequests(R1, R2) ->
+ wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% -- ActionReply --
+
+is_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep}) ->
+ d("is_ActionReply -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ErrorDescriptor(ED) andalso
+ is_opt_ContextRequest(CtxRep) andalso
+ is_ActionReply_commandReply(CmdRep);
+is_ActionReply(_) ->
+ false.
+
+is_ActionReply_commandReply([]) ->
+ d("is_ActionReply_commandReply -> entry when done"),
+ true;
+is_ActionReply_commandReply([H|T]) ->
+ d("is_ActionReply_commandReply -> entry"),
+ is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+is_ActionReply_commandReply(_) ->
+ false.
+
+chk_ActionReply(A, A) ->
+ d("chk_ActionReply -> entry (1)"),
+ chk_type(fun is_ActionReply/1, 'ActionReply', A);
+chk_ActionReply(#'ActionReply'{contextId = Id1,
+ errorDescriptor = ED1,
+ contextReply = CtxRep1,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = Id2,
+ errorDescriptor = ED2,
+ contextReply = CtxRep2,
+ commandReply = CmdRep2}) ->
+ d("chk_ActionReply -> entry (2)"),
+ chk_ContextID(Id1, Id2),
+ chk_opt_ErrorDescriptor(ED1, ED2),
+ chk_opt_ContextRequest(CtxRep1, CtxRep2),
+ chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+chk_ActionReply_commandReply([], []) ->
+ ok;
+chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+ case is_CommandReply(H) of
+ true ->
+ chk_ActionReply_commandReply(T1, T2);
+ false ->
+ wrong_type('ActionReply_commandReply_val', H)
+ end;
+chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandReply(H1, H2) end,
+ 'ActionReply_commandReply_val'),
+ chk_ActionReply_commandReply(T1, T2);
+chk_ActionReply_commandReply(R1, R2) ->
+ wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% -- ContextRequest --
+
+is_opt_ContextRequest(V) ->
+ is_OPTIONAL(fun is_ContextRequest/1, V).
+
+is_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReq,
+ iepscallind = Ieps,
+ contextProp = CtxProp,
+ contextList = CtxList}) ->
+ d("is_ContextRequest -> entry"),
+ is_ContextRequest_priority(Prio) andalso
+ is_ContextRequest_emergency(Em) andalso
+ is_ContextRequest_topologyReq(TopReq) andalso
+ is_ContextRequest_iepscallind(Ieps) andalso
+ is_ContextRequest_contextProp(CtxProp) andalso
+ is_ContextRequest_contextList(CtxList);
+is_ContextRequest(_) ->
+ false.
+
+is_ContextRequest_priority(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_priority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextRequest_emergency(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_emergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_topologyReq([]) ->
+ true;
+is_ContextRequest_topologyReq([H|T]) ->
+ is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+is_ContextRequest_topologyReq(_) ->
+ false.
+
+is_ContextRequest_iepscallind(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_iepscallind(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_contextProp(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextProp([]) ->
+ true;
+is_ContextRequest_contextProp([H|T]) ->
+ is_PropertyParm(H) andalso is_ContextRequest_contextProp(T);
+is_ContextRequest_contextProp(_) ->
+ false.
+
+is_ContextRequest_contextList(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextList([]) ->
+ true;
+is_ContextRequest_contextList([H|T]) ->
+ is_ContextID(H) andalso is_ContextRequest_contextList(T);
+is_ContextRequest_contextList(_) ->
+ false.
+
+chk_opt_ContextRequest(R1, R2) ->
+ chk_OPTIONAL('ContextRequest', R1, R2,
+ fun is_ContextRequest/1, fun chk_ContextRequest/2).
+
+chk_ContextRequest(R, R) ->
+ chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1,
+ iepscallind = Ieps1,
+ contextProp = CtxProp1,
+ contextList = CtxList1},
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2,
+ iepscallind = Ieps2,
+ contextProp = CtxProp2,
+ contextList = CtxList2}) ->
+ chk_ContextRequest_priority(Prio1, Prio2),
+ chk_ContextRequest_emergency(Em1, Em2),
+ chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+ chk_ContextRequest_iepscallind(Ieps1, Ieps2),
+ chk_ContextRequest_contextProp(CtxProp1, CtxProp2),
+ chk_ContextRequest_contextList(CtxList1, CtxList2),
+ ok;
+chk_ContextRequest(R1, R2) ->
+ wrong_type('ContextRequest', R1, R2).
+
+
+chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_priority(P, P) ->
+ chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+chk_ContextRequest_priority(P1, P2) ->
+ case (is_ContextRequest_priority(P1) andalso
+ is_ContextRequest_priority(P2)) of
+ true ->
+ not_equal('ContextRequest_priority', P1, P2);
+ false ->
+ wrong_type(contextRequest_priority, P1, P2)
+ end.
+
+
+chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_emergency(E, E) ->
+ chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+chk_ContextRequest_emergency(E1, E2) ->
+ case (is_ContextRequest_emergency(E1) andalso
+ is_ContextRequest_emergency(E2)) of
+ true ->
+ not_equal('ContextRequest_emergency', E1, E2);
+ false ->
+ wrong_type('ContextRequest_emergency', E1, E2)
+ end.
+
+chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_topologyReq([], []) ->
+ ok;
+chk_ContextRequest_topologyReq([] = T1, T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq(T1, [] = T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+ case is_TopologyRequest(H) of
+ true ->
+ chk_ContextRequest_topologyReq(T1, T2);
+ false ->
+ wrong_type('ContextRequest_topologyReq_val', H)
+ end;
+chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TopologyRequest(H1, H2) end,
+ 'ContextRequest_topologyReq_val'),
+ chk_ContextRequest_topologyReq(T1, T2);
+chk_ContextRequest_topologyReq(T1, T2) ->
+ wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+chk_ContextRequest_iepscallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_iepscallind(E, E) ->
+ chk_type(fun is_ContextRequest_iepscallind/1,
+ 'ContextRequest_iepscallind', E);
+chk_ContextRequest_iepscallind(E1, E2) ->
+ case (is_ContextRequest_iepscallind(E1) andalso
+ is_ContextRequest_iepscallind(E2)) of
+ true ->
+ case (((E1 == false) and (E2 == asn1_NOVALUE)) or
+ ((E1 == asn1_NOVALUE) and (E2 == false))) of
+ true ->
+ ok;
+ false ->
+ not_equal('ContextRequest_iepscallind', E1, E2)
+ end;
+
+ false ->
+ wrong_type('ContextRequest_iepscallind', E1, E2)
+ end.
+
+chk_ContextRequest_contextProp(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextProp([], []) ->
+ ok;
+chk_ContextRequest_contextProp([] = T1, T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp(T1, [] = T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ContextRequest_contextProp(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextProp_val', H)
+ end;
+chk_ContextRequest_contextProp([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextRequest_contextProp_val'),
+ chk_ContextRequest_contextProp(T1, T2);
+chk_ContextRequest_contextProp(T1, T2) ->
+ wrong_type('ContextRequest_contextProp', T1, T2).
+
+chk_ContextRequest_contextList(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextList([], []) ->
+ ok;
+chk_ContextRequest_contextList([] = T1, T2) ->
+ not_equal('ContextRequest_contextList', T1, T2);
+chk_ContextRequest_contextList(T1, [] = T2) ->
+ not_equal('ContextRequest_contextList', T1, T2);
+chk_ContextRequest_contextList([H|T1], [H|T2]) ->
+ case is_ContextID(H) of
+ true ->
+ chk_ContextRequest_contextList(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextList_val', H)
+ end;
+chk_ContextRequest_contextList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ContextID(H1, H2) end,
+ 'ContextRequest_contextList_val'),
+ chk_ContextRequest_contextList(T1, T2);
+chk_ContextRequest_contextList(T1, T2) ->
+ wrong_type('ContextRequest_contextList', T1, T2).
+
+
+%% -- ContextAttrAuditRequest --
+
+is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextAttrAuditRequest(V) ->
+ is_ContextAttrAuditRequest(V).
+
+is_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = T,
+ emergency = E,
+ priority = P,
+ iepscallind = I,
+ contextPropAud = A,
+ selectpriority = SP,
+ selectemergency = SE,
+ selectiepscallind = SI,
+ selectLogic = SL}) ->
+ d("is_ContextAttrAuditRequest -> entry"),
+ is_opt_NULL(T) andalso
+ is_opt_NULL(E) andalso
+ is_opt_NULL(P) andalso
+ is_opt_NULL(I) andalso
+ is_ContextAttrAuditRequest_contextPropAud(A) andalso
+ is_ContextAttrAuditRequest_selectpriority(SP) andalso
+ is_ContextAttrAuditRequest_selectemergency(SE) andalso
+ is_ContextAttrAuditRequest_selectiepscallind(SI) andalso
+ is_opt_SelectLogic(SL);
+is_ContextAttrAuditRequest(_) ->
+ false.
+
+is_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([]) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([H|T]) ->
+ d("is_ContextAttrAuditRequest_contextPropAud -> entry"),
+ is_IndAudPropertyParm(H) andalso
+ is_ContextAttrAuditRequest_contextPropAud(T).
+
+is_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectpriority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectemergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectiepscallind(V) ->
+ is_BOOLEAN(V).
+
+
+chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextAttrAuditRequest(R1, R2) ->
+ chk_ContextAttrAuditRequest(R1, R2).
+
+chk_ContextAttrAuditRequest(R, R) ->
+ chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+chk_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1,
+ iepscallind = I1,
+ contextPropAud = A1,
+ selectpriority = SP1,
+ selectemergency = SE1,
+ selectiepscallind = SI1,
+ selectLogic = SL1},
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2,
+ iepscallind = I2,
+ contextPropAud = A2,
+ selectpriority = SP2,
+ selectemergency = SE2,
+ selectiepscallind = SI2,
+ selectLogic = SL2}) ->
+ validate(fun() -> chk_opt_NULL(T1, T2) end,
+ 'ContextAttrAuditRequest_topology'),
+ validate(fun() -> chk_opt_NULL(E1, E2) end,
+ 'ContextAttrAuditRequest_emergency'),
+ validate(fun() -> chk_opt_NULL(P1, P2) end,
+ 'ContextAttrAuditRequest_priority'),
+ validate(fun() -> chk_opt_NULL(I1, I2) end,
+ 'ContextAttrAuditRequest_iepscallind'),
+ chk_ContextAttrAuditRequest_contextPropAud(lists:sort(A1),
+ lists:sort(A2)),
+ chk_ContextAttrAuditRequest_selectpriority(SP1, SP2),
+ chk_ContextAttrAuditRequest_selectemergency(SE1, SE2),
+ chk_ContextAttrAuditRequest_selectiepscallind(SI1, SI2),
+ chk_ContextAttrAuditRequest_selectLogic(SL1, SL2),
+ ok.
+
+chk_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_contextPropAud/1,
+ 'ContextAttrAuditRequest_contextPropAud', A);
+chk_ContextAttrAuditRequest_contextPropAud([], []) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud([] = T1, T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, [] = T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud_val', H)
+ end;
+chk_ContextAttrAuditRequest_contextPropAud([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextAttrAuditRequest_contextPropAud_val'),
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, T2) ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud', T1, T2).
+
+chk_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectpriority(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectpriority/1,
+ 'ContextAttrAuditRequest_selectpriority', A);
+chk_ContextAttrAuditRequest_selectpriority(SP1, SP2) ->
+ case (is_ContextAttrAuditRequest_selectpriority(SP1) andalso
+ is_ContextAttrAuditRequest_selectpriority(SP2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectpriority', SP1, SP2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectpriority', SP1, SP2)
+ end.
+
+chk_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectemergency(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectemergency/1,
+ 'ContextAttrAuditRequest_selectemergency', A);
+chk_ContextAttrAuditRequest_selectemergency(SE1, SE2) ->
+ case (is_ContextAttrAuditRequest_selectemergency(SE1) andalso
+ is_ContextAttrAuditRequest_selectemergency(SE2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectemergency', SE1, SE2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectemergency', SE1, SE2)
+ end.
+
+chk_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectiepscallind(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectiepscallind/1,
+ 'ContextAttrAuditRequest_selectiepscallind', A);
+chk_ContextAttrAuditRequest_selectiepscallind(SI1, SI2) ->
+ case (is_ContextAttrAuditRequest_selectiepscallind(SI1) andalso
+ is_ContextAttrAuditRequest_selectiepscallind(SI2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectiepscallind', SI1, SI2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectiepscallind', SI1, SI2)
+ end.
+
+chk_ContextAttrAuditRequest_selectLogic(SL1, SL2) ->
+ validate(fun() -> chk_opt_SelectLogic(SL1, SL2) end,
+ 'ContextAttrAuditRequest_selectLogic').
+
+
+%% -- SelectLogic --
+
+is_opt_SelectLogic(asn1_NOVALUE) ->
+ true;
+is_opt_SelectLogic(SL) ->
+ is_SelectLogic(SL).
+
+is_SelectLogic({Tag, Val}) ->
+ d("is_SelectLogic -> entry"),
+ is_SelectLogic_tag(Tag) andalso is_SelectLogic_val(Tag, Val);
+is_SelectLogic(_) ->
+ false.
+
+is_SelectLogic_tag(Tag) ->
+ Tags = [andAUDITSelect, orAUDITSelect],
+ lists:member(Tag, Tags).
+
+is_SelectLogic_val(andAUDITSelect, 'NULL') -> true;
+is_SelectLogic_val(orAUDITSelect, 'NULL') -> true;
+is_SelectLogic_val(_, _) -> false.
+
+chk_opt_SelectLogic(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SelectLogic(SL1, SL2) ->
+ chk_SelectLogic(SL1, SL2).
+
+chk_SelectLogic(SL, SL) ->
+ chk_type(fun is_SelectLogic/1, 'SelectLogic', SL);
+chk_SelectLogic(asn1_NOVALUE, {andAUDITSelect, 'NULL'}) ->
+ ok; % AND is default
+chk_SelectLogic({andAUDITSelect, 'NULL'}, asn1_NOVALUE) ->
+ ok; % AND is default
+chk_SelectLogic({Tag, Val1} = SL1, {Tag, Val2} = SL2) ->
+ case (is_SelectLogic_tag(Tag) andalso
+ is_SelectLogic_val(Tag, Val1) andalso
+ is_SelectLogic_val(Tag, Val2)) of
+ true ->
+ chk_SelectLogic_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SelectLogic', SL1, SL2)
+ end;
+chk_SelectLogic({Tag1, Val1} = SL1, {Tag2, Val2} = SL2) ->
+ case ((is_SelectLogic_tag(Tag1) andalso
+ is_SelectLogic_val(Tag1, Val1)) andalso
+ (is_SelectLogic_tag(Tag2) andalso
+ is_SelectLogic_val(Tag2, Val2))) of
+ true ->
+ not_equal('SelectLogic', SL1, SL2);
+ false ->
+ wrong_type('SelectLogic', SL1, SL2)
+ end;
+chk_SelectLogic(SL1, SL2) ->
+ wrong_type('SelectLogic', SL1, SL2).
+
+chk_SelectLogic_val(andAUDITSelect, SL1, SL2) ->
+ validate(fun() -> chk_NULL(SL1, SL2) end, 'SelectLogic_andAUDITSelect');
+chk_SelectLogic_val(orAUDITSelect, SL1, SL2) ->
+ validate(fun() -> chk_NULL(SL1, SL2) end, 'SelectLogic_orAUDITSelect').
+
+
+%% -- CommandRequest --
+
+is_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}) ->
+ d("is_CommandRequest -> entry with"
+ "~n Cmd: ~p"
+ "~n Opt: ~p"
+ "~n WR: ~p", [Cmd, Opt, WR]),
+ is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+is_CommandRequest(_) ->
+ false.
+
+chk_CommandRequest(C, C) ->
+ chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+ optional = Opt1,
+ wildcardReturn = WR1},
+ #'CommandRequest'{command = Cmd2,
+ optional = Opt2,
+ wildcardReturn = WR2}) ->
+ validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+ ok;
+chk_CommandRequest(R1, R2) ->
+ wrong_type('CommandRequest', R1, R2).
+
+
+%% -- Command --
+
+is_Command({Tag, Val}) ->
+ d("is_Command -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+is_Command(_) ->
+ false.
+
+is_Command_tag(Tag) ->
+ Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+ auditValueRequest, notifyReq, serviceChangeReq],
+ lists:member(Tag, Tags).
+
+is_Command_val(addReq, V) -> is_AmmRequest(V);
+is_Command_val(moveReq, V) -> is_AmmRequest(V);
+is_Command_val(modReq, V) -> is_AmmRequest(V);
+is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+chk_Command(Cmd, Cmd) ->
+ chk_type(fun is_Command/1, 'Command', Cmd);
+chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_Command_tag(Tag) andalso
+ is_Command_val(Tag, Val1) andalso
+ is_Command_val(Tag, Val2)) of
+ true ->
+ chk_Command_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+ (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+ true ->
+ not_equal('Command', Cmd1, Cmd2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command(Cmd1, Cmd2) ->
+ wrong_type('Command', Cmd1, Cmd2).
+
+
+chk_Command_val(addReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+chk_Command_val(moveReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+chk_Command_val(modReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+chk_Command_val(subtractReq, R1, R2) ->
+ validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+chk_Command_val(auditCapRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+chk_Command_val(auditValueRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end,
+ 'Command_auditValueRequest');
+chk_Command_val(notifyReq, R1, R2) ->
+ validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+chk_Command_val(serviceChangeReq, R1, R2) ->
+ validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+ 'Command_serviceChangeReq').
+
+
+%% -- CommandReply --
+
+is_CommandReply({Tag, Val}) ->
+ d("is_CommandReply -> entry"),
+ is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+is_CommandReply(_) ->
+ false.
+
+is_CommandReply_tag(Tag) ->
+ Tags = [addReply, moveReply, modReply, subtractReply,
+ auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+ lists:member(Tag, Tags).
+
+is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+ case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('CommandReply', Cmd)
+ end;
+chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_CommandReply_tag(Tag) andalso
+ is_CommandReply_val(Tag, Val1) andalso
+ is_CommandReply_val(Tag, Val2)) of
+ true ->
+ chk_CommandReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_CommandReply_tag(Tag1) andalso
+ is_CommandReply_val(Tag1, Val1)) andalso
+ (is_CommandReply_tag(Tag2) andalso
+ is_CommandReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('CommandReply', Cmd1, Cmd2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply(Cmd1, Cmd2) ->
+ wrong_type('CommandReply', Cmd1, Cmd2).
+
+chk_CommandReply_val(addReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+chk_CommandReply_val(moveReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+chk_CommandReply_val(modReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+chk_CommandReply_val(subtractReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+chk_CommandReply_val(auditCapReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditCapReply');
+chk_CommandReply_val(auditValueReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditValueReply');
+chk_CommandReply_val(notifyReply, V1, V2) ->
+ validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+ validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+ 'CommandReply_serviceChangeReply').
+
+
+%% -- TopologyRequest --
+
+is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+ terminationTo = T,
+ topologyDirection = TD,
+ streamID = S,
+ topologyDirectionExtension = TDE}) ->
+ d("is_TopologyRequest -> entry"),
+ is_TerminationID(F) andalso
+ is_TerminationID(T) andalso
+ is_TopologyRequest_topologyDirection(TD) andalso
+ is_opt_StreamID(S) andalso
+ is_TopologyRequest_topologyDirectionExtension(TDE);
+is_TopologyRequest(_) ->
+ false.
+
+is_TopologyRequest_topologyDirection(D) ->
+ lists:member(D, [bothway, isolate, oneway]).
+
+is_TopologyRequest_topologyDirectionExtension(asn1_NOVALUE) ->
+ true;
+is_TopologyRequest_topologyDirectionExtension(D) ->
+ lists:member(D, [onewayexternal, onewayboth]).
+
+
+chk_TopologyRequest(T, T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = TD1,
+ streamID = S1,
+ topologyDirectionExtension = TDE1},
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = TD2,
+ streamID = S2,
+ topologyDirectionExtension = TDE2}) ->
+ validate(fun() -> chk_TerminationID(F1, F2) end,
+ 'TopologyRequest_terminationFrom'),
+ validate(fun() -> chk_TerminationID(T1, T2) end,
+ 'TopologyRequest_terminationTo'),
+ chk_TopologyRequest_topologyDirection(TD1, TD2),
+ validate(fun() -> chk_opt_StreamID(S1, S2) end,
+ 'TopologyRequest_streamID'),
+ chk_TopologyRequest_topologyDirectionExtension(TDE1, TDE2),
+ ok.
+
+chk_TopologyRequest_topologyDirection(D, D) ->
+ case is_TopologyRequest_topologyDirection(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D)
+ end;
+chk_TopologyRequest_topologyDirection(D1, D2) ->
+ case (is_TopologyRequest_topologyDirection(D1) andalso
+ is_TopologyRequest_topologyDirection(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirection', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D1, D2)
+ end.
+
+chk_TopologyRequest_topologyDirectionExtension(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_TopologyRequest_topologyDirectionExtension(D, D) ->
+ case is_TopologyRequest_topologyDirectionExtension(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirectionExtension', D)
+ end;
+chk_TopologyRequest_topologyDirectionExtension(D1, D2) ->
+ case (is_TopologyRequest_topologyDirectionExtension(D1) andalso
+ is_TopologyRequest_topologyDirectionExtension(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirectionExtension', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirectionExtension', D1, D2)
+ end.
+
+
+%% -- AmmRequest --
+
+is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+ descriptors = Descs}) ->
+ d("is_AmmRequest -> entry with"
+ "~n Tids: ~p", [Tids]),
+ is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+is_AmmRequest(_) ->
+ false.
+
+is_AmmRequest_descriptors(Descs) ->
+ d("is_AmmRequest_descriptors -> entry"),
+ is_AmmRequest_descriptors(Descs, []).
+
+is_AmmRequest_descriptors([], _) ->
+ true;
+is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+ d("is_AmmRequest_descriptors -> entry with"
+ "~n Tag: ~p"
+ "~n FoundDescs: ~p", [Tag, FoundDescs]),
+ case lists:member(Tag, FoundDescs) of
+ true ->
+ atmost_once('AmmRequest_descriptors', Tag);
+ false ->
+ case is_AmmDescriptor(Desc) of
+ true ->
+ is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+ false ->
+ wrong_type('AmmRequest_descriptors', Desc)
+ end
+ end;
+is_AmmRequest_descriptors(Descs, _) ->
+ d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+ "~n Descs: ~p", [Descs]),
+ wrong_type('AmmRequest_descriptors', Descs).
+
+
+chk_AmmRequest(R, R) when is_record(R, 'AmmRequest') ->
+ d("chk_AmmRequest -> entry when equal"),
+ chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = Descs1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = Descs2}) ->
+ d("chk_AmmRequest -> entry with not equal"
+ "~n Tids1: ~p"
+ "~n Tids2: ~p", [Tids1, Tids2]),
+ validate(
+ fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'AmmRequest'),
+ validate(
+ fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+ 'AmmRequest'),
+ ok.
+
+
+chk_AmmRequest_descriptors([], []) ->
+ d("chk_AmmRequest_descriptors -> done when OK"),
+ ok;
+chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when equal"),
+ case is_AmmDescriptor(H) of
+ true ->
+ chk_AmmRequest_descriptors(T1, T2);
+ false ->
+ wrong_type('AmmRequest_descriptors_val', H)
+ end;
+chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when not equal"),
+ validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+ 'AmmRequest_descriptors_val'),
+ chk_AmmRequest_descriptors(T1, T2);
+chk_AmmRequest_descriptors(Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% -- AmmDescriptor --
+
+is_AmmDescriptor({Tag, Val}) ->
+ d("is_AmmDescriptor -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p",[Tag, Val]),
+ is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+is_AmmDescriptor(_) ->
+ false.
+
+is_AmmDescriptor_tag(Tag) ->
+ Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+ eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+ auditDescriptor, statisticsDescriptor],
+ lists:member(Tag, Tags).
+
+is_AmmDescriptor_val(mediaDescriptor, D) ->
+ is_MediaDescriptor(D);
+is_AmmDescriptor_val(modemDescriptor, D) ->
+ is_ModemDescriptor(D);
+is_AmmDescriptor_val(muxDescriptor, D) ->
+ is_MuxDescriptor(D);
+is_AmmDescriptor_val(eventsDescriptor, D) ->
+ is_EventsDescriptor(D);
+is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+ is_EventBufferDescriptor(D);
+is_AmmDescriptor_val(signalsDescriptor, D) ->
+ is_SignalsDescriptor(D);
+is_AmmDescriptor_val(digitMapDescriptor, D) ->
+ is_DigitMapDescriptor(D);
+is_AmmDescriptor_val(auditDescriptor, D) ->
+ is_AuditDescriptor(D);
+is_AmmDescriptor_val(statisticsDescriptor, D) ->
+ is_StatisticsDescriptor(D).
+
+chk_AmmDescriptor(D, D) ->
+ chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_AmmDescriptor_tag(Tag) andalso
+ is_AmmDescriptor_val(Tag, Val1) andalso
+ is_AmmDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_AmmDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_AmmDescriptor_tag(Tag1) andalso
+ is_AmmDescriptor_val(Tag1, Val1)) andalso
+ (is_AmmDescriptor_tag(Tag2) andalso
+ is_AmmDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('AmmDescriptor', Cmd1, Cmd2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor(Cmd1, Cmd2) ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+ validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+ validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+ validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+ validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+ validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+ validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% -- AmmsReply --
+
+is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+ terminationAudit = TA}) ->
+ is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+is_AmmsReply(_) ->
+ false.
+
+chk_AmmsReply(R, R) ->
+ is_AmmsReply(R);
+chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = TID2,
+ terminationAudit = TA2}) ->
+ validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+ validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+ ok;
+chk_AmmsReply(R1, R2) ->
+ wrong_type('AmmsReply', R1, R2).
+
+
+%% -- SubtractRequest --
+
+is_SubtractRequest(#'SubtractRequest'{terminationID = TID,
+ auditDescriptor = AD}) ->
+ d("is_SubtractDescriptor -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p",[TID, AD]),
+ is_TerminationIDList(TID) andalso is_opt_AuditDescriptor(AD);
+is_SubtractRequest(_) ->
+ false.
+
+chk_SubtractRequest(R, R) ->
+ chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'SubtractRequest'),
+ validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+ 'SubtractRequest'),
+ ok;
+chk_SubtractRequest(SR1, SR2) ->
+ wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% -- AuditRequest --
+
+is_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = asn1_NOVALUE}) ->
+ d("is_AuditRequest -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p",[TID, AD]),
+ is_TerminationID(TID) andalso
+ is_AuditDescriptor(AD);
+is_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = [TID|_] = TIDs}) ->
+ d("is_AuditRequest -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p"
+ "~n TIDs: ~p",[TID, AD, TIDs]),
+ is_TerminationID(TID) andalso
+ is_AuditDescriptor(AD) andalso
+ is_TerminationIDList(TIDs);
+is_AuditRequest(_) ->
+ false.
+
+chk_AuditRequest(R, R) ->
+ chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+chk_AuditRequest(#'AuditRequest'{terminationID = TID1,
+ auditDescriptor = AD1,
+ terminationIDList = [TID1|_] = TIDs1},
+ #'AuditRequest'{terminationID = TID2,
+ auditDescriptor = AD2,
+ terminationIDList = [TID2|_] = TIDs2}) ->
+ validate(fun() -> chk_TerminationID(TID1, TID2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_opt_TerminationIDList(TIDs1, TIDs2) end,
+ 'AuditRequest'),
+ ok;
+chk_AuditRequest(AR1, AR2) ->
+ wrong_type('AuditRequest', AR1, AR2).
+
+
+%% -- AuditReply --
+
+is_AuditReply({Tag, Val}) ->
+ is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+is_AuditReply(_) ->
+ false.
+
+is_AuditReply_tag(Tag) ->
+ Tags = [contextAuditResult, error, auditResult, auditResultTermList],
+ lists:member(Tag, Tags).
+
+is_AuditReply_val(contextAuditResult, Val) ->
+ is_TerminationIDList(Val);
+is_AuditReply_val(error, Val) ->
+ is_ErrorDescriptor(Val);
+is_AuditReply_val(auditResult, Val) ->
+ is_AuditResult(Val);
+is_AuditReply_val(auditResultTermList, Val) ->
+ is_TermListAuditResult(Val).
+
+chk_AuditReply(R, R) ->
+ chk_type(fun is_AuditReply/1, 'AuditReply', R);
+chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_AuditReply_tag(Tag) andalso
+ is_AuditReply_val(Tag, Val1)andalso
+ is_AuditReply_val(Tag, Val2)) of
+ true ->
+ chk_AuditReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_AuditReply_tag(Tag1) andalso
+ is_AuditReply_val(Tag1, Val1)) andalso
+ (is_AuditReply_tag(Tag2) andalso
+ is_AuditReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReply', R1, R2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply(AR1, AR2) ->
+ wrong_type('AuditReply', AR1, AR2).
+
+chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+ chk_TerminationIDList(Val1, Val2);
+chk_AuditReply_val(error, Val1, Val2) ->
+ chk_ErrorDescriptor(Val1, Val2);
+chk_AuditReply_val(auditResult, Val1, Val2) ->
+ chk_AuditResult(Val1, Val2);
+chk_AuditReply_val(auditResultTermList, Val1, Val2) ->
+ chk_TermListAuditResult(Val1, Val2).
+
+
+%% -- AuditResult --
+
+is_AuditResult(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}) ->
+ is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+is_AuditResult(_) ->
+ false.
+
+chk_AuditResult(R, R) ->
+ d("chk_AuditResult -> entry (1)"),
+ chk_type(fun is_AuditResult/1, 'AuditResult', R);
+chk_AuditResult(#'AuditResult'{terminationID = TID1,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = TID2,
+ terminationAuditResult = TAR2}) ->
+ d("chk_AuditResult -> entry (2)"),
+ validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+ ok;
+chk_AuditResult(AR1, AR2) ->
+ d("chk_AuditResult -> entry (3)"),
+ wrong_type('AuditResult', AR1, AR2).
+
+
+%% -- TermListAuditResult --
+
+is_TermListAuditResult(#'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TAR}) ->
+ is_TerminationIDList(TIDs) andalso is_TerminationAudit(TAR);
+is_TermListAuditResult(_) ->
+ false.
+
+chk_TermListAuditResult(TLAR, TLAR) ->
+ d("chk_TermListAuditResult(1) -> entry with"
+ "~n TLAR: ~p", [TLAR]),
+ chk_type(fun is_TermListAuditResult/1, 'TermListAuditResult', TLAR);
+chk_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDs1,
+ terminationAuditResult = TAR1},
+ #'TermListAuditResult'{terminationIDList = TIDs2,
+ terminationAuditResult = TAR2}) ->
+ d("chk_TermListAuditResult(2) -> entry with"
+ "~n TIDs1: ~p"
+ "~n TAR1: ~p"
+ "~n TIDs2: ~p"
+ "~n TAR2: ~p", [TIDs1, TAR1, TIDs2, TAR2]),
+ validate(fun() -> chk_TerminationIDList(TIDs1, TIDs2) end,
+ 'TermListAuditResult_terminationIDList'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end,
+ 'TermListAuditResult_terminationAuditResult'),
+ ok;
+chk_TermListAuditResult(TLAR1, TLAR2) ->
+ d("chk_TermListAuditResult(3) -> entry with"
+ "~n TLAR1: ~p"
+ "~n TLAR2: ~p", [TLAR1, TLAR2]),
+ wrong_type('TermListAuditResult', TLAR1, TLAR2).
+
+
+%% -- TerminationAudit --
+
+is_opt_TerminationAudit(TA) ->
+ is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+is_TerminationAudit([]) ->
+ true;
+is_TerminationAudit([H|T]) ->
+ is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+is_TerminationAudit(_) ->
+ false.
+
+chk_opt_TerminationAudit(TA1, TA2) ->
+ d("chk_opt_TerminationAudit -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ chk_OPTIONAL('TerminationAudit',
+ strip_TerminationAudit(TA1),
+ strip_TerminationAudit(TA2),
+ fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+strip_TerminationAudit(L) when is_list(L) ->
+ d("strip_TerminationAudit(1) -> entry with"
+ "~n L: ~p", [L]),
+ %% Drop all empty emptyDescriptor's
+ F = fun({emptyDescriptors, AD}) ->
+ case AD of
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE} ->
+ true;
+ _ ->
+ false
+ end;
+ (_) ->
+ false
+ end,
+ lists:dropwhile(F, L);
+strip_TerminationAudit(asn1_NOVALUE) ->
+ d("strip_TerminationAudit(2) -> entry"),
+ [];
+strip_TerminationAudit(X) ->
+ d("strip_TerminationAudit(3) -> entry with"
+ "~n X: ~p", [X]),
+ X.
+
+chk_TerminationAudit(TA1, TA2) ->
+ d("chk_TerminationAudit -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ do_chk_TerminationAudit(strip_TerminationAudit(TA1),
+ strip_TerminationAudit(TA2)).
+
+do_chk_TerminationAudit([], []) ->
+ d("do_chk_TerminationAudit(1) -> entry"),
+ ok;
+do_chk_TerminationAudit([], asn1_NOVALUE) ->
+ d("do_chk_TerminationAudit(2) -> entry"),
+ ok;
+do_chk_TerminationAudit(asn1_NOVALUE, []) ->
+ d("do_chk_TerminationAudit(3) -> entry"),
+ ok;
+do_chk_TerminationAudit([] = TA1, TA2) ->
+ d("do_chk_TerminationAudit(4) -> entry with"
+ "~n TA2: ~p", [TA2]),
+ not_equal('TerminationAudit', TA1, TA2);
+do_chk_TerminationAudit(TA1, [] = TA2) ->
+ d("do_chk_TerminationAudit(5) -> entry with"
+ "~n TA1: ~p", [TA1]),
+ not_equal('TerminationAudit', TA1, TA2);
+do_chk_TerminationAudit([H|T1], [H|T2]) ->
+ d("do_chk_TerminationAudit(6) -> entry with"
+ "~n H: ~p", [H]),
+ case is_AuditReturnParameter(H) of
+ true ->
+ do_chk_TerminationAudit(T1, T2);
+ false ->
+ wrong_type('TerminationAudit', H)
+ end;
+do_chk_TerminationAudit([H1|T1], [H2|T2]) ->
+ d("do_chk_TerminationAudit(7) -> entry with"
+ "~n H1: ~p"
+ "~n H2: ~p", [H1, H2]),
+ chk_AuditReturnParameter(H1, H2),
+ do_chk_TerminationAudit(T1, T2);
+do_chk_TerminationAudit(TA1, TA2) ->
+ d("do_chk_TerminationAudit(8) -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ not_equal('TerminationAudit', TA1, TA2).
+
+
+%% -- AuditReturnParameter --
+
+is_AuditReturnParameter({Tag, Val}) ->
+ is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val);
+is_AuditReturnParameter(_) ->
+ false.
+
+is_AuditReturnParameter_tag(Tag) ->
+ Tags = [errorDescriptor,
+ mediaDescriptor,
+ modemDescriptor,
+ muxDescriptor,
+ eventsDescriptor,
+ eventBufferDescriptor,
+ signalsDescriptor,
+ digitMapDescriptor,
+ observedEventsDescriptor,
+ statisticsDescriptor,
+ packagesDescriptor,
+ emptyDescriptors],
+ lists:member(Tag, Tags).
+
+is_AuditReturnParameter_val(errorDescriptor, V) ->
+ is_ErrorDescriptor(V);
+is_AuditReturnParameter_val(mediaDescriptor, V) ->
+ is_MediaDescriptor(V);
+is_AuditReturnParameter_val(modemDescriptor, V) ->
+ is_ModemDescriptor(V);
+is_AuditReturnParameter_val(muxDescriptor, V) ->
+ is_MuxDescriptor(V);
+is_AuditReturnParameter_val(eventsDescriptor, V) ->
+ is_EventsDescriptor(V);
+is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+ is_EventBufferDescriptor(V);
+is_AuditReturnParameter_val(signalsDescriptor, V) ->
+ is_SignalsDescriptor(V);
+is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+ is_DigitMapDescriptor(V);
+is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+ is_ObservedEventsDescriptor(V);
+is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+ is_StatisticsDescriptor(V);
+is_AuditReturnParameter_val(packagesDescriptor, V) ->
+ is_PackagesDescriptor(V);
+is_AuditReturnParameter_val(emptyDescriptors, V) ->
+ is_AuditDescriptor(V).
+
+chk_AuditReturnParameter(ARP, ARP) ->
+ chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+ case (is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val1) andalso
+ is_AuditReturnParameter_val(Tag, Val2)) of
+ true ->
+ chk_AuditReturnParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+ case ((is_AuditReturnParameter_tag(Tag1) andalso
+ is_AuditReturnParameter_val(Tag1, Val1)) andalso
+ (is_AuditReturnParameter_tag(Tag2) andalso
+ is_AuditReturnParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReturnParameter', ARP1, ARP2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter(ARP1, ARP2) ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+ validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+ validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+ validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+ validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+ validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+ validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+ validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+ validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+ validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+ 'AuditReturnParameter').
+
+
+%% -- AuditDescriptor --
+
+is_opt_AuditDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_AuditDescriptor(V) ->
+ is_AuditDescriptor(V).
+
+is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}) ->
+ d("is_AuditDescriptor -> entry with"
+ "~n AT: ~p"
+ "~n APT: ~p", [AT, APT]),
+ is_AuditDescriptor_auditToken(AT) andalso
+ is_AuditDescriptor_auditPropertyToken(APT);
+is_AuditDescriptor(_) ->
+ false.
+
+is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditToken([]) ->
+ true;
+is_AuditDescriptor_auditToken([H|T]) ->
+ is_AuditDescriptor_auditToken_val(H) andalso
+ is_AuditDescriptor_auditToken(T);
+is_AuditDescriptor_auditToken(_) ->
+ false.
+
+is_AuditDescriptor_auditToken_val(V) ->
+ Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, observedEventsToken,
+ packagesToken, eventBufferToken],
+ lists:member(V, Toks).
+
+is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([]) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([H|T]) ->
+ d("is_AuditDescriptor_auditPropertyToken -> entry with"
+ "~n H: ~p", [H]),
+ is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+is_AuditDescriptor_auditPropertyToken(_) ->
+ false.
+
+chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(AD1, AD2) ->
+ chk_AuditDescriptor(AD1, AD2).
+
+chk_AuditDescriptor(AD, AD) ->
+ chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = AT2,
+ auditPropertyToken = APT2}) ->
+ chk_AuditDescriptor_auditToken(maybe_sort(AT1), maybe_sort(AT2)),
+ chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+ ok;
+chk_AuditDescriptor(AD1, AD2) ->
+ wrong_type('AuditDescriptor', AD1, AD2).
+
+chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+ case is_AuditDescriptor_auditToken_val(H) of
+ true ->
+ chk_AuditDescriptor_auditToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H)
+ end;
+chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+ case (is_AuditDescriptor_auditToken_val(H1) andalso
+ is_AuditDescriptor_auditToken_val(H2)) of
+ true ->
+ not_equal('AuditDescriptor_auditToken_val', H1, H2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+ end;
+chk_AuditDescriptor_auditToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+ case is_IndAuditParameter(H) of
+ true ->
+ chk_AuditDescriptor_auditPropertyToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+ end;
+chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+ chk_IndAuditParameter(H1, H2),
+ not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% -- IndAuditParameter --
+
+is_IndAuditParameter({Tag, Val}) ->
+ is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+is_IndAuditParameter(_) ->
+ false.
+
+is_IndAuditParameter_tag(Tag) ->
+ Tags = [indAudMediaDescriptor,
+ indAudEventsDescriptor,
+ indAudEventBufferDescriptor,
+ indAudSignalsDescriptor,
+ indAudDigitMapDescriptor,
+ indAudStatisticsDescriptor,
+ indAudPackagesDescriptor],
+ lists:member(Tag, Tags).
+
+is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+ is_IndAudMediaDescriptor(Val);
+is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+ is_IndAudEventsDescriptor(Val);
+is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+ is_IndAudEventBufferDescriptor(Val);
+is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+ is_IndAudSignalsDescriptor(Val);
+is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+ is_IndAudDigitMapDescriptor(Val);
+is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+ is_IndAudStatisticsDescriptor(Val);
+is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+ is_IndAudPackagesDescriptor(Val).
+
+chk_IndAuditParameter(IAP, IAP) ->
+ chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+ case (is_IndAuditParameter_tag(Tag) andalso
+ is_IndAuditParameter_val(Tag, Val1) andalso
+ is_IndAuditParameter_val(Tag, Val2)) of
+ true ->
+ chk_IndAuditParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+ case ((is_IndAuditParameter_tag(Tag1) andalso
+ is_IndAuditParameter_val(Tag1, Val1)) andalso
+ (is_IndAuditParameter_tag(Tag2) andalso
+ is_IndAuditParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAuditParameter', IAP1, IAP2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter(IAP1, IAP2) ->
+ wrong_type('IndAuditParameter', IAP1, IAP2).
+
+chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+ 'IndAuditParameter').
+
+
+%% -- IndAudMediaDescriptor --
+
+is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_IndAudMediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+ is_IndAudMediaDescriptor_streams(S);
+is_IndAudMediaDescriptor(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+ d("is_IndAudMediaDescriptor_streams -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val);
+is_IndAudMediaDescriptor_streams(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+ d("is_IndAudMediaDescriptor_streams_val(oneStream) -> entry with"
+ "~n Val: ~p", [Val]),
+ is_IndAudStreamParms(Val);
+is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+ d("is_IndAudMediaDescriptor_streams_val(multiStream) -> entry with"
+ "~n Val: ~p", [Val]),
+ is_IndAudMediaDescriptor_multiStream(Val).
+
+is_IndAudMediaDescriptor_multiStream([]) ->
+ true;
+is_IndAudMediaDescriptor_multiStream([H|T]) ->
+ d("is_IndAudMediaDescriptor_multiStream -> entry with"
+ "~n H: ~p", [H]),
+ is_IndAudStreamDescriptor(H) andalso
+ is_IndAudMediaDescriptor_multiStream(T);
+is_IndAudMediaDescriptor_multiStream(_) ->
+ false.
+
+chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+ chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+ 'IndAudMediaDescriptor'),
+ validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+ 'IndAudMediaDescriptor'),
+ ok;
+chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+ wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+ {Tag, Val2} = S2) ->
+ case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+ true ->
+ chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+ {Tag2, Val2} = S2) ->
+ case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+ (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudMediaDescriptor_streams', S1, S2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams(S1, S2) ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams');
+chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams').
+
+chk_IndAudMediaDescriptor_multiStream([], []) ->
+ ok;
+chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_IndAudStreamDescriptor(H) of
+ true ->
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+ end;
+chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+ 'IndAudMediaDescriptor_multiStream_val'),
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% -- IndAudStreamDescriptor --
+
+is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_IndAudStreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+is_IndAudStreamDescriptor(_) ->
+ false.
+
+chk_IndAudStreamDescriptor(D, D) ->
+ chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'IndAudStreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+ validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+ 'IndAudStreamDescriptor'),
+ ok;
+chk_IndAudStreamDescriptor(D1, D2) ->
+ wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% -- IndAudStreamParms --
+
+is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ d("is_IndAudStreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p", [LCD, LD, RD]),
+ is_opt_IndAudLocalControlDescriptor(LCD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(RD);
+is_IndAudStreamParms(_) ->
+ false.
+
+chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+ 'IndAudStreamParms'),
+ ok;
+chk_IndAudStreamParms(D1, D2) ->
+ wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% -- IndAudLocalControlDescriptor --
+
+is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalControlDescriptor(D) ->
+ is_IndAudLocalControlDescriptor(D).
+
+is_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs,
+ streamModeSel = SMS}) ->
+ d("is_IndAudLocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PPs: ~p"
+ "~n SMS: ~p", [SM, RV, RG, PPs, SMS]),
+ is_opt_NULL(SM) andalso
+ is_opt_NULL(RV) andalso
+ is_opt_NULL(RG) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(PPs) andalso
+ is_opt_StreamMode(SMS);
+is_IndAudLocalControlDescriptor(_) ->
+ false.
+
+is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([]) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(T);
+is_IndAudLocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PPs1,
+ streamModeSel = SMS1},
+ #'IndAudLocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PPs2,
+ streamModeSel = SMS2}) ->
+ chk_IndAudLocalControlDescriptor_streamMode(SM1, SM2),
+ chk_IndAudLocalControlDescriptor_reserveValue(RV1, RV2),
+ chk_IndAudLocalControlDescriptor_reserveGroup(RG1, RG2),
+ chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+ chk_IndAudLocalControlDescriptor_streamModeSel(SMS1, SMS2),
+ ok;
+chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+chk_IndAudLocalControlDescriptor_streamMode(SM1, SM2) ->
+ validate(fun() -> chk_opt_NULL(SM1, SM2) end,
+ 'IndAudLocalControlDescriptor_streamMode').
+
+chk_IndAudLocalControlDescriptor_reserveValue(RV1, RV2) ->
+ validate(fun() -> chk_opt_NULL(RV1, RV2) end,
+ 'IndAudLocalControlDescriptor_reserveValue').
+
+chk_IndAudLocalControlDescriptor_reserveGroup(RG1, RG2) ->
+ validate(fun() -> chk_opt_NULL(RG1, RG2) end,
+ 'IndAudLocalControlDescriptor_reserveGroup').
+
+chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudLocalControlDescriptor_propertyParms_val'),
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+chk_IndAudLocalControlDescriptor_streamModeSel(SMS1, SMS2) ->
+ validate(fun() -> chk_opt_StreamMode(SMS1, SMS2) end,
+ 'IndAudLocalControlDescriptor_streamModeSel').
+
+
+%% -- IndAudPropertyParm --
+
+is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name,
+ propertyParms = PP}) ->
+ d("is_IndAudPropertyParm -> entry"),
+ is_PkgdName(Name) andalso is_opt_PropertyParm(PP);
+is_IndAudPropertyParm(_) ->
+ false.
+
+chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1,
+ propertyParms = PP1},
+ #'IndAudPropertyParm'{name = Name2,
+ propertyParms = PP2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end, 'IndAudPropertyParm'),
+ validate(fun() -> chk_opt_PropertyParm(PP1, PP2) end,
+ 'IndAudPropertyParm'),
+ ok;
+chk_IndAudPropertyParm(P1, P2) ->
+ wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% -- IndAudLocalRemoteDescriptor --
+
+is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalRemoteDescriptor(D) ->
+ is_IndAudLocalRemoteDescriptor(D).
+
+is_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps}) ->
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+ is_IndAudPropertyGroup(Grps);
+is_IndAudLocalRemoteDescriptor(_) ->
+ false.
+
+is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+ chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+chk_IndAudLocalRemoteDescriptor(D, D) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+ 'IndAudLocalRemoteDescriptor', D);
+chk_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+ propGrps = Grps1},
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+ propGrps = Grps2}) ->
+ chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+ chk_IndAudPropertyGroup(Grps1, Grps2),
+ ok;
+chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+ 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+ case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+ true ->
+ not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+ false ->
+ wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+ end.
+
+
+%% -- IndAudPropertyGroup --
+
+is_IndAudPropertyGroup([]) ->
+ true;
+is_IndAudPropertyGroup([H|T]) ->
+ is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+is_IndAudPropertyGroup(_) ->
+ false.
+
+chk_IndAudPropertyGroup([], []) ->
+ ok;
+chk_IndAudPropertyGroup([] = PG1, PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudPropertyGroup(T1, T2);
+ false ->
+ wrong_type('IndAudPropertyGroup_val', H)
+ end;
+chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudPropertyGroup_val'),
+ chk_IndAudPropertyGroup(T1, T2);
+chk_IndAudPropertyGroup(P1, P2) ->
+ wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% -- IndAudTerminationStateDescriptor --
+
+is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudTerminationStateDescriptor(D) ->
+ is_IndAudTerminationStateDescriptor(D).
+
+is_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS}) ->
+ is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+ is_opt_NULL(EBC) andalso
+ is_opt_NULL(SS) andalso
+ is_opt_ServiceState(SSS);
+is_IndAudTerminationStateDescriptor(_) ->
+ false.
+
+is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudTerminationStateDescriptor_propertyParms(T);
+is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+ chk_IndAudTerminationStateDescriptor(D1, D2).
+
+chk_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+ eventBufferControl = EBC1,
+ serviceState = SS1,
+ serviceStateSel = SSS1},
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}) ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+ chk_IndAudTerminationStateDescriptor_eventBufferControl(EBC1, EBC2),
+ chk_IndAudTerminationStateDescriptor_serviceState(SS1, SS2),
+ chk_IndAudTerminationStateDescriptor_serviceStateSel(SSS1, SSS2),
+ ok;
+chk_IndAudTerminationStateDescriptor(D1, D2) ->
+ wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+ end;
+chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudTerminationStateDescriptor_propertyParms'),
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+chk_IndAudTerminationStateDescriptor_eventBufferControl(EBC1, EBC2) ->
+ validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+ 'IndAudTerminationStateDescriptor_eventBufferControl').
+
+chk_IndAudTerminationStateDescriptor_serviceState(SS1, SS2) ->
+ validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+ 'IndAudTerminationStateDescriptor_serviceState').
+
+chk_IndAudTerminationStateDescriptor_serviceStateSel(SSS1, SSS2) ->
+ validate(fun() -> chk_opt_ServiceState(SSS1, SSS2) end,
+ 'IndAudTerminationStateDescriptor_serviceStateSel').
+
+%% -- IndAudEventsDescriptor --
+
+is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = SID}) ->
+ is_opt_RequestID(RID) andalso
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID);
+is_IndAudEventsDescriptor(_) ->
+ false.
+
+chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+ pkgdName = Name1,
+ streamID = SID1},
+ #'IndAudEventsDescriptor'{requestID = RID2,
+ pkgdName = Name2,
+ streamID = SID2}) ->
+ chk_opt_RequestID(RID1, RID2),
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventsDescriptor(D1, D2) ->
+ wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% -- IndAudEventBufferDescriptor --
+
+is_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudEventBufferDescriptor(_) ->
+ false.
+
+chk_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name1,
+ streamID = SID1},
+ #'IndAudEventBufferDescriptor'{eventName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventBufferDescriptor(D1, D2) ->
+ wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% -- IndAudSignalsDescriptor --
+
+is_IndAudSignalsDescriptor({Tag, Val}) ->
+ is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val);
+is_IndAudSignalsDescriptor(_) ->
+ false.
+
+is_IndAudSignalsDescriptor_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_IndAudSignalsDescriptor_val(signal, Val) ->
+ is_IndAudSignal(Val);
+is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+ is_IndAudSeqSigList(Val).
+
+chk_IndAudSignalsDescriptor(D, D) ->
+ chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+ case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+ case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+ is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+ (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+ is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudSignalsDescriptor', D1, D2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor(D1, D2) ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+ chk_IndAudSignal(Val1, Val2);
+chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+ chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% -- IndAudSeqSigList --
+
+is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+is_IndAudSeqSigList(_) ->
+ false.
+
+is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+chk_IndAudSeqSigList(L, L) ->
+ chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+ signalList = SL1},
+ #'IndAudSeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ chk_IndAudSeqSigList_id(ID1, ID2),
+ chk_opt_IndAudSignal(SL1, SL2),
+ ok;
+chk_IndAudSeqSigList(L1, L2) ->
+ wrong_type('IndAudSeqSigList', L1, L2).
+
+chk_IndAudSeqSigList_id(ID, ID) ->
+ chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+chk_IndAudSeqSigList_id(ID1, ID2) ->
+ case (is_IndAudSeqSigList_id(ID1) andalso
+ is_IndAudSeqSigList_id(ID2)) of
+ true ->
+ not_equal('IndAudSeqSigList_id', ID1, ID2);
+ false ->
+ wrong_type('IndAudSeqSigList_id', ID1, ID2)
+ end.
+
+
+%% -- IndAudSignal --
+
+is_opt_IndAudSignal(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudSignal(V) ->
+ is_IndAudSignal(V).
+
+is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+ streamID = SID,
+ signalRequestID = SRID}) ->
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestID(SRID);
+is_IndAudSignal(_) ->
+ false.
+
+chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudSignal(S1, S2) ->
+ chk_IndAudSignal(S1, S2).
+
+chk_IndAudSignal(S, S) ->
+ chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+ streamID = SID1,
+ signalRequestID = SRID1},
+ #'IndAudSignal'{signalName = Name2,
+ streamID = SID2,
+ signalRequestID = SRID2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudSignal_signalName'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'IndAudSignal_streamID'),
+ validate(fun() -> chk_opt_RequestID(SRID1, SRID2) end,
+ 'IndAudSignal_signalRequestID'),
+ ok;
+chk_IndAudSignal(S1, S2) ->
+ wrong_type('IndAudSignal', S1, S2).
+
+
+%% -- IndAudDigitMapDescriptor --
+
+is_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+ is_opt_DigitMapName(Name);
+is_IndAudDigitMapDescriptor(_) ->
+ false.
+
+chk_IndAudDigitMapDescriptor(D, D) ->
+ chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+chk_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+ #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'IndAudDigitMapDescriptor'),
+ ok;
+chk_IndAudDigitMapDescriptor(D1, D2) ->
+ wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% -- IndAudStatisticsDescriptor --
+
+is_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name}) ->
+ is_PkgdName(Name);
+is_IndAudStatisticsDescriptor(_) ->
+ false.
+
+chk_IndAudStatisticsDescriptor(D, D) ->
+ chk_type(fun is_IndAudStatisticsDescriptor/1,
+ 'IndAudStatisticsDescriptor', D);
+chk_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name1},
+ #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudStatisticsDescriptor'),
+ ok;
+chk_IndAudStatisticsDescriptor(D1, D2) ->
+ wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% -- IndAudPackagesDescriptor --
+
+is_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = Ver}) ->
+ is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+is_IndAudPackagesDescriptor(_) ->
+ false.
+
+is_IndAudPackagesDescriptor_packageVersion(V) ->
+ is_INTEGER(V, {range, 0, 99}).
+
+chk_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name1,
+ packageVersion = Ver1},
+ #'IndAudPackagesDescriptor'{packageName = Name2,
+ packageVersion = Ver2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+ chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+ ok;
+chk_IndAudPackagesDescriptor(D1, D2) ->
+ wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+ chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+ 'IndAudPackagesDescriptor_packageVersion', V);
+chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+ case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+ is_IndAudPackagesDescriptor_packageVersion(V2)) of
+ true ->
+ not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+ false ->
+ wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+ end.
+
+
+%% -- NotifyRequest --
+
+is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso
+ is_ObservedEventsDescriptor(OED) andalso
+ is_opt_ErrorDescriptor(ED);
+is_NotifyRequest(_) ->
+ false.
+
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = OED1,
+ errorDescriptor = ED1},
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = OED2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+ 'NotifyRequest'),
+ ok;
+chk_NotifyRequest(NR1, NR2) ->
+ wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% -- NotifyReply --
+
+is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+is_NotifyReply(_) ->
+ false.
+
+chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+ errorDescriptor = ED1},
+ #'NotifyReply'{terminationID = Tids2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+ ok;
+chk_NotifyReply(NR1, NR2) ->
+ wrong_type('NotifyReply', NR1, NR2).
+
+
+%% -- ObservedEventsDescriptor --
+
+is_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}) ->
+ is_RequestID(RID) andalso
+ is_ObservedEventsDescriptor_observedEventLst(OEL);
+is_ObservedEventsDescriptor(_) ->
+ false.
+
+is_ObservedEventsDescriptor_observedEventLst([]) ->
+ true;
+is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+ is_ObservedEvent(H) andalso
+ is_ObservedEventsDescriptor_observedEventLst(T);
+is_ObservedEventsDescriptor_observedEventLst(_) ->
+ false.
+
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID1,
+ observedEventLst = OEL1},
+ #'ObservedEventsDescriptor'{requestId = RID2,
+ observedEventLst = OEL2}) ->
+ validate(fun() -> chk_RequestID(RID1, RID2) end,
+ 'ObservedEventsDescriptor'),
+ validate(
+ fun() ->
+ chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+ end,
+ 'ObservedEventsDescriptor'),
+ ok;
+chk_ObservedEventsDescriptor(D1, D2) ->
+ wrong_type('ObservedEventsDescriptor', D1, D2).
+
+chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+ ok;
+chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+ case is_ObservedEvent(H) of
+ true ->
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+ false ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+ end;
+chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ObservedEvent(H1, H2) end,
+ 'ObservedEventsDescriptor_observedEventLst_val'),
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% -- ObservedEvent --
+
+is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}) ->
+ is_EventName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_ObservedEvent_eventParList(EPL) andalso
+ is_opt_TimeNotation(TN);
+is_ObservedEvent(_) ->
+ false.
+
+is_ObservedEvent_eventParList([]) ->
+ true;
+is_ObservedEvent_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+is_ObservedEvent_eventParList(_) ->
+ false.
+
+chk_ObservedEvent(E, E) ->
+ chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+ streamID = SID1,
+ eventParList = EPL1,
+ timeNotation = TN1},
+ #'ObservedEvent'{eventName = Name2,
+ streamID = SID2,
+ eventParList = EPL2,
+ timeNotation = TN2}) ->
+ validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+ chk_ObservedEvent_eventParList(EPL1, EPL2),
+ validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+ ok;
+chk_ObservedEvent(E1, E2) ->
+ wrong_type('ObservedEvent', E1, E2).
+
+chk_ObservedEvent_eventParList([], []) ->
+ ok;
+chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_ObservedEvent_eventParList(T1, T2);
+ false ->
+ wrong_type('ObservedEvent_eventParList_val', H)
+ end;
+chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'ObservedEvent_eventParList'),
+ chk_ObservedEvent_eventParList(T1, T2);
+chk_ObservedEvent_eventParList(L1, L2) ->
+ wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+chk_EventName(N, N) ->
+ chk_type(fun is_EventName/1, 'EventName', N);
+chk_EventName(N1, N2) ->
+ case (is_EventName(N1) andalso is_EventName(N2)) of
+ true ->
+ not_equal('EventName', N1, N2);
+ false ->
+ wrong_type('EventName', N1, N2)
+ end.
+
+
+%% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+ value = Val1,
+ extraInfo = EI1},
+ #'EventParameter'{eventParameterName = Name2,
+ value = Val2,
+ extraInfo = EI2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+ validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+ chk_EventParameter_extraInfo(EI1, EI2),
+ ok;
+chk_EventParameter(P1, P2) ->
+ wrong_type('EventParameter', P1, P2).
+
+chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_EventParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_EventParameter_extraInfo/1,
+ 'EventParameter_extraInfo', EI);
+chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val1) andalso
+ is_EventParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+ is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+ (is_EventParameter_extraInfo_tag(Tag2) andalso
+ is_EventParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo(EI1, EI2) ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val').
+
+
+%% -- ServiceChangeRequest --
+
+is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+ serviceChangeParms = Parms}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+is_ServiceChangeRequest(_) ->
+ false.
+
+chk_ServiceChangeRequest(R, R) ->
+ chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+chk_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = Parms1},
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = Parms2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeRequest'),
+ validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+ 'ServiceChangeRequest'),
+ ok;
+chk_ServiceChangeRequest(R1, R2) ->
+ wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% -- ServiceChangeReply --
+
+is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+ serviceChangeResult = Res}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+is_ServiceChangeReply(_) ->
+ false.
+
+chk_ServiceChangeReply(R, R) ->
+ chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+chk_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = Tids1,
+ serviceChangeResult = Res1},
+ #'ServiceChangeReply'{terminationID = Tids2,
+ serviceChangeResult = Res2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeReply'),
+ validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+ 'ServiceChangeReply'),
+ ok;
+chk_ServiceChangeReply(R1, R2) ->
+ wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% -- ServiceChangeResult --
+
+is_ServiceChangeResult({Tag, Val}) ->
+ is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val);
+is_ServiceChangeResult(_) ->
+ false.
+
+is_ServiceChangeResult_tag(Tag) ->
+ Tags = [errorDescriptor, serviceChangeResParms],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeResult_val(errorDescriptor, Val) ->
+ is_ErrorDescriptor(Val);
+is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+ is_ServiceChangeResParm(Val).
+
+chk_ServiceChangeResult(Res, Res) ->
+ chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+ case (is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val1) andalso
+ is_ServiceChangeResult_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+ case ((is_ServiceChangeResult_tag(Tag1) andalso
+ is_ServiceChangeResult_val(Tag1, Val1)) andalso
+ (is_ServiceChangeResult_tag(Tag2) andalso
+ is_ServiceChangeResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeResult', Res1, Res2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult(Res1, Res2) ->
+ wrong_type('ServiceChangeResult', Res1, Res2).
+
+chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'ServiceChangeResult');
+chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+ validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+ 'ServiceChangeResult').
+
+
+%% -- WildcardField --
+
+is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+chk_WildcardField(WF, WF) ->
+ case is_WildcardField(WF) of
+ true ->
+ ok;
+ false ->
+ wrong_type('WildcardField', WF)
+ end;
+chk_WildcardField(WF1, WF2) ->
+ case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+ true ->
+ not_equal('WildcardField', WF1, WF2);
+ false ->
+ wrong_type('WildcardField', WF1, WF2)
+ end.
+
+
+%% -- TerminationID --
+
+is_TerminationID(#'TerminationID'{wildcard = W,
+ id = ID}) ->
+ is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+ id = _ID}) ->
+ true; % What are the types?
+is_TerminationID(_) ->
+ false.
+
+is_TerminationID_wildcard([]) ->
+ true;
+is_TerminationID_wildcard([H|T]) ->
+ is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+is_TerminationID_wildcard(_) ->
+ false.
+
+is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+chk_TerminationID(Id,Id) ->
+ d("chk_TerminationID(1) -> entry with"
+ "~n Id: ~p", [Id]),
+ chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+chk_TerminationID(#'TerminationID'{wildcard = W1,
+ id = I1},
+ #'TerminationID'{wildcard = W2,
+ id = I2}) ->
+ d("chk_TerminationID(2) -> entry with"
+ "~n W1: ~p"
+ "~n W2: ~p"
+ "~n I1: ~p"
+ "~n I2: ~p", [W1, W2, I1, I2]),
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+ id = I1},
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2}) ->
+ d("chk_TerminationID(3) -> entry with"
+ "~n W1: ~p"
+ "~n W2: ~p"
+ "~n I1: ~p"
+ "~n I2: ~p", [W1, W2, I1, I2]),
+ validate(fun() -> chk_BOOLEAN(W1, W2) end, 'TerminationID_wildcard'),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(Tid1, Tid2) ->
+ d("chk_TerminationID(4) -> entry with"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p", [Tid1, Tid2]),
+ wrong_type('TerminationID', Tid1, Tid2).
+
+chk_TerminationID_wildcard([], []) ->
+ ok;
+chk_TerminationID_wildcard([] = WF1, WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard(WF1, [] = WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+ case is_WildcardField(H) of
+ true ->
+ chk_TerminationID_wildcard(T1, T2);
+ false ->
+ wrong_type('TerminationID_wildcard_val', H)
+ end;
+chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_WildcardField(H1, H2) end,
+ 'TerminationID_wildcard_val'),
+ chk_TerminationID_wildcard(T1, T2);
+chk_TerminationID_wildcard(WF1,WF2) ->
+ not_equal('TerminationId_wildcard', WF1, WF2).
+
+chk_TerminationID_id(Id, Id) ->
+ case is_OCTET_STRING(Id, {range, 1, 8}) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TerminationID_id', Id, Id)
+ end;
+chk_TerminationID_id(Id1, Id2) ->
+ Id12 = flatten_TerminationID_id(Id1, []),
+ Id22 = flatten_TerminationID_id(Id2, []),
+ case Id12 == Id22 of
+ true ->
+ ok;
+ false ->
+ not_equal(terminationId_id, Id1, Id2)
+ end.
+
+flatten_TerminationID_id([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+flatten_TerminationID_id([H|T], Acc) ->
+ flatten_TerminationID_id(T, [string:tokens(H, [$/])|Acc]).
+
+%% -- TerminationIDList --
+
+%% is_opt_TerminationIDList(asn1_NOVALUE) ->
+%% true;
+%% is_opt_TerminationIDList(TIDs) ->
+%% is_TerminationIDList(TIDs).
+
+is_TerminationIDList([]) ->
+ true;
+is_TerminationIDList([H|T]) ->
+ is_TerminationID(H) andalso is_TerminationIDList(T);
+is_TerminationIDList(_) ->
+ false.
+
+chk_opt_TerminationIDList(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TerminationIDList(TIDs1, TIDs2) ->
+ chk_TerminationIDList(TIDs1, TIDs2).
+
+chk_TerminationIDList([], []) ->
+ ok;
+chk_TerminationIDList([] = L1, L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList(L1, [] = L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_TerminationIDList(T1, T2);
+ false ->
+ wrong_type('TerminationIDList', H)
+ end;
+chk_TerminationIDList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+ chk_TerminationIDList(T1, T2);
+chk_TerminationIDList(L1, L2) ->
+ wrong_type('TerminationIDList', L1, L2).
+
+
+%% -- MediaDescriptor --
+
+is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_MediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_TerminationStateDescriptor(TSD) andalso
+ is_MediaDescriptor_streams(S);
+is_MediaDescriptor(_) ->
+ false.
+
+is_MediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_MediaDescriptor_streams({Tag, Val}) ->
+ is_MediaDescriptor_streams_tag(Tag) andalso
+ is_MediaDescriptor_streams_val(Tag, Val);
+is_MediaDescriptor_streams(_) ->
+ false.
+
+is_MediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_MediaDescriptor_streams_val(oneStream, SP) ->
+ is_StreamParms(SP);
+is_MediaDescriptor_streams_val(multiStream, SDL) ->
+ is_MediaDescriptor_multiStream(SDL).
+
+is_MediaDescriptor_multiStream([]) ->
+ true;
+is_MediaDescriptor_multiStream([H|T]) ->
+ is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+is_MediaDescriptor_multiStream(_) ->
+ false.
+
+chk_MediaDescriptor(D, D) ->
+ chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'MediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(
+ fun() ->
+ chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+ end,
+ 'MediaDescriptor'),
+ validate(
+ fun() ->
+ chk_MediaDescriptor_streams(S1, S2)
+ end,
+ 'MediaDescriptor'),
+ ok;
+chk_MediaDescriptor(D1, D2) ->
+ wrong_type('MediaDescriptor', D1, D2).
+
+
+chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+ validate(fun() ->
+ chk_StreamParms(SP1, SP2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+ validate(fun() ->
+ chk_MediaDescriptor_multiStream(SDs1, SDs2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams(S1, S2) ->
+ wrong_type('MediaDescriptor_streams', S1, S2).
+
+chk_MediaDescriptor_multiStream([], []) ->
+ ok;
+chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_StreamDescriptor(H) of
+ true ->
+ chk_MediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('MediaDescriptor_multiStream_val', H)
+ end;
+chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+ 'MediaDescriptor_multiStream_val'),
+ chk_MediaDescriptor_multiStream(T1, T2);
+chk_MediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% -- StreamDescriptor --
+
+is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_StreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_StreamParms(Parms);
+is_StreamDescriptor(X) ->
+ d("is_StreamDescriptor -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamDescriptor(D, D) ->
+ chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+ validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+ ok;
+chk_StreamDescriptor(D1, D2) ->
+ wrong_type('StreamDescriptor', D1, D2).
+
+
+%% -- StreamParms --
+
+is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}) ->
+ d("is_StreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p"
+ "~n SD: ~p", [LCD, LD, RD, SD]),
+ is_opt_LocalControlDescriptor(LCD) andalso
+ is_opt_LocalRemoteDescriptor(LD) andalso
+ is_opt_LocalRemoteDescriptor(RD) andalso
+ is_opt_StatisticsDescriptor(SD);
+is_StreamParms(X) ->
+ d("is_StreamParms -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamParms(SP, SP) ->
+ chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1,
+ statisticsDescriptor = SD1},
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_LocalControlDescriptor(LCD1, LCD2) end,
+ 'StreamParms_localControlDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+ 'StreamParms_localDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+ 'StreamParms_remoteDescriptor'),
+ validate(fun() -> chk_opt_StatisticsDescriptor(SD1, SD2) end,
+ 'StreamParms_statisticsDescriptor'),
+ ok;
+chk_StreamParms(P1, P2) ->
+ wrong_type('StreamParms', P1, P2).
+
+
+%% -- LocalControlDescriptor --
+
+is_opt_LocalControlDescriptor(D) ->
+ d("is_opt_LocalControlDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalControlDescriptor/1, D).
+
+is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}) ->
+ d("is_LocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PP: ~p", [SM, RV, RG, PP]),
+ is_opt_StreamMode(SM) andalso
+ is_opt_BOOLEAN(RV) andalso
+ is_opt_BOOLEAN(RG) andalso
+ is_LocalControlDescriptor_propertyParms(PP);
+is_LocalControlDescriptor(_) ->
+ false.
+
+is_LocalControlDescriptor_propertyParms([]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry when done"),
+ true;
+is_LocalControlDescriptor_propertyParms([H|T]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry with"
+ "~n H: ~p"
+ "~n T: ~p", [H, T]),
+ is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+is_LocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+ chk_OPTIONAL('LocalControlDescriptor', LCD1, LCD2,
+ fun is_LocalControlDescriptor/1,
+ fun chk_LocalControlDescriptor/2).
+
+chk_LocalControlDescriptor(LCD, LCD) ->
+ chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PP1},
+ #'LocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PP2}) ->
+ validate(
+ fun() -> chk_opt_StreamMode(SM1, SM2) end,
+ 'LocalControlDescriptor'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+ 'LocalControlDescriptor_reserveValue'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+ 'LocalControlDescriptor_reserveGroup'),
+ chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+ ok;
+chk_LocalControlDescriptor(LCD1, LCD2) ->
+ wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+chk_LocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('LocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'LocalControlDescriptor_propertyParms_val'),
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- StreamMode --
+
+is_opt_StreamMode(asn1_NOVALUE) ->
+ true;
+is_opt_StreamMode(SM) ->
+ is_StreamMode(SM).
+
+is_StreamMode(SM) ->
+ lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamMode(SM1, SM2) ->
+ chk_StreamMode(SM1, SM2).
+
+chk_StreamMode(SM, SM) ->
+ chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+chk_StreamMode(SM1, SM2) ->
+ case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+ true ->
+ not_equal('StreamMode', SM1, SM2);
+ false ->
+ wrong_type('StreamMode', SM1, SM2)
+ end.
+
+
+%% -- PropertyParm --
+
+is_opt_PropertyParm(asn1_NOVALUE) ->
+ true;
+is_opt_PropertyParm(PP) ->
+ is_PropertyParm(PP).
+
+is_PropertyParm(#'PropertyParm'{name = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_PropertyParm -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_PkgdName(N) andalso
+ is_PropertyParm_value(V) andalso
+ is_PropertyParm_extraInfo(I);
+is_PropertyParm(_) ->
+ false.
+
+is_PropertyParm_value([]) ->
+ d("is_PropertyParm_value -> entry when done"),
+ true;
+is_PropertyParm_value([H|T]) ->
+ d("is_PropertyParm_value -> entry with"
+ "~n H: ~p", [H]),
+ is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+is_PropertyParm_value(_) ->
+ false.
+
+is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+ true;
+is_PropertyParm_extraInfo({Tag, Val}) ->
+ d("is_PropertyParm_extraInfo -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_PropertyParm_extraInfo_tag(Tag) andalso
+ is_PropertyParm_extraInfo_val(Tag, Val);
+is_PropertyParm_extraInfo(_) ->
+ false.
+
+is_PropertyParm_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_PropertyParm_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_PropertyParm_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_PropertyParm_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+
+chk_opt_PropertyParm(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_PropertyParm(P1, P2) ->
+ chk_PropertyParm(P1, P2).
+
+chk_PropertyParm(P, P) ->
+ chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+chk_PropertyParm(#'PropertyParm'{name = N1,
+ value = V1,
+ extraInfo = I1},
+ #'PropertyParm'{name = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+ chk_PropertyParm_value(V1, V2),
+ chk_PropertyParm_extraInfo(I1, I2),
+ ok;
+chk_PropertyParm(P1, P2) ->
+ wrong_type('PropertyParm', P1, P2).
+
+chk_PropertyParm_value([], []) ->
+ ok;
+chk_PropertyParm_value([] = V1, V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value(V1, [] = V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value([H|T1], [H|T2]) ->
+ case is_OCTET_STRING(H) of
+ true ->
+ chk_PropertyParm_value(T1, T2);
+ false ->
+ wrong_type('PropertyParm_value_val', H)
+ end;
+chk_PropertyParm_value([H1|_], [H2|_]) ->
+ case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+ true ->
+ not_equal('PropertyParm_value_val', H1, H2);
+ false ->
+ wrong_type('PropertyParm_value_val', H1, H2)
+ end;
+chk_PropertyParm_value(V1, V2) ->
+ wrong_type('PropertyParm_value', V1, V2).
+
+chk_PropertyParm_extraInfo(EI, EI) ->
+ chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_PropertyParm_extraInfo_tag(Tag) and
+ is_PropertyParm_extraInfo_val(Tag, Val1) and
+ is_PropertyParm_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_PropertyParm_extraInfo_tag(Tag1) and
+ is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+ (is_PropertyParm_extraInfo_tag(Tag2) and
+ is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('PropertyParm_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo(EI1, EI2) ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $9, $0 =< H ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+chk_Name(N, N) ->
+ chk_type(fun is_Name/1, 'Name', N);
+chk_Name(N1, N2) ->
+ case (is_Name(N1) andalso is_Name(N2)) of
+ true ->
+ not_equal('Name', N1, N2);
+ false ->
+ wrong_type('Name', N1, N2)
+ end.
+
+
+%% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+chk_PkgdName(N, N) ->
+ case is_PkgdName(N) of
+ true ->
+ ok;
+ false ->
+ wrong_type('PkgdName', N, N)
+ end;
+chk_PkgdName(N1, N2) ->
+ case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+ true ->
+ not_equal('PkgdName', N1, N2);
+ false ->
+ wrong_type('PkgdName', N1, N2)
+ end.
+
+
+%% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+chk_Relation(R, R) ->
+ chk_type(fun is_Relation/1, 'Relation', R);
+chk_Relation(R1, R2) ->
+ case (is_Relation(R1) andalso is_Relation(R2)) of
+ true ->
+ not_equal('Relation', R1, R2);
+ false ->
+ wrong_type('Relation', R1, R2)
+ end.
+
+
+%% -- LocalRemoteDescriptor --
+
+is_opt_LocalRemoteDescriptor(D) ->
+ d("is_LocalRemoteDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+ d("is_LocalRemoteDescriptor -> entry with"
+ "~n PGs: ~p", [PGs]),
+ is_LocalRemoteDescriptor_propGrps(PGs);
+is_LocalRemoteDescriptor(_) ->
+ false.
+
+is_LocalRemoteDescriptor_propGrps([]) ->
+ true;
+is_LocalRemoteDescriptor_propGrps([H|T]) ->
+ is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+is_LocalRemoteDescriptor_propGrps(_) ->
+ false.
+
+chk_opt_LocalRemoteDescriptor(D1, D2) ->
+ chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+ fun is_LocalRemoteDescriptor/1,
+ fun chk_LocalRemoteDescriptor/2).
+
+chk_LocalRemoteDescriptor(LRD, LRD) ->
+ chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+ #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+ chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+ ok;
+chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+ wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+chk_LocalRemoteDescriptor_propGrps([], []) ->
+ ok;
+chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+ case is_PropertyGroup(H) of
+ true ->
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+ false ->
+ wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+ end;
+chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyGroup(H1, H2) end,
+ 'LocalRemoteDescriptor_propGrps_val'),
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+ wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% -- PropertyGroup --
+
+is_PropertyGroup([]) ->
+ true;
+is_PropertyGroup([H|T]) ->
+ is_PropertyParm(H) andalso is_PropertyGroup(T);
+is_PropertyGroup(_) ->
+ false.
+
+chk_PropertyGroup([], []) ->
+ ok;
+chk_PropertyGroup([] = PG1, PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup(PG1, [] = PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_PropertyGroup(T1, T2);
+ false ->
+ wrong_type('PropertyGroup_val', H)
+ end;
+chk_PropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+ chk_PropertyGroup(T1, T2);
+chk_PropertyGroup(PG1, PG2) ->
+ wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% -- TerminationStateDescriptor --
+
+is_opt_TerminationStateDescriptor(D) ->
+ is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+is_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_TerminationStateDescriptor_propertyParms(PP) andalso
+ is_opt_EventBufferControl(EBC) andalso
+ is_opt_ServiceState(SS);
+is_TerminationStateDescriptor(_) ->
+ false.
+
+is_TerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_TerminationStateDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+is_TerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_TerminationStateDescriptor(D1, D2) ->
+ chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+ fun is_TerminationStateDescriptor/1,
+ fun chk_TerminationStateDescriptor/2).
+
+chk_TerminationStateDescriptor(D, D) ->
+ chk_type(fun is_TerminationStateDescriptor/1,
+ 'TerminationStateDescriptor', D);
+chk_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'TerminationStateDescriptor'{propertyParms = PP2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+ validate(
+ fun() ->
+ chk_opt_EventBufferControl(EBC1, EBC2)
+ end,
+ 'TerminationStateDescriptor'),
+ validate(
+ fun() ->
+ chk_opt_ServiceState(SS1, SS2)
+ end,
+ 'TerminationStateDescriptor'),
+ ok;
+chk_TerminationStateDescriptor(D1, D2) ->
+ wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+chk_TerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_TerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+ end;
+chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+ case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+ true ->
+ not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+ end;
+chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+ wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% -- EventBufferControl --
+
+is_opt_EventBufferControl(asn1_NOVALUE) ->
+ true;
+is_opt_EventBufferControl(EBC) ->
+ is_EventBufferControl(EBC).
+
+is_EventBufferControl(EBC) ->
+ lists:member(EBC, [off, lockStep]).
+
+chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_EventBufferControl(EBC1, EBC2) ->
+ chk_EventBufferControl(EBC1, EBC2).
+
+chk_EventBufferControl(EBC, EBC) ->
+ chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+chk_EventBufferControl(EBC1, EBC2) ->
+ case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+ true ->
+ not_equal('EventBufferControl', EBC1, EBC2);
+ false ->
+ wrong_type('EventBufferControl', EBC1, EBC2)
+ end.
+
+
+%% -- ServiceState --
+
+is_opt_ServiceState(asn1_NOVALUE) ->
+ true;
+is_opt_ServiceState(SS) ->
+ is_ServiceState(SS).
+
+is_ServiceState(SS) ->
+ lists:member(SS, [test, outOfSvc, inSvc]).
+
+chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ServiceState(SS1, SS2) ->
+ chk_ServiceState(SS1, SS2).
+
+chk_ServiceState(SS, SS) ->
+ chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+chk_ServiceState(SS1, SS2) ->
+ case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+ true ->
+ not_equal('ServiceState', SS1, SS2);
+ false ->
+ wrong_type('ServiceState', SS1, SS2)
+ end.
+
+
+%% -- MuxDescriptor --
+
+is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+ termList = TL,
+ nonStandardData = NSD}) ->
+ is_MuxType(MT) andalso
+ is_MuxDescriptor_termList(TL) andalso
+ is_NonStandardData(NSD);
+is_MuxDescriptor(_) ->
+ false.
+
+is_MuxDescriptor_termList([]) ->
+ true;
+is_MuxDescriptor_termList([H|T]) ->
+ is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+is_MuxDescriptor_termList(_) ->
+ false.
+
+chk_MuxDescriptor(D, D) ->
+ chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+ termList = TL1,
+ nonStandardData = NSD1},
+ #'MuxDescriptor'{muxType = MT2,
+ termList = TL2,
+ nonStandardData = NSD2}) ->
+ validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+ chk_MuxDescriptor_termList(TL1, TL2),
+ validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+ ok;
+chk_MuxDescriptor(D1, D2) ->
+ wrong_type('MuxDescriptor', D1, D2).
+
+chk_MuxDescriptor_termList([], []) ->
+ ok;
+chk_MuxDescriptor_termList([] = TL1, TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_MuxDescriptor_termList(T1, T2);
+ false ->
+ wrong_type('MuxDescriptor_termList_val', H)
+ end;
+chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end,
+ 'MuxDescriptor_termList_val'),
+ chk_MuxDescriptor_termList(T1, T2);
+chk_MuxDescriptor_termList(TL1, TL2) ->
+ wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% -- MuxType --
+
+is_MuxType(MT) ->
+ lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+chk_MuxType(MT, MT) ->
+ chk_type(fun is_MuxType/1, 'MuxType', MT);
+chk_MuxType(MT1, MT2) ->
+ case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+ true ->
+ not_equal('MuxType', MT1, MT2);
+ false ->
+ wrong_type('MuxType', MT1, MT2)
+ end.
+
+
+%% -- StreamID --
+
+is_opt_StreamID(V) ->
+ is_OPTIONAL(fun is_StreamID/1, V).
+
+is_StreamID(V) ->
+ d("is_StreamID -> entry with"
+ "~n V: ~p", [V]),
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_StreamID(V1, V2) ->
+ chk_OPTIONAL('StreamID', V1, V2, fun is_StreamID/1, fun chk_StreamID/2).
+
+chk_StreamID(ID, ID) ->
+ chk_type(fun is_StreamID/1, 'StreamID', ID);
+chk_StreamID(ID1, ID2) ->
+ case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+ true ->
+ not_equal('StreamID', ID1, ID2);
+ false ->
+ wrong_type('StreamID', ID1, ID2)
+ end.
+
+
+%% -- EventsDescriptor --
+
+is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = EVL}) ->
+ d("is_EventsDescriptor -> entry with"
+ "~n RID: ~p"
+ "~n EVL: ~p", [RID, EVL]),
+ is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+is_EventsDescriptor(_) ->
+ false.
+
+is_EventsDescriptor_eventList([]) ->
+ true;
+is_EventsDescriptor_eventList([H|T]) ->
+ is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+is_EventsDescriptor_eventList(_) ->
+ false.
+
+chk_EventsDescriptor(D, D) ->
+ chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+ eventList = EVL1},
+ #'EventsDescriptor'{requestID = RID2,
+ eventList = EVL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+ chk_EventsDescriptor_eventList(EVL1, EVL2),
+ ok;
+chk_EventsDescriptor(D1, D2) ->
+ wrong_type('EventsDescriptor', D1, D2).
+
+chk_EventsDescriptor_eventList([], []) ->
+ ok;
+chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_RequestedEvent(H) of
+ true ->
+ chk_EventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('EventsDescriptor_eventList_val', H)
+ end;
+chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_RequestedEvent(H1, H2) end,
+ 'EventsDescriptor_eventList_val'),
+ chk_EventsDescriptor_eventList(T1, T2);
+chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+ wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% -- RequestedEvent --
+
+is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ d("is_RequestedEvent -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n EA: ~p"
+ "~n EPL: ~p", [N, SID, EA, EPL]),
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestedActions(EA) andalso
+ is_RequestedEvent_evParList(EPL);
+is_RequestedEvent(_) ->
+ false.
+
+is_RequestedEvent_evParList([]) ->
+ true;
+is_RequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+is_RequestedEvent_evParList(_) ->
+ false.
+
+chk_RequestedEvent(RE, RE) ->
+ chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'RequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+ 'RequestedEvent'),
+ chk_RequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_RequestedEvent(RE1, RE2) ->
+ wrong_type('RequestedEvent', RE1, RE2).
+
+chk_RequestedEvent_evParList([], []) ->
+ ok;
+chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_RequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('RequestedEvent_evParList_val', H)
+ end;
+chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'RequestedEvent_evParList_val'),
+ chk_RequestedEvent_evParList(T1, T2);
+chk_RequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- RegulatedEmbeddedDescriptor --
+
+is_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD);
+is_RegulatedEmbeddedDescriptor(_) ->
+ false.
+
+
+chk_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE1,
+ signalsDescriptor = SD1},
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}) ->
+ chk_RegulatedEmbeddedDescriptor_secondEvent(SE1, SE2),
+ chk_RegulatedEmbeddedDescriptor_signalsDescriptor(SD1, SD2),
+ ok;
+chk_RegulatedEmbeddedDescriptor(RED1, RED2) ->
+ wrong_type('RegulatedEmbeddedDescriptor', RED1, RED2).
+
+chk_RegulatedEmbeddedDescriptor_secondEvent(SE1, SE2) ->
+ validate(fun() -> chk_opt_SecondEventsDescriptor(SE1, SE2) end,
+ 'RegulatedEmbeddedDescriptor_secondEvent').
+
+chk_RegulatedEmbeddedDescriptor_signalsDescriptor(SD1, SD2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'RegulatedEmbeddedDescriptor_signalsDescriptor').
+
+
+%% -- NotifyBehaviour --
+
+tags_NotifyBehaviour() ->
+ [
+ {notifyImmediate,
+ fun is_NULL/1,
+ fun chk_NULL/2},
+
+ {notifyRegulated,
+ fun is_RegulatedEmbeddedDescriptor/1,
+ fun chk_RegulatedEmbeddedDescriptor/2},
+
+ {neverNotify,
+ fun is_NULL/1,
+ fun chk_NULL/2}
+ ].
+
+is_opt_NotifyBehaviour(asn1_NOVALUE) ->
+ true;
+is_opt_NotifyBehaviour(NB) ->
+ is_NotifyBehaviour(NB).
+
+is_NotifyBehaviour(NB) ->
+ is_CHOICE(NB, tags_NotifyBehaviour()).
+
+chk_opt_NotifyBehaviour(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_NotifyBehaviour(NB1, NB2) ->
+ chk_NotifyBehaviour(NB1, NB2).
+
+chk_NotifyBehaviour(NB1, NB2) ->
+ chk_CHOICE(NB1, NB2, 'NotifyBehaviour', tags_NotifyBehaviour()).
+
+
+%% -- RequestedActions --
+
+is_opt_RequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_RequestedActions(RA) ->
+ is_RequestedActions(RA).
+
+is_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ d("is_RequestedActions -> entry with"
+ "~n KA: ~p"
+ "~n EDM: ~p"
+ "~n SE: ~p"
+ "~n SD: ~p"
+ "~n NB: ~p"
+ "~n RED: ~p", [KA, EDM, SE, SD, NB, RED]),
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD) andalso
+ is_opt_NotifyBehaviour(SD) andalso
+ is_opt_NULL(SD);
+is_RequestedActions(_) ->
+ false.
+
+chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestedActions(RA1, RA2) ->
+ chk_RequestedActions(RA1, RA2).
+
+chk_RequestedActions(RA, RA) ->
+ chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ secondEvent = SE1,
+ signalsDescriptor = SD1,
+ notifyBehaviour = NB1,
+ resetEventsDescriptor = RED1},
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RED2}) ->
+ chk_RequestedActions_keepActive(KA1, KA2),
+ chk_RequestedActions_eventDM(EDM1, EDM2),
+ chk_RequestedActions_secondEvent(SE1, SE2),
+ chk_RequestedActions_signalsDescriptor(SD1, SD2),
+ chk_RequestedActions_notifyBehaviour(NB1, NB2),
+ chk_RequestedActions_resetEventsDescriptor(RED1, RED2),
+ ok;
+chk_RequestedActions(RA1, RA2) ->
+ wrong_type('RequestedActions', RA1, RA2).
+
+chk_RequestedActions_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end,
+ 'RequestedActions_keepActive').
+
+chk_RequestedActions_eventDM(V1, V2) ->
+ validate(fun() -> chk_opt_EventDM(V1, V2) end,
+ 'RequestedActions_eventDM').
+
+chk_RequestedActions_secondEvent(V1, V2) ->
+ validate(fun() -> chk_opt_SecondEventsDescriptor(V1, V2) end,
+ 'RequestedActions_secondEvent').
+
+chk_RequestedActions_signalsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(V1, V2) end,
+ 'RequestedActions_signalsDescriptor').
+
+chk_RequestedActions_notifyBehaviour(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyBehaviour(V1, V2) end,
+ 'RequestedActions_notifyBehaviour').
+
+chk_RequestedActions_resetEventsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_NULL(V1, V2) end,
+ 'RequestedActions_resetEventsDescriptor').
+
+
+%% -- EventDM --
+
+is_opt_EventDM(EDM) ->
+ is_OPTIONAL(fun is_EventDM/1, EDM).
+
+is_EventDM({Tag, Val}) ->
+ is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+is_EventDM(_) ->
+ false.
+
+is_EventDM_tag(Tag) ->
+ Tags = [digitMapName, digitMapValue],
+ lists:member(Tag, Tags).
+
+is_EventDM_val(digitMapName, Val) ->
+ is_DigitMapName(Val);
+is_EventDM_val(digitMapValue, Val) ->
+ is_DigitMapValue(Val).
+
+chk_opt_EventDM(EDM1, EDM2) ->
+ chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+chk_EventDM(EDM, EDM) ->
+ chk_type(fun is_EventDM/1, 'EventDM', EDM);
+chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+ case (is_EventDM_tag(Tag) andalso
+ is_EventDM_val(Tag, Val1) andalso
+ is_EventDM_val(Tag, Val2)) of
+ true ->
+ chk_EventDM_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+ case ((is_EventDM_tag(Tag1) andalso
+ is_EventDM_val(Tag1, Val1)) andalso
+ (is_EventDM_tag(Tag2) andalso
+ is_EventDM_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventDM', EDM1, EDM2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM(EDM1, EDM2) ->
+ wrong_type('EventDM', EDM1, EDM2).
+
+chk_EventDM_val(digitMapName, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+chk_EventDM_val(digitMapValue, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% -- SecondEventsDescriptor --
+
+is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SecondEventsDescriptor(D) ->
+ is_SecondEventsDescriptor(D).
+
+is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = EL}) ->
+ is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+is_SecondEventsDescriptor(_) ->
+ false.
+
+is_SecondEventsDescriptor_eventList([]) ->
+ true;
+is_SecondEventsDescriptor_eventList([H|T]) ->
+ is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+is_SecondEventsDescriptor_eventList(_) ->
+ false.
+
+chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondEventsDescriptor(D1, D2) ->
+ chk_SecondEventsDescriptor(D1, D2).
+
+chk_SecondEventsDescriptor(D, D) ->
+ chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+ eventList = EL1},
+ #'SecondEventsDescriptor'{requestID = RID2,
+ eventList = EL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+ 'SecondEventsDescriptor'),
+ chk_SecondEventsDescriptor_eventList(EL1, EL2),
+ ok;
+chk_SecondEventsDescriptor(D1, D2) ->
+ wrong_type('SecondEventsDescriptor', D1, D2).
+
+chk_SecondEventsDescriptor_eventList([], []) ->
+ ok;
+chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_SecondRequestedEvent(H) of
+ true ->
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('SecondEventsDescriptor_eventList_val', H)
+ end;
+chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+ 'SecondEventsDescriptor_eventList_val'),
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+chk_SecondEventsDescriptor_eventList(L1, L2) ->
+ wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% -- SecondRequestedEvent --
+
+is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SecondRequestedActions(EA) andalso
+ is_SecondRequestedEvent_evParList(EPL);
+is_SecondRequestedEvent(_) ->
+ false.
+
+is_SecondRequestedEvent_evParList([]) ->
+ true;
+is_SecondRequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+is_SecondRequestedEvent_evParList(_) ->
+ false.
+
+chk_SecondRequestedEvent(RE, RE) ->
+ chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'SecondRequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+ 'SecondRequestedEvent'),
+ chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_SecondRequestedEvent(RE1, RE2) ->
+ wrong_type('SecondRequestedEvent', RE1, RE2).
+
+chk_SecondRequestedEvent_evParList([], []) ->
+ ok;
+chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_SecondRequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('SecondRequestedEvent_evParList_val', H)
+ end;
+chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'SecondRequestedEvent_evParList_val'),
+ chk_SecondRequestedEvent_evParList(T1, T2);
+chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- SecondRequestedActions --
+
+is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_SecondRequestedActions(SRA) ->
+ is_SecondRequestedActions(SRA).
+
+is_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SignalsDescriptor(SD) andalso
+ is_opt_NotifyBehaviour(NB) andalso
+ is_opt_NULL(RED);
+is_SecondRequestedActions(_) ->
+ false.
+
+chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+ chk_SecondRequestedActions(SRA1, SRA2).
+
+chk_SecondRequestedActions(SRA, SRA) ->
+ chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+chk_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ signalsDescriptor = SD1,
+ notifyBehaviour = NB1,
+ resetEventsDescriptor = RED1},
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RED2}) ->
+ chk_SecondRequestedActions_keepActive(KA1, KA2),
+ chk_SecondRequestedActions_eventDM(EDM1, EDM2),
+ chk_SecondRequestedActions_signalsDescriptor(SD1, SD2),
+ chk_SecondRequestedActions_notifyBehaviour(NB1, NB2),
+ chk_SecondRequestedActions_resetEventsDescriptor(RED1, RED2),
+ ok;
+chk_SecondRequestedActions(SRA1, SRA2) ->
+ wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+chk_SecondRequestedActions_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end,
+ 'SecondRequestedActions_keepActive').
+
+chk_SecondRequestedActions_eventDM(V1, V2) ->
+ validate(fun() -> chk_opt_EventDM(V1, V2) end,
+ 'SecondRequestedActions_eventDM').
+
+chk_SecondRequestedActions_signalsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(V1, V2) end,
+ 'SecondRequestedActions_signalsDescriptor').
+
+chk_SecondRequestedActions_notifyBehaviour(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyBehaviour(V1, V2) end,
+ 'SecondRequestedActions_notifyBehaviour').
+
+chk_SecondRequestedActions_resetEventsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_NULL(V1, V2) end,
+ 'SecondRequestedActions_resetEventsDescriptor').
+
+
+%% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor(D) ->
+ is_SEQUENCE_OF(D, fun is_EventSpec/1).
+
+chk_EventBufferDescriptor(D1, D2) ->
+ chk_SEQUENCE_OF(D1, D2, 'EventBufferDescriptor',
+ fun is_EventSpec/1, fun chk_EventSpec/2).
+
+
+%% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+chk_EventSpec(ES, ES) ->
+ chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = SID1,
+ eventParList = EPL1},
+ #'EventSpec'{eventName = N2,
+ streamID = SID2,
+ eventParList = EPL2}) ->
+ validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+ chk_EventSpec_eventParList(EPL1, EPL2),
+ ok;
+chk_EventSpec(ES1, ES2) ->
+ wrong_type('EventSpec', ES1, ES2).
+
+chk_EventSpec_eventParList([], []) ->
+ ok;
+chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_EventSpec_eventParList(T1, T2);
+ false ->
+ wrong_type('EventSpec_eventParList_val', H)
+ end;
+chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'EventSpec_eventParList_val'),
+ chk_EventSpec_eventParList(T1, T2);
+chk_EventSpec_eventParList(EPL1, EPL2) ->
+ wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% -- SignalsDescriptor --
+
+is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SignalsDescriptor(D) ->
+ is_SignalsDescriptor(D).
+
+is_SignalsDescriptor(D) ->
+ is_SEQUENCE_OF(D, fun is_SignalRequest/1).
+
+chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalsDescriptor(D1, D2) ->
+ chk_SignalsDescriptor(D1, D2).
+
+chk_SignalsDescriptor(D1, D2) ->
+ chk_SEQUENCE_OF(D1, D2, 'SignalsDescriptor',
+ fun is_SignalRequest/1, fun chk_SignalRequest/2).
+
+
+%% -- SignalRequest --
+
+tags_SignalRequest() ->
+ [
+ {signal, fun is_Signal/1, fun chk_Signal/2},
+ {seqSigList, fun is_SeqSigList/1, fun chk_SeqSigList/2}
+ ].
+
+is_SignalRequest(SR) ->
+ is_CHOICE(SR, tags_SignalRequest()).
+
+chk_SignalRequest(R1, R2) ->
+ chk_CHOICE(R1, R2, 'SignalRequest', tags_SignalRequest()).
+
+
+%% -- SeqSigList --
+
+%% fields_SeqSigList() ->
+%% [
+%% {id,
+%% 'INTEGER(0,65535)',
+%% fun(ID) -> is_INTEGER(ID, {range, 0, 65535}) end,
+%% fun(ID1, ID2) -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end},
+
+%% {signalList,
+%% 'SEQUENCE OF Signal',
+%% fun(S) ->
+%% is_SEQUENCE_OF(S, fun is_Signal/1)
+%% end,
+%% fun(S1, S2) ->
+%% chk_SEQUENCE_OF(S1, S2, fun is_Signal/1, fun chk_Signal/2)
+%% end}
+%% ].
+
+%% is_SeqSigList(V) ->
+%% is_SEQUENCE(V, 'SeqSigList', fields_SeqSigList()).
+
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+chk_SeqSigList(L, L) ->
+ chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+chk_SeqSigList(#'SeqSigList'{id = ID1,
+ signalList = SL1},
+ #'SeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+ 'SeqSigList'),
+ chk_SeqSigList_signalList(SL1, SL2),
+ ok;
+chk_SeqSigList(L1, L2) ->
+ wrong_type('SeqSigList', L1, L2).
+
+chk_SeqSigList_signalList([], []) ->
+ ok;
+chk_SeqSigList_signalList([] = L1, L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList(L1, [] = L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+ case is_Signal(H) of
+ true ->
+ chk_SeqSigList_signalList(T1, T2);
+ false ->
+ wrong_type('SeqSigList_signalList_val', H)
+ end;
+chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Signal(H1, H2) end,
+ 'SeqSigList_signalList_val'),
+ chk_SeqSigList_signalList(T1, T2);
+chk_SeqSigList_signalList(L1, L2) ->
+ wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ISD}) ->
+ d("is_Signal -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n ST: ~p"
+ "~n Dur: ~p"
+ "~n NC: ~p"
+ "~n KA: ~p"
+ "~n SPL: ~p"
+ "~n Dir: ~p"
+ "~n RID: ~p"
+ "~n ISD: ~p", [N, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD]),
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL) andalso
+ is_opt_SignalDirection(Dir) andalso
+ is_opt_RequestID(RID) andalso
+ is_opt_INTEGER(ISD, {range, 0, 65535}).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+chk_Signal(S, S) ->
+ chk_type(fun is_Signal/1, 'Signal', S);
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = SID1,
+ sigType = ST1,
+ duration = Dur1,
+ notifyCompletion = NC1,
+ keepActive = KA1,
+ sigParList = SPL1,
+ direction = Dir1,
+ requestID = RID1,
+ intersigDelay = ISD1},
+ #'Signal'{signalName = N2,
+ streamID = SID2,
+ sigType = ST2,
+ duration = Dur2,
+ notifyCompletion = NC2,
+ keepActive = KA2,
+ sigParList = SPL2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ISD2}) ->
+ chk_Signal_signalName(N1, N2),
+ chk_Signal_streamID(SID1, SID2),
+ chk_Signal_sigType(ST1, ST2),
+ chk_Signal_duration(Dur1, Dur2),
+ chk_Signal_notifyCompletion(NC1, NC2),
+ chk_Signal_keepActive(KA1, KA2),
+ chk_Signal_sigParList(SPL1, SPL2),
+ chk_Signal_direction(Dir1, Dir2),
+ chk_Signal_requestID(RID1, RID2),
+ chk_Signal_intersigDelay(ISD1, ISD2),
+ ok;
+chk_Signal(S1, S2) ->
+ wrong_type('Signal', S1, S2).
+
+chk_Signal_signalName(N1, N2) ->
+ validate(fun() -> chk_SignalName(N1, N2) end, 'Signal_signalName').
+
+chk_Signal_streamID(V1, V2) ->
+ validate(fun() -> chk_opt_StreamID(V1, V2) end, 'Signal_streamID').
+
+chk_Signal_sigType(V1, V2) ->
+ validate(fun() -> chk_opt_SignalType(V1, V2) end, 'Signal_sigType').
+
+chk_Signal_duration(V1, V2) ->
+ validate(fun() ->
+ chk_opt_INTEGER(V1, V2, {range, 0, 65535})
+ end,
+ 'Signal_duration').
+
+chk_Signal_notifyCompletion(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyCompletion(V1, V2) end,
+ 'Signal_notifyCompletion').
+
+chk_Signal_keepActive(false, asn1_NOVALUE) ->
+ ok;
+chk_Signal_keepActive(asn1_NOVALUE, false) ->
+ ok;
+chk_Signal_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end, 'Signal_keepActive').
+
+chk_Signal_sigParList([], []) ->
+ ok;
+chk_Signal_sigParList([] = L1, L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList(L1, [] = L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList([H|T1], [H|T2]) ->
+ case is_SigParameter(H) of
+ true ->
+ chk_Signal_sigParList(T1, T2);
+ false ->
+ wrong_type('Signal_sigParList_val', H)
+ end;
+chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SigParameter(H1, H2) end,
+ 'Signal_sigParList_val'),
+ chk_Signal_sigParList(T1, T2);
+chk_Signal_sigParList(L1, L2) ->
+ wrong_type('Signal_sigParList', L1, L2).
+
+chk_Signal_direction(V1, V2) ->
+ validate(fun() -> chk_opt_SignalDirection(V1, V2) end, 'Signal_direction').
+
+chk_Signal_requestID(V1, V2) ->
+ validate(fun() -> chk_opt_RequestID(V1, V2) end, 'Signal_requestID').
+
+chk_Signal_intersigDelay(V1, V2) ->
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 65535}) end,
+ 'Signal_intersigDelay').
+
+
+%% -- SignalType --
+
+is_opt_SignalType(T) ->
+ is_OPTIONAL(fun is_SignalType/1, T).
+
+is_SignalType(T) ->
+ d("is_SignalType -> entry with"
+ "~n T: ~p", [T]),
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+chk_opt_SignalType(T1, T2) ->
+ chk_OPTIONAL('SignalType', T1, T2,
+ fun is_SignalType/1, fun chk_SignalType/2).
+
+chk_SignalType(T, T) ->
+ chk_type(fun is_SignalType/1, 'SignalType', T);
+chk_SignalType(T1, T2) ->
+ case (is_SignalType(T1) andalso is_SignalType(T2)) of
+ true ->
+ not_equal('SignalType', T1, T2);
+ false ->
+ wrong_type('SignalType', T1, T2)
+ end.
+
+
+%% -- SignalDirection --
+
+is_opt_SignalDirection(T) ->
+ is_OPTIONAL(fun is_SignalDirection/1, T).
+
+is_SignalDirection(Dir) ->
+ d("is_SignalDirection -> entry with"
+ "~n Dir: ~p", [Dir]),
+ Dirs = [internal, external, both],
+ lists:member(Dir, Dirs).
+
+chk_opt_SignalDirection(T1, T2) ->
+ chk_OPTIONAL('SignalDirection', T1, T2,
+ fun is_SignalDirection/1, fun chk_SignalDirection/2).
+
+chk_SignalDirection(Dir, Dir) ->
+ chk_type(fun is_SignalDirection/1, 'SignalDirection', Dir);
+chk_SignalDirection(Dir1, Dir2) ->
+ case (is_SignalDirection(Dir1) andalso is_SignalDirection(Dir2)) of
+ true ->
+ not_equal('SignalDirection', Dir1, Dir2);
+ false ->
+ wrong_type('SignalDirection', Dir1, Dir2)
+ end.
+
+
+%% -- SignalName --
+
+is_SignalName(N) ->
+ d("is_SignalName -> entry with"
+ "~n N: ~p", [N]),
+ is_PkgdName(N).
+
+chk_SignalName(N1, N2) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ d("is_NotifyCompletion -> entry with"
+ "~n NC: ~p", [NC]),
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:all(fun(X) -> lists:member(X, Valids) end, NC).
+
+chk_opt_NotifyCompletion(NC1, NC2) ->
+ chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+ fun is_NotifyCompletion/1,
+ fun chk_NotifyCompletion/2).
+
+chk_NotifyCompletion(NC, NC) ->
+ chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+chk_NotifyCompletion(NC1, NC2) ->
+ case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+ true ->
+ not_equal('NotifyCompletion', NC1, NC2);
+ false ->
+ wrong_type('NotifyCompletion', NC1, NC2)
+ end.
+
+
+%% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_SigParameter -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_SigParameter(P, P) ->
+ chk_type(fun is_SigParameter/1, 'SigParameter', P);
+chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = I1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+ validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+ chk_SigParameter_extraInfo(I1, I2),
+ ok;
+chk_SigParameter(P1, P2) ->
+ wrong_type('SigParameter', P1, P2).
+
+chk_SigParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_SigParameter_extraInfo_tag(Tag) and
+ is_SigParameter_extraInfo_val(Tag, Val1) and
+ is_SigParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_SigParameter_extraInfo_tag(Tag1) and
+ is_SigParameter_extraInfo_val(Tag1, Val1)) and
+ (is_SigParameter_extraInfo_tag(Tag2) and
+ is_SigParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('SigParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo(EI1, EI2) ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% -- RequestID --
+
+is_opt_RequestID(asn1_NOVALUE) ->
+ true;
+is_opt_RequestID(V) ->
+ is_RequestID(V).
+
+is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestID(V1, V2) ->
+ chk_RequestID(V1, V2).
+
+chk_RequestID(ID, ID) ->
+ chk_type(fun is_RequestID/1, 'RequestID', ID);
+chk_RequestID(ID1, ID2) ->
+ case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+ true ->
+ not_equal('RequestID', ID1, ID2);
+ false ->
+ wrong_type('RequestID', ID1, ID2)
+ end.
+
+
+%% -- ModemDescriptor --
+
+is_ModemDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ true;
+is_ModemDescriptor(_) ->
+ false.
+
+chk_ModemDescriptor(D, D) when is_record(D, 'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+ mpl = MPL1,
+ nonStandardData = NSD1},
+ #'ModemDescriptor'{mtl = MTL2,
+ mpl = MPL2,
+ nonStandardData = NSD2}) ->
+ chk_ModemDescriptor_mtl(MTL1, MTL2),
+ chk_ModemDescriptor_mpl(MPL1, MPL2),
+ chk_opt_NonStandardData(NSD1, NSD2),
+ ok;
+chk_ModemDescriptor(D1, D2) ->
+ wrong_type('ModemDescriptor', D1, D2).
+
+chk_ModemDescriptor_mtl([], []) ->
+ ok;
+chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+ case is_ModemType(H) of
+ true ->
+ chk_ModemDescriptor_mtl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mtl_val', H)
+ end;
+chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+ chk_ModemDescriptor_mtl(T1, T2);
+chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+ wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+chk_ModemDescriptor_mpl([], []) ->
+ ok;
+chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ModemDescriptor_mpl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mpl_val', H)
+ end;
+chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+ chk_ModemDescriptor_mpl(T1, T2);
+chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+ wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% -- ModemType --
+
+chk_ModemType(MT, MT) ->
+ case is_ModemType(MT) of
+ true ->
+ ok;
+ false ->
+ wrong_type('ModemType', MT, MT)
+ end;
+chk_ModemType(MT1, MT2) ->
+ case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+ true ->
+ not_equal('ModemType', MT1, MT2);
+ false ->
+ wrong_type('ModemType', MT1, MT2)
+ end.
+
+is_ModemType(MT) ->
+ lists:member(MT,
+ [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% -- DigitMapDescriptor --
+
+is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Val}) ->
+ is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+is_DigitMapDescriptor(_) ->
+ false.
+
+chk_DigitMapDescriptor(D, D) ->
+ chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+ digitMapValue = Val1},
+ #'DigitMapDescriptor'{digitMapName = Name2,
+ digitMapValue = Val2}) ->
+ d("chk_DigitMapDescriptor -> entry with"
+ "~n Name1: ~p"
+ "~n Name2: ~p"
+ "~n Val1: ~p"
+ "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'DigitMapDescriptor'),
+ validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+ 'DigitMapDescriptor'),
+ ok;
+chk_DigitMapDescriptor(D1, D2) ->
+ wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% -- DigitMapName --
+
+is_opt_DigitMapName(asn1_NOVALUE) ->
+ true;
+is_opt_DigitMapName(N) ->
+ is_DigitMapName(N).
+
+is_DigitMapName(N) -> is_Name(N).
+
+chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_DigitMapName(N1, N2) ->
+ chk_DigitMapName(N1, N2).
+
+chk_DigitMapName(N, N) ->
+ chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+chk_DigitMapName(N1, N2) ->
+ case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+ true ->
+ not_equal('DigitMapName', N1, N2);
+ false ->
+ wrong_type('DigitMapName', N1, N2)
+ end.
+
+
+%% -- DigitMapValue --
+
+is_opt_DigitMapValue(V) ->
+ is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Dur}) ->
+ is_DigitMapValue_startTimer(Start) andalso
+ is_DigitMapValue_shortTimer(Short) andalso
+ is_DigitMapValue_longTimer(Long) andalso
+ is_IA5String(Body) andalso
+ is_DigitMapValue_durationTimer(Dur);
+is_DigitMapValue(_) ->
+ false.
+
+is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+chk_opt_DigitMapValue(V1, V2) ->
+ chk_OPTIONAL('DigitMapValue', V1, V2,
+ fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1,
+ digitMapBody = Body1,
+ durationTimer = Dur1},
+ #'DigitMapValue'{startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2,
+ digitMapBody = Body2,
+ durationTimer = Dur2}) ->
+ d("chk_DigitMapValue -> entry with"
+ "~n Start1: ~p"
+ "~n Start2: ~p"
+ "~n Short1: ~p"
+ "~n Short2: ~p"
+ "~n Long1: ~p"
+ "~n Long2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p"
+ "~n Dur1: ~p"
+ "~n Dur2: ~p", [Start1, Start2,
+ Short1, Short2,
+ Long1, Long2,
+ Body1, Body2,
+ Dur1, Dur2]),
+ chk_DigitMapValue_startTimer(Start1, Start2),
+ chk_DigitMapValue_shortTimer(Short1, Short2),
+ chk_DigitMapValue_longTimer(Long1, Long2),
+ chk_DigitMapValue_digitMapBody(Body1, Body2),
+ chk_DigitMapValue_durationTimer(Dur1, Dur2),
+ ok;
+chk_DigitMapValue(V1, V2) ->
+ wrong_type('DigitMapValue', V1, V2).
+
+chk_DigitMapValue_startTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+chk_DigitMapValue_startTimer(T1, T2) ->
+ case (is_DigitMapValue_startTimer(T1) andalso
+ is_DigitMapValue_startTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_startTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_startTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_shortTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+chk_DigitMapValue_shortTimer(T1, T2) ->
+ case (is_DigitMapValue_shortTimer(T1) andalso
+ is_DigitMapValue_shortTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_shortTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_shortTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_longTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+chk_DigitMapValue_longTimer(T1, T2) ->
+ case (is_DigitMapValue_longTimer(T1) andalso
+ is_DigitMapValue_longTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_longTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_longTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_durationTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_durationTimer/1,
+ 'DigitMapValue_durationTimer', T);
+chk_DigitMapValue_durationTimer(T1, T2) ->
+ case (is_DigitMapValue_durationTimer(T1) andalso
+ is_DigitMapValue_durationTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_durationTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_durationTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_digitMapBody(B, B) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B: ~p", [B]),
+ chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+chk_DigitMapValue_digitMapBody(B1, B2) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B1: ~p"
+ "~n B2: ~p", [B1, B2]),
+ case (is_IA5String(B1) andalso is_IA5String(B2)) of
+ true ->
+ %% If they are different it could be because
+ %% of trailing tab's and newline's.
+ case compare_strings(B1, B2) of
+ {[], []} ->
+ ok;
+ {Str1, []} ->
+ case strip_tab_and_newline(Str1) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ {[], Str2} ->
+ case strip_tab_and_newline(Str2) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ false ->
+ wrong_type('DigitMapValue_digitMapBody', B1, B2)
+ end.
+
+%% -- ServiceChangeParm --
+
+is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Id,
+ timeStamp = TS,
+ nonStandardData = NSD,
+ serviceChangeInfo = I}) ->
+ is_ServiceChangeMethod(M) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_Value(R) andalso
+ is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+ is_opt_MId(Id) andalso
+ is_opt_TimeNotation(TS) andalso
+ is_opt_NonStandardData(NSD) andalso
+ is_opt_AuditDescriptor(I);
+is_ServiceChangeParm(_) ->
+ false.
+
+chk_ServiceChangeParm(P, P) ->
+ chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Id1,
+ timeStamp = TS1,
+ nonStandardData = NSD1,
+ serviceChangeInfo = I1},
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Id2,
+ timeStamp = TS2,
+ nonStandardData = NSD2,
+ serviceChangeInfo = I2}) ->
+ validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_Value(R1, R2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_MId(Id1, Id2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+ 'ServiceChangeParm'),
+ ok;
+chk_ServiceChangeParm(P1, P2) ->
+ wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% -- ServiceChangeAddress --
+
+is_opt_ServiceChangeAddress(A) ->
+ is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+is_ServiceChangeAddress({Tag, Val}) ->
+ is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val);
+is_ServiceChangeAddress(_) ->
+ false.
+
+is_ServiceChangeAddress_tag(Tag) ->
+ Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+ mtpAddress],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeAddress_val(portNumber, Val) ->
+ is_INTEGER(Val, {range, 0, 65535});
+is_ServiceChangeAddress_val(ip4Address, Val) ->
+ is_IP4Address(Val);
+is_ServiceChangeAddress_val(ip6Address, Val) ->
+ is_IP6Address(Val);
+is_ServiceChangeAddress_val(domainName, Val) ->
+ is_DomainName(Val);
+is_ServiceChangeAddress_val(deviceName, Val) ->
+ is_PathName(Val);
+is_ServiceChangeAddress_val(mtpAddress, Val) ->
+ is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+chk_opt_ServiceChangeAddress(A1, A2) ->
+ chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+ fun is_ServiceChangeAddress/1,
+ fun chk_ServiceChangeAddress/2).
+
+chk_ServiceChangeAddress(A, A) ->
+ chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+ case (is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val1) andalso
+ is_ServiceChangeAddress_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+ case ((is_ServiceChangeAddress_tag(Tag1) andalso
+ is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+ (is_ServiceChangeAddress_tag(Tag2) andalso
+ is_ServiceChangeAddress_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeAddress', A1, A2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress(A1, A2) ->
+ wrong_type('ServiceChangeAddress', A1, A2).
+
+chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+ validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+ validate(fun() -> chk_IP4Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+ validate(fun() -> chk_IP6Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+ validate(fun() -> chk_DomainName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+ validate(fun() -> chk_PathName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+ validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+ 'ServiceChangeAddress').
+
+
+%% -- ServiceChangeResParm --
+
+is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ timeStamp = TS}) ->
+ is_opt_MId(Id) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_opt_TimeNotation(TS);
+is_ServiceChangeResParm(_) ->
+ false.
+
+chk_ServiceChangeResParm(P, P) ->
+ chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+chk_ServiceChangeResParm(
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ timeStamp = TS1},
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ timeStamp = TS2}) ->
+ validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeResParm'),
+ ok;
+chk_ServiceChangeResParm(P1, P2) ->
+ wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% -- ServiceChangeMethod --
+
+is_ServiceChangeMethod(M) ->
+ Methods = [failover, forced, graceful, restart, disconnected, handOff],
+ lists:member(M, Methods).
+
+chk_ServiceChangeMethod(M, M) ->
+ chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+chk_ServiceChangeMethod(M1, M2) ->
+ case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+ true ->
+ not_equal('ServiceChangeMethod', M1, M2);
+ false ->
+ wrong_type('ServiceChangeMethod', M1, M2)
+ end.
+
+
+%% -- ServiceChangeProfile --
+
+is_opt_ServiceChangeProfile(P) ->
+ is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+ is_IA5String(N, {range, 1, 67});
+is_ServiceChangeProfile(_) ->
+ false.
+
+chk_opt_ServiceChangeProfile(P1, P2) ->
+ chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+ fun is_ServiceChangeProfile/1,
+ fun chk_ServiceChangeProfile/2).
+
+chk_ServiceChangeProfile(P, P) ->
+ chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+ #'ServiceChangeProfile'{profileName = N2}) ->
+ validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+ 'ServiceChangeProfile'),
+ ok;
+chk_ServiceChangeProfile(P1, P2) ->
+ wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% -- PackagesDescriptor --
+
+is_PackagesDescriptor([]) ->
+ true;
+is_PackagesDescriptor([H|T]) ->
+ is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+is_PackagesDescriptor(_) ->
+ false.
+
+chk_PackagesDescriptor([], []) ->
+ ok;
+chk_PackagesDescriptor([] = D1, D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor(D1, [] = D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor([H|T1], [H|T2]) ->
+ case is_PackagesItem(H) of
+ true ->
+ chk_PackagesDescriptor(T1, T2);
+ false ->
+ wrong_type('PackagesDescriptor_val', H)
+ end;
+chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PackagesItem(H1, H2) end,
+ 'PackagesDescriptor_val'),
+ chk_PackagesDescriptor(T1, T2);
+chk_PackagesDescriptor(D1, D2) ->
+ wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% -- PackagesItem --
+
+is_PackagesItem(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+is_PackagesItem(_) ->
+ false.
+
+chk_PackagesItem(I, I) ->
+ chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+chk_PackagesItem(#'PackagesItem'{packageName = N1,
+ packageVersion = V1},
+ #'PackagesItem'{packageName = N2,
+ packageVersion = V2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+ ok;
+chk_PackagesItem(I1, I2) ->
+ wrong_type('PackagesItem', I1, I2).
+
+
+%% -- StatisticsDescriptor --
+
+is_opt_StatisticsDescriptor(D) ->
+ is_OPTIONAL(fun is_StatisticsDescriptor/1, D).
+
+is_StatisticsDescriptor([]) ->
+ true;
+is_StatisticsDescriptor([H|T]) ->
+ is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+is_StatisticsDescriptor(_) ->
+ false.
+
+chk_opt_StatisticsDescriptor(D1, D2) ->
+ chk_OPTIONAL('StatisticsDescriptor', D1, D2,
+ fun is_StatisticsDescriptor/1,
+ fun chk_StatisticsDescriptor/2).
+
+chk_StatisticsDescriptor([], []) ->
+ ok;
+chk_StatisticsDescriptor([] = D1, D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor(D1, [] = D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+ case is_StatisticsParameter(H) of
+ true ->
+ chk_StatisticsDescriptor(T1, T2);
+ false ->
+ wrong_type('StatisticsDescriptor_val', H)
+ end;
+chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+ 'StatisticsDescriptor_val'),
+ chk_StatisticsDescriptor(T1, T2);
+chk_StatisticsDescriptor(D1, D2) ->
+ wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% -- StatisticsParameter --
+
+is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+ statValue = V}) ->
+ is_PkgdName(N) andalso is_opt_Value(V);
+is_StatisticsParameter(_) ->
+ false.
+
+chk_StatisticsParameter(P, P) ->
+ chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+ statValue = V1},
+ #'StatisticsParameter'{statName = N2,
+ statValue = V2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+ validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+ ok;
+chk_StatisticsParameter(P1, P2) ->
+ wrong_type('StatisticsParameter', P1, P2).
+
+
+%% -- NonStandardData --
+
+is_opt_NonStandardData(asn1_NOVALUE) ->
+ true;
+is_opt_NonStandardData(NSD) ->
+ is_NonStandardData(NSD).
+
+%% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% data = D}) ->
+%% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% is_NonStandardData(_) ->
+%% false.
+
+is_NonStandardData(_) ->
+ true.
+
+chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+ true;
+chk_opt_NonStandardData(NSD1, NSD2) ->
+ chk_NonStandardData(NSD1, NSD2).
+
+chk_NonStandardData(NSD, NSD) ->
+ chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% data = D1},
+%% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% data = D2}) ->
+%% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% 'NonStandardData'),
+%% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% ok;
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% wrong_type('NonStandardData', NSD1, NSD2).
+chk_NonStandardData(NSD1, NSD2) ->
+ not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% -- NonStandardIdentifier --
+
+%% is_NonStandardIdentifier({Tag, Val}) ->
+%% is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val);
+%% is_NonStandardIdentifier(_) ->
+%% false.
+
+%% is_NonStandardIdentifier_tag(Tag) ->
+%% Tags = [object, h221NonStandard, experimental],
+%% lists:member(Tag, Tags).
+
+%% is_NonStandardIdentifier_val(object, Val) ->
+%% is_OBJECT_IDENTIFIER(Val);
+%% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% is_H221NonStandard(Val);
+%% is_NonStandardIdentifier_val(experimental, Val) ->
+%% is_IA5String(Val, {exact, 8}).
+
+%% chk_NonStandardIdentifier(Id, Id) ->
+%% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% true ->
+%% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% true ->
+%% not_equal('NonStandardIdentifier', Id1, Id2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier(Id1, Id2) ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% chk_H221NonStandard(Val1, Val2);
+%% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% -- H221NonStandard --
+
+%% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}) ->
+%% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 65535});
+%% is_H221NonStandard(_) ->
+%% false.
+
+%% chk_H221NonStandard(NS, NS) ->
+%% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% t35CountryCode2 = CC21,
+%% t35Extension = Ext1,
+%% manufacturerCode = MC1},
+%% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% t35CountryCode2 = CC22,
+%% t35Extension = Ext2,
+%% manufacturerCode = MC2}) ->
+%% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% 'H221NonStandard'),
+%% ok;
+%% chk_H221NonStandard(NS1, NS2) ->
+%% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% -- TimeNotation --
+
+is_opt_TimeNotation(asn1_NOVALUE) ->
+ true;
+is_opt_TimeNotation(TN) ->
+ is_TimeNotation(TN).
+
+is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+ is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+is_TimeNotation(_) ->
+ false.
+
+chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(TN1, TN2) ->
+ chk_TimeNotation(TN1, TN2).
+
+chk_TimeNotation(TN, TN) ->
+ chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+ #'TimeNotation'{date = D2, time = T2}) ->
+ validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+ validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+ ok;
+chk_TimeNotation(TN1, TN2) ->
+ wrong_type('TimeNotation', TN1, TN2).
+
+
+%% -- Value --
+
+is_opt_Value(V) ->
+ is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+chk_opt_Value(V1, V2) ->
+ chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+chk_Value(V, V) ->
+ case is_Value(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Value', V, V)
+ end;
+chk_Value(V1, V2) ->
+ case (is_Value(V1) andalso is_Value(V2)) of
+ true ->
+ not_equal('Value', V1, V2);
+ false ->
+ wrong_type('Value', V1, V2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Basic type check functions
+%% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ d("is_BOOLEAN -> entry with"
+ "~n B: ~p", [B]),
+ lists:member(B, [true, false]).
+
+chk_opt_BOOLEAN(B1, B2) ->
+ chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+chk_BOOLEAN(B, B) ->
+ chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+chk_BOOLEAN(B1, B2) ->
+ case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+ true ->
+ not_equal('BOOLEAN', B1, B2);
+ false ->
+ wrong_type('BOOLEAN', B1, B2)
+ end.
+
+
+is_IA5String(S) when is_list(S) ->
+ true;
+is_IA5String(_) ->
+ false.
+
+% chk_IA5String(S, S) ->
+% chk_type(fun is_IA5String/1, 'IA5String', S);
+% chk_IA5String(S1, S2) ->
+% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+% true ->
+% not_equal('IA5String', S1, S2);
+% false ->
+% wrong_type('IA5String', S1, S2)
+% end.
+
+is_IA5String(S, _) when is_list(S) ->
+ true;
+is_IA5String(_, _) ->
+ false.
+
+chk_IA5String(S, S, R) ->
+ chk_type(fun is_IA5String/2, 'IA5String', S, R);
+chk_IA5String(S1, S2, R) ->
+ case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+ true ->
+ not_equal('IA5String', S1, S2);
+ false ->
+ wrong_type('IA5String', S1, S2)
+ end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) andalso (length(L) =:= Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) andalso (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) andalso (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) andalso (Min =< length(L)) andalso (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% chk_OCTET_STRING(L1, L2) ->
+%% chk_OCTET_STRING(L1, L2, any).
+
+chk_OCTET_STRING(L, L, R) ->
+ chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+chk_OCTET_STRING(L1, L2, R) ->
+ case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+ true ->
+ not_equal('OCTET STRING', L1, L2);
+ false ->
+ wrong_type('OCTET STRING', L1, L2)
+ end.
+
+
+%% is_OBJECT_IDENTIFIER(_) ->
+%% true.
+
+%% chk_OBJECT_IDENTIFIER(X, X) ->
+%% ok;
+%% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+is_opt_NULL(N) ->
+ is_OPTIONAL(fun is_NULL/1, N).
+
+is_NULL('NULL') ->
+ true;
+is_NULL(_) ->
+ false.
+
+chk_opt_NULL(N1, N2) ->
+ chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+chk_NULL(N, N) ->
+ chk_type(fun is_NULL/1, 'NULL', N);
+chk_NULL(N1, N2) ->
+ case (is_NULL(N1) andalso is_NULL(N2)) of
+ true ->
+ not_equal('NULL', N1, N2);
+ false ->
+ wrong_type('NULL', N1, N2)
+ end.
+
+
+is_opt_INTEGER(I, R) ->
+ d("is_opt_INTEGER -> entry with"
+ "~n I: ~p"
+ "~n R: ~p", [I, R]),
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min})
+ when is_integer(I) andalso is_integer(Min) andalso (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max})
+ when is_integer(I) andalso is_integer(Max) andalso (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Min =< I) andalso
+ (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+chk_opt_INTEGER(I1, I2, R) ->
+ chk_OPTIONAL('INTEGER', I1, I2,
+ fun(X) -> is_INTEGER(X, R) end,
+ fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+chk_INTEGER(I, I, R) ->
+ chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+chk_INTEGER(I1, I2, R) ->
+ case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+ true ->
+ not_equal('INTEGER', I1, I2);
+ false ->
+ wrong_type('INTEGER', I1, I2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Various utility functions
+%% ----------------------------------------------------------------------
+
+
+to_lower([C|Cs]) when (C >= $A) andalso (C =< $Z) ->
+ [C+($a-$A)|to_lower(Cs)];
+to_lower([C|Cs]) ->
+ [C|to_lower(Cs)];
+to_lower([]) ->
+ [].
+
+
+validate(F, Type) when is_function(F) ->
+ case (catch F()) of
+ {error, Reason} ->
+ error({Type, Reason});
+ ok ->
+ ok
+ end.
+
+
+chk_type(F, T, V) when is_function(F) andalso is_atom(T) ->
+ case F(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V)
+ end.
+
+chk_type(F, T, V1, V2) when is_function(F) andalso is_atom(T) ->
+ case F(V1, V2) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V1)
+ end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+ ok;
+chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when is_function(IS) ->
+ case IS(V2) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when is_function(IS) ->
+ case IS(V1) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when is_function(CHK) ->
+ CHK(V1, V2).
+
+
+%% -- CHOICE --
+
+is_CHOICE({Tag, Val}, Tags) when is_list(Tags) ->
+ d("is_CHOICE -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_CHOICE_tag(Tag, Tags) andalso
+ is_CHOICE_val(Tag, Val, Tags);
+is_CHOICE(_, _) ->
+ false.
+
+is_CHOICE_tag(Tag, Tags) ->
+ lists:keymember(Tag, 1, Tags).
+
+is_CHOICE_val(Tag, Val, Tags) ->
+ {value, {_, IsVal, _}} = lists:keysearch(Tag, 1, Tags),
+ IsVal(Val).
+
+
+chk_CHOICE(V1, V2, Type, Tags) when is_atom(Type) and is_list(Tags) ->
+ IsTag = fun(Tag) -> is_CHOICE_tag(Tag, Tags) end,
+ IsVal = fun(Tag, Val) -> is_CHOICE_val(Tag, Val, Tags) end,
+ ChkVal = fun(Tag, Val1, Val2) ->
+ chk_CHOICE_val(Tag, Val1, Val2, Tags)
+ end,
+ chk_CHOICE(V1, V2, Type, IsTag, IsVal, ChkVal).
+
+chk_CHOICE_val(Tag, Val1, Val2, Tags) ->
+ {value, {_, _, ChkVal}} = lists:keysearch(Tag, 1, Tags),
+ ChkVal(Val1, Val2).
+
+chk_CHOICE({Tag, Val1} = V1, {Tag, Val2} = V2, Type, IsTag, IsVal, ChkVal) ->
+ case (IsTag(Tag) andalso
+ IsVal(Tag, Val1) andalso IsVal(Tag, Val2)) of
+ true ->
+ ChkVal(Tag, Val1, Val2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_CHOICE({Tag1, Val1} = V1, {Tag2, Val2} = V2, Type,
+ IsTag, IsVal, _ChkVal) ->
+ case ((IsTag(Tag1) andalso IsVal(Tag1, Val1)) andalso
+ (IsTag(Tag2) andalso IsVal(Tag2, Val2))) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_CHOICE(V1, V2, Type, _, _, _) ->
+ wrong_type(Type, V1, V2).
+
+
+%% -- SEQUENCE OF --
+
+is_SEQUENCE_OF([], _) ->
+ true;
+is_SEQUENCE_OF([H|T], IS) when is_function(IS) ->
+ IS(H) andalso is_SEQUENCE_OF(T, IS);
+is_SEQUENCE_OF(_, _) ->
+ false.
+
+chk_SEQUENCE_OF([], [], _, _, _) ->
+ ok;
+chk_SEQUENCE_OF([] = V1, V2, Type, _, _) ->
+ not_equal(Type, V1, V2);
+chk_SEQUENCE_OF(V1, [] = V2, Type, _, _) ->
+ not_equal(Type, V1, V2);
+chk_SEQUENCE_OF([H|T1], [H|T2], Type, IS, CHK) ->
+ case IS(H) of
+ true ->
+ chk_SEQUENCE_OF(T1, T2, Type, IS, CHK);
+ false ->
+ Type2 = list_to_atom(atom_to_list(Type) ++ "_val"),
+ wrong_type(Type2, H)
+ end;
+chk_SEQUENCE_OF([H1|T1], [H2|T2], Type, IS, CHK) ->
+ Type2 = list_to_atom(atom_to_list(Type) ++ "_val"),
+ validate(fun() -> CHK(H1, H2) end, Type2),
+ chk_SEQUENCE_OF(T1, T2, Type, IS, CHK);
+chk_SEQUENCE_OF(V1, V2, Type, _, _) ->
+ wrong_type(Type, V1, V2).
+
+
+%% ----------------------------------------------------------------------
+
+compare_strings([] = L1, L2) ->
+ {L1, L2};
+compare_strings(L1, [] = L2) ->
+ {L1, L2};
+compare_strings([H|T1], [H|T2]) ->
+ compare_strings(T1, T2);
+compare_strings(L1, L2) ->
+ {L1, L2}.
+
+strip_tab_and_newline([]) ->
+ [];
+strip_tab_and_newline([$\n|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([$\t|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([H|T]) ->
+ [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+maybe_sort(L) when is_list(L) ->
+ lists:sort(L);
+maybe_sort(X) ->
+ X.
+
+
+%% ----------------------------------------------------------------------
+
+atmost_once(Type, Val) ->
+ error({atmost_once, {Type, Val}}).
+
+wrong_type(Type, Val) ->
+ error({wrong_type, {Type, Val}}).
+
+wrong_type(Type, Val1, Val2) ->
+ error({wrong_type, {Type, Val1, Val2}}).
+
+not_equal(What, Val1, Val2) ->
+ error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_msg_v1_lib.erl b/lib/megaco/test/megaco_test_msg_v1_lib.erl
new file mode 100644
index 0000000000..638215e8c1
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_v1_lib.erl
@@ -0,0 +1,7024 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%% This file is originally a copy of megaco_test_msg_v2_lib.erl
+%% which is why so much of it is commented out.
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_v1_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_v1.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([
+ cre_MegacoMessage/1, cre_MegacoMessage/2,
+%% cre_AuthenticationHeader/3,
+ cre_Message/3,
+%% cre_ErrorDescriptor/1, cre_ErrorDescriptor/2,
+%% cre_ErrorCode/1,
+%% cre_ErrorText/1,
+ cre_ContextID/1,
+ cre_Transaction/1,
+ cre_TransactionId/1,
+ cre_TransactionRequest/2,
+%% cre_TransactionPending/1,
+%% cre_TransactionReply/2, cre_TransactionReply/3,
+%% cre_TransactionAck/1, cre_TransactionAck/2,
+ cre_ActionRequest/2, cre_ActionRequest/3, cre_ActionRequest/4,
+%% cre_ActionReply/2, cre_ActionReply/3, cre_ActionReply/4,
+%% cre_ContextRequest/0, cre_ContextRequest/1, cre_ContextRequest/2,
+%% cre_ContextRequest/3,
+%% cre_ContextAttrAuditRequest/0, cre_ContextAttrAuditRequest/3,
+%% cre_CommandRequest/1, cre_CommandRequest/2, cre_CommandRequest/3,
+%% cre_Command/2,
+%% cre_CommandReply/2,
+%% cre_TopologyRequest/3, cre_TopologyRequest/4,
+%% cre_AmmRequest/2,
+ cre_AmmDescriptor/1,
+%% cre_AmmsReply/1, cre_AmmsReply/2,
+%% cre_SubtractRequest/1, cre_SubtractRequest/2,
+%% cre_AuditRequest/2,
+%% cre_AuditReply/1,
+%% cre_AuditResult/2,
+%% cre_AuditReturnParameter/1,
+%% cre_AuditDescriptor/0, cre_AuditDescriptor/1, cre_AuditDescriptor/2,
+%% cre_IndAuditParameter/1,
+%% cre_IndAudMediaDescriptor/0, cre_IndAudMediaDescriptor/1,
+%% cre_IndAudMediaDescriptor/2,
+%% cre_IndAudStreamDescriptor/2,
+%% cre_IndAudStreamParms/0, cre_IndAudStreamParms/1,
+%% cre_IndAudStreamParms/3,
+%% cre_IndAudLocalControlDescriptor/0,
+%% cre_IndAudLocalControlDescriptor/4,
+%% cre_IndAudPropertyParm/1,
+%% cre_IndAudLocalRemoteDescriptor/1,
+%% cre_IndAudLocalRemoteDescriptor/2,
+%% cre_IndAudPropertyGroup/1,
+%% cre_IndAudTerminationStateDescriptor/1,
+%% cre_IndAudTerminationStateDescriptor/3,
+%% cre_IndAudEventsDescriptor/1, cre_IndAudEventsDescriptor/2,
+%% cre_IndAudEventsDescriptor/3,
+%% cre_IndAudEventBufferDescriptor/1,
+%% cre_IndAudEventBufferDescriptor/2,
+%% cre_IndAudSignalsDescriptor/1,
+%% cre_IndAudSeqSigList/1,
+%% cre_IndAudSeqSigList/2,
+%% cre_IndAudSignal/1, cre_IndAudSignal/2,
+%% cre_IndAudDigitMapDescriptor/0, cre_IndAudDigitMapDescriptor/1,
+%% cre_IndAudStatisticsDescriptor/1,
+%% cre_IndAudPackagesDescriptor/2,
+%% cre_NotifyRequest/2, cre_NotifyRequest/3,
+%% cre_NotifyReply/1, cre_NotifyReply/2,
+%% cre_ObservedEventsDescriptor/2,
+%% cre_ObservedEvent/2, cre_ObservedEvent/3, cre_ObservedEvent/4,
+ cre_EventName/1,
+ cre_EventParameter/2, cre_EventParameter/4,
+%% cre_ServiceChangeRequest/2,
+%% cre_ServiceChangeReply/2,
+%% cre_ServiceChangeResult/1,
+%% %% cre_WildcardField/1,
+%% cre_TerminationID/2,
+%% cre_TerminationIDList/1,
+%% cre_MediaDescriptor/0, cre_MediaDescriptor/1, cre_MediaDescriptor/2,
+%% cre_StreamDescriptor/2,
+%% cre_StreamParms/0, cre_StreamParms/1, cre_StreamParms/2,
+%% cre_StreamParms/3,
+%% cre_LocalControlDescriptor/1, cre_LocalControlDescriptor/2,
+%% cre_LocalControlDescriptor/4,
+%% cre_StreamMode/1,
+%% cre_PropertyParm/2, cre_PropertyParm/4,
+%% cre_Name/1,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+%% cre_Relation/1,
+%% cre_LocalRemoteDescriptor/1,
+%% cre_PropertyGroup/1,
+%% cre_TerminationStateDescriptor/1,
+%% cre_TerminationStateDescriptor/2,
+%% cre_TerminationStateDescriptor/3,
+%% cre_EventBufferControl/1,
+%% cre_ServiceState/1,
+%% cre_MuxDescriptor/2, %% cre_MuxDescriptor/3,
+%% cre_MuxType/1,
+%% cre_StreamID/1,
+%% cre_EventsDescriptor/0, cre_EventsDescriptor/2,
+%% cre_RequestedEvent/1,
+%% cre_RequestedEvent/2, cre_RequestedEvent/3, cre_RequestedEvent/4,
+%% cre_RequestedActions/0,
+%% cre_RequestedActions/1, cre_RequestedActions/4,
+%% cre_EventDM/1,
+%% cre_SecondEventsDescriptor/1, cre_SecondEventsDescriptor/2,
+%% cre_SecondRequestedEvent/2, cre_SecondRequestedEvent/3,
+%% cre_SecondRequestedEvent/4,
+%% cre_SecondRequestedActions/0, cre_SecondRequestedActions/1,
+%% cre_SecondRequestedActions/2, cre_SecondRequestedActions/3,
+ cre_EventBufferDescriptor/1,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+%% cre_SignalsDescriptor/1,
+%% cre_SignalRequest/1,
+%% cre_SeqSigList/2,
+%% cre_Signal/1, cre_Signal/2, cre_Signal/7,
+%% cre_SignalType/1,
+%% cre_SignalName/1,
+%% cre_NotifyCompletion/1,
+%% cre_SigParameter/2, cre_SigParameter/4,
+%% cre_RequestID/1,
+%% cre_ModemDescriptor/2, %% cre_ModemDescriptor/3,
+%% cre_ModemType/1,
+%% cre_DigitMapDescriptor/0, cre_DigitMapDescriptor/1,
+%% cre_DigitMapDescriptor/2,
+%% cre_DigitMapName/1,
+%% cre_DigitMapValue/1, cre_DigitMapValue/4, cre_DigitMapValue/5,
+%% cre_ServiceChangeParm/2, cre_ServiceChangeParm/4,
+%% cre_ServiceChangeParm/9,
+%% cre_ServiceChangeAddress/2,
+%% cre_ServiceChangeResParm/0, cre_ServiceChangeResParm/2,
+%% cre_ServiceChangeResParm/5,
+%% cre_ServiceChangeMethod/1,
+%% cre_ServiceChangeProfile/1, cre_ServiceChangeProfile/2,
+%% cre_PackagesDescriptor/1,
+%% cre_PackagesItem/2,
+%% cre_StatisticsDescriptor/1,
+%% cre_StatisticsParameter/1, cre_StatisticsParameter/2,
+%% %% cre_NonStandardData/2,
+%% %% cre_NonStandardIdentifier/1,
+%% %% cre_H221NonStandard/4,
+%% cre_TimeNotation/2,
+%% cre_Value/1,
+ cre_BOOLEAN/1
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') andalso
+ is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+%% cre_AuthenticationHeader(SPI, SN, AD) ->
+%% #'AuthenticationHeader'{secParmIndex = SPI,
+%% seqNum = SN,
+%% ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+%% cre_ErrorDescriptor(EC) when integer(EC) ->
+%% #'ErrorDescriptor'{errorCode = EC}.
+
+%% cre_ErrorDescriptor(EC, ET) when integer(EC), list(ET) ->
+%% #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+%% cre_ErrorCode(C) when integer(C), 0 =< C, C =< 65535 ->
+%% C;
+%% cre_ErrorCode(C) ->
+%% exit({invalid_ErrorCode, C}).
+
+%% cre_ErrorText(T) when list(T) ->
+%% T.
+
+cre_ContextID(Val) when (0 =< Val) and (Val =< 4294967295) ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA}.
+
+cre_TransactionId(Val) when (0 =< Val) andalso (Val =< 4294967295) ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs) when is_integer(TransID) andalso is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+%% cre_TransactionPending(TransID) when integer(TransID) ->
+%% #'TransactionPending'{transactionId = TransID}.
+
+%% cre_TransactionReply(TransID, ED)
+%% when integer(TransID), record(ED, 'ErrorDescriptor') ->
+%% Res = {transactionError, ED},
+%% #'TransactionReply'{transactionId = TransID,
+%% transactionResult = Res};
+%% cre_TransactionReply(TransID, ARs)
+%% when integer(TransID), list(ARs) ->
+%% Res = {actionReplies, ARs},
+%% #'TransactionReply'{transactionId = TransID,
+%% transactionResult = Res}.
+
+%% cre_TransactionReply(TransID, IAR, ED)
+%% when is_integer(TransID) and
+%% ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+%% is_record(ED, 'ErrorDescriptor') ->
+%% Res = {transactionError, ED},
+%% #'TransactionReply'{transactionId = TransID,
+%% transactionResult = Res};
+%% cre_TransactionReply(TransID, IAR, ARs)
+%% when is_integer(TransID) and
+%% ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+%% is_list(ARs) ->
+%% Res = {actionReplies, ARs},
+%% #'TransactionReply'{transactionId = TransID,
+%% transactionResult = Res}.
+
+%% cre_TransactionAck(FirstAck) ->
+%% #'TransactionAck'{firstAck = FirstAck}.
+
+%% cre_TransactionAck(FirstAck, FirstAck) ->
+%% #'TransactionAck'{firstAck = FirstAck};
+%% cre_TransactionAck(FirstAck, LastAck) ->
+%% #'TransactionAck'{firstAck = FirstAck,
+%% lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) and is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+%% cre_ActionReply(CtxID, CmdReps)
+%% when integer(CtxID),
+%% list(CmdReps) ->
+%% #'ActionReply'{contextId = CtxID,
+%% commandReply = CmdReps}.
+
+%% cre_ActionReply(CtxID, ED, CmdReps)
+%% when integer(CtxID),
+%% record(ED, 'ErrorDescriptor'),
+%% list(CmdReps) ->
+%% #'ActionReply'{contextId = CtxID,
+%% errorDescriptor = ED,
+%% commandReply = CmdReps};
+%% cre_ActionReply(CtxID, CtxReq, CmdReps)
+%% when integer(CtxID),
+%% record(CtxReq, 'ContextRequest'),
+%% list(CmdReps) ->
+%% #'ActionReply'{contextId = CtxID,
+%% contextReply = CtxReq,
+%% commandReply = CmdReps}.
+
+%% cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+%% when integer(CtxID),
+%% record(ED, 'ErrorDescriptor'),
+%% record(CtxReq, 'ContextRequest'),
+%% list(CmdReps) ->
+%% #'ActionReply'{contextId = CtxID,
+%% errorDescriptor = ED,
+%% contextReply = CtxReq,
+%% commandReply = CmdReps}.
+
+%% cre_ContextRequest() ->
+%% #'ContextRequest'{}.
+
+%% cre_ContextRequest(Prio) when integer(Prio), 0 =< Prio, Prio =< 15 ->
+%% #'ContextRequest'{priority = Prio};
+%% cre_ContextRequest(Em) when Em == true; Em == false; Em == asn1_NOVALUE ->
+%% #'ContextRequest'{emergency = Em};
+%% cre_ContextRequest(Top) when list(Top) ->
+%% #'ContextRequest'{topologyReq = Top}.
+
+%% cre_ContextRequest(Prio, Em)
+%% when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+%% ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) ->
+%% #'ContextRequest'{priority = Prio,
+%% emergency = Em};
+%% cre_ContextRequest(Prio, Top)
+%% when integer(Prio), 0 =< Prio, Prio =< 15, list(Top) ->
+%% #'ContextRequest'{priority = Prio,
+%% topologyReq = Top}.
+
+%% cre_ContextRequest(Prio, Em, Top)
+%% when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+%% ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+%% is_list(Top) ->
+%% #'ContextRequest'{priority = Prio,
+%% emergency = Em,
+%% topologyReq = Top}.
+
+%% cre_ContextAttrAuditRequest() ->
+%% #'ContextAttrAuditRequest'{}.
+
+%% cre_ContextAttrAuditRequest(Top, Em, Prio)
+%% when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+%% ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+%% ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) ->
+%% #'ContextAttrAuditRequest'{topology = Top,
+%% emergency = Em,
+%% priority = Prio}.
+
+%% cre_CommandRequest(Cmd) ->
+%% #'CommandRequest'{command = Cmd}.
+
+%% cre_CommandRequest(Cmd, Opt)
+%% when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+%% #'CommandRequest'{command = Cmd,
+%% optional = Opt}.
+
+%% cre_CommandRequest(Cmd, Opt, WR)
+%% when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+%% ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+%% #'CommandRequest'{command = Cmd,
+%% optional = Opt,
+%% wildcardReturn = WR}.
+
+%% cre_Command(addReq = Tag, Req)
+%% when record(Req, 'AmmRequest') ->
+%% {Tag, Req};
+%% cre_Command(moveReq = Tag, Req)
+%% when record(Req, 'AmmRequest') ->
+%% {Tag, Req};
+%% cre_Command(modReq = Tag, Req)
+%% when record(Req, 'AmmRequest') ->
+%% {Tag, Req};
+%% cre_Command(subtractReq = Tag, Req)
+%% when record(Req, 'SubtractRequest') ->
+%% {Tag, Req};
+%% cre_Command(auditCapRequest = Tag, Req)
+%% when record(Req, 'AuditRequest') ->
+%% {Tag, Req};
+%% cre_Command(auditValueRequest = Tag, Req)
+%% when record(Req, 'AuditRequest') ->
+%% {Tag, Req};
+%% cre_Command(notifyReq = Tag, Req)
+%% when record(Req, 'NotifyRequest') ->
+%% {Tag, Req};
+%% cre_Command(serviceChangeReq = Tag, Req)
+%% when record(Req, 'ServiceChangeRequest') ->
+%% {Tag, Req}.
+
+%% cre_CommandReply(addReply = Tag, Rep)
+%% when record(Rep, 'AmmsReply') ->
+%% {Tag, Rep};
+%% cre_CommandReply(moveReply = Tag, Rep)
+%% when record(Rep, 'AmmsReply') ->
+%% {Tag, Rep};
+%% cre_CommandReply(modReply = Tag, Rep)
+%% when record(Rep, 'AmmsReply') ->
+%% {Tag, Rep};
+%% cre_CommandReply(subtractReply = Tag, Rep)
+%% when record(Rep, 'AmmsReply') ->
+%% {Tag, Rep};
+%% cre_CommandReply(auditCapReply = Tag, Rep)
+%% when tuple(Rep) ->
+%% {Tag, Rep};
+%% cre_CommandReply(auditValueReply = Tag, Rep)
+%% when tuple(Rep) ->
+%% {Tag, Rep};
+%% cre_CommandReply(notifyReply = Tag, Rep)
+%% when record(Rep, 'NotifyReply') ->
+%% {Tag, Rep};
+%% cre_CommandReply(serviceChangeReply = Tag, Rep)
+%% when record(Rep, 'ServiceChangeReply') ->
+%% {Tag, Rep}.
+
+%% cre_TopologyRequest(From, To, Dir)
+%% when is_record(From, 'TerminationID') and
+%% is_record(To, 'TerminationID') and
+%% ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) ->
+%% #'TopologyRequest'{terminationFrom = From,
+%% terminationTo = To,
+%% topologyDirection = Dir}.
+
+%% cre_TopologyRequest(From, To, Dir, SID)
+%% when is_record(From, 'TerminationID') and
+%% is_record(To, 'TerminationID') and
+%% ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) and
+%% (is_integer(SID) or (SID == asn1_NOVALUE)) ->
+%% #'TopologyRequest'{terminationFrom = From,
+%% terminationTo = To,
+%% topologyDirection = Dir,
+%% streamID = SID}.
+
+%% cre_AmmRequest(TermIDs, Descs) when list(TermIDs), list(Descs) ->
+%% #'AmmRequest'{terminationID = TermIDs,
+%% descriptors = Descs}.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end.
+
+%% cre_AmmsReply(TermIDs) when list(TermIDs) ->
+%% #'AmmsReply'{terminationID = TermIDs}.
+
+%% cre_AmmsReply(TermIDs, TAs) when list(TermIDs), list(TAs) ->
+%% #'AmmsReply'{terminationID = TermIDs,
+%% terminationAudit = TAs}.
+
+%% cre_SubtractRequest(TermIDs) when list(TermIDs) ->
+%% #'SubtractRequest'{terminationID = TermIDs}.
+
+%% cre_SubtractRequest(TermIDs, Audit)
+%% when list(TermIDs), record(Audit, 'AuditDescriptor') ->
+%% #'SubtractRequest'{terminationID = TermIDs,
+%% auditDescriptor = Audit}.
+
+%% cre_AuditRequest(TermID, Audit)
+%% when record(TermID, megaco_term_id), record(Audit, 'AuditDescriptor') ->
+%% #'AuditRequest'{terminationID = TermID,
+%% auditDescriptor = Audit}.
+
+%% cre_AuditReply(TermIDs) when list(TermIDs) ->
+%% {contextAuditResult, TermIDs};
+%% cre_AuditReply(ED) when record(ED, 'ErrorDescriptor') ->
+%% {error, ED};
+%% cre_AuditReply(Audit) when record(Audit, 'AuditResult') ->
+%% {auditResult, Audit}.
+
+%% cre_AuditResult(TermID, TAs)
+%% when record(TermID, megaco_term_id), list(TAs) ->
+%% #'AuditResult'{terminationID = TermID,
+%% terminationAuditResult = TAs}.
+
+%% cre_AuditReturnParameter(D) when record(D, 'ErrorDescriptor') ->
+%% {errorDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'MediaDescriptor') ->
+%% {mediaDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'ModemDescriptor') ->
+%% {modemDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'MuxDescriptor') ->
+%% {muxDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'EventsDescriptor') ->
+%% {eventsDescriptor, D};
+%% cre_AuditReturnParameter([H|_] = D) when record(H, 'EventSpec') ->
+%% {eventBufferDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'DigitMapDescriptor') ->
+%% {digitMapDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'ObservedEventsDescriptor') ->
+%% {observedEventsDescriptor, D};
+%% cre_AuditReturnParameter([H|_] = D) when record(H, 'StatisticsParameter') ->
+%% {statisticsDescriptor, D};
+%% cre_AuditReturnParameter([H|_] = D) when record(H, 'PackagesItem') ->
+%% {packagesDescriptor, D};
+%% cre_AuditReturnParameter(D) when record(D, 'AuditDescriptor') ->
+%% {emptyDescriptors, D};
+%% cre_AuditReturnParameter([H|_] = D) when tuple(H) ->
+%% {signalsDescriptor, D}.
+
+%% cre_AuditDescriptor() ->
+%% #'AuditDescriptor'{}.
+
+%% cre_AuditDescriptor([H|_] = AT) when atom(H) ->
+%% #'AuditDescriptor'{auditToken = AT};
+%% cre_AuditDescriptor(APT) ->
+%% #'AuditDescriptor'{auditPropertyToken = APT}.
+
+%% cre_AuditDescriptor(AT, APT) ->
+%% #'AuditDescriptor'{auditToken = AT,
+%% auditPropertyToken = APT}.
+
+%% cre_IndAuditParameter(D) when record(D, 'IndAudMediaDescriptor') ->
+%% {indAudMediaDescriptor, D};
+%% cre_IndAuditParameter(D) when record(D, 'IndAudEventsDescriptor') ->
+%% {indAudEventsDescriptor, D};
+%% cre_IndAuditParameter(D) when record(D, 'IndAudEventBufferDescriptor') ->
+%% {indAudEventBufferDescriptor, D};
+%% cre_IndAuditParameter({signal, _} = D) ->
+%% {indAudSignalsDescriptor, D};
+%% cre_IndAuditParameter({seqSigList, _} = D) ->
+%% {indAudSignalsDescriptor, D};
+%% cre_IndAuditParameter(D) when record(D, 'IndAudDigitMapDescriptor') ->
+%% {indAudDigitMapDescriptor, D};
+%% cre_IndAuditParameter(D) when record(D, 'IndAudStatisticsDescriptor') ->
+%% {indAudStatisticsDescriptor, D};
+%% cre_IndAuditParameter(D) when record(D, 'IndAudPackagesDescriptor') ->
+%% {indAudPackagesDescriptor, D}.
+
+%% cre_IndAudMediaDescriptor() ->
+%% #'IndAudMediaDescriptor'{}.
+
+%% cre_IndAudMediaDescriptor(TSD)
+%% when record(TSD, 'IndAudTerminationStateDescriptor') ->
+%% #'IndAudMediaDescriptor'{termStateDescr = TSD};
+%% cre_IndAudMediaDescriptor(Parms) when record(Parms, 'IndAudStreamParms') ->
+%% Streams = {oneStream, Parms},
+%% #'IndAudMediaDescriptor'{streams = Streams};
+%% cre_IndAudMediaDescriptor(Descs) when list(Descs) ->
+%% Streams = {multiStream, Descs},
+%% #'IndAudMediaDescriptor'{streams = Streams}.
+
+%% cre_IndAudMediaDescriptor(TSD, Parms)
+%% when record(TSD, 'IndAudTerminationStateDescriptor'),
+%% record(Parms, 'IndAudStreamParms') ->
+%% Streams = {oneStream, Parms},
+%% #'IndAudMediaDescriptor'{termStateDescr = TSD,
+%% streams = Streams};
+%% cre_IndAudMediaDescriptor(TSD, Descs)
+%% when record(TSD, 'IndAudTerminationStateDescriptor'), list(Descs) ->
+%% Streams = {multiStream, Descs},
+%% #'IndAudMediaDescriptor'{termStateDescr = TSD,
+%% streams = Streams}.
+
+%% cre_IndAudStreamDescriptor(SID, Parms)
+%% when integer(SID), record(Parms, 'IndAudStreamParms') ->
+%% #'IndAudStreamDescriptor'{streamID = SID,
+%% streamParms = Parms}.
+
+%% cre_IndAudStreamParms() ->
+%% #'IndAudStreamParms'{}.
+
+%% cre_IndAudStreamParms(LCD) when record(LCD, 'IndAudLocalControlDescriptor') ->
+%% #'IndAudStreamParms'{localControlDescriptor = LCD}.
+
+%% cre_IndAudStreamParms(LCD, L, R)
+%% when record(LCD, 'IndAudLocalControlDescriptor'),
+%% record(L, 'IndAudLocalRemoteDescriptor'),
+%% record(R, 'IndAudLocalRemoteDescriptor') ->
+%% #'IndAudStreamParms'{localControlDescriptor = LCD,
+%% localDescriptor = L,
+%% remoteDescriptor = R}.
+
+%% cre_IndAudLocalControlDescriptor() ->
+%% #'IndAudLocalControlDescriptor'{}.
+
+%% cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+%% when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+%% ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+%% ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+%% (is_list(PP) or (PP == asn1_NOVALUE)) ->
+%% #'IndAudLocalControlDescriptor'{streamMode = SM,
+%% reserveValue = RV,
+%% reserveGroup = RG,
+%% propertyParms = PP}.
+
+%% cre_IndAudPropertyParm(PkgdName) when list(PkgdName) ->
+%% #'IndAudPropertyParm'{name = PkgdName}.
+
+%% cre_IndAudLocalRemoteDescriptor(Grps)
+%% when list(Grps) ->
+%% #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+%% cre_IndAudLocalRemoteDescriptor(GrpID, Grps)
+%% when integer(GrpID), 0 =< GrpID, GrpID =< 65535, list(Grps) ->
+%% #'IndAudLocalRemoteDescriptor'{propGroupID = GrpID,
+%% propGrps = Grps}.
+
+%% cre_IndAudPropertyGroup([]) ->
+%% [];
+%% cre_IndAudPropertyGroup([H|_] = PG)
+%% when record(H, 'IndAudPropertyParm') ->
+%% PG.
+
+%% cre_IndAudTerminationStateDescriptor([] = PP) ->
+%% #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+%% cre_IndAudTerminationStateDescriptor([H|_] = PP)
+%% when record(H, 'IndAudPropertyParm') ->
+%% #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+%% cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+%% when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+%% ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+%% #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+%% eventBufferControl = EBC,
+%% serviceState = SS};
+%% cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+%% when is_record(H, 'IndAudPropertyParm') and
+%% ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+%% ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+%% #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+%% eventBufferControl = EBC,
+%% serviceState = SS}.
+
+%% cre_IndAudEventsDescriptor(PkgdName)
+%% when list(PkgdName) ->
+%% #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+%% cre_IndAudEventsDescriptor(RID, PkgdName)
+%% when integer(RID), list(PkgdName) ->
+%% #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+%% cre_IndAudEventsDescriptor(PkgdName, SID)
+%% when list(PkgdName), integer(SID) ->
+%% #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+%% cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+%% when integer(RID), list(PkgdName), integer(SID) ->
+%% #'IndAudEventsDescriptor'{requestID = RID,
+%% pkgdName = PkgdName,
+%% streamID = SID}.
+
+%% cre_IndAudEventBufferDescriptor(EventName) when list(EventName) ->
+%% #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+%% cre_IndAudEventBufferDescriptor(EventName, SID)
+%% when list(EventName), integer(SID) ->
+%% #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+%% cre_IndAudSignalsDescriptor(S) when record(S, 'IndAudSignal') ->
+%% {signal, S};
+%% cre_IndAudSignalsDescriptor(S) when record(S, 'IndAudSeqSigList') ->
+%% {seqSigList, S}.
+
+%% cre_IndAudSeqSigList(ID) when integer(ID), 0=< ID, ID =< 65535 ->
+%% #'IndAudSeqSigList'{id = ID}.
+
+%% cre_IndAudSeqSigList(ID, S)
+%% when integer(ID), 0=< ID, ID =< 65535,
+%% record(S, 'IndAudSignal') ->
+%% #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+%% cre_IndAudSignal(SigName) when list(SigName) ->
+%% #'IndAudSignal'{signalName = SigName}.
+
+%% cre_IndAudSignal(SigName, SID) when list(SigName), integer(SID) ->
+%% #'IndAudSignal'{signalName = SigName, streamID = SID}.
+
+%% cre_IndAudDigitMapDescriptor() ->
+%% #'IndAudDigitMapDescriptor'{}.
+
+%% cre_IndAudDigitMapDescriptor(DMN) when list(DMN) ->
+%% #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+%% cre_IndAudStatisticsDescriptor(StatName) when list(StatName) ->
+%% #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+%% cre_IndAudPackagesDescriptor(N, V)
+%% when list(N),
+%% integer(V), 0 =< V, V =< 99 ->
+%% #'IndAudPackagesDescriptor'{packageName = N,
+%% packageVersion = V}.
+
+%% cre_NotifyRequest(TermIDs, D)
+%% when list(TermIDs), record(D, 'ObservedEventsDescriptor') ->
+%% #'NotifyRequest'{terminationID = TermIDs,
+%% observedEventsDescriptor = D}.
+
+%% cre_NotifyRequest(TermIDs, D, ED)
+%% when list(TermIDs),
+%% record(D, 'ObservedEventsDescriptor'),
+%% record(ED, 'ErrorDescriptor') ->
+%% #'NotifyRequest'{terminationID = TermIDs,
+%% observedEventsDescriptor = D,
+%% errorDescriptor = ED}.
+
+%% cre_NotifyReply(TermIDs) when list(TermIDs) ->
+%% #'NotifyReply'{terminationID = TermIDs}.
+
+%% cre_NotifyReply(TermIDs, ED)
+%% when list(TermIDs),
+%% record(ED, 'ErrorDescriptor') ->
+%% #'NotifyReply'{terminationID = TermIDs,
+%% errorDescriptor = ED}.
+
+%% cre_ObservedEventsDescriptor(RID, [H|_] = L)
+%% when integer(RID), record(H, 'ObservedEvent') ->
+%% #'ObservedEventsDescriptor'{requestId = RID,
+%% observedEventLst = L}.
+
+%% cre_ObservedEvent(EN, EPL) when list(EN), list(EPL) ->
+%% #'ObservedEvent'{eventName = EN,
+%% eventParList = EPL};
+%% cre_ObservedEvent(EN, TN) when list(EN), record(TN, 'TimeNotation') ->
+%% #'ObservedEvent'{eventName = EN,
+%% timeNotation = TN}.
+
+%% cre_ObservedEvent(EN, SID, EPL) when list(EN), integer(SID), list(EPL) ->
+%% #'ObservedEvent'{eventName = EN,
+%% streamID = SID,
+%% eventParList = EPL};
+%% cre_ObservedEvent(EN, EPL, TN)
+%% when list(EN), list(EPL), record(TN, 'TimeNotation') ->
+%% #'ObservedEvent'{eventName = EN,
+%% eventParList = EPL,
+%% timeNotation = TN}.
+
+%% cre_ObservedEvent(EN, SID, EPL, TN)
+%% when list(EN), integer(SID), list(EPL), record(TN, 'TimeNotation') ->
+%% #'ObservedEvent'{eventName = EN,
+%% streamID = SID,
+%% eventParList = EPL,
+%% timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+%% cre_ServiceChangeRequest(TermIDs, SCP)
+%% when list(TermIDs),
+%% record(SCP, 'ServiceChangeParm') ->
+%% #'ServiceChangeRequest'{terminationID = TermIDs,
+%% serviceChangeParms = SCP}.
+
+%% cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+%% when list(TermIDs), atom(Tag), tuple(R) ->
+%% #'ServiceChangeReply'{terminationID = TermIDs,
+%% serviceChangeResult = SCR}.
+
+%% cre_ServiceChangeResult(ED) when record(ED, 'ErrorDescriptor') ->
+%% {errorDescriptor, ED};
+%% cre_ServiceChangeResult(SCRP) when record(SCRP, 'ServiceChangeResParm') ->
+%% {serviceChangeResParms, SCRP}.
+
+%% %% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+%% cre_TerminationID(W, ID)
+%% when list(W),
+%% list(ID), 1 =< length(ID), length(ID) =< 8 ->
+%% #'TerminationID'{wildcard = W,
+%% id = ID}.
+
+%% cre_TerminationIDList(L) when list(L) ->
+%% L.
+
+%% cre_MediaDescriptor() ->
+%% #'MediaDescriptor'{}.
+
+%% cre_MediaDescriptor(TSD) when record(TSD, 'TerminationStateDescriptor') ->
+%% #'MediaDescriptor'{termStateDescr = TSD};
+%% cre_MediaDescriptor(SP) when record(SP, 'StreamParms') ->
+%% Streams = {oneStream, SP},
+%% #'MediaDescriptor'{streams = Streams};
+%% cre_MediaDescriptor([H|_] = SDs) when record(H, 'StreamDescriptor') ->
+%% Streams = {multiStream, SDs},
+%% #'MediaDescriptor'{streams = Streams}.
+
+%% cre_MediaDescriptor(TSD, SP)
+%% when record(TSD, 'TerminationStateDescriptor'),
+%% record(SP, 'StreamParms') ->
+%% Streams = {oneStream, SP},
+%% #'MediaDescriptor'{termStateDescr = TSD,
+%% streams = Streams};
+%% cre_MediaDescriptor(TSD, [H|_] = SDs)
+%% when record(TSD, 'TerminationStateDescriptor'),
+%% record(H, 'StreamDescriptor') ->
+%% Streams = {multiStream, SDs},
+%% #'MediaDescriptor'{termStateDescr = TSD,
+%% streams = Streams}.
+
+%% cre_StreamDescriptor(SID, SP) when integer(SID), record(SP, 'StreamParms') ->
+%% #'StreamDescriptor'{streamID = SID,
+%% streamParms = SP}.
+
+%% cre_StreamParms() ->
+%% #'StreamParms'{}.
+
+%% cre_StreamParms(LCD) when record(LCD, 'LocalControlDescriptor') ->
+%% #'StreamParms'{localControlDescriptor = LCD};
+%% cre_StreamParms(LD) when record(LD, 'LocalRemoteDescriptor') ->
+%% #'StreamParms'{localDescriptor = LD}.
+
+%% cre_StreamParms(LCD, LD)
+%% when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+%% (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+%% #'StreamParms'{localControlDescriptor = LCD,
+%% localDescriptor = LD}.
+
+%% cre_StreamParms(LCD, LD, RD)
+%% when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+%% (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+%% (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+%% #'StreamParms'{localControlDescriptor = LCD,
+%% localDescriptor = LD,
+%% remoteDescriptor = RD}.
+
+%% cre_LocalControlDescriptor(SM) when atom(SM) ->
+%% #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+%% cre_LocalControlDescriptor([H|_] = PP) when record(H, 'PropertyParm') ->
+%% #'LocalControlDescriptor'{propertyParms = PP}.
+
+%% cre_LocalControlDescriptor(SM, [H|_] = PP)
+%% when atom(SM), record(H, 'PropertyParm') ->
+%% #'LocalControlDescriptor'{streamMode = SM,
+%% propertyParms = PP}.
+
+%% cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+%% when is_atom(SM) and
+%% ((RV == true) or (RV == false) or (RV == asn1_NOVALUE)) and
+%% ((RG == true) or (RG == false) or (RG == asn1_NOVALUE)) and
+%% is_record(H, 'PropertyParm') ->
+%% #'LocalControlDescriptor'{streamMode = SM,
+%% reserveValue = RV,
+%% reserveGroup = RG,
+%% propertyParms = PP}.
+
+%% cre_StreamMode(sendOnly = M) ->
+%% M;
+%% cre_StreamMode(recvOnly = M) ->
+%% M;
+%% cre_StreamMode(sendRecv = M) ->
+%% M;
+%% cre_StreamMode(inactive = M) ->
+%% M;
+%% cre_StreamMode(loopBack = M) ->
+%% M.
+
+%% cre_PropertyParm(N, [H|_] = V) when list(N), list(H) ->
+%% #'PropertyParm'{name = N, value = V}.
+
+%% cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+%% when list(N), list(H), atom(R) ->
+%% EI = {Tag, R},
+%% #'PropertyParm'{name = N, value = V, extraInfo = EI};
+%% cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+%% when list(N), list(H), atom(B) ->
+%% EI = {Tag, B},
+%% #'PropertyParm'{name = N, value = V, extraInfo = EI};
+%% cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+%% when list(N), list(H), atom(B) ->
+%% EI = {Tag, B},
+%% #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+%% cre_Name(N) when list(N), length(N) == 2 ->
+%% N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) and (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) and (length(PackageName) =< 64)) and
+ (is_list(ItemID) and (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+%% cre_Relation(greaterThan = R) ->
+%% R;
+%% cre_Relation(smallerThan = R) ->
+%% R;
+%% cre_Relation(unequalTo = R) ->
+%% R.
+
+%% cre_LocalRemoteDescriptor([H|_] = PGs) when list(H) ->
+%% #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+%% cre_PropertyGroup([H|_] = PG) when record(H, 'PropertyParm') ->
+%% PG.
+
+%% cre_TerminationStateDescriptor([H|_] = PPs) when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+%% cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+%% when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% eventBufferControl = EBC};
+%% cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+%% when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% eventBufferControl = EBC};
+%% cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+%% when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% serviceState = SS};
+%% cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+%% when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% serviceState = SS};
+%% cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+%% when record(H, 'PropertyParm') ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% serviceState = SS}.
+
+%% cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+%% when record(H, 'PropertyParm'),
+%% ((EMC == off) or (EMC == lockStep)) and
+%% ((SS == test) or (SS == outOfSvc) or (SS == inSvc)) ->
+%% #'TerminationStateDescriptor'{propertyParms = PPs,
+%% eventBufferControl = EMC,
+%% serviceState = SS}.
+
+%% cre_EventBufferControl(off = EBC) ->
+%% EBC;
+%% cre_EventBufferControl(lockStep = EBC) ->
+%% EBC.
+
+%% cre_ServiceState(test = SS) ->
+%% SS;
+%% cre_ServiceState(outOfSvc = SS) ->
+%% SS;
+%% cre_ServiceState(inSvc = SS) ->
+%% SS.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL)
+%% when atom(MT), record(H, 'TerminationID') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% %% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% %% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% %% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+%% cre_MuxType(h221 = MT) ->
+%% MT;
+%% cre_MuxType(h223 = MT) ->
+%% MT;
+%% cre_MuxType(h226 = MT) ->
+%% MT;
+%% cre_MuxType(v76 = MT) ->
+%% MT;
+%% cre_MuxType(nx64k = MT) ->
+%% MT.
+
+%% cre_StreamID(Val) when 0 =< Val, Val =< 65535 ->
+%% Val;
+%% cre_StreamID(Val) ->
+%% exit({invalid_ContextID, Val}).
+
+%% %% RequestID must be present if eventList is non empty
+%% cre_EventsDescriptor() ->
+%% #'EventsDescriptor'{eventList = []}.
+
+%% cre_EventsDescriptor(RID, [H|_] = EL)
+%% when integer(RID), record(H, 'RequestedEvent') ->
+%% #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+%% cre_RequestedEvent(N) ->
+%% #'RequestedEvent'{pkgdName = N}.
+
+%% cre_RequestedEvent(N, [H|_] = EPL)
+%% when list(N),
+%% record(H, 'EventParameter') ->
+%% #'RequestedEvent'{pkgdName = N,
+%% evParList = EPL};
+%% cre_RequestedEvent(N, EA)
+%% when list(N),
+%% record(EA, 'RequestedActions')->
+%% #'RequestedEvent'{pkgdName = N,
+%% eventAction = EA}.
+
+
+%% cre_RequestedEvent(N, SID, [H|_] = EPL)
+%% when list(N),
+%% integer(SID),
+%% record(H, 'EventParameter') ->
+%% #'RequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% evParList = EPL};
+%% cre_RequestedEvent(N, EA, [H|_] = EPL)
+%% when list(N),
+%% record(EA, 'RequestedActions'),
+%% record(H, 'EventParameter') ->
+%% #'RequestedEvent'{pkgdName = N,
+%% eventAction = EA,
+%% evParList = EPL}.
+
+%% cre_RequestedEvent(N, SID, EA, [H|_] = EPL)
+%% when list(N),
+%% integer(SID),
+%% record(EA, 'RequestedActions'),
+%% record(H, 'EventParameter') ->
+%% #'RequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% eventAction = EA,
+%% evParList = EPL}.
+
+%% cre_RequestedActions() ->
+%% #'RequestedActions'{}.
+
+%% cre_RequestedActions(KA)
+%% when (KA == true) or (KA == true) or (KA == asn1_NOVALUE) ->
+%% #'RequestedActions'{keepActive = KA};
+%% cre_RequestedActions(SE)
+%% when is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE) ->
+%% #'RequestedActions'{secondEvent = SE};
+%% cre_RequestedActions(SD)
+%% when is_list(SD) or (SD == asn1_NOVALUE) ->
+%% #'RequestedActions'{signalsDescriptor = SD};
+%% cre_RequestedActions({Tag, _} = EDM)
+%% when is_atom(Tag) or (EDM == asn1_NOVALUE) ->
+%% #'RequestedActions'{eventDM = EDM}.
+
+%% cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+%% when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+%% (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+%% (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+%% (is_list(SD) or (SD == asn1_NOVALUE)) ->
+%% #'RequestedActions'{keepActive = KA,
+%% eventDM = EDM,
+%% secondEvent = SE,
+%% signalsDescriptor = SD}.
+
+%% cre_EventDM(N) when list(N) ->
+%% {digitMapName, N};
+%% cre_EventDM(V) when record(V, 'DigitMapValue') ->
+%% {digitMapValue, V}.
+
+%% cre_SecondEventsDescriptor([H|_] = EL)
+%% when record(H, 'SecondRequestedEvent') ->
+%% #'SecondEventsDescriptor'{eventList = EL}.
+
+%% cre_SecondEventsDescriptor(RID, [H|_] = EL)
+%% when integer(RID), record(H, 'SecondRequestedEvent') ->
+%% #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+%% cre_SecondRequestedEvent(N, [H|_] = EPL)
+%% when list(N),
+%% record(H, 'EventParameter') ->
+%% #'SecondRequestedEvent'{pkgdName = N,
+%% evParList = EPL}.
+
+%% cre_SecondRequestedEvent(N, SID, [H|_] = EPL)
+%% when list(N),
+%% integer(SID),
+%% record(H, 'EventParameter') ->
+%% #'SecondRequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% evParList = EPL};
+%% cre_SecondRequestedEvent(N, EA, [H|_] = EPL)
+%% when list(N),
+%% record(EA, 'SecondRequestedActions'),
+%% record(H, 'EventParameter') ->
+%% #'SecondRequestedEvent'{pkgdName = N,
+%% eventAction = EA,
+%% evParList = EPL}.
+
+%% cre_SecondRequestedEvent(N, SID, EA, [H|_] = EPL)
+%% when list(N),
+%% integer(SID),
+%% record(EA, 'SecondRequestedActions'),
+%% record(H, 'EventParameter') ->
+%% #'SecondRequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% eventAction = EA,
+%% evParList = EPL}.
+
+%% cre_SecondRequestedActions() ->
+%% #'SecondRequestedActions'{}.
+
+%% cre_SecondRequestedActions(KA)
+%% when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+%% #'SecondRequestedActions'{keepActive = KA};
+%% cre_SecondRequestedActions(SD) when list(SD) ->
+%% #'SecondRequestedActions'{signalsDescriptor = SD};
+%% cre_SecondRequestedActions({Tag, _} = EDM) when atom(Tag) ->
+%% #'SecondRequestedActions'{eventDM = EDM}.
+
+%% cre_SecondRequestedActions(KA, SD)
+%% when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+%% is_list(SD) ->
+%% #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+%% cre_SecondRequestedActions(KA, {Tag, _} = EDM)
+%% when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+%% is_atom(Tag) ->
+%% #'SecondRequestedActions'{keepActive = KA, eventDM = EDM}.
+
+%% cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+%% when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+%% is_atom(Tag),
+%% is_list(SD) ->
+%% #'SecondRequestedActions'{keepActive = KA,
+%% eventDM = EDM,
+%% signalsDescriptor = SD}.
+
+cre_EventBufferDescriptor([H|_] = D)
+ when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL)
+ when is_list(N) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+%% cre_SignalsDescriptor(D) when list(D) ->
+%% D.
+
+%% cre_SignalRequest(S) when record(S, 'Signal') ->
+%% {signal, S};
+%% cre_SignalRequest(S) when record(S, 'SeqSigList') ->
+%% {seqSigList, S}.
+
+%% cre_SeqSigList(ID, [H|_] = SL)
+%% when integer(ID), 0 =< ID, ID =< 65535, record(H, 'Signal') ->
+%% #'SeqSigList'{id = ID, signalList = SL}.
+
+%% cre_Signal(N) when list(N) ->
+%% #'Signal'{signalName = N}.
+
+%% cre_Signal(N, [H|_] = SPL) when list(N), record(H, 'SigParameter') ->
+%% #'Signal'{signalName = N,
+%% sigParList = SPL}.
+
+%% cre_Signal(N, SID, ST, Dur, NC, KA, [H|_] = SPL)
+%% when is_list(N) and
+%% (is_integer(SID) or (SID == asn1_NOVALUE)) and
+%% ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+%% (ST == asn1_NOVALUE)) and
+%% ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+%% (Dur == asm1_NOVALUE)) and
+%% is_list(NC) and
+%% ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+%% is_record(H, 'SigParameter') ->
+%% #'Signal'{signalName = N,
+%% streamID = SID,
+%% sigType = ST,
+%% duration = Dur,
+%% notifyCompletion = NC,
+%% keepActive = KA,
+%% sigParList = SPL}.
+
+%% cre_SignalType(brief = ST) ->
+%% ST;
+%% cre_SignalType(onOff = ST) ->
+%% ST;
+%% cre_SignalType(timeOut = ST) ->
+%% ST.
+
+%% cre_SignalName(N) ->
+%% cre_PkgdName(N).
+
+%% cre_NotifyCompletion(L) when list(L) ->
+%% Vals = [onTimeOut, onInterruptByEvent,
+%% onInterruptByNewSignalDescr, otherReason],
+%% F = fun(E) -> case lists:member(E, Vals) of
+%% true ->
+%% ok;
+%% false ->
+%% exit({invalid_NotifyCompletion, E})
+%% end
+%% end,
+%% lists:foreach(F, L),
+%% L.
+
+%% cre_SigParameter(N, V) when list(N), list(V) ->
+%% #'SigParameter'{sigParameterName = N, value = V}.
+
+%% cre_SigParameter(N, V, relation = Tag, R)
+%% when is_list(N) and is_list(V) and is_atom(R) ->
+%% EI = {Tag, R},
+%% #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+%% cre_SigParameter(N, V, range = Tag, B)
+%% when is_list(N) and is_list(V) and is_atom(B) ->
+%% EI = {Tag, B},
+%% #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+%% cre_SigParameter(N, V, sublist = Tag, B)
+%% when is_list(N) and is_list(V) and is_atom(B) ->
+%% EI = {Tag, B},
+%% #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+%% cre_RequestID(Val) when 0 =< Val, Val =< 4294967295 ->
+%% Val;
+%% cre_RequestID(Val) ->
+%% exit({invalid_RequestID, Val}).
+
+%% cre_ModemDescriptor(MTL, MPL) when list(MTL), list(MPL) ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% %% cre_ModemDescriptor(MTL, MPL, NSD)
+%% %% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% %% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemType(v18 = MT) ->
+%% MT;
+%% cre_ModemType(v22 = MT) ->
+%% MT;
+%% cre_ModemType(v22bis = MT) ->
+%% MT;
+%% cre_ModemType(v32 = MT) ->
+%% MT;
+%% cre_ModemType(v32bis = MT) ->
+%% MT;
+%% cre_ModemType(v34 = MT) ->
+%% MT;
+%% cre_ModemType(v90 = MT) ->
+%% MT;
+%% cre_ModemType(v91 = MT) ->
+%% MT;
+%% cre_ModemType(synchISDN = MT) ->
+%% MT.
+
+%% cre_DigitMapDescriptor() ->
+%% #'DigitMapDescriptor'{}.
+
+%% cre_DigitMapDescriptor(N) when list(N) ->
+%% #'DigitMapDescriptor'{digitMapName = N};
+%% cre_DigitMapDescriptor(V) when record(V, 'DigitMapValue') ->
+%% #'DigitMapDescriptor'{digitMapValue = V}.
+
+%% cre_DigitMapDescriptor(N, V) when list(N), record(V, 'DigitMapValue') ->
+%% #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+%% cre_DigitMapName(N) ->
+%% cre_Name(N).
+
+%% cre_DigitMapValue(DMB) when list(DMB) ->
+%% #'DigitMapValue'{digitMapBody = DMB}.
+
+%% cre_DigitMapValue(Start, Short, Long, DMB) ->
+%% cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+%% cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+%% when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+%% (Start == asn1_NOVALUE)) and
+%% ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+%% (Short == asn1_NOVALUE)) and
+%% ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+%% (Long == asn1_NOVALUE)) and
+%% is_list(DMB) and
+%% ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+%% (Dur == asn1_NOVALUE)) ->
+%% #'DigitMapValue'{startTimer = Start,
+%% shortTimer = Short,
+%% longTimer = Long,
+%% digitMapBody = DMB,
+%% durationTimer = Dur}.
+
+%% cre_ServiceChangeParm(M, R) when atom(M), list(R) ->
+%% #'ServiceChangeParm'{serviceChangeMethod = M,
+%% serviceChangeReason = R}.
+
+%% cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+%% cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+%% asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE).
+
+%% %% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+%% cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I)
+%% when is_atom(M) and
+%% ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+%% (Ver == asn1_NOVALUE)) and
+%% (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+%% is_list(R) and
+%% ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+%% (D == asn1_NOVALUE)) and
+%% (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+%% (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) ->
+%% F = fun(A) ->
+%% (A == asn1_NOVALUE) orelse
+%% (is_tuple(A)
+%% andalso is_atom(element(1, A)))
+%% end,
+%% case (F(Addr) andalso F(Mid)) of
+%% true ->
+%% #'ServiceChangeParm'{serviceChangeMethod = M,
+%% serviceChangeAddress = Addr,
+%% serviceChangeVersion = Ver,
+%% serviceChangeProfile = Prof,
+%% serviceChangeReason = R,
+%% serviceChangeDelay = D,
+%% serviceChangeMgcId = Mid,
+%% timeStamp = TS,
+%% serviceChangeInfo = I};
+%% _ ->
+%% exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+%% end.
+
+%% cre_ServiceChangeAddress(portNumber = Tag, P)
+%% when integer(P), 0 =< P, P =< 65535 ->
+%% {Tag, P};
+%% cre_ServiceChangeAddress(ip4Address = Tag, A) when record(A, 'IP4Address') ->
+%% {Tag, A};
+%% cre_ServiceChangeAddress(ip6Address = Tag, A) when record(A, 'IP6Address') ->
+%% {Tag, A};
+%% cre_ServiceChangeAddress(domainName = Tag, N) when record(N, 'DomainName') ->
+%% {Tag, N};
+%% cre_ServiceChangeAddress(deviceName = Tag, N) when list(N) ->
+%% {Tag, N};
+%% cre_ServiceChangeAddress(mtpAddress = Tag, A) when list(A) ->
+%% {Tag, A}.
+
+%% cre_ServiceChangeResParm() ->
+%% #'ServiceChangeResParm'{}.
+%% cre_ServiceChangeResParm(Addr, Prof) ->
+%% cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+%% Prof, asn1_NOVALUE).
+%% cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+%% when ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+%% (Ver == asn1_NOVALUE)) and
+%% (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+%% (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) ->
+%% F = fun(A) ->
+%% (A == asn1_NOVALUE) orelse
+%% (is_tuple(A)
+%% andalso is_atom(element(1, A)))
+%% end,
+%% case (F(Addr) andalso F(Mid)) of
+%% true ->
+%% #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+%% serviceChangeAddress = Addr,
+%% serviceChangeVersion = Ver,
+%% serviceChangeProfile = Prof,
+%% timeStamp = TS};
+%% _ ->
+%% exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+%% end.
+
+%% cre_ServiceChangeMethod(failover = M) ->
+%% M;
+%% cre_ServiceChangeMethod(forced = M) ->
+%% M;
+%% cre_ServiceChangeMethod(graceful = M) ->
+%% M;
+%% cre_ServiceChangeMethod(restart = M) ->
+%% M;
+%% cre_ServiceChangeMethod(disconnected = M) ->
+%% M;
+%% cre_ServiceChangeMethod(handOff = M) ->
+%% M.
+
+%% %% The version field is added to make it look more like ABNF
+%% cre_ServiceChangeProfile(N) ->
+%% cre_ServiceChangeProfile(N, 1).
+
+%% cre_ServiceChangeProfile(N, V)
+%% when is_list(N) and is_integer(V) and (0 =< V) and (V =< 99) ->
+%% #'ServiceChangeProfile'{profileName = N, version = V}.
+
+%% cre_PackagesDescriptor([H|_] = D) when record(H, 'PackagesItem') ->
+%% D.
+
+%% cre_PackagesItem(N, Ver) when list(N), integer(Ver), 0 =< Ver, Ver =< 99 ->
+%% #'PackagesItem'{packageName = N,
+%% packageVersion = Ver}.
+
+%% cre_StatisticsDescriptor([H|_] = D) when record(H, 'StatisticsParameter') ->
+%% D.
+
+%% cre_StatisticsParameter(N) when list(N) ->
+%% #'StatisticsParameter'{statName = N}.
+
+%% cre_StatisticsParameter(N, V) when list(N), list(V) ->
+%% #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% %% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% %% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% %% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% %% {h221NonStandard, H221};
+%% %% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% %% {object, Obj};
+%% %% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% %% {experimental, Exp}.
+
+%% %% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% %% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% %% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% %% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% %% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% %% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% %% t35CountryCode2 = CC2,
+%% %% t35Extension = Ext,
+%% %% manufacturerCode = MC}.
+
+%% cre_TimeNotation(D, T)
+%% when list(D), length(D) == 8, list(T), length(T) == 8 ->
+%% #'TimeNotation'{date = D, time = T}.
+
+%% cre_Value([H|_] = V) when list(H) ->
+%% V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% %% -- MegacoMessage --
+
+%% is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+%% mess = Mess}) ->
+%% is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+%% is_MegacoMessage(_) ->
+%% false.
+
+
+%% chk_MegacoMessage(M, M) ->
+%% chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+%% chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+%% mess = Mess1},
+%% #'MegacoMessage'{authHeader = Auth2,
+%% mess = Mess2}) ->
+%% chk_opt_AuthenticationHeader(Auth1,Auth2),
+%% chk_Message(Mess1,Mess2),
+%% ok;
+%% chk_MegacoMessage(M1, M2) ->
+%% wrong_type('MegacoMessage', M1, M2).
+
+
+%% %% -- AuthenticationHeader --
+
+%% is_opt_AuthenticationHeader(AH) ->
+%% is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+%% is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+%% seqNum = SN,
+%% ad = AD}) ->
+%% is_SecurityParmIndex(SPI) andalso
+%% is_SequenceNum(SN) andalso
+%% is_AuthData(AD);
+%% is_AuthenticationHeader(_) ->
+%% false.
+
+%% %% This stuff is not really used, so make it simple...
+%% chk_opt_AuthenticationHeader(A1, A2) ->
+%% chk_OPTIONAL('AuthenticationHeader', A1, A2,
+%% fun is_AuthenticationHeader/1,
+%% fun chk_AuthenticationHeader/2).
+
+%% chk_AuthenticationHeader(A, A) ->
+%% chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+%% chk_AuthenticationHeader(A1, A2) ->
+%% case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+%% true ->
+%% not_equal('AuthenticationHeader', A1, A2);
+%% false ->
+%% wrong_type('AuthenticationHeader', A1, A2)
+%% end.
+
+
+%% %% -- SecurityParmIndex --
+
+%% is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% %% -- SequenceNum --
+
+%% is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% %% -- AuthData --
+
+%% is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% %% -- Message --
+
+%% is_Message(#'Message'{version = V,
+%% mId = MID,
+%% messageBody = Body}) ->
+%% is_INTEGER(V, {range, 0, 99}) andalso
+%% is_MId(MID) andalso
+%% is_Message_messageBody(Body);
+%% is_Message(_) ->
+%% false.
+
+%% chk_Message(M,M) when record(M,'Message') ->
+%% ok;
+%% chk_Message(#'Message'{version = V1,
+%% mId = MID1,
+%% messageBody = Body1},
+%% #'Message'{version = V2,
+%% mId = MID2,
+%% messageBody = Body2}) ->
+%% validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'Message'),
+%% validate(fun() -> chk_MId(MID1, MID2) end, 'Message'),
+%% chk_Message_messageBody(Body1, Body2),
+%% ok;
+%% chk_Message(M1, M2) ->
+%% wrong_type('Message', M1, M2).
+
+
+%% is_Message_messageBody({Tag, Val}) ->
+%% is_Message_messageBody_tag(Tag) andalso
+%% is_Message_messageBody_val(Tag, Val);
+%% is_Message_messageBody(_) ->
+%% false.
+
+%% is_Message_messageBody_tag(Tag) ->
+%% Tags = [messageError, transactions],
+%% lists:member(Tag, Tags).
+
+%% is_Message_messageBody_val(messageError, Val) ->
+%% is_ErrorDescriptor(Val);
+%% is_Message_messageBody_val(transactions, Val) ->
+%% is_Message_messageBody_transactions(Val).
+
+%% is_Message_messageBody_transactions([]) ->
+%% true;
+%% is_Message_messageBody_transactions([H|T]) ->
+%% is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+%% is_Message_messageBody_transactions(_) ->
+%% false.
+
+%% chk_Message_messageBody(B, B) ->
+%% chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+%% chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+%% case (is_Message_messageBody_tag(Tag) andalso
+%% is_Message_messageBody_val(Tag, Val1) andalso
+%% is_Message_messageBody_val(Tag, Val2)) of
+%% true ->
+%% chk_Message_messageBody_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('Message_messageBody', B1, B2)
+%% end;
+%% chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+%% case ((is_Message_messageBody_tag(Tag1) andalso
+%% is_Message_messageBody_val(Tag1, Val1)) andalso
+%% (is_Message_messageBody_tag(Tag2) andalso
+%% is_Message_messageBody_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('Message_messageBody', B1, B2);
+%% false ->
+%% wrong_type('Message_messageBody', B1, B2)
+%% end;
+%% chk_Message_messageBody(B1, B2) ->
+%% wrong_type('Message_messageBody', B1, B2).
+
+%% chk_Message_messageBody_val(messageError, Val1, Val2) ->
+%% validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+%% 'Message_messageBody');
+%% chk_Message_messageBody_val(transactions, Val1, Val2) ->
+%% chk_Message_messageBody_transactions(Val1, Val2).
+
+%% chk_Message_messageBody_transactions([], []) ->
+%% ok;
+%% chk_Message_messageBody_transactions([] = T1, T2) ->
+%% not_equal('Message_messageBody_transactions', T1, T2);
+%% chk_Message_messageBody_transactions(T1, [] = T2) ->
+%% not_equal('Message_messageBody_transactions', T1, T2);
+%% chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+%% case is_Transaction(H) of
+%% true ->
+%% chk_Message_messageBody_transactions(T1, T2);
+%% false ->
+%% wrong_type('Message_messageBody_transactions_val', H)
+%% end;
+%% chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_Transaction(H1, H2) end,
+%% 'Message_messageBody_transactions_val'),
+%% chk_Message_messageBody_transactions(T1, T2);
+%% chk_Message_messageBody_transactions(T1, T2) ->
+%% wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% %% -- MId --
+
+%% is_opt_MId(M) ->
+%% is_OPTIONAL(fun is_MId/1, M).
+
+%% is_MId({Tag, Val}) ->
+%% is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+%% is_MId(_) ->
+%% false.
+
+%% is_MId_tag(Tag) ->
+%% Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+%% lists:member(Tag, Tags).
+
+%% is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+%% is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+%% is_MId_val(domainName, Val) -> is_DomainName(Val);
+%% is_MId_val(deviceName, Val) -> is_PathName(Val);
+%% is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+%% chk_opt_MId(M1, M2) ->
+%% chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+%% chk_MId(M, M) ->
+%% chk_type(fun is_MId/1, 'MId', M);
+%% chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+%% case (is_MId_tag(Tag) andalso
+%% is_MId_val(Tag, Val1) andalso
+%% is_MId_val(Tag, Val2)) of
+%% true ->
+%% chk_MId_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('MId', M1, M2)
+%% end;
+%% chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+%% case ((is_MId_tag(Tag1) andalso
+%% is_MId_val(Tag1, Val1)) andalso
+%% (is_MId_tag(Tag2) andalso
+%% is_MId_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('MId', M1, M2);
+%% false ->
+%% wrong_type('MId', M1, M2)
+%% end;
+%% chk_MId(M1, M2) ->
+%% wrong_type('MId', M1, M2).
+
+%% chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+%% chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+%% chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+%% chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+%% chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% %% -- DomainName --
+
+%% is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+%% is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+%% is_DomainName(_) ->
+%% false.
+
+%% chk_DomainName(N, N) ->
+%% ok;
+%% chk_DomainName(N1, N2) ->
+%% not_equal('DomainName', N1, N2).
+
+
+%% %% -- IP4Address --
+
+%% is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+%% is_OCTET_STRING(A, {exact, 4}) andalso
+%% is_opt_INTEGER(PN, {range, 0, 65535});
+%% is_IP4Address(_) ->
+%% false.
+
+%% chk_IP4Address(A, A) ->
+%% ok;
+%% chk_IP4Address(A1, A2) ->
+%% not_equal('IP4Address', A1, A2).
+
+
+%% %% -- IP6Address --
+
+%% is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+%% is_OCTET_STRING(A, {exact, 16}) andalso
+%% is_opt_INTEGER(PN, {range, 0, 65535});
+%% is_IP6Address(_) ->
+%% false.
+
+%% chk_IP6Address(A, A) ->
+%% ok;
+%% chk_IP6Address(A1, A2) ->
+%% not_equal('IP6Address', A1, A2).
+
+
+%% %% -- PathName --
+
+%% is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+%% chk_PathName(N, N) ->
+%% ok;
+%% chk_PathName(N1, N2) ->
+%% not_equal('PathName', N1, N2).
+
+
+%% %% -- Transaction --
+
+%% is_Transaction({Tag, Val}) ->
+%% is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+%% is_Transaction(_) ->
+%% false.
+
+%% is_Transaction_tag(Tag) ->
+%% Tags = [transactionRequest,
+%% transactionPending,
+%% transactionReply,
+%% transactionResponseAck],
+%% lists:member(Tag, Tags).
+
+%% is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+%% is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+%% is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+%% is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+%% chk_Transaction({Tag, Val} = Trans, {Tag, Val}) ->
+%% case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('Transaction', Trans, Trans)
+%% end;
+%% chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+%% case (is_Transaction_tag(Tag) and
+%% is_Transaction_val(Tag, Val1) and
+%% is_Transaction_val(Tag, Val2)) of
+%% true ->
+%% chk_Transaction_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('Transaction', Trans1, Trans2)
+%% end;
+%% chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+%% case ((is_Transaction_tag(Tag1) andalso
+%% is_Transaction_val(Tag1, Val1)) andalso
+%% (is_Transaction_tag(Tag2) andalso
+%% is_Transaction_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('Transaction', Trans1, Trans2);
+%% false ->
+%% wrong_type('Transaction', Trans1, Trans2)
+%% end;
+%% chk_Transaction(Trans1, Trans2) ->
+%% wrong_type('Transaction', Trans1, Trans2).
+
+%% chk_Transaction_val(transactionRequest, T1, T2) ->
+%% chk_TransactionRequest(T1, T2);
+%% chk_Transaction_val(transactionPending, T1, T2) ->
+%% chk_TransactionPending(T1, T2);
+%% chk_Transaction_val(transactionReply, T1, T2) ->
+%% chk_TransactionReply(T1,T2);
+%% chk_Transaction_val(transactionResponseAck, T1, T2) ->
+%% chk_TransactionResponseAck(T1, T2).
+
+
+%% %% -- TransactionId --
+
+%% is_opt_TransactionId(TID) ->
+%% is_OPTIONAL(fun is_TransactionId/1, TID).
+
+%% is_TransactionId(TID) -> is_INTEGER(TID, {range, 0, 4294967295}).
+
+%% chk_opt_TransactionId(TID1, TID2) ->
+%% chk_OPTIONAL('TransactionId', TID1, TID2,
+%% fun is_TransactionId/1, fun chk_TransactionId/2).
+
+%% chk_TransactionId(TID, TID) ->
+%% chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+%% chk_TransactionId(TID1, TID2) ->
+%% case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+%% true ->
+%% not_equal('TransactionId', TID1, TID2);
+%% false ->
+%% wrong_type('TransactionId', TID1, TID2)
+%% end.
+
+
+%% %% -- TransactionRequest --
+
+%% is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+%% actions = Acts}) ->
+%% is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+%% is_TransactionRequest(_) ->
+%% false.
+
+%% chk_TransactionRequest(T, T) ->
+%% chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+%% chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+%% actions = Acts1},
+%% #'TransactionRequest'{transactionId = TID2,
+%% actions = Acts2}) ->
+%% validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+%% chk_TransactionRequest_actions(Acts1, Acts2),
+%% ok;
+%% chk_TransactionRequest(T1, T2) ->
+%% wrong_type('TransactionRequest', T1, T2).
+
+%% is_TransactionRequest_actions([]) ->
+%% true;
+%% is_TransactionRequest_actions([H|T]) ->
+%% is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+%% is_TransactionRequest_actions(_) ->
+%% false.
+
+%% chk_TransactionRequest_actions([], []) ->
+%% ok;
+%% chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+%% not_equal('TransactionRequest_actions', Acts1, Acts2);
+%% chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+%% not_equal('TransactionRequest_actions', Acts1, Acts2);
+%% chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+%% case is_ActionRequest(H) of
+%% true ->
+%% chk_TransactionRequest_actions(T1, T2);
+%% false ->
+%% wrong_type('TransactionRequest_actions_val', H)
+%% end;
+%% chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_ActionRequest(H1, H2) end,
+%% 'TransactionRequest_actions_val'),
+%% chk_TransactionRequest_actions(T1, T2);
+%% chk_TransactionRequest_actions(Acts1, Acts2) ->
+%% wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% %% -- TransactionPending --
+
+%% is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+%% is_TransactionId(TID);
+%% is_TransactionPending(_) ->
+%% false.
+
+%% chk_TransactionPending(T, T) ->
+%% chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+%% chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+%% #'TransactionPending'{transactionId = TID2}) ->
+%% validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+%% ok;
+%% chk_TransactionPending(T1, T2) ->
+%% wrong_type('TransactionPending', T1, T2).
+
+
+%% %% -- TransactionReply --
+
+%% is_TransactionReply(#'TransactionReply'{transactionId = TID,
+%% immAckRequired = IAR,
+%% transactionResult = TR}) ->
+%% is_TransactionId(TID) andalso
+%% is_opt_NULL(IAR) andalso
+%% is_TransactionReply_transactionResult(TR);
+%% is_TransactionReply(_) ->
+%% false.
+
+%% chk_TransactionReply(T, T) ->
+%% chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+%% chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+%% immAckRequired = IAR1,
+%% transactionResult = TR1},
+%% #'TransactionReply'{transactionId = TID2,
+%% immAckRequired = IAR2,
+%% transactionResult = TR2}) ->
+%% validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+%% validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+%% chk_TransactionReply_transactionResult(TR1, TR2),
+%% ok;
+%% chk_TransactionReply(T1, T2) ->
+%% wrong_type('TransactionReply', T1, T2).
+
+%% is_TransactionReply_transactionResult({Tag, Val}) ->
+%% is_TransactionReply_transactionResult_tag(Tag) andalso
+%% is_TransactionReply_transactionResult_val(Tag, Val);
+%% is_TransactionReply_transactionResult(_) ->
+%% false.
+
+%% is_TransactionReply_transactionResult_tag(T) ->
+%% lists:member(T, [transactionError, actionReplies]).
+
+%% is_TransactionReply_transactionResult_val(transactionError, V) ->
+%% is_ErrorDescriptor(V);
+%% is_TransactionReply_transactionResult_val(actionReplies, V) ->
+%% is_TransactionReply_actionReplies(V).
+
+%% chk_TransactionReply_transactionResult(Res, Res) ->
+%% chk_type(fun is_TransactionReply_transactionResult/1,
+%% 'TransactionReply_transactionResult', Res);
+%% chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+%% {Tag, Val2} = Res2) ->
+%% case (is_TransactionReply_transactionResult_tag(Tag) and
+%% is_TransactionReply_transactionResult_val(Tag, Val1) and
+%% is_TransactionReply_transactionResult_val(Tag, Val2)) of
+%% true ->
+%% chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('TransactionReply_transactionResult', Res1, Res2)
+%% end;
+%% chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+%% {Tag2, Val2} = Res2) ->
+%% case ((is_TransactionReply_transactionResult_tag(Tag1) and
+%% is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+%% (is_TransactionReply_transactionResult_tag(Tag2) and
+%% is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('TransactionReply_transactionResult', Res1, Res2);
+%% false ->
+%% wrong_type('TransactionReply_transactionResult', Res1, Res2)
+%% end;
+%% chk_TransactionReply_transactionResult(Res1, Res2) ->
+%% wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+%% chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+%% validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+%% 'TransactionReply_transactionResult');
+%% chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+%% validate(fun() -> chk_TransactionReply_actionReplies(R1, R2) end,
+%% 'TransactionReply_transactionResult').
+
+%% is_TransactionReply_actionReplies([]) ->
+%% true;
+%% is_TransactionReply_actionReplies([H|T]) ->
+%% is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+%% is_TransactionReply_actionReplies(_) ->
+%% false.
+
+%% chk_TransactionReply_actionReplies([], []) ->
+%% ok;
+%% chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+%% not_equal('TransactionReply_actionReplies', AR1, AR2);
+%% chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+%% not_equal('TransactionReply_actionReplies', AR1, AR2);
+%% chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+%% case is_ActionReply(H) of
+%% true ->
+%% chk_TransactionReply_actionReplies(T1, T2);
+%% false ->
+%% wrong_type('TransactionReply_actionReplies_val', H)
+%% end;
+%% chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_ActionReply(H1, H2) end,
+%% 'TransactionReply_actionReplies_val'),
+%% chk_TransactionReply_actionReplies(T1, T2);
+%% chk_TransactionReply_actionReplies(AR1, AR2) ->
+%% wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% %% -- TransactionResponseAck --
+
+%% is_TransactionResponseAck([]) ->
+%% true;
+%% is_TransactionResponseAck([H|T]) ->
+%% is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+%% is_TransactionResponseAck(_) ->
+%% false.
+
+%% chk_TransactionResponseAck([], []) ->
+%% ok;
+%% chk_TransactionResponseAck([] = AR1, AR2) ->
+%% not_equal('TransactionResponseAck', AR1, AR2);
+%% chk_TransactionResponseAck(AR1, [] = AR2) ->
+%% not_equal('TransactionResponseAck', AR1, AR2);
+%% chk_TransactionResponseAck([H|T1], [H|T2]) ->
+%% case is_TransactionAck(H) of
+%% true ->
+%% chk_TransactionResponseAck(T1, T2);
+%% false ->
+%% wrong_type('TransactionResponseAck_val', H)
+%% end;
+%% chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_TransactionAck(H1, H2) end,
+%% 'TransactionResponseAck'),
+%% chk_TransactionResponseAck(T1, T2);
+%% chk_TransactionResponseAck(AR1, AR2) ->
+%% wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% %% -- TransactionAck --
+
+%% is_TransactionAck(#'TransactionAck'{firstAck = F,
+%% lastAck = L}) ->
+%% is_TransactionId(F) andalso is_opt_TransactionId(L);
+%% is_TransactionAck(_) ->
+%% false.
+
+%% chk_TransactionAck(T, T) ->
+%% chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+%% chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+%% lastAck = L1},
+%% #'TransactionAck'{firstAck = F2,
+%% lastAck = L2}) ->
+%% validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+%% validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+%% ok;
+%% chk_TransactionAck(T1, T2) ->
+%% wrong_type('TransactionAck', T1, T2).
+
+
+%% %% -- ErrorDescriptor --
+
+%% is_opt_ErrorDescriptor(V) ->
+%% is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+%% is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+%% errorText = Text}) ->
+%% is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+%% is_ErrorDescriptor(_) ->
+%% false.
+
+%% chk_opt_ErrorDescriptor(E1, E2) ->
+%% chk_OPTIONAL('ErrorDescriptor', E1, E2,
+%% fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+%% chk_ErrorDescriptor(E, E) ->
+%% chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+%% chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+%% errorText = Text1},
+%% #'ErrorDescriptor'{errorCode = Code2,
+%% errorText = Text2}) ->
+%% chk_ErrorCode(Code1, Code2),
+%% chk_opt_ErrorText(Text1, Text2),
+%% ok;
+%% chk_ErrorDescriptor(E1, E2) ->
+%% wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% %% -- ErrorCode --
+
+%% is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+%% chk_ErrorCode(C, C) ->
+%% case is_ErrorCode(C) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type(errorCode, C, C)
+%% end;
+%% chk_ErrorCode(C1, C2) ->
+%% case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+%% true ->
+%% not_equal(errorCode, C1, C2);
+%% false ->
+%% wrong_type(errorCode, C1, C2)
+%% end.
+
+
+%% %% -- ErrorText --
+
+%% is_opt_ErrorText(V) ->
+%% is_OPTIONAL(fun is_ErrorText/1, V).
+
+%% is_ErrorText(V) -> is_IA5String(V).
+
+%% chk_opt_ErrorText(T1, T2) ->
+%% chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+%% chk_ErrorText(T, T) ->
+%% chk_type(fun is_ErrorText/1, 'ErrorText', T);
+%% chk_ErrorText(T1, T2) ->
+%% case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+%% true ->
+%% case {to_lower(T1), to_lower(T2)} of
+%% {T, T} ->
+%% ok;
+%% _ ->
+%% not_equal('ErrorText', T1, T2)
+%% end;
+%% false ->
+%% wrong_type('ErrorText', T1, T2)
+%% end.
+
+
+%% %% -- ContextID --
+
+%% is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+%% chk_ContextID(Id, Id) ->
+%% chk_type(fun is_ContextID/1, 'ContextID', Id);
+%% chk_ContextID(Id1, Id2) ->
+%% case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+%% true ->
+%% not_equal('ContextID', Id1, Id2);
+%% false ->
+%% wrong_type('ContextID', Id1, Id2)
+%% end.
+
+
+%% %% -- ActionRequest --
+
+%% is_ActionRequest(#'ActionRequest'{contextId = Id,
+%% contextRequest = CtxReq,
+%% contextAttrAuditReq = AuditReq,
+%% commandRequests = CmdReqs}) ->
+%% is_ContextID(Id) andalso
+%% is_opt_ContextRequest(CtxReq) andalso
+%% is_opt_ContextAttrAuditRequest(AuditReq) andalso
+%% is_ActionRequest_commandRequests(CmdReqs);
+%% is_ActionRequest(_) ->
+%% false.
+
+%% chk_ActionRequest(A, A) ->
+%% chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+%% chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+%% contextRequest = Req1,
+%% contextAttrAuditReq = AuditReq1,
+%% commandRequests = CmdReqs1},
+%% #'ActionRequest'{contextId = Id2,
+%% contextRequest = Req2,
+%% contextAttrAuditReq = AuditReq2,
+%% commandRequests = CmdReqs2}) ->
+%% validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+%% validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+%% validate(fun() ->
+%% chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+%% end,
+%% 'ActionRequest'),
+%% chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+%% ok.
+
+
+%% is_ActionRequest_commandRequests([]) ->
+%% true;
+%% is_ActionRequest_commandRequests([H|T]) ->
+%% is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+%% is_ActionRequest_commandRequests(_) ->
+%% false.
+
+%% chk_ActionRequest_commandRequests([], []) ->
+%% ok;
+%% chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+%% not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+%% chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+%% not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+%% chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+%% case is_CommandRequest(H) of
+%% true ->
+%% chk_ActionRequest_commandRequests(T1, T2);
+%% false ->
+%% wrong_type('ActionRequest_commandRequest_val', H)
+%% end;
+%% chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_CommandRequest(H1, H2) end,
+%% 'ActionRequest_commandRequests_val'),
+%% chk_ActionRequest_commandRequests(T1, T2);
+%% chk_ActionRequest_commandRequests(R1, R2) ->
+%% wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% %% -- ActionReply --
+
+%% is_ActionReply(#'ActionReply'{contextId = Id,
+%% errorDescriptor = ED,
+%% contextReply = CtxRep,
+%% commandReply = CmdRep}) ->
+%% is_ContextID(Id) andalso
+%% is_opt_ErrorDescriptor(ED) andalso
+%% is_opt_ContextRequest(CtxRep) andalso
+%% is_ActionReply_commandReply(CmdRep);
+%% is_ActionReply(_) ->
+%% false.
+
+%% is_ActionReply_commandReply([]) ->
+%% true;
+%% is_ActionReply_commandReply([H|T]) ->
+%% is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+%% is_ActionReply_commandReply(_) ->
+%% false.
+
+%% chk_ActionReply(A, A) ->
+%% chk_type(fun is_ActionReply/1, 'ActionReply', A);
+%% chk_ActionReply(#'ActionReply'{contextId = Id1,
+%% errorDescriptor = ED1,
+%% contextReply = CtxRep1,
+%% commandReply = CmdRep1},
+%% #'ActionReply'{contextId = Id2,
+%% errorDescriptor = ED2,
+%% contextReply = CtxRep2,
+%% commandReply = CmdRep2}) ->
+%% chk_ContextID(Id1, Id2),
+%% chk_opt_ErrorDescriptor(ED1, ED2),
+%% chk_opt_ContextRequest(CtxRep1, CtxRep2),
+%% chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+%% chk_ActionReply_commandReply([], []) ->
+%% ok;
+%% chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+%% not_equal('ActionReply_commandReply', Reps1, Reps2);
+%% chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+%% not_equal('ActionReply_commandReply', Reps1, Reps2);
+%% chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+%% case is_CommandReply(H) of
+%% true ->
+%% chk_ActionReply_commandReply(T1, T2);
+%% false ->
+%% wrong_type('ActionReply_commandReply_val', H)
+%% end;
+%% chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_CommandReply(H1, H2) end,
+%% 'ActionReply_commandReply_val'),
+%% chk_ActionReply_commandReply(T1, T2);
+%% chk_ActionReply_commandReply(R1, R2) ->
+%% wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% %% -- ContextRequest --
+
+%% is_opt_ContextRequest(asn1_NOVALUE) ->
+%% true;
+%% is_opt_ContextRequest(V) ->
+%% is_ContextRequest(V).
+
+%% is_ContextRequest(#'ContextRequest'{priority = Prio,
+%% emergency = Em,
+%% topologyReq = TopReq}) ->
+%% is_ContextRequest_priority(Prio) andalso
+%% is_ContextRequest_emergency(Em) andalso
+%% is_ContextRequest_topologyReq(TopReq);
+%% is_ContextRequest(_) ->
+%% false.
+
+%% is_ContextRequest_priority(asn1_NOVALUE) ->
+%% true;
+%% is_ContextRequest_priority(V) ->
+%% is_INTEGER(V, {range, 1, 15}).
+
+%% is_ContextRequest_emergency(asn1_NOVALUE) ->
+%% true;
+%% is_ContextRequest_emergency(V) ->
+%% is_BOOLEAN(V).
+
+%% is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+%% true;
+%% is_ContextRequest_topologyReq([]) ->
+%% true;
+%% is_ContextRequest_topologyReq([H|T]) ->
+%% is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+%% is_ContextRequest_topologyReq(_) ->
+%% false.
+
+%% chk_opt_ContextRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_ContextRequest(R, R) ->
+%% chk_ContextRequest(R, R).
+
+%% chk_ContextRequest(R, R) ->
+%% chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+%% chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+%% emergency = Em1,
+%% topologyReq = TopReq1},
+%% #'ContextRequest'{priority = Prio2,
+%% emergency = Em2,
+%% topologyReq = TopReq2}) ->
+%% chk_ContextRequest_priority(Prio1, Prio2),
+%% chk_ContextRequest_emergency(Em1, Em2),
+%% chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+%% ok;
+%% chk_ContextRequest(R1, R2) ->
+%% wrong_type('ContextRequest', R1, R2).
+
+
+%% chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+%% ok;
+%% chk_ContextRequest_priority(P, P) ->
+%% chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+%% chk_ContextRequest_priority(P1, P2) ->
+%% case (is_ContextRequest_priority(P1) andalso
+%% is_ContextRequest_priority(P2)) of
+%% true ->
+%% not_equal('ContextRequest_priority', P1, P2);
+%% false ->
+%% wrong_type(contextRequest_priority, P1, P2)
+%% end.
+
+
+%% chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_ContextRequest_emergency(E, E) ->
+%% chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+%% chk_ContextRequest_emergency(E1, E2) ->
+%% case (is_ContextRequest_emergency(E1) andalso
+%% is_ContextRequest_emergency(E2)) of
+%% true ->
+%% not_equal('ContextRequest_emergency', E1, E2);
+%% false ->
+%% wrong_type('ContextRequest_emergency', E1, E2)
+%% end.
+
+%% chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_ContextRequest_topologyReq([], []) ->
+%% ok;
+%% chk_ContextRequest_topologyReq([] = T1, T2) ->
+%% not_equal('ContextRequest_topologyReq', T1, T2);
+%% chk_ContextRequest_topologyReq(T1, [] = T2) ->
+%% not_equal('ContextRequest_topologyReq', T1, T2);
+%% chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+%% case is_TopologyRequest(H) of
+%% true ->
+%% chk_ContextRequest_topologyReq(T1, T2);
+%% false ->
+%% wrong_type('ContextRequest_topologyReq_val', H)
+%% end;
+%% chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_TopologyRequest(H1, H2) end,
+%% 'ContextRequest_topologyReq_val'),
+%% chk_ContextRequest_topologyReq(T1, T2);
+%% chk_ContextRequest_topologyReq(T1, T2) ->
+%% wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+%% %% -- ContextAttrAuditRequest --
+
+%% is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+%% true;
+%% is_opt_ContextAttrAuditRequest(V) ->
+%% is_ContextAttrAuditRequest(V).
+
+%% is_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T,
+%% emergency = E,
+%% priority = P}) ->
+%% is_opt_NULL(T) andalso is_opt_NULL(E) andalso is_opt_NULL(P);
+%% is_ContextAttrAuditRequest(_) ->
+%% false.
+
+%% chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_ContextAttrAuditRequest(R1, R2) ->
+%% chk_ContextAttrAuditRequest(R1, R2).
+
+%% chk_ContextAttrAuditRequest(R, R) ->
+%% chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+%% chk_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T1,
+%% emergency = E1,
+%% priority = P1},
+%% #'ContextAttrAuditRequest'{topology = T2,
+%% emergency = E2,
+%% priority = P2}) ->
+%% validate(fun() -> chk_opt_NULL(T1, T2) end,
+%% 'ContextAttrAuditRequest_topology'),
+%% validate(fun() -> chk_opt_NULL(E1, E2) end,
+%% 'ContextAttrAuditRequest_emergency'),
+%% validate(fun() -> chk_opt_NULL(P1, P2) end,
+%% 'ContextAttrAuditRequest_priority'),
+%% ok.
+
+
+%% %% -- CommandRequest --
+
+%% is_CommandRequest(#'CommandRequest'{command = Cmd,
+%% optional = Opt,
+%% wildcardReturn = WR}) ->
+%% is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+%% is_CommandRequest(_) ->
+%% false.
+
+%% chk_CommandRequest(C, C) ->
+%% chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+%% chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+%% optional = Opt1,
+%% wildcardReturn = WR1},
+%% #'CommandRequest'{command = Cmd2,
+%% optional = Opt2,
+%% wildcardReturn = WR2}) ->
+%% validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+%% validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+%% validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+%% ok;
+%% chk_CommandRequest(R1, R2) ->
+%% wrong_type('CommandRequest', R1, R2).
+
+
+%% %% -- Command --
+
+%% is_Command({Tag, Val}) ->
+%% is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+%% is_Command(_) ->
+%% false.
+
+%% is_Command_tag(Tag) ->
+%% Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+%% auditValueRequest, notifyReq, serviceChangeReq],
+%% lists:member(Tag, Tags).
+
+%% is_Command_val(addReq, V) -> is_AmmRequest(V);
+%% is_Command_val(moveReq, V) -> is_AmmRequest(V);
+%% is_Command_val(modReq, V) -> is_AmmRequest(V);
+%% is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+%% is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+%% is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+%% is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+%% is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+%% chk_Command(Cmd, Cmd) ->
+%% chk_type(fun is_Command/1, 'Command', Cmd);
+%% chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+%% case (is_Command_tag(Tag) andalso
+%% is_Command_val(Tag, Val1) andalso
+%% is_Command_val(Tag, Val2)) of
+%% true ->
+%% chk_Command_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('Command', Cmd1, Cmd2)
+%% end;
+%% chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+%% case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+%% (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('Command', Cmd1, Cmd2);
+%% false ->
+%% wrong_type('Command', Cmd1, Cmd2)
+%% end;
+%% chk_Command(Cmd1, Cmd2) ->
+%% wrong_type('Command', Cmd1, Cmd2).
+
+
+%% chk_Command_val(addReq, R1, R2) ->
+%% validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+%% chk_Command_val(moveReq, R1, R2) ->
+%% validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+%% chk_Command_val(modReq, R1, R2) ->
+%% validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+%% chk_Command_val(subtractReq, R1, R2) ->
+%% validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+%% chk_Command_val(auditCapRequest, R1, R2) ->
+%% validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+%% chk_Command_val(auditValueRequest, R1, R2) ->
+%% validate(fun() -> chk_AuditRequest(R1, R2) end,
+%% 'Command_auditValueRequest');
+%% chk_Command_val(notifyReq, R1, R2) ->
+%% validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+%% chk_Command_val(serviceChangeReq, R1, R2) ->
+%% validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+%% 'Command_serviceChangeReq').
+
+
+%% %% -- CommandReply --
+
+%% is_CommandReply({Tag, Val}) ->
+%% is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+%% is_CommandReply(_) ->
+%% false.
+
+%% is_CommandReply_tag(Tag) ->
+%% Tags = [addReply, moveReply, modReply, subtractReply,
+%% auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+%% lists:member(Tag, Tags).
+
+%% is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+%% is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+%% is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+%% is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+%% is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+%% is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+%% is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+%% is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+%% chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+%% case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('CommandReply', Cmd)
+%% end;
+%% chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+%% case (is_CommandReply_tag(Tag) andalso
+%% is_CommandReply_val(Tag, Val1) andalso
+%% is_CommandReply_val(Tag, Val2)) of
+%% true ->
+%% chk_CommandReply_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('CommandReply', Cmd1, Cmd2)
+%% end;
+%% chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+%% case ((is_CommandReply_tag(Tag1) andalso
+%% is_CommandReply_val(Tag1, Val1)) andalso
+%% (is_CommandReply_tag(Tag2) andalso
+%% is_CommandReply_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('CommandReply', Cmd1, Cmd2);
+%% false ->
+%% wrong_type('CommandReply', Cmd1, Cmd2)
+%% end;
+%% chk_CommandReply(Cmd1, Cmd2) ->
+%% wrong_type('CommandReply', Cmd1, Cmd2).
+
+%% chk_CommandReply_val(addReply, V1, V2) ->
+%% validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+%% chk_CommandReply_val(moveReply, V1, V2) ->
+%% validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+%% chk_CommandReply_val(modReply, V1, V2) ->
+%% validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+%% chk_CommandReply_val(subtractReply, V1, V2) ->
+%% validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+%% chk_CommandReply_val(auditCapReply, V1, V2) ->
+%% validate(fun() -> chk_AuditReply(V1, V2) end,
+%% 'CommandReply_auditCapReply');
+%% chk_CommandReply_val(auditValueReply, V1, V2) ->
+%% validate(fun() -> chk_AuditReply(V1, V2) end,
+%% 'CommandReply_auditValueReply');
+%% chk_CommandReply_val(notifyReply, V1, V2) ->
+%% validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+%% chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+%% validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+%% 'CommandReply_serviceChangeReply').
+
+
+%% %% -- TopologyRequest --
+
+%% is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+%% terminationTo = T,
+%% topologyDirection = D,
+%% streamID = S}) ->
+%% is_TerminationID(F) andalso
+%% is_TerminationID(T) andalso
+%% is_TopologyRequest_topologyDirection(D) andalso
+%% is_opt_StreamID(S);
+%% is_TopologyRequest(_) ->
+%% false.
+
+%% is_TopologyRequest_topologyDirection(D) ->
+%% lists:member(D, [bothway, isolate, oneway]).
+
+
+%% chk_TopologyRequest(T, T) when record(T,'TopologyRequest') ->
+%% ok;
+%% chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+%% terminationTo = T1,
+%% topologyDirection = D1,
+%% streamID = S1},
+%% #'TopologyRequest'{terminationFrom = F2,
+%% terminationTo = T2,
+%% topologyDirection = D2,
+%% streamID = S2}) ->
+%% validate(fun() -> chk_TerminationID(F1, F2) end,
+%% 'TopologyRequest_terminationFrom'),
+%% validate(fun() -> chk_TerminationID(T1, T2) end,
+%% 'TopologyRequest_terminationTo'),
+%% chk_TopologyRequest_topologyDirection(D1,D2),
+%% validate(fun() -> chk_StreamID(S1, S2) end, 'TopologyRequest_streamID'),
+%% ok.
+
+%% chk_TopologyRequest_topologyDirection(D, D) ->
+%% case is_TopologyRequest_topologyDirection(D) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('TopologyRequest_topologyDirection', D)
+%% end;
+%% chk_TopologyRequest_topologyDirection(D1, D2) ->
+%% case (is_TopologyRequest_topologyDirection(D1) andalso
+%% is_TopologyRequest_topologyDirection(D1)) of
+%% true ->
+%% not_equal('TopologyRequest_topologyDirection', D1, D2);
+%% false ->
+%% wrong_type('TopologyRequest_topologyDirection', D1, D2)
+%% end.
+
+
+%% %% -- AmmRequest --
+
+%% is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+%% descriptors = Descs}) ->
+%% d("is_AmmRequest -> entry with"
+%% "~n Tids: ~p", [Tids]),
+%% is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+%% is_AmmRequest(_) ->
+%% false.
+
+%% is_AmmRequest_descriptors(Descs) ->
+%% is_AmmRequest_descriptors(Descs, []).
+
+%% is_AmmRequest_descriptors([], _) ->
+%% true;
+%% is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+%% d("is_AmmRequest_descriptors -> entry with"
+%% "~n Tag: ~p"
+%% "~n FoundDescs: ~p", [Tag, FoundDescs]),
+%% case lists:member(Tag, FoundDescs) of
+%% true ->
+%% atmost_once('AmmRequest_descriptors', Tag);
+%% false ->
+%% case is_AmmDescriptor(Desc) of
+%% true ->
+%% is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+%% false ->
+%% wrong_type('AmmRequest_descriptors', Desc)
+%% end
+%% end;
+%% is_AmmRequest_descriptors(Descs, _) ->
+%% d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+%% "~n Descs: ~p", [Descs]),
+%% wrong_type('AmmRequest_descriptors', Descs).
+
+
+%% chk_AmmRequest(R, R) when record(R, 'AmmRequest') ->
+%% d("chk_AmmRequest -> entry when equal"),
+%% chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+%% chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+%% descriptors = Descs1},
+%% #'AmmRequest'{terminationID = Tids2,
+%% descriptors = Descs2}) ->
+%% d("chk_AmmRequest -> entry with not equal"
+%% "~n Tids1: ~p"
+%% "~n Tids2: ~p", [Tids1, Tids2]),
+%% validate(
+%% fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+%% 'AmmRequest'),
+%% validate(
+%% fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+%% 'AmmRequest'),
+%% ok.
+
+
+%% chk_AmmRequest_descriptors([], []) ->
+%% d("chk_AmmRequest_descriptors -> done when OK"),
+%% ok;
+%% chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+%% d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+%% "~n Descs1: ~p"
+%% "~n Descs1: ~p", [Descs1, Descs2]),
+%% not_equal('AmmRequest_descriptors', Descs1, Descs2);
+%% chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+%% d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+%% "~n Descs1: ~p"
+%% "~n Descs1: ~p", [Descs1, Descs2]),
+%% not_equal('AmmRequest_descriptors', Descs1, Descs2);
+%% chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+%% d("chk_AmmRequest_descriptors -> entry when equal"),
+%% case is_AmmDescriptor(H) of
+%% true ->
+%% chk_AmmRequest_descriptors(T1, T2);
+%% false ->
+%% wrong_type('AmmRequest_descriptors_val', H)
+%% end;
+%% chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+%% d("chk_AmmRequest_descriptors -> entry when not equal"),
+%% validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+%% 'AmmRequest_descriptors_val'),
+%% chk_AmmRequest_descriptors(T1, T2);
+%% chk_AmmRequest_descriptors(Descs1, Descs2) ->
+%% d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+%% "~n Descs1: ~p"
+%% "~n Descs1: ~p", [Descs1, Descs2]),
+%% wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% %% -- AmmDescriptor --
+
+%% is_AmmDescriptor({Tag, Val}) ->
+%% d("is_AmmDescriptor -> entry with"
+%% "~n Tag: ~p"
+%% "~n Val: ~p",[Tag, Val]),
+%% is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+%% is_AmmDescriptor(_) ->
+%% false.
+
+%% is_AmmDescriptor_tag(Tag) ->
+%% Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+%% eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+%% auditDescriptor],
+%% lists:member(Tag, Tags).
+
+%% is_AmmDescriptor_val(mediaDescriptor, D) ->
+%% is_MediaDescriptor(D);
+%% is_AmmDescriptor_val(modemDescriptor, D) ->
+%% is_ModemDescriptor(D);
+%% is_AmmDescriptor_val(muxDescriptor, D) ->
+%% is_MuxDescriptor(D);
+%% is_AmmDescriptor_val(eventsDescriptor, D) ->
+%% is_EventsDescriptor(D);
+%% is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+%% is_EventBufferDescriptor(D);
+%% is_AmmDescriptor_val(signalsDescriptor, D) ->
+%% is_SignalsDescriptor(D);
+%% is_AmmDescriptor_val(digitMapDescriptor, D) ->
+%% is_DigitMapDescriptor(D);
+%% is_AmmDescriptor_val(auditDescriptor, D) ->
+%% is_AuditDescriptor(D).
+
+%% chk_AmmDescriptor(D, D) ->
+%% chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+%% chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+%% case (is_AmmDescriptor_tag(Tag) andalso
+%% is_AmmDescriptor_val(Tag, Val1) andalso
+%% is_AmmDescriptor_val(Tag, Val2)) of
+%% true ->
+%% chk_AmmDescriptor_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('AmmDescriptor', Cmd1, Cmd2)
+%% end;
+%% chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+%% case ((is_AmmDescriptor_tag(Tag1) andalso
+%% is_AmmDescriptor_val(Tag1, Val1)) andalso
+%% (is_AmmDescriptor_tag(Tag2) andalso
+%% is_AmmDescriptor_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('AmmDescriptor', Cmd1, Cmd2);
+%% false ->
+%% wrong_type('AmmDescriptor', Cmd1, Cmd2)
+%% end;
+%% chk_AmmDescriptor(Cmd1, Cmd2) ->
+%% wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+%% chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+%% validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+%% validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+%% validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+%% validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+%% validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+%% validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+%% validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+%% chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+%% validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% %% -- AmmsReply --
+
+%% is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+%% terminationAudit = TA}) ->
+%% is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+%% is_AmmsReply(_) ->
+%% false.
+
+%% chk_AmmsReply(R, R) ->
+%% is_AmmsReply(R);
+%% chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+%% terminationAudit = TA1},
+%% #'AmmsReply'{terminationID = TID2,
+%% terminationAudit = TA2}) ->
+%% validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+%% validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+%% ok;
+%% chk_AmmsReply(R1, R2) ->
+%% wrong_type('AmmsReply', R1, R2).
+
+
+%% %% -- SubtractRequest --
+
+%% is_SubtractRequest(#'SubtractRequest'{terminationID = Tids,
+%% auditDescriptor = AD}) ->
+%% is_TerminationIDList(Tids) andalso is_opt_AuditDescriptor(AD);
+%% is_SubtractRequest(_) ->
+%% false.
+
+%% chk_SubtractRequest(R, R) ->
+%% chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+%% chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+%% auditDescriptor = AD1},
+%% #'SubtractRequest'{terminationID = Tids2,
+%% auditDescriptor = AD2}) ->
+%% validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+%% 'SubtractRequest'),
+%% validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+%% 'SubtractRequest'),
+%% ok;
+%% chk_SubtractRequest(SR1, SR2) ->
+%% wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% %% -- AuditRequest --
+
+%% is_AuditRequest(#'AuditRequest'{terminationID = Tid,
+%% auditDescriptor = AD}) ->
+%% is_TerminationID(Tid) andalso is_AuditDescriptor(AD);
+%% is_AuditRequest(_) ->
+%% false.
+
+%% chk_AuditRequest(R, R) ->
+%% chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+%% chk_AuditRequest(#'AuditRequest'{terminationID = Tids1,
+%% auditDescriptor = AD1},
+%% #'AuditRequest'{terminationID = Tids2,
+%% auditDescriptor = AD2}) ->
+%% validate(fun() -> chk_TerminationID(Tids1, Tids2) end,
+%% 'AuditRequest'),
+%% validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+%% 'AuditRequest'),
+%% ok;
+%% chk_AuditRequest(AR1, AR2) ->
+%% wrong_type('AuditRequest', AR1, AR2).
+
+
+%% %% -- AuditReply --
+
+%% is_AuditReply({Tag, Val}) ->
+%% is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+%% is_AuditReply(_) ->
+%% false.
+
+%% is_AuditReply_tag(Tag) ->
+%% Tags = [contextAuditResult, error, auditResult],
+%% lists:member(Tag, Tags).
+
+%% is_AuditReply_val(contextAuditResult, Val) ->
+%% is_TerminationIDList(Val);
+%% is_AuditReply_val(error, Val) ->
+%% is_ErrorDescriptor(Val);
+%% is_AuditReply_val(auditResult, Val) ->
+%% is_AuditResult(Val).
+
+%% chk_AuditReply(R, R) ->
+%% chk_type(fun is_AuditReply/1, 'AuditReply', R);
+%% chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+%% case (is_AuditReply_tag(Tag) andalso
+%% is_AuditReply_val(Tag, Val1)andalso
+%% is_AuditReply_val(Tag, Val2)) of
+%% true ->
+%% chk_AuditReply_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('AuditReply', R1, R2)
+%% end;
+%% chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+%% case ((is_AuditReply_tag(Tag1) andalso
+%% is_AuditReply_val(Tag1, Val1)) andalso
+%% (is_AuditReply_tag(Tag2) andalso
+%% is_AuditReply_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('AuditReply', R1, R2);
+%% false ->
+%% wrong_type('AuditReply', R1, R2)
+%% end;
+%% chk_AuditReply(AR1, AR2) ->
+%% wrong_type('AuditReply', AR1, AR2).
+
+%% chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+%% chk_TerminationIDList(Val1, Val2);
+%% chk_AuditReply_val(error, Val1, Val2) ->
+%% chk_ErrorDescriptor(Val1, Val2);
+%% chk_AuditReply_val(auditResult, Val1, Val2) ->
+%% chk_AuditResult(Val1, Val2).
+
+
+%% %% -- AuditResult --
+
+%% is_AuditResult(#'AuditResult'{terminationID = TID,
+%% terminationAuditResult = TAR}) ->
+%% is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+%% is_AuditResult(_) ->
+%% false.
+
+%% chk_AuditResult(R, R) ->
+%% chk_type(fun is_AuditResult/1, 'AuditResult', R);
+%% chk_AuditResult(#'AuditResult'{terminationID = TID1,
+%% terminationAuditResult = TAR1},
+%% #'AuditResult'{terminationID = TID2,
+%% terminationAuditResult = TAR2}) ->
+%% validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+%% validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+%% ok;
+%% chk_AuditResult(AR1, AR2) ->
+%% wrong_type('AuditResult', AR1, AR2).
+
+
+%% %% -- TerminationAudit --
+
+%% is_opt_TerminationAudit(TA) ->
+%% is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+%% is_TerminationAudit([]) ->
+%% true;
+%% is_TerminationAudit([H|T]) ->
+%% is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+%% is_TerminationAudit(_) ->
+%% false.
+
+%% chk_opt_TerminationAudit(TA1, TA2) ->
+%% chk_OPTIONAL('TerminationAudit', TA1, TA2,
+%% fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+%% chk_TerminationAudit([], []) ->
+%% ok;
+%% chk_TerminationAudit([] = TA1, TA2) ->
+%% not_equal('TerminationAudit', TA1, TA2);
+%% chk_TerminationAudit(TA1, [] = TA2) ->
+%% not_equal('TerminationAudit', TA1, TA2);
+%% chk_TerminationAudit([H|T1], [H|T2]) ->
+%% case is_AuditReturnParameter(H) of
+%% true ->
+%% chk_TerminationAudit(T1, T2);
+%% false ->
+%% wrong_type('TerminationAudit', H)
+%% end;
+%% chk_TerminationAudit([H1|_], [H2|_]) ->
+%% chk_AuditReturnParameter(H1, H2),
+%% not_equal('TerminationAudit_val', H1, H2);
+%% chk_TerminationAudit(TA1, TA2) ->
+%% not_equal('TerminationAudit', TA1, TA2).
+
+
+%% %% -- AuditReturnParameter --
+
+%% is_AuditReturnParameter({Tag, Val}) ->
+%% is_AuditReturnParameter_tag(Tag) andalso
+%% is_AuditReturnParameter_val(Tag, Val);
+%% is_AuditReturnParameter(_) ->
+%% false.
+
+%% is_AuditReturnParameter_tag(Tag) ->
+%% Tags = [errorDescriptor,
+%% mediaDescriptor,
+%% modemDescriptor,
+%% muxDescriptor,
+%% eventsDescriptor,
+%% eventBufferDescriptor,
+%% signalsDescriptor,
+%% digitMapDescriptor,
+%% observedEventsDescriptor,
+%% statisticsDescriptor,
+%% packagesDescriptor,
+%% emptyDescriptors],
+%% lists:member(Tag, Tags).
+
+%% is_AuditReturnParameter_val(errorDescriptor, V) ->
+%% is_ErrorDescriptor(V);
+%% is_AuditReturnParameter_val(mediaDescriptor, V) ->
+%% is_MediaDescriptor(V);
+%% is_AuditReturnParameter_val(modemDescriptor, V) ->
+%% is_ModemDescriptor(V);
+%% is_AuditReturnParameter_val(muxDescriptor, V) ->
+%% is_MuxDescriptor(V);
+%% is_AuditReturnParameter_val(eventsDescriptor, V) ->
+%% is_EventsDescriptor(V);
+%% is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+%% is_EventBufferDescriptor(V);
+%% is_AuditReturnParameter_val(signalsDescriptor, V) ->
+%% is_SignalsDescriptor(V);
+%% is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+%% is_DigitMapDescriptor(V);
+%% is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+%% is_ObservedEventsDescriptor(V);
+%% is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+%% is_StatisticsDescriptor(V);
+%% is_AuditReturnParameter_val(packagesDescriptor, V) ->
+%% is_PackagesDescriptor(V);
+%% is_AuditReturnParameter_val(emptyDescriptors, V) ->
+%% is_AuditDescriptor(V).
+
+%% chk_AuditReturnParameter(ARP, ARP) ->
+%% chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+%% chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+%% case (is_AuditReturnParameter_tag(Tag) andalso
+%% is_AuditReturnParameter_val(Tag, Val1) andalso
+%% is_AuditReturnParameter_val(Tag, Val2)) of
+%% true ->
+%% chk_AuditReturnParameter_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('AuditReturnParameter', ARP1, ARP2)
+%% end;
+%% chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+%% case ((is_AuditReturnParameter_tag(Tag1) andalso
+%% is_AuditReturnParameter_val(Tag1, Val1)) andalso
+%% (is_AuditReturnParameter_tag(Tag2) andalso
+%% is_AuditReturnParameter_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('AuditReturnParameter', ARP1, ARP2);
+%% false ->
+%% wrong_type('AuditReturnParameter', ARP1, ARP2)
+%% end;
+%% chk_AuditReturnParameter(ARP1, ARP2) ->
+%% wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+%% chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+%% validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+%% validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+%% validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+%% validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+%% validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+%% validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+%% validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+%% validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+%% validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+%% validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+%% validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+%% 'AuditReturnParameter');
+%% chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+%% validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+%% 'AuditReturnParameter').
+
+
+%% %% -- AuditDescriptor --
+
+%% is_opt_AuditDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_AuditDescriptor(V) ->
+%% is_AuditDescriptor(V).
+
+%% is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+%% auditPropertyToken = APT}) ->
+%% is_AuditDescriptor_auditToken(AT) andalso
+%% is_AuditDescriptor_auditPropertyToken(APT);
+%% is_AuditDescriptor(_) ->
+%% false.
+
+%% is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+%% true;
+%% is_AuditDescriptor_auditToken([]) ->
+%% true;
+%% is_AuditDescriptor_auditToken([H|T]) ->
+%% is_AuditDescriptor_auditToken_val(H) andalso
+%% is_AuditDescriptor_auditToken(T);
+%% is_AuditDescriptor_auditToken(_) ->
+%% false.
+
+%% is_AuditDescriptor_auditToken_val(V) ->
+%% Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+%% digitMapToken, statsToken, observedEventsToken,
+%% packagesToken, eventBufferToken],
+%% lists:member(V, Toks).
+
+%% is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+%% true;
+%% is_AuditDescriptor_auditPropertyToken([]) ->
+%% true;
+%% is_AuditDescriptor_auditPropertyToken([H|T]) ->
+%% is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+%% is_AuditDescriptor_auditPropertyToken(_) ->
+%% false.
+
+%% chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_AuditDescriptor(AD1, AD2) ->
+%% chk_AuditDescriptor(AD1, AD2).
+
+%% chk_AuditDescriptor(AD, AD) ->
+%% chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+%% chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+%% auditPropertyToken = APT1},
+%% #'AuditDescriptor'{auditToken = AT2,
+%% auditPropertyToken = APT2}) ->
+%% chk_AuditDescriptor_auditToken(AT1, AT2),
+%% chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+%% ok;
+%% chk_AuditDescriptor(AD1, AD2) ->
+%% wrong_type('AuditDescriptor', AD1, AD2).
+
+%% chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_AuditDescriptor_auditToken([], []) ->
+%% ok;
+%% chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+%% not_equal('AuditDescriptor_auditToken', AT1, AT2);
+%% chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+%% not_equal('AuditDescriptor_auditToken', AT1, AT2);
+%% chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+%% case is_AuditDescriptor_auditToken_val(H) of
+%% true ->
+%% chk_AuditDescriptor_auditToken(T1, T2);
+%% false ->
+%% wrong_type('AuditDescriptor_auditToken_val', H)
+%% end;
+%% chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+%% case (is_AuditDescriptor_auditToken_val(H1) andalso
+%% is_AuditDescriptor_auditToken_val(H2)) of
+%% true ->
+%% not_equal('AuditDescriptor_auditToken_val', H1, H2);
+%% false ->
+%% wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+%% end;
+%% chk_AuditDescriptor_auditToken(AT1, AT2) ->
+%% wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+%% chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_AuditDescriptor_auditPropertyToken([], []) ->
+%% ok;
+%% chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+%% not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+%% chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+%% not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+%% chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+%% case is_IndAuditParameter(H) of
+%% true ->
+%% chk_AuditDescriptor_auditPropertyToken(T1, T2);
+%% false ->
+%% wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+%% end;
+%% chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+%% chk_IndAuditParameter(H1, H2),
+%% not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+%% chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+%% wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% %% -- IndAuditParameter --
+
+%% is_IndAuditParameter({Tag, Val}) ->
+%% is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+%% is_IndAuditParameter(_) ->
+%% false.
+
+%% is_IndAuditParameter_tag(Tag) ->
+%% Tags = [indAudMediaDescriptor,
+%% indAudEventsDescriptor,
+%% indAudEventBufferDescriptor,
+%% indAudSignalsDescriptor,
+%% indAudDigitMapDescriptor,
+%% indAudStatisticsDescriptor,
+%% indAudPackagesDescriptor],
+%% lists:member(Tag, Tags).
+
+%% is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+%% is_IndAudMediaDescriptor(Val);
+%% is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+%% is_IndAudEventsDescriptor(Val);
+%% is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+%% is_IndAudEventBufferDescriptor(Val);
+%% is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+%% is_IndAudSignalsDescriptor(Val);
+%% is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+%% is_IndAudDigitMapDescriptor(Val);
+%% is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+%% is_IndAudStatisticsDescriptor(Val);
+%% is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+%% is_IndAudPackagesDescriptor(Val).
+
+%% chk_IndAuditParameter(IAP, IAP) ->
+%% chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+%% chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+%% case (is_IndAuditParameter_tag(Tag) andalso
+%% is_IndAuditParameter_val(Tag, Val1) andalso
+%% is_IndAuditParameter_val(Tag, Val2)) of
+%% true ->
+%% chk_IndAuditParameter_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('IndAuditParameter', IAP1, IAP2)
+%% end;
+%% chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+%% case ((is_IndAuditParameter_tag(Tag1) andalso
+%% is_IndAuditParameter_val(Tag1, Val1)) andalso
+%% (is_IndAuditParameter_tag(Tag2) andalso
+%% is_IndAuditParameter_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('IndAuditParameter', IAP1, IAP2);
+%% false ->
+%% wrong_type('IndAuditParameter', IAP1, IAP2)
+%% end;
+%% chk_IndAuditParameter(IAP1, IAP2) ->
+%% wrong_type('IndAuditParameter', IAP1, IAP2).
+
+%% chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter');
+%% chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+%% 'IndAuditParameter').
+
+
+%% %% -- IndAudMediaDescriptor --
+
+%% is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+%% streams = S}) ->
+%% is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+%% is_IndAudMediaDescriptor_streams(S);
+%% is_IndAudMediaDescriptor(_) ->
+%% false.
+
+%% is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+%% true;
+%% is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+%% is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+%% is_IndAudMediaDescriptor_streams_val(Tag, Val);
+%% is_IndAudMediaDescriptor_streams(_) ->
+%% false.
+
+%% is_IndAudMediaDescriptor_streams_tag(Tag) ->
+%% Tags = [oneStream, multiStream],
+%% lists:member(Tag, Tags).
+
+%% is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+%% is_IndAudStreamParms(Val);
+%% is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+%% is_IndAudMediaDescriptor_multiStream(Val).
+
+%% is_IndAudMediaDescriptor_multiStream([]) ->
+%% true;
+%% is_IndAudMediaDescriptor_multiStream([H|T]) ->
+%% is_IndAudStreamDescriptor(H) andalso
+%% is_IndAudMediaDescriptor_multiStream(T);
+%% is_IndAudMediaDescriptor_multiStream(_) ->
+%% false.
+
+%% chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+%% chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+%% chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+%% streams = S1},
+%% #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+%% streams = S2}) ->
+%% validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+%% 'IndAudMediaDescriptor'),
+%% validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+%% 'IndAudMediaDescriptor'),
+%% ok;
+%% chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+%% wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+%% chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+%% {Tag, Val2} = S2) ->
+%% case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+%% is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+%% is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+%% true ->
+%% chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+%% end;
+%% chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+%% {Tag2, Val2} = S2) ->
+%% case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+%% is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+%% (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+%% is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('IndAudMediaDescriptor_streams', S1, S2);
+%% false ->
+%% wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+%% end;
+%% chk_IndAudMediaDescriptor_streams(S1, S2) ->
+%% wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+%% chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+%% 'IndAudMediaDescriptor_streams');
+%% chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+%% validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+%% 'IndAudMediaDescriptor_streams').
+
+%% chk_IndAudMediaDescriptor_multiStream([], []) ->
+%% ok;
+%% chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+%% not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+%% chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+%% not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+%% chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+%% case is_IndAudStreamDescriptor(H) of
+%% true ->
+%% chk_IndAudMediaDescriptor_multiStream(T1, T2);
+%% false ->
+%% wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+%% end;
+%% chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+%% 'IndAudMediaDescriptor_multiStream_val'),
+%% chk_IndAudMediaDescriptor_multiStream(T1, T2);
+%% chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+%% wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% %% -- IndAudStreamDescriptor --
+
+%% is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+%% streamParms = Parms}) ->
+%% is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+%% is_IndAudStreamDescriptor(_) ->
+%% false.
+
+%% chk_IndAudStreamDescriptor(D, D) ->
+%% chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+%% chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+%% streamParms = Parms1},
+%% #'IndAudStreamDescriptor'{streamID = SID2,
+%% streamParms = Parms2}) ->
+%% validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+%% validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+%% 'IndAudStreamDescriptor'),
+%% ok;
+%% chk_IndAudStreamDescriptor(D1, D2) ->
+%% wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% %% -- IndAudStreamParms --
+
+%% is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+%% localDescriptor = LD,
+%% remoteDescriptor = RD}) ->
+%% is_opt_IndAudLocalControlDescriptor(LCD) andalso
+%% is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+%% is_opt_IndAudLocalRemoteDescriptor(RD);
+%% is_IndAudStreamParms(_) ->
+%% false.
+
+%% chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+%% localDescriptor = LD1,
+%% remoteDescriptor = RD1},
+%% #'IndAudStreamParms'{localControlDescriptor = LCD2,
+%% localDescriptor = LD2,
+%% remoteDescriptor = RD2}) ->
+%% validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+%% 'IndAudStreamParms'),
+%% validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+%% 'IndAudStreamParms'),
+%% validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+%% 'IndAudStreamParms'),
+%% ok;
+%% chk_IndAudStreamParms(D1, D2) ->
+%% wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% %% -- IndAudLocalControlDescriptor --
+
+%% is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_IndAudLocalControlDescriptor(D) ->
+%% is_IndAudLocalControlDescriptor(D).
+
+%% is_IndAudLocalControlDescriptor(
+%% #'IndAudLocalControlDescriptor'{streamMode = SM,
+%% reserveValue = RV,
+%% reserveGroup = RG,
+%% propertyParms = PPs}) ->
+%% is_opt_NULL(SM) andalso is_opt_NULL(RV) andalso is_opt_NULL(RG) andalso
+%% is_IndAudLocalControlDescriptor_propertyParms(PPs);
+%% is_IndAudLocalControlDescriptor(_) ->
+%% false.
+
+%% is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+%% true;
+%% is_IndAudLocalControlDescriptor_propertyParms([]) ->
+%% true;
+%% is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+%% is_IndAudPropertyParm(H) andalso
+%% is_IndAudLocalControlDescriptor_propertyParms(T);
+%% is_IndAudLocalControlDescriptor_propertyParms(_) ->
+%% false.
+
+%% chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_IndAudLocalControlDescriptor(
+%% #'IndAudLocalControlDescriptor'{streamMode = SM1,
+%% reserveValue = RV1,
+%% reserveGroup = RG1,
+%% propertyParms = PPs1},
+%% #'IndAudLocalControlDescriptor'{streamMode = SM2,
+%% reserveValue = RV2,
+%% reserveGroup = RG2,
+%% propertyParms = PPs2}) ->
+%% chk_opt_NULL(SM1, SM2),
+%% chk_opt_NULL(RV1, RV2),
+%% chk_opt_NULL(RG1, RG2),
+%% chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+%% ok;
+%% chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+%% wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+%% chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+%% ok;
+%% chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+%% not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+%% chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+%% not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+%% chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+%% case is_IndAudPropertyParm(H) of
+%% true ->
+%% chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+%% false ->
+%% wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+%% end;
+%% chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+%% 'IndAudLocalControlDescriptor_propertyParms_val'),
+%% chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+%% chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+%% wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+
+%% %% -- IndAudPropertyParm --
+
+%% is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name}) ->
+%% is_PkgdName(Name);
+%% is_IndAudPropertyParm(_) ->
+%% false.
+
+%% chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1},
+%% #'IndAudPropertyParm'{name = Name2}) ->
+%% chk_PkgdName(Name1, Name2),
+%% ok;
+%% chk_IndAudPropertyParm(P1, P2) ->
+%% wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% %% -- IndAudLocalRemoteDescriptor --
+
+%% is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_IndAudLocalRemoteDescriptor(D) ->
+%% is_IndAudLocalRemoteDescriptor(D).
+
+%% is_IndAudLocalRemoteDescriptor(
+%% #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+%% propGrps = Grps}) ->
+%% is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+%% is_IndAudPropertyGroup(Grps);
+%% is_IndAudLocalRemoteDescriptor(_) ->
+%% false.
+
+%% is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+%% true;
+%% is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+%% is_INTEGER(V, {range, 0, 65535}).
+
+%% chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+%% chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+%% chk_IndAudLocalRemoteDescriptor(D, D) ->
+%% chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+%% 'IndAudLocalRemoteDescriptor', D);
+%% chk_IndAudLocalRemoteDescriptor(
+%% #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+%% propGrps = Grps1},
+%% #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+%% propGrps = Grps2}) ->
+%% chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+%% chk_IndAudPropertyGroup(Grps1, Grps2),
+%% ok;
+%% chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+%% wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+%% chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+%% chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+%% 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+%% chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+%% case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+%% is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+%% true ->
+%% not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+%% false ->
+%% wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+%% end.
+
+
+%% %% -- IndAudPropertyGroup --
+
+%% is_IndAudPropertyGroup([]) ->
+%% true;
+%% is_IndAudPropertyGroup([H|T]) ->
+%% is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+%% is_IndAudPropertyGroup(_) ->
+%% false.
+
+%% chk_IndAudPropertyGroup([], []) ->
+%% ok;
+%% chk_IndAudPropertyGroup([] = PG1, PG2) ->
+%% not_equal('IndAudPropertyGroup', PG1, PG2);
+%% chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+%% not_equal('IndAudPropertyGroup', PG1, PG2);
+%% chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+%% case is_IndAudPropertyParm(H) of
+%% true ->
+%% chk_IndAudPropertyGroup(T1, T2);
+%% false ->
+%% wrong_type('IndAudPropertyGroup_val', H)
+%% end;
+%% chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+%% 'IndAudPropertyGroup_val'),
+%% chk_IndAudPropertyGroup(T1, T2);
+%% chk_IndAudPropertyGroup(P1, P2) ->
+%% wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% %% -- IndAudTerminationStateDescriptor --
+
+%% is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_IndAudTerminationStateDescriptor(D) ->
+%% is_IndAudTerminationStateDescriptor(D).
+
+%% is_IndAudTerminationStateDescriptor(
+%% #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+%% eventBufferControl = EBC,
+%% serviceState = SS}) ->
+%% is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+%% is_opt_NULL(EBC) andalso is_opt_NULL(SS);
+%% is_IndAudTerminationStateDescriptor(_) ->
+%% false.
+
+%% is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+%% true;
+%% is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+%% is_IndAudPropertyParm(H) andalso
+%% is_IndAudTerminationStateDescriptor_propertyParms(T);
+%% is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+%% false.
+
+%% chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+%% chk_IndAudTerminationStateDescriptor(D1, D2).
+
+%% chk_IndAudTerminationStateDescriptor(
+%% #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+%% eventBufferControl = EBC1,
+%% serviceState = SS1},
+%% #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+%% eventBufferControl = EBC2,
+%% serviceState = SS2}) ->
+%% chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+%% validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+%% 'IndAudTerminationStateDescriptor'),
+%% validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+%% 'IndAudTerminationStateDescriptor'),
+%% ok;
+%% chk_IndAudTerminationStateDescriptor(D1, D2) ->
+%% wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+%% chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+%% ok;
+%% chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+%% not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+%% chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+%% not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+%% chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+%% case is_IndAudPropertyParm(H) of
+%% true ->
+%% chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+%% false ->
+%% wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+%% end;
+%% chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+%% 'IndAudTerminationStateDescriptor_propertyParms'),
+%% chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+%% chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+%% wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+
+%% %% -- IndAudEventsDescriptor --
+
+%% is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+%% pkgdName = Name,
+%% streamID = SID}) ->
+%% is_opt_RequestID(RID) andalso
+%% is_PkgdName(Name) andalso
+%% is_opt_StreamID(SID);
+%% is_IndAudEventsDescriptor(_) ->
+%% false.
+
+%% chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+%% pkgdName = Name1,
+%% streamID = SID1},
+%% #'IndAudEventsDescriptor'{requestID = RID2,
+%% pkgdName = Name2,
+%% streamID = SID2}) ->
+%% chk_opt_RequestID(RID1, RID2),
+%% chk_PkgdName(Name1, Name2),
+%% chk_opt_StreamID(SID1, SID2),
+%% ok;
+%% chk_IndAudEventsDescriptor(D1, D2) ->
+%% wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% %% -- IndAudEventBufferDescriptor --
+
+%% is_IndAudEventBufferDescriptor(
+%% #'IndAudEventBufferDescriptor'{eventName = Name,
+%% streamID = SID}) ->
+%% is_PkgdName(Name) andalso is_opt_StreamID(SID);
+%% is_IndAudEventBufferDescriptor(_) ->
+%% false.
+
+%% chk_IndAudEventBufferDescriptor(
+%% #'IndAudEventBufferDescriptor'{eventName = Name1,
+%% streamID = SID1},
+%% #'IndAudEventBufferDescriptor'{eventName = Name2,
+%% streamID = SID2}) ->
+%% chk_PkgdName(Name1, Name2),
+%% chk_opt_StreamID(SID1, SID2),
+%% ok;
+%% chk_IndAudEventBufferDescriptor(D1, D2) ->
+%% wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% %% -- IndAudSignalsDescriptor --
+
+%% is_IndAudSignalsDescriptor({Tag, Val}) ->
+%% is_IndAudSignalsDescriptor_tag(Tag) andalso
+%% is_IndAudSignalsDescriptor_val(Tag, Val);
+%% is_IndAudSignalsDescriptor(_) ->
+%% false.
+
+%% is_IndAudSignalsDescriptor_tag(Tag) ->
+%% Tags = [signal, seqSigList],
+%% lists:member(Tag, Tags).
+
+%% is_IndAudSignalsDescriptor_val(signal, Val) ->
+%% is_IndAudSignal(Val);
+%% is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+%% is_IndAudSeqSigList(Val).
+
+%% chk_IndAudSignalsDescriptor(D, D) ->
+%% chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+%% chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+%% case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+%% is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+%% is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+%% true ->
+%% chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('IndAudSignalsDescriptor', D1, D2)
+%% end;
+%% chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+%% case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+%% is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+%% (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+%% is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('IndAudSignalsDescriptor', D1, D2);
+%% false ->
+%% wrong_type('IndAudSignalsDescriptor', D1, D2)
+%% end;
+%% chk_IndAudSignalsDescriptor(D1, D2) ->
+%% wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+%% chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+%% chk_IndAudSignal(Val1, Val2);
+%% chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+%% chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% %% -- IndAudSeqSigList --
+
+%% is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+%% signalList = SL}) ->
+%% is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+%% is_IndAudSeqSigList(_) ->
+%% false.
+
+%% is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+%% chk_IndAudSeqSigList(L, L) ->
+%% chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+%% chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+%% signalList = SL1},
+%% #'IndAudSeqSigList'{id = ID2,
+%% signalList = SL2}) ->
+%% chk_IndAudSeqSigList_id(ID1, ID2),
+%% chk_opt_IndAudSignal(SL1, SL2),
+%% ok;
+%% chk_IndAudSeqSigList(L1, L2) ->
+%% wrong_type('IndAudSeqSigList', L1, L2).
+
+%% chk_IndAudSeqSigList_id(ID, ID) ->
+%% chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+%% chk_IndAudSeqSigList_id(ID1, ID2) ->
+%% case (is_IndAudSeqSigList_id(ID1) andalso
+%% is_IndAudSeqSigList_id(ID2)) of
+%% true ->
+%% not_equal('IndAudSeqSigList_id', ID1, ID2);
+%% false ->
+%% wrong_type('IndAudSeqSigList_id', ID1, ID2)
+%% end.
+
+
+%% %% -- IndAudSignal --
+
+%% is_opt_IndAudSignal(asn1_NOVALUE) ->
+%% true;
+%% is_opt_IndAudSignal(V) ->
+%% is_IndAudSignal(V).
+
+%% is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+%% streamID = SID}) ->
+%% is_PkgdName(Name) andalso is_opt_StreamID(SID);
+%% is_IndAudSignal(_) ->
+%% false.
+
+%% chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_IndAudSignal(S1, S2) ->
+%% chk_IndAudSignal(S1, S2).
+
+%% chk_IndAudSignal(S, S) ->
+%% chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+%% chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+%% streamID = SID1},
+%% #'IndAudSignal'{signalName = Name2,
+%% streamID = SID2}) ->
+%% chk_PkgdName(Name1, Name2),
+%% chk_opt_StreamID(SID1, SID2),
+%% ok;
+%% chk_IndAudSignal(S1, S2) ->
+%% wrong_type('IndAudSignal', S1, S2).
+
+
+%% %% -- IndAudDigitMapDescriptor --
+
+%% is_IndAudDigitMapDescriptor(
+%% #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+%% is_opt_DigitMapName(Name);
+%% is_IndAudDigitMapDescriptor(_) ->
+%% false.
+
+%% chk_IndAudDigitMapDescriptor(D, D) ->
+%% chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+%% chk_IndAudDigitMapDescriptor(
+%% #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+%% #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+%% validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+%% 'IndAudDigitMapDescriptor'),
+%% ok;
+%% chk_IndAudDigitMapDescriptor(D1, D2) ->
+%% wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% %% -- IndAudStatisticsDescriptor --
+
+%% is_IndAudStatisticsDescriptor(
+%% #'IndAudStatisticsDescriptor'{statName = Name}) ->
+%% is_PkgdName(Name);
+%% is_IndAudStatisticsDescriptor(_) ->
+%% false.
+
+%% chk_IndAudStatisticsDescriptor(D, D) ->
+%% chk_type(fun is_IndAudStatisticsDescriptor/1,
+%% 'IndAudStatisticsDescriptor', D);
+%% chk_IndAudStatisticsDescriptor(
+%% #'IndAudStatisticsDescriptor'{statName = Name1},
+%% #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+%% validate(fun() -> chk_PkgdName(Name1, Name2) end,
+%% 'IndAudStatisticsDescriptor'),
+%% ok;
+%% chk_IndAudStatisticsDescriptor(D1, D2) ->
+%% wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% %% -- IndAudPackagesDescriptor --
+
+%% is_IndAudPackagesDescriptor(
+%% #'IndAudPackagesDescriptor'{packageName = Name,
+%% packageVersion = Ver}) ->
+%% is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+%% is_IndAudPackagesDescriptor(_) ->
+%% false.
+
+%% is_IndAudPackagesDescriptor_packageVersion(V) ->
+%% is_INTEGER(V, {range, 0, 99}).
+
+%% chk_IndAudPackagesDescriptor(
+%% #'IndAudPackagesDescriptor'{packageName = Name1,
+%% packageVersion = Ver1},
+%% #'IndAudPackagesDescriptor'{packageName = Name2,
+%% packageVersion = Ver2}) ->
+%% validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+%% chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+%% ok;
+%% chk_IndAudPackagesDescriptor(D1, D2) ->
+%% wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+%% chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+%% chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+%% 'IndAudPackagesDescriptor_packageVersion', V);
+%% chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+%% case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+%% is_IndAudPackagesDescriptor_packageVersion(V2)) of
+%% true ->
+%% not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+%% false ->
+%% wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+%% end.
+
+
+%% %% -- NotifyRequest --
+
+%% is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+%% observedEventsDescriptor = OED,
+%% errorDescriptor = ED}) ->
+%% is_TerminationIDList(Tids) andalso
+%% is_ObservedEventsDescriptor(OED) andalso
+%% is_opt_ErrorDescriptor(ED);
+%% is_NotifyRequest(_) ->
+%% false.
+
+%% chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+%% observedEventsDescriptor = OED1,
+%% errorDescriptor = ED1},
+%% #'NotifyRequest'{terminationID = Tids2,
+%% observedEventsDescriptor = OED2,
+%% errorDescriptor = ED2}) ->
+%% validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+%% 'NotifyRequest'),
+%% validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+%% 'NotifyRequest'),
+%% validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+%% 'NotifyRequest'),
+%% ok;
+%% chk_NotifyRequest(NR1, NR2) ->
+%% wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% %% -- NotifyReply --
+
+%% is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+%% errorDescriptor = ED}) ->
+%% is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+%% is_NotifyReply(_) ->
+%% false.
+
+%% chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+%% errorDescriptor = ED1},
+%% #'NotifyReply'{terminationID = Tids2,
+%% errorDescriptor = ED2}) ->
+%% validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+%% validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+%% ok;
+%% chk_NotifyReply(NR1, NR2) ->
+%% wrong_type('NotifyReply', NR1, NR2).
+
+
+%% %% -- ObservedEventsDescriptor --
+
+%% is_ObservedEventsDescriptor(
+%% #'ObservedEventsDescriptor'{requestId = RID,
+%% observedEventLst = OEL}) ->
+%% is_RequestID(RID) andalso
+%% is_ObservedEventsDescriptor_observedEventLst(OEL);
+%% is_ObservedEventsDescriptor(_) ->
+%% false.
+
+%% is_ObservedEventsDescriptor_observedEventLst([]) ->
+%% true;
+%% is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+%% is_ObservedEvent(H) andalso
+%% is_ObservedEventsDescriptor_observedEventLst(T);
+%% is_ObservedEventsDescriptor_observedEventLst(_) ->
+%% false.
+
+%% chk_ObservedEventsDescriptor(
+%% #'ObservedEventsDescriptor'{requestId = RID1,
+%% observedEventLst = OEL1},
+%% #'ObservedEventsDescriptor'{requestId = RID2,
+%% observedEventLst = OEL2}) ->
+%% validate(fun() -> chk_RequestID(RID1, RID2) end,
+%% 'ObservedEventsDescriptor'),
+%% validate(
+%% fun() ->
+%% chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+%% end,
+%% 'ObservedEventsDescriptor'),
+%% ok;
+%% chk_ObservedEventsDescriptor(D1, D2) ->
+%% wrong_type('ObservedEventsDescriptor', D1, D2).
+
+%% chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+%% ok;
+%% chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+%% not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+%% chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+%% not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+%% chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+%% case is_ObservedEvent(H) of
+%% true ->
+%% chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+%% false ->
+%% wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+%% end;
+%% chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_ObservedEvent(H1, H2) end,
+%% 'ObservedEventsDescriptor_observedEventLst_val'),
+%% chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+%% chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+%% wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% %% -- ObservedEvent --
+
+%% is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+%% streamID = SID,
+%% eventParList = EPL,
+%% timeNotation = TN}) ->
+%% is_EventName(Name) andalso
+%% is_opt_StreamID(SID) andalso
+%% is_ObservedEvent_eventParList(EPL) andalso
+%% is_opt_TimeNotation(TN);
+%% is_ObservedEvent(_) ->
+%% false.
+
+%% is_ObservedEvent_eventParList([]) ->
+%% true;
+%% is_ObservedEvent_eventParList([H|T]) ->
+%% is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+%% is_ObservedEvent_eventParList(_) ->
+%% false.
+
+%% chk_ObservedEvent(E, E) ->
+%% chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+%% chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+%% streamID = SID1,
+%% eventParList = EPL1,
+%% timeNotation = TN1},
+%% #'ObservedEvent'{eventName = Name2,
+%% streamID = SID2,
+%% eventParList = EPL2,
+%% timeNotation = TN2}) ->
+%% validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+%% validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+%% chk_ObservedEvent_eventParList(EPL1, EPL2),
+%% validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+%% ok;
+%% chk_ObservedEvent(E1, E2) ->
+%% wrong_type('ObservedEvent', E1, E2).
+
+%% chk_ObservedEvent_eventParList([], []) ->
+%% ok;
+%% chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+%% not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+%% chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+%% not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+%% chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+%% case is_EventParameter(H) of
+%% true ->
+%% chk_ObservedEvent_eventParList(T1, T2);
+%% false ->
+%% wrong_type('ObservedEvent_eventParList_val', H)
+%% end;
+%% chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_EventParameter(H1, H2) end,
+%% 'ObservedEvent_eventParList'),
+%% chk_ObservedEvent_eventParList(T1, T2);
+%% chk_ObservedEvent_eventParList(L1, L2) ->
+%% wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% %% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+%% chk_EventName(N, N) ->
+%% chk_type(fun is_EventName/1, 'EventName', N);
+%% chk_EventName(N1, N2) ->
+%% case (is_EventName(N1) andalso is_EventName(N2)) of
+%% true ->
+%% not_equal('EventName', N1, N2);
+%% false ->
+%% wrong_type('EventName', N1, N2)
+%% end.
+
+
+%% %% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+%% chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+%% value = Val1,
+%% extraInfo = EI1},
+%% #'EventParameter'{eventParameterName = Name2,
+%% value = Val2,
+%% extraInfo = EI2}) ->
+%% validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+%% validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+%% chk_EventParameter_extraInfo(EI1, EI2),
+%% ok;
+%% chk_EventParameter(P1, P2) ->
+%% wrong_type('EventParameter', P1, P2).
+
+%% chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_EventParameter_extraInfo(EI, EI) ->
+%% chk_type(fun is_EventParameter_extraInfo/1,
+%% 'EventParameter_extraInfo', EI);
+%% chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+%% case (is_EventParameter_extraInfo_tag(Tag) andalso
+%% is_EventParameter_extraInfo_val(Tag, Val1) andalso
+%% is_EventParameter_extraInfo_val(Tag, Val2)) of
+%% true ->
+%% chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('EventParameter_extraInfo', EI1, EI2)
+%% end;
+%% chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+%% case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+%% is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+%% (is_EventParameter_extraInfo_tag(Tag2) andalso
+%% is_EventParameter_extraInfo_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('EventParameter_extraInfo', EI1, EI2);
+%% false ->
+%% wrong_type('EventParameter_extraInfo', EI1, EI2)
+%% end;
+%% chk_EventParameter_extraInfo(EI1, EI2) ->
+%% wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+%% chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+%% validate(fun() -> chk_Relation(Val1, Val2) end,
+%% 'EventParameter_extraInfo_val');
+%% chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+%% 'EventParameter_extraInfo_val');
+%% chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+%% 'EventParameter_extraInfo_val').
+
+
+%% %% -- ServiceChangeRequest --
+
+%% is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+%% serviceChangeParms = Parms}) ->
+%% is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+%% is_ServiceChangeRequest(_) ->
+%% false.
+
+%% chk_ServiceChangeRequest(R, R) ->
+%% chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+%% chk_ServiceChangeRequest(
+%% #'ServiceChangeRequest'{terminationID = Tids1,
+%% serviceChangeParms = Parms1},
+%% #'ServiceChangeRequest'{terminationID = Tids2,
+%% serviceChangeParms = Parms2}) ->
+%% validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+%% 'ServiceChangeRequest'),
+%% validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+%% 'ServiceChangeRequest'),
+%% ok;
+%% chk_ServiceChangeRequest(R1, R2) ->
+%% wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% %% -- ServiceChangeReply --
+
+%% is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+%% serviceChangeResult = Res}) ->
+%% is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+%% is_ServiceChangeReply(_) ->
+%% false.
+
+%% chk_ServiceChangeReply(R, R) ->
+%% chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+%% chk_ServiceChangeReply(
+%% #'ServiceChangeReply'{terminationID = Tids1,
+%% serviceChangeResult = Res1},
+%% #'ServiceChangeReply'{terminationID = Tids2,
+%% serviceChangeResult = Res2}) ->
+%% validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+%% 'ServiceChangeReply'),
+%% validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+%% 'ServiceChangeReply'),
+%% ok;
+%% chk_ServiceChangeReply(R1, R2) ->
+%% wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% %% -- ServiceChangeResult --
+
+%% is_ServiceChangeResult({Tag, Val}) ->
+%% is_ServiceChangeResult_tag(Tag) andalso
+%% is_ServiceChangeResult_val(Tag, Val);
+%% is_ServiceChangeResult(_) ->
+%% false.
+
+%% is_ServiceChangeResult_tag(Tag) ->
+%% Tags = [errorDescriptor, serviceChangeResParms],
+%% lists:member(Tag, Tags).
+
+%% is_ServiceChangeResult_val(errorDescriptor, Val) ->
+%% is_ErrorDescriptor(Val);
+%% is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+%% is_ServiceChangeResParm(Val).
+
+%% chk_ServiceChangeResult(Res, Res) ->
+%% chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+%% chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+%% case (is_ServiceChangeResult_tag(Tag) andalso
+%% is_ServiceChangeResult_val(Tag, Val1) andalso
+%% is_ServiceChangeResult_val(Tag, Val2)) of
+%% true ->
+%% chk_ServiceChangeResult_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('ServiceChangeResult', Res1, Res2)
+%% end;
+%% chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+%% case ((is_ServiceChangeResult_tag(Tag1) andalso
+%% is_ServiceChangeResult_val(Tag1, Val1)) andalso
+%% (is_ServiceChangeResult_tag(Tag2) andalso
+%% is_ServiceChangeResult_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('ServiceChangeResult', Res1, Res2);
+%% false ->
+%% wrong_type('ServiceChangeResult', Res1, Res2)
+%% end;
+%% chk_ServiceChangeResult(Res1, Res2) ->
+%% wrong_type('ServiceChangeResult', Res1, Res2).
+
+%% chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+%% validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+%% 'ServiceChangeResult');
+%% chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+%% validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+%% 'ServiceChangeResult').
+
+
+%% %% -- WildcardField --
+
+%% is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+%% chk_WildcardField(WF, WF) ->
+%% case is_WildcardField(WF) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('WildcardField', WF)
+%% end;
+%% chk_WildcardField(WF1, WF2) ->
+%% case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+%% true ->
+%% not_equal('WildcardField', WF1, WF2);
+%% false ->
+%% wrong_type('WildcardField', WF1, WF2)
+%% end.
+
+
+%% %% -- TerminationID --
+
+%% is_TerminationID(#'TerminationID'{wildcard = W,
+%% id = ID}) ->
+%% is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+%% is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+%% id = _ID}) ->
+%% true; % What are the types?
+%% is_TerminationID(_) ->
+%% false.
+
+%% is_TerminationID_wildcard([]) ->
+%% true;
+%% is_TerminationID_wildcard([H|T]) ->
+%% is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+%% is_TerminationID_wildcard(_) ->
+%% false.
+
+%% is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+%% chk_TerminationID(Id,Id) ->
+%% chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+%% chk_TerminationID(#'TerminationID'{wildcard = W1,
+%% id = I1},
+%% #'TerminationID'{wildcard = W2,
+%% id = I2}) ->
+%% chk_TerminationID_wildcard(W1, W2),
+%% chk_TerminationID_id(I1, I2),
+%% ok;
+%% chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+%% id = I1},
+%% #megaco_term_id{contains_wildcards = W2,
+%% id = I2}) ->
+%% chk_TerminationID_wildcard(W1, W2),
+%% chk_TerminationID_id(I1, I2),
+%% ok;
+%% chk_TerminationID(Tid1, Tid2) ->
+%% wrong_type('TerminationID', Tid1, Tid2).
+
+%% chk_TerminationID_wildcard([], []) ->
+%% ok;
+%% chk_TerminationID_wildcard([] = WF1, WF2) ->
+%% not_equal('TerminationID_wildcard', WF1, WF2);
+%% chk_TerminationID_wildcard(WF1, [] = WF2) ->
+%% not_equal('TerminationID_wildcard', WF1, WF2);
+%% chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+%% case is_WildcardField(H) of
+%% true ->
+%% chk_TerminationID_wildcard(T1, T2);
+%% false ->
+%% wrong_type('TerminationID_wildcard_val', H)
+%% end;
+%% chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_WildcardField(H1, H2) end,
+%% 'TerminationID_wildcard_val'),
+%% chk_TerminationID_wildcard(T1, T2);
+%% chk_TerminationID_wildcard(WF1,WF2) ->
+%% not_equal('TerminationId_wildcard', WF1, WF2).
+
+%% chk_TerminationID_id(Id, Id) ->
+%% case is_OCTET_STRING(Id, {range, 1, 8}) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('TerminationID_id', Id, Id)
+%% end;
+%% chk_TerminationID_id(Id1, Id2) ->
+%% not_equal(terminationId_id, Id1, Id2).
+
+
+%% %% -- TerminationIDList --
+
+%% is_TerminationIDList([]) ->
+%% true;
+%% is_TerminationIDList([H|T]) ->
+%% is_TerminationID(H) andalso is_TerminationIDList(T);
+%% is_TerminationIDList(_) ->
+%% false.
+
+%% chk_TerminationIDList([], []) ->
+%% ok;
+%% chk_TerminationIDList([] = L1, L2) ->
+%% not_equal('TerminationIDList', L1, L2);
+%% chk_TerminationIDList(L1, [] = L2) ->
+%% not_equal('TerminationIDList', L1, L2);
+%% chk_TerminationIDList([H|T1], [H|T2]) ->
+%% case is_TerminationID(H) of
+%% true ->
+%% chk_TerminationIDList(T1, T2);
+%% false ->
+%% wrong_type('TerminationIDList', H)
+%% end;
+%% chk_TerminationIDList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+%% chk_TerminationIDList(T1, T2);
+%% chk_TerminationIDList(L1, L2) ->
+%% wrong_type('TerminationIDList', L1, L2).
+
+
+%% %% -- MediaDescriptor --
+
+%% is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+%% streams = S}) ->
+%% is_opt_TerminationStateDescriptor(TSD) andalso
+%% is_MediaDescriptor_streams(S);
+%% is_MediaDescriptor(_) ->
+%% false.
+
+%% is_MediaDescriptor_streams(asn1_NOVALUE) ->
+%% true;
+%% is_MediaDescriptor_streams({Tag, Val}) ->
+%% is_MediaDescriptor_streams_tag(Tag) andalso
+%% is_MediaDescriptor_streams_val(Tag, Val);
+%% is_MediaDescriptor_streams(_) ->
+%% false.
+
+%% is_MediaDescriptor_streams_tag(Tag) ->
+%% Tags = [oneStream, multiStream],
+%% lists:member(Tag, Tags).
+
+%% is_MediaDescriptor_streams_val(oneStream, SP) ->
+%% is_StreamParms(SP);
+%% is_MediaDescriptor_streams_val(multiStream, SDL) ->
+%% is_MediaDescriptor_multiStream(SDL).
+
+%% is_MediaDescriptor_multiStream([]) ->
+%% true;
+%% is_MediaDescriptor_multiStream([H|T]) ->
+%% is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+%% is_MediaDescriptor_multiStream(_) ->
+%% false.
+
+%% chk_MediaDescriptor(D, D) ->
+%% chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+%% chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+%% streams = S1},
+%% #'MediaDescriptor'{termStateDescr = TSD2,
+%% streams = S2}) ->
+%% validate(
+%% fun() ->
+%% chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+%% end,
+%% 'MediaDescriptor'),
+%% validate(
+%% fun() ->
+%% chk_MediaDescriptor_streams(S1, S2)
+%% end,
+%% 'MediaDescriptor'),
+%% ok;
+%% chk_MediaDescriptor(D1, D2) ->
+%% wrong_type('MediaDescriptor', D1, D2).
+
+
+%% chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+%% validate(fun() ->
+%% chk_StreamParms(SP1, SP2)
+%% end,
+%% 'MediaDescriptor_streams');
+%% chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+%% validate(fun() ->
+%% chk_MediaDescriptor_multiStream(SDs1, SDs2)
+%% end,
+%% 'MediaDescriptor_streams');
+%% chk_MediaDescriptor_streams(S1, S2) ->
+%% wrong_type('MediaDescriptor_streams', S1, S2).
+
+%% chk_MediaDescriptor_multiStream([], []) ->
+%% ok;
+%% chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+%% not_equal('MediaDescriptor_multiStream', MS1, MS2);
+%% chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+%% not_equal('MediaDescriptor_multiStream', MS1, MS2);
+%% chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+%% case is_StreamDescriptor(H) of
+%% true ->
+%% chk_MediaDescriptor_multiStream(T1, T2);
+%% false ->
+%% wrong_type('MediaDescriptor_multiStream_val', H)
+%% end;
+%% chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+%% 'MediaDescriptor_multiStream_val'),
+%% chk_MediaDescriptor_multiStream(T1, T2);
+%% chk_MediaDescriptor_multiStream(MS1, MS2) ->
+%% wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% %% -- StreamDescriptor --
+
+%% is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+%% streamParms = Parms}) ->
+%% is_StreamID(SID) andalso is_StreamParms(Parms);
+%% is_StreamDescriptor(_) ->
+%% false.
+
+%% chk_StreamDescriptor(D, D) ->
+%% chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+%% chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+%% streamParms = Parms1},
+%% #'StreamDescriptor'{streamID = SID2,
+%% streamParms = Parms2}) ->
+%% validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+%% validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+%% ok;
+%% chk_StreamDescriptor(D1, D2) ->
+%% wrong_type('StreamDescriptor', D1, D2).
+
+
+%% %% -- StreamParms --
+
+%% is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+%% localDescriptor = LD,
+%% remoteDescriptor = RD}) ->
+%% is_opt_LocalControlDescriptor(LCD) andalso
+%% is_opt_LocalRemoteDescriptor(LD) andalso
+%% is_opt_LocalRemoteDescriptor(RD);
+%% is_StreamParms(_) ->
+%% false.
+
+%% chk_StreamParms(SP, SP) ->
+%% chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+%% chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+%% localDescriptor = LD1,
+%% remoteDescriptor = RD1},
+%% #'StreamParms'{localControlDescriptor = LCD2,
+%% localDescriptor = LD2,
+%% remoteDescriptor = RD2}) ->
+%% chk_opt_LocalControlDescriptor(LCD1, LCD2),
+%% validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+%% localDescriptor),
+%% validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+%% remoteDescriptor),
+%% ok;
+%% chk_StreamParms(P1, P2) ->
+%% wrong_type('StreamParms', P1, P2).
+
+
+%% %% -- LocalControlDescriptor --
+
+%% is_opt_LocalControlDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_LocalControlDescriptor(D) ->
+%% is_LocalControlDescriptor(D).
+
+%% is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+%% reserveValue = RV,
+%% reserveGroup = RG,
+%% propertyParms = PP}) ->
+%% is_opt_StreamMode(SM) andalso
+%% is_opt_BOOLEAN(RV) andalso
+%% is_opt_BOOLEAN(RG) andalso
+%% is_LocalControlDescriptor_propertyParms(PP);
+%% is_LocalControlDescriptor(_) ->
+%% false.
+
+%% is_LocalControlDescriptor_propertyParms([]) ->
+%% true;
+%% is_LocalControlDescriptor_propertyParms([H|T]) ->
+%% is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+%% is_LocalControlDescriptor_propertyParms(_) ->
+%% false.
+
+%% chk_opt_LocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+%% chk_LocalControlDescriptor(LCD1, LCD2).
+
+%% chk_LocalControlDescriptor(LCD, LCD) ->
+%% chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+%% chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+%% reserveValue = RV1,
+%% reserveGroup = RG1,
+%% propertyParms = PP1},
+%% #'LocalControlDescriptor'{streamMode = SM2,
+%% reserveValue = RV2,
+%% reserveGroup = RG2,
+%% propertyParms = PP2}) ->
+%% validate(
+%% fun() -> chk_opt_StreamMode(SM1, SM2) end,
+%% 'LocalControlDescriptor'),
+%% validate(
+%% fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+%% 'LocalControlDescriptor_reserveValue'),
+%% validate(
+%% fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+%% 'LocalControlDescriptor_reserveGroup'),
+%% chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+%% ok;
+%% chk_LocalControlDescriptor(LCD1, LCD2) ->
+%% wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+%% chk_LocalControlDescriptor_propertyParms([], []) ->
+%% ok;
+%% chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+%% not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+%% chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+%% not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+%% chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+%% case is_PropertyParm(H) of
+%% true ->
+%% chk_LocalControlDescriptor_propertyParms(T1, T2);
+%% false ->
+%% wrong_type('LocalControlDescriptor_propertyParms_val', H)
+%% end;
+%% chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_PropertyParm(H1, H2) end,
+%% 'LocalControlDescriptor_propertyParms_val'),
+%% chk_LocalControlDescriptor_propertyParms(T1, T2);
+%% chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+%% wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% %% -- StreamMode --
+
+%% is_opt_StreamMode(asn1_NOVALUE) ->
+%% true;
+%% is_opt_StreamMode(SM) ->
+%% is_StreamMode(SM).
+
+%% is_StreamMode(SM) ->
+%% lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+%% chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_StreamMode(SM1, SM2) ->
+%% chk_StreamMode(SM1, SM2).
+
+%% chk_StreamMode(SM, SM) ->
+%% chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+%% chk_StreamMode(SM1, SM2) ->
+%% case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+%% true ->
+%% not_equal('StreamMode', SM1, SM2);
+%% false ->
+%% wrong_type('StreamMode', SM1, SM2)
+%% end.
+
+
+%% %% -- PropertyParm --
+
+%% is_PropertyParm(#'PropertyParm'{name = N,
+%% value = V,
+%% extraInfo = I}) ->
+%% is_PkgdName(N) andalso
+%% is_PropertyParm_value(V) andalso
+%% is_PropertyParm_extraInfo(I);
+%% is_PropertyParm(_) ->
+%% false.
+
+%% is_PropertyParm_value([]) ->
+%% true;
+%% is_PropertyParm_value([H|T]) ->
+%% is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+%% is_PropertyParm_value(_) ->
+%% false.
+
+%% is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+%% true;
+%% is_PropertyParm_extraInfo({Tag, Val}) ->
+%% is_PropertyParm_extraInfo_tag(Tag) andalso
+%% is_PropertyParm_extraInfo_val(Tag, Val);
+%% is_PropertyParm_extraInfo(_) ->
+%% false.
+
+%% is_PropertyParm_extraInfo_tag(Tag) ->
+%% Tags = [relation, range, sublist],
+%% lists:member(Tag, Tags).
+
+%% is_PropertyParm_extraInfo_val(relation, Val) ->
+%% is_Relation(Val);
+%% is_PropertyParm_extraInfo_val(range, Val) ->
+%% is_BOOLEAN(Val);
+%% is_PropertyParm_extraInfo_val(sublist, Val) ->
+%% is_BOOLEAN(Val).
+
+%% chk_PropertyParm(P, P) ->
+%% chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+%% chk_PropertyParm(#'PropertyParm'{name = N1,
+%% value = V1,
+%% extraInfo = I1},
+%% #'PropertyParm'{name = N2,
+%% value = V2,
+%% extraInfo = I2}) ->
+%% validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+%% chk_PropertyParm_value(V1, V2),
+%% chk_PropertyParm_extraInfo(I1, I2),
+%% ok;
+%% chk_PropertyParm(P1, P2) ->
+%% wrong_type('PropertyParm', P1, P2).
+
+%% chk_PropertyParm_value([], []) ->
+%% ok;
+%% chk_PropertyParm_value([] = V1, V2) ->
+%% not_equal('PropertyParm_value', V1, V2);
+%% chk_PropertyParm_value(V1, [] = V2) ->
+%% not_equal('PropertyParm_value', V1, V2);
+%% chk_PropertyParm_value([H|T1], [H|T2]) ->
+%% case is_OCTET_STRING(H) of
+%% true ->
+%% chk_PropertyParm_value(T1, T2);
+%% false ->
+%% wrong_type('PropertyParm_value_val', H)
+%% end;
+%% chk_PropertyParm_value([H1|_], [H2|_]) ->
+%% case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+%% true ->
+%% not_equal('PropertyParm_value_val', H1, H2);
+%% false ->
+%% wrong_type('PropertyParm_value_val', H1, H2)
+%% end;
+%% chk_PropertyParm_value(V1, V2) ->
+%% wrong_type('PropertyParm_value', V1, V2).
+
+%% chk_PropertyParm_extraInfo(EI, EI) ->
+%% chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+%% chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+%% case (is_PropertyParm_extraInfo_tag(Tag) and
+%% is_PropertyParm_extraInfo_val(Tag, Val1) and
+%% is_PropertyParm_extraInfo_val(Tag, Val2)) of
+%% true ->
+%% chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('PropertyParm_extraInfo', EI1, EI2)
+%% end;
+%% chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+%% case ((is_PropertyParm_extraInfo_tag(Tag1) and
+%% is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+%% (is_PropertyParm_extraInfo_tag(Tag2) and
+%% is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('PropertyParm_extraInfo', EI1, EI2);
+%% false ->
+%% wrong_type('PropertyParm_extraInfo', EI1, EI2)
+%% end;
+%% chk_PropertyParm_extraInfo(EI1, EI2) ->
+%% wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+%% chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+%% validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+%% chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+%% chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% %% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $9, $0 =< H ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+%% chk_Name(N, N) ->
+%% chk_type(fun is_Name/1, 'Name', N);
+%% chk_Name(N1, N2) ->
+%% case (is_Name(N1) andalso is_Name(N2)) of
+%% true ->
+%% not_equal('Name', N1, N2);
+%% false ->
+%% wrong_type('Name', N1, N2)
+%% end.
+
+
+%% %% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+%% chk_PkgdName(N, N) ->
+%% case is_PkgdName(N) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('PkgdName', N, N)
+%% end;
+%% chk_PkgdName(N1, N2) ->
+%% case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+%% true ->
+%% not_equal('PkgdName', N1, N2);
+%% false ->
+%% wrong_type('PkgdName', N1, N2)
+%% end.
+
+
+%% %% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+%% chk_Relation(R, R) ->
+%% chk_type(fun is_Relation/1, 'Relation', R);
+%% chk_Relation(R1, R2) ->
+%% case (is_Relation(R1) andalso is_Relation(R2)) of
+%% true ->
+%% not_equal('Relation', R1, R2);
+%% false ->
+%% wrong_type('Relation', R1, R2)
+%% end.
+
+
+%% %% -- LocalRemoteDescriptor --
+
+%% is_opt_LocalRemoteDescriptor(D) ->
+%% is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+%% is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+%% is_LocalRemoteDescriptor_propGrps(PGs);
+%% is_LocalRemoteDescriptor(_) ->
+%% false.
+
+%% is_LocalRemoteDescriptor_propGrps([]) ->
+%% true;
+%% is_LocalRemoteDescriptor_propGrps([H|T]) ->
+%% is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+%% is_LocalRemoteDescriptor_propGrps(_) ->
+%% false.
+
+%% chk_opt_LocalRemoteDescriptor(D1, D2) ->
+%% chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+%% fun is_LocalRemoteDescriptor/1,
+%% fun chk_LocalRemoteDescriptor/2).
+
+%% chk_LocalRemoteDescriptor(LRD, LRD) ->
+%% chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+%% chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+%% #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+%% chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+%% ok;
+%% chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+%% wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+%% chk_LocalRemoteDescriptor_propGrps([], []) ->
+%% ok;
+%% chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+%% not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+%% chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+%% not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+%% chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+%% case is_PropertyGroup(H) of
+%% true ->
+%% chk_LocalRemoteDescriptor_propGrps(T1, T2);
+%% false ->
+%% wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+%% end;
+%% chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_PropertyGroup(H1, H2) end,
+%% 'LocalRemoteDescriptor_propGrps_val'),
+%% chk_LocalRemoteDescriptor_propGrps(T1, T2);
+%% chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+%% wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% %% -- PropertyGroup --
+
+%% is_PropertyGroup([]) ->
+%% true;
+%% is_PropertyGroup([H|T]) ->
+%% is_PropertyParm(H) andalso is_PropertyGroup(T);
+%% is_PropertyGroup(_) ->
+%% false.
+
+%% chk_PropertyGroup([], []) ->
+%% ok;
+%% chk_PropertyGroup([] = PG1, PG2) ->
+%% not_equal('PropertyGroup', PG1, PG2);
+%% chk_PropertyGroup(PG1, [] = PG2) ->
+%% not_equal('PropertyGroup', PG1, PG2);
+%% chk_PropertyGroup([H|T1], [H|T2]) ->
+%% case is_PropertyParm(H) of
+%% true ->
+%% chk_PropertyGroup(T1, T2);
+%% false ->
+%% wrong_type('PropertyGroup_val', H)
+%% end;
+%% chk_PropertyGroup([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+%% chk_PropertyGroup(T1, T2);
+%% chk_PropertyGroup(PG1, PG2) ->
+%% wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% %% -- TerminationStateDescriptor --
+
+%% is_opt_TerminationStateDescriptor(D) ->
+%% is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+%% is_TerminationStateDescriptor(
+%% #'TerminationStateDescriptor'{propertyParms = PP,
+%% eventBufferControl = EBC,
+%% serviceState = SS}) ->
+%% is_TerminationStateDescriptor_propertyParms(PP) andalso
+%% is_opt_EventBufferControl(EBC) andalso
+%% is_opt_ServiceState(SS);
+%% is_TerminationStateDescriptor(_) ->
+%% false.
+
+%% is_TerminationStateDescriptor_propertyParms([]) ->
+%% true;
+%% is_TerminationStateDescriptor_propertyParms([H|T]) ->
+%% is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+%% is_TerminationStateDescriptor_propertyParms(_) ->
+%% false.
+
+%% chk_opt_TerminationStateDescriptor(D1, D2) ->
+%% chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+%% fun is_TerminationStateDescriptor/1,
+%% fun chk_TerminationStateDescriptor/2).
+
+%% chk_TerminationStateDescriptor(D, D) ->
+%% chk_type(fun is_TerminationStateDescriptor/1,
+%% 'TerminationStateDescriptor', D);
+%% chk_TerminationStateDescriptor(
+%% #'TerminationStateDescriptor'{propertyParms = PP1,
+%% eventBufferControl = EBC1,
+%% serviceState = SS1},
+%% #'TerminationStateDescriptor'{propertyParms = PP2,
+%% eventBufferControl = EBC2,
+%% serviceState = SS2}) ->
+%% chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+%% validate(
+%% fun() ->
+%% chk_opt_EventBufferControl(EBC1, EBC2)
+%% end,
+%% 'TerminationStateDescriptor'),
+%% validate(
+%% fun() ->
+%% chk_opt_ServiceState(SS1, SS2)
+%% end,
+%% 'TerminationStateDescriptor'),
+%% ok;
+%% chk_TerminationStateDescriptor(D1, D2) ->
+%% wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+%% chk_TerminationStateDescriptor_propertyParms([], []) ->
+%% ok;
+%% chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+%% not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+%% chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+%% not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+%% chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+%% case is_PropertyParm(H) of
+%% true ->
+%% chk_TerminationStateDescriptor_propertyParms(T1, T2);
+%% false ->
+%% wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+%% end;
+%% chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+%% case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+%% true ->
+%% not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+%% false ->
+%% wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+%% end;
+%% chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+%% wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% %% -- EventBufferControl --
+
+%% is_opt_EventBufferControl(asn1_NOVALUE) ->
+%% true;
+%% is_opt_EventBufferControl(EBC) ->
+%% is_EventBufferControl(EBC).
+
+%% is_EventBufferControl(EBC) ->
+%% lists:member(EBC, [off, lockStep]).
+
+%% chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_EventBufferControl(EBC1, EBC2) ->
+%% chk_EventBufferControl(EBC1, EBC2).
+
+%% chk_EventBufferControl(EBC, EBC) ->
+%% chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+%% chk_EventBufferControl(EBC1, EBC2) ->
+%% case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+%% true ->
+%% not_equal('EventBufferControl', EBC1, EBC2);
+%% false ->
+%% wrong_type('EventBufferControl', EBC1, EBC2)
+%% end.
+
+
+%% %% -- ServiceState --
+
+%% is_opt_ServiceState(asn1_NOVALUE) ->
+%% true;
+%% is_opt_ServiceState(SS) ->
+%% is_ServiceState(SS).
+
+%% is_ServiceState(SS) ->
+%% lists:member(SS, [test, outOfSvc, inSvc]).
+
+%% chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_ServiceState(SS1, SS2) ->
+%% chk_ServiceState(SS1, SS2).
+
+%% chk_ServiceState(SS, SS) ->
+%% chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+%% chk_ServiceState(SS1, SS2) ->
+%% case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+%% true ->
+%% not_equal('ServiceState', SS1, SS2);
+%% false ->
+%% wrong_type('ServiceState', SS1, SS2)
+%% end.
+
+
+%% %% -- MuxDescriptor --
+
+%% is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+%% termList = TL,
+%% nonStandardData = NSD}) ->
+%% is_MuxType(MT) andalso
+%% is_MuxDescriptor_termList(TL) andalso
+%% is_NonStandardData(NSD);
+%% is_MuxDescriptor(_) ->
+%% false.
+
+%% is_MuxDescriptor_termList([]) ->
+%% true;
+%% is_MuxDescriptor_termList([H|T]) ->
+%% is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+%% is_MuxDescriptor_termList(_) ->
+%% false.
+
+%% chk_MuxDescriptor(D, D) ->
+%% chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+%% chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+%% termList = TL1,
+%% nonStandardData = NSD1},
+%% #'MuxDescriptor'{muxType = MT2,
+%% termList = TL2,
+%% nonStandardData = NSD2}) ->
+%% validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+%% chk_MuxDescriptor_termList(TL1, TL2),
+%% validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+%% ok;
+%% chk_MuxDescriptor(D1, D2) ->
+%% wrong_type('MuxDescriptor', D1, D2).
+
+%% chk_MuxDescriptor_termList([], []) ->
+%% ok;
+%% chk_MuxDescriptor_termList([] = TL1, TL2) ->
+%% not_equal('MuxDescriptor_termList', TL1, TL2);
+%% chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+%% not_equal('MuxDescriptor_termList', TL1, TL2);
+%% chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+%% case is_TerminationID(H) of
+%% true ->
+%% chk_MuxDescriptor_termList(T1, T2);
+%% false ->
+%% wrong_type('MuxDescriptor_termList_val', H)
+%% end;
+%% chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_TerminationID(H1, H2) end,
+%% 'MuxDescriptor_termList_val'),
+%% chk_MuxDescriptor_termList(T1, T2);
+%% chk_MuxDescriptor_termList(TL1, TL2) ->
+%% wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% %% -- MuxType --
+
+%% is_MuxType(MT) ->
+%% lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+%% chk_MuxType(MT, MT) ->
+%% chk_type(fun is_MuxType/1, 'MuxType', MT);
+%% chk_MuxType(MT1, MT2) ->
+%% case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+%% true ->
+%% not_equal('MuxType', MT1, MT2);
+%% false ->
+%% wrong_type('MuxType', MT1, MT2)
+%% end.
+
+
+%% %% -- StreamID --
+
+is_opt_StreamID(asn1_NOVALUE) ->
+ true;
+is_opt_StreamID(V) ->
+ is_StreamID(V).
+
+is_StreamID(V) -> is_INTEGER(V, {range, 0, 65535}).
+
+%% chk_opt_StreamID(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_StreamID(V1, V2) ->
+%% chk_StreamID(V1, V2).
+
+%% chk_StreamID(ID, ID) ->
+%% chk_type(fun is_StreamID/1, 'StreamID', ID);
+%% chk_StreamID(ID1, ID2) ->
+%% case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+%% true ->
+%% not_equal('StreamID', ID1, ID2);
+%% false ->
+%% wrong_type('StreamID', ID1, ID2)
+%% end.
+
+
+%% %% -- EventsDescriptor --
+
+%% is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+%% eventList = EVL}) ->
+%% d("is_EventsDescriptor -> entry with"
+%% "~n RID: ~p"
+%% "~n EVL: ~p", [RID, EVL]),
+%% is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+%% is_EventsDescriptor(_) ->
+%% false.
+
+%% is_EventsDescriptor_eventList([]) ->
+%% true;
+%% is_EventsDescriptor_eventList([H|T]) ->
+%% is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+%% is_EventsDescriptor_eventList(_) ->
+%% false.
+
+%% chk_EventsDescriptor(D, D) ->
+%% chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+%% chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+%% eventList = EVL1},
+%% #'EventsDescriptor'{requestID = RID2,
+%% eventList = EVL2}) ->
+%% validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+%% chk_EventsDescriptor_eventList(EVL1, EVL2),
+%% ok;
+%% chk_EventsDescriptor(D1, D2) ->
+%% wrong_type('EventsDescriptor', D1, D2).
+
+%% chk_EventsDescriptor_eventList([], []) ->
+%% ok;
+%% chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+%% not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+%% chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+%% not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+%% chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+%% case is_RequestedEvent(H) of
+%% true ->
+%% chk_EventsDescriptor_eventList(T1, T2);
+%% false ->
+%% wrong_type('EventsDescriptor_eventList_val', H)
+%% end;
+%% chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_RequestedEvent(H1, H2) end,
+%% 'EventsDescriptor_eventList_val'),
+%% chk_EventsDescriptor_eventList(T1, T2);
+%% chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+%% wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% %% -- RequestedEvent --
+
+%% is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% eventAction = EA,
+%% evParList = EPL}) ->
+%% d("is_RequestedEvent -> entry with"
+%% "~n N: ~p"
+%% "~n SID: ~p"
+%% "~n EA: ~p"
+%% "~n EPL: ~p", [N, SID, EA, EPL]),
+%% is_PkgdName(N) andalso
+%% is_opt_StreamID(SID) andalso
+%% is_opt_RequestedActions(EA) andalso
+%% is_RequestedEvent_evParList(EPL);
+%% is_RequestedEvent(_) ->
+%% false.
+
+%% is_RequestedEvent_evParList([]) ->
+%% true;
+%% is_RequestedEvent_evParList([H|T]) ->
+%% is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+%% is_RequestedEvent_evParList(_) ->
+%% false.
+
+%% chk_RequestedEvent(RE, RE) ->
+%% chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+%% chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+%% streamID = SID1,
+%% eventAction = EA1,
+%% evParList = EPL1},
+%% #'RequestedEvent'{pkgdName = N2,
+%% streamID = SID2,
+%% eventAction = EA2,
+%% evParList = EPL2}) ->
+%% validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+%% validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+%% validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+%% 'RequestedEvent'),
+%% chk_RequestedEvent_evParList(EPL1, EPL2),
+%% ok;
+%% chk_RequestedEvent(RE1, RE2) ->
+%% wrong_type('RequestedEvent', RE1, RE2).
+
+%% chk_RequestedEvent_evParList([], []) ->
+%% ok;
+%% chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+%% not_equal('RequestedEvent_evParList', EPL1, EPL2);
+%% chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+%% not_equal('RequestedEvent_evParList', EPL1, EPL2);
+%% chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+%% case is_EventParameter(H) of
+%% true ->
+%% chk_RequestedEvent_evParList(T1, T2);
+%% false ->
+%% wrong_type('RequestedEvent_evParList_val', H)
+%% end;
+%% chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_EventParameter(H1, H2) end,
+%% 'RequestedEvent_evParList_val'),
+%% chk_RequestedEvent_evParList(T1, T2);
+%% chk_RequestedEvent_evParList(EPL1, EPL2) ->
+%% wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% %% -- RequestedActions --
+
+%% is_opt_RequestedActions(asn1_NOVALUE) ->
+%% true;
+%% is_opt_RequestedActions(RA) ->
+%% is_RequestedActions(RA).
+
+%% is_RequestedActions(#'RequestedActions'{keepActive = KA,
+%% eventDM = EDM,
+%% secondEvent = SE,
+%% signalsDescriptor = SD}) ->
+%% d("is_RequestedActions -> entry with"
+%% "~n KA: ~p"
+%% "~n EDM: ~p"
+%% "~n SE: ~p"
+%% "~n SD: ~p", [KA, EDM, SE, SD]),
+%% is_opt_BOOLEAN(KA) andalso
+%% is_opt_EventDM(EDM) andalso
+%% is_opt_SecondEventsDescriptor(SE) andalso
+%% is_opt_SignalsDescriptor(SD);
+%% is_RequestedActions(_) ->
+%% false.
+
+%% chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_RequestedActions(RA1, RA2) ->
+%% chk_RequestedActions(RA1, RA2).
+
+%% chk_RequestedActions(RA, RA) ->
+%% chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+%% chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+%% eventDM = EDM1,
+%% secondEvent = SA1,
+%% signalsDescriptor = SD1},
+%% #'RequestedActions'{keepActive = KA2,
+%% eventDM = EDM2,
+%% secondEvent = SA2,
+%% signalsDescriptor = SD2}) ->
+%% validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'RequestedActions'),
+%% validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end, 'RequestedActions'),
+%% validate(fun() -> chk_opt_SecondEventsDescriptor(SA1, SA2) end,
+%% 'RequestedActions'),
+%% validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+%% 'RequestedActions'),
+%% ok;
+%% chk_RequestedActions(RA1, RA2) ->
+%% wrong_type('RequestedActions', RA1, RA2).
+
+
+%% %% -- EventDM --
+
+%% is_opt_EventDM(EDM) ->
+%% is_OPTIONAL(fun is_EventDM/1, EDM).
+
+%% is_EventDM({Tag, Val}) ->
+%% is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+%% is_EventDM(_) ->
+%% false.
+
+%% is_EventDM_tag(Tag) ->
+%% Tags = [digitMapName, digitMapValue],
+%% lists:member(Tag, Tags).
+
+%% is_EventDM_val(digitMapName, Val) ->
+%% is_DigitMapName(Val);
+%% is_EventDM_val(digitMapValue, Val) ->
+%% is_DigitMapValue(Val).
+
+%% chk_opt_EventDM(EDM1, EDM2) ->
+%% chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+%% chk_EventDM(EDM, EDM) ->
+%% chk_type(fun is_EventDM/1, 'EventDM', EDM);
+%% chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+%% case (is_EventDM_tag(Tag) andalso
+%% is_EventDM_val(Tag, Val1) andalso
+%% is_EventDM_val(Tag, Val2)) of
+%% true ->
+%% chk_EventDM_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('EventDM', EDM1, EDM2)
+%% end;
+%% chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+%% case ((is_EventDM_tag(Tag1) andalso
+%% is_EventDM_val(Tag1, Val1)) andalso
+%% (is_EventDM_tag(Tag2) andalso
+%% is_EventDM_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('EventDM', EDM1, EDM2);
+%% false ->
+%% wrong_type('EventDM', EDM1, EDM2)
+%% end;
+%% chk_EventDM(EDM1, EDM2) ->
+%% wrong_type('EventDM', EDM1, EDM2).
+
+%% chk_EventDM_val(digitMapName, Val1, Val2) ->
+%% validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+%% chk_EventDM_val(digitMapValue, Val1, Val2) ->
+%% validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% %% -- SecondEventsDescriptor --
+
+%% is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_SecondEventsDescriptor(D) ->
+%% is_SecondEventsDescriptor(D).
+
+%% is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+%% eventList = EL}) ->
+%% is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+%% is_SecondEventsDescriptor(_) ->
+%% false.
+
+%% is_SecondEventsDescriptor_eventList([]) ->
+%% true;
+%% is_SecondEventsDescriptor_eventList([H|T]) ->
+%% is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+%% is_SecondEventsDescriptor_eventList(_) ->
+%% false.
+
+%% chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_SecondEventsDescriptor(D1, D2) ->
+%% chk_SecondEventsDescriptor(D1, D2).
+
+%% chk_SecondEventsDescriptor(D, D) ->
+%% chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+%% chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+%% eventList = EL1},
+%% #'SecondEventsDescriptor'{requestID = RID2,
+%% eventList = EL2}) ->
+%% validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+%% 'SecondEventsDescriptor'),
+%% chk_SecondEventsDescriptor_eventList(EL1, EL2),
+%% ok;
+%% chk_SecondEventsDescriptor(D1, D2) ->
+%% wrong_type('SecondEventsDescriptor', D1, D2).
+
+%% chk_SecondEventsDescriptor_eventList([], []) ->
+%% ok;
+%% chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+%% not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+%% chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+%% not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+%% chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+%% case is_SecondRequestedEvent(H) of
+%% true ->
+%% chk_SecondEventsDescriptor_eventList(T1, T2);
+%% false ->
+%% wrong_type('SecondEventsDescriptor_eventList_val', H)
+%% end;
+%% chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+%% 'SecondEventsDescriptor_eventList_val'),
+%% chk_SecondEventsDescriptor_eventList(T1, T2);
+%% chk_SecondEventsDescriptor_eventList(L1, L2) ->
+%% wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% %% -- SecondRequestedEvent --
+
+%% is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+%% streamID = SID,
+%% eventAction = EA,
+%% evParList = EPL}) ->
+%% is_PkgdName(N) andalso
+%% is_opt_StreamID(SID) andalso
+%% is_opt_SecondRequestedActions(EA) andalso
+%% is_SecondRequestedEvent_evParList(EPL);
+%% is_SecondRequestedEvent(_) ->
+%% false.
+
+%% is_SecondRequestedEvent_evParList([]) ->
+%% true;
+%% is_SecondRequestedEvent_evParList([H|T]) ->
+%% is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+%% is_SecondRequestedEvent_evParList(_) ->
+%% false.
+
+%% chk_SecondRequestedEvent(RE, RE) ->
+%% chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+%% chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+%% streamID = SID1,
+%% eventAction = EA1,
+%% evParList = EPL1},
+%% #'SecondRequestedEvent'{pkgdName = N2,
+%% streamID = SID2,
+%% eventAction = EA2,
+%% evParList = EPL2}) ->
+%% validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+%% validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+%% 'SecondRequestedEvent'),
+%% validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+%% 'SecondRequestedEvent'),
+%% chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+%% ok;
+%% chk_SecondRequestedEvent(RE1, RE2) ->
+%% wrong_type('SecondRequestedEvent', RE1, RE2).
+
+%% chk_SecondRequestedEvent_evParList([], []) ->
+%% ok;
+%% chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+%% not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+%% chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+%% not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+%% chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+%% case is_EventParameter(H) of
+%% true ->
+%% chk_SecondRequestedEvent_evParList(T1, T2);
+%% false ->
+%% wrong_type('SecondRequestedEvent_evParList_val', H)
+%% end;
+%% chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_EventParameter(H1, H2) end,
+%% 'SecondRequestedEvent_evParList_val'),
+%% chk_SecondRequestedEvent_evParList(T1, T2);
+%% chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+%% wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% %% -- SecondRequestedActions --
+
+%% is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+%% true;
+%% is_opt_SecondRequestedActions(SRA) ->
+%% is_SecondRequestedActions(SRA).
+
+%% is_SecondRequestedActions(#'SecondRequestedActions'{keepActive = KA,
+%% eventDM = EDM,
+%% signalsDescriptor = SD}) ->
+%% is_opt_BOOLEAN(KA) andalso
+%% is_opt_EventDM(EDM) andalso
+%% is_opt_SignalsDescriptor(SD);
+%% is_SecondRequestedActions(_) ->
+%% false.
+
+%% chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+%% chk_SecondRequestedActions(SRA1, SRA2).
+
+%% chk_SecondRequestedActions(SRA, SRA) ->
+%% chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+%% chk_SecondRequestedActions(
+%% #'SecondRequestedActions'{keepActive = KA1,
+%% eventDM = EDM1,
+%% signalsDescriptor = SD1},
+%% #'SecondRequestedActions'{keepActive = KA2,
+%% eventDM = EDM2,
+%% signalsDescriptor = SD2}) ->
+%% validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end,
+%% 'SecondRequestedActions'),
+%% validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end,
+%% 'SecondRequestedActions'),
+%% validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+%% 'SecondRequestedActions'),
+%% ok;
+%% chk_SecondRequestedActions(SRA1, SRA2) ->
+%% wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+
+%% %% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor([]) ->
+ true;
+is_EventBufferDescriptor([H|T]) ->
+ is_EventSpec(H) andalso is_EventBufferDescriptor(T);
+is_EventBufferDescriptor(_) ->
+ false.
+
+%% chk_EventBufferDescriptor([], []) ->
+%% ok;
+%% chk_EventBufferDescriptor([] = D1, D2) ->
+%% not_equal('EventBufferDescriptor', D1, D2);
+%% chk_EventBufferDescriptor(D1, [] = D2) ->
+%% not_equal('EventBufferDescriptor', D1, D2);
+%% chk_EventBufferDescriptor([H|T1], [H|T2]) ->
+%% case is_EventSpec(H) of
+%% true ->
+%% chk_EventBufferDescriptor(T1, T2);
+%% false ->
+%% wrong_type('EventBufferDescriptor_val', H)
+%% end;
+%% chk_EventBufferDescriptor([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_EventSpec(H1, H2) end,
+%% 'EventBufferDescriptor_val'),
+%% chk_EventBufferDescriptor(T1, T2);
+%% chk_EventBufferDescriptor(D1, D2) ->
+%% wrong_type('EventBufferDescriptor_val', D1, D2).
+
+
+%% %% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+%% chk_EventSpec(ES, ES) ->
+%% chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+%% chk_EventSpec(#'EventSpec'{eventName = N1,
+%% streamID = SID1,
+%% eventParList = EPL1},
+%% #'EventSpec'{eventName = N2,
+%% streamID = SID2,
+%% eventParList = EPL2}) ->
+%% validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+%% validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+%% chk_EventSpec_eventParList(EPL1, EPL2),
+%% ok;
+%% chk_EventSpec(ES1, ES2) ->
+%% wrong_type('EventSpec', ES1, ES2).
+
+%% chk_EventSpec_eventParList([], []) ->
+%% ok;
+%% chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+%% not_equal('EventSpec_eventParList', EPL1, EPL2);
+%% chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+%% not_equal('EventSpec_eventParList', EPL1, EPL2);
+%% chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+%% case is_EventParameter(H) of
+%% true ->
+%% chk_EventSpec_eventParList(T1, T2);
+%% false ->
+%% wrong_type('EventSpec_eventParList_val', H)
+%% end;
+%% chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_EventParameter(H1, H2) end,
+%% 'EventSpec_eventParList_val'),
+%% chk_EventSpec_eventParList(T1, T2);
+%% chk_EventSpec_eventParList(EPL1, EPL2) ->
+%% wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% %% -- SignalsDescriptor --
+
+%% is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+%% true;
+%% is_opt_SignalsDescriptor(D) ->
+%% is_SignalsDescriptor(D).
+
+is_SignalsDescriptor([]) ->
+ true;
+is_SignalsDescriptor([H|T]) ->
+ is_SignalRequest(H) andalso is_SignalsDescriptor(T);
+is_SignalsDescriptor(_) ->
+ false.
+
+%% chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_SignalsDescriptor(D1, D2) ->
+%% chk_SignalsDescriptor(D1, D2).
+
+%% chk_SignalsDescriptor([], []) ->
+%% ok;
+%% chk_SignalsDescriptor([] = D1, D2) ->
+%% not_equal('SignalsDescriptor', D1, D2);
+%% chk_SignalsDescriptor(D1, [] = D2) ->
+%% not_equal('SignalsDescriptor', D1, D2);
+%% chk_SignalsDescriptor([H|T1], [H|T2]) ->
+%% case is_SignalRequest(H) of
+%% true ->
+%% chk_SignalsDescriptor(T1, T2);
+%% false ->
+%% wrong_type('SignalsDescriptor_val', H)
+%% end;
+%% chk_SignalsDescriptor([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_SignalRequest(H1, H2) end, 'SignalsDescriptor_val'),
+%% chk_SignalsDescriptor(T1, T2);
+%% chk_SignalsDescriptor(D1, D2) ->
+%% wrong_type('SignalsDescriptor', D1, D2).
+
+
+%% %% -- SignalRequest --
+
+is_SignalRequest({Tag, Val}) ->
+ is_SignalRequest_tag(Tag) andalso is_SignalRequest_val(Tag, Val);
+is_SignalRequest(_) ->
+ false.
+
+is_SignalRequest_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_SignalRequest_val(signal, Val) ->
+ is_Signal(Val);
+is_SignalRequest_val(seqSigList, Val) ->
+ is_SeqSigList(Val).
+
+%% chk_SignalRequest(R, R) ->
+%% chk_type(fun is_SignalRequest/1, 'SignalRequest', R);
+%% chk_SignalRequest({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+%% case (is_SignalRequest_tag(Tag) andalso
+%% is_SignalRequest_val(Tag, Val1) andalso
+%% is_SignalRequest_val(Tag, Val2)) of
+%% true ->
+%% chk_SignalRequest_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('SignalRequest', R1, R2)
+%% end;
+%% chk_SignalRequest({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+%% case ((is_SignalRequest_tag(Tag1) andalso
+%% is_SignalRequest_val(Tag1, Val1)) andalso
+%% (is_SignalRequest_tag(Tag2) andalso
+%% is_SignalRequest_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('SignalRequest', R1, R2);
+%% false ->
+%% wrong_type('SignalRequest', R1, R2)
+%% end;
+%% chk_SignalRequest(R1, R2) ->
+%% wrong_type('SignalRequest', R1, R2).
+
+%% chk_SignalRequest_val(signal, Val1, Val2) ->
+%% validate(fun() -> chk_Signal(Val1, Val2) end, 'SignalRequest');
+%% chk_SignalRequest_val(seqSigList, Val1, Val2) ->
+%% validate(fun() -> chk_SeqSigList(Val1, Val2) end, 'SignalRequest').
+
+
+%% %% -- SeqSigList --
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+%% chk_SeqSigList(L, L) ->
+%% chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+%% chk_SeqSigList(#'SeqSigList'{id = ID1,
+%% signalList = SL1},
+%% #'SeqSigList'{id = ID2,
+%% signalList = SL2}) ->
+%% validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+%% 'SeqSigList'),
+%% chk_SeqSigList_signalList(SL1, SL2),
+%% ok;
+%% chk_SeqSigList(L1, L2) ->
+%% wrong_type('SeqSigList', L1, L2).
+
+%% chk_SeqSigList_signalList([], []) ->
+%% ok;
+%% chk_SeqSigList_signalList([] = L1, L2) ->
+%% not_equal('SeqSigList_signalList', L1, L2);
+%% chk_SeqSigList_signalList(L1, [] = L2) ->
+%% not_equal('SeqSigList_signalList', L1, L2);
+%% chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+%% case is_Signal(H) of
+%% true ->
+%% chk_SeqSigList_signalList(T1, T2);
+%% false ->
+%% wrong_type('SeqSigList_signalList_val', H)
+%% end;
+%% chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_Signal(H1, H2) end,
+%% 'SeqSigList_signalList_val'),
+%% chk_SeqSigList_signalList(T1, T2);
+%% chk_SeqSigList_signalList(L1, L2) ->
+%% wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% %% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}) ->
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+%% chk_Signal(S, S) ->
+%% chk_type(fun is_Signal/1, 'Signal', S);
+%% chk_Signal(#'Signal'{signalName = N1,
+%% streamID = SID1,
+%% sigType = ST1,
+%% duration = Dur1,
+%% notifyCompletion = NC1,
+%% keepActive = KA1,
+%% sigParList = SPL1},
+%% #'Signal'{signalName = N2,
+%% streamID = SID2,
+%% sigType = ST2,
+%% duration = Dur2,
+%% notifyCompletion = NC2,
+%% keepActive = KA2,
+%% sigParList = SPL2}) ->
+%% validate(fun() -> chk_SignalName(N1, N2) end, 'Signal'),
+%% validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'Signal'),
+%% validate(fun() -> chk_opt_SignalType(ST1, ST2) end, 'Signal'),
+%% validate(fun() -> chk_opt_INTEGER(Dur1, Dur2, {range, 0, 65535}) end,
+%% 'Signal'),
+%% validate(fun() -> chk_opt_NotifyCompletion(NC1, NC2) end, 'Signal'),
+%% validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'Signal'),
+%% chk_Signal_sigParList(SPL1, SPL2),
+%% ok;
+%% chk_Signal(S1, S2) ->
+%% wrong_type('Signal', S1, S2).
+
+%% chk_Signal_sigParList([], []) ->
+%% ok;
+%% chk_Signal_sigParList([] = L1, L2) ->
+%% not_equal('Signal_sigParList', L1, L2);
+%% chk_Signal_sigParList(L1, [] = L2) ->
+%% not_equal('Signal_sigParList', L1, L2);
+%% chk_Signal_sigParList([H|T1], [H|T2]) ->
+%% case is_SigParameter(H) of
+%% true ->
+%% chk_Signal_sigParList(T1, T2);
+%% false ->
+%% wrong_type('Signal_sigParList_val', H)
+%% end;
+%% chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_SigParameter(H1, H2) end,
+%% 'Signal_sigParList_val'),
+%% chk_Signal_sigParList(T1, T2);
+%% chk_Signal_sigParList(L1, L2) ->
+%% wrong_type('Signal_sigParList', L1, L2).
+
+
+%% %% -- SignalType --
+
+is_opt_SignalType(asn1_NOVALUE) ->
+ true;
+is_opt_SignalType(T) ->
+ is_SignalType(T).
+
+is_SignalType(T) ->
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+%% chk_opt_SignalType(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_SignalType(T1, T2) ->
+%% chk_SignalType(T1, T2).
+
+%% chk_SignalType(T, T) ->
+%% chk_type(fun is_SignalType/1, 'SignalType', T);
+%% chk_SignalType(T1, T2) ->
+%% case (is_SignalType(T1) andalso is_SignalType(T2)) of
+%% true ->
+%% not_equal('SignalType', T1, T2);
+%% false ->
+%% wrong_type('SignalType', T1, T2)
+%% end.
+
+
+%% %% -- SignalName --
+
+is_SignalName(N) -> is_PkgdName(N).
+
+%% chk_SignalName(N1, N2) ->
+%% validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% %% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:member(NC, Valids).
+
+%% chk_opt_NotifyCompletion(NC1, NC2) ->
+%% chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+%% fun is_NotifyCompletion/1,
+%% fun chk_NotifyCompletion/2).
+
+%% chk_NotifyCompletion(NC, NC) ->
+%% chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+%% chk_NotifyCompletion(NC1, NC2) ->
+%% case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+%% true ->
+%% not_equal('NotifyCompletion', NC1, NC2);
+%% false ->
+%% wrong_type('NotifyCompletion', NC1, NC2)
+%% end.
+
+
+%% %% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+%% chk_SigParameter(P, P) ->
+%% chk_type(fun is_SigParameter/1, 'SigParameter', P);
+%% chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+%% value = V1,
+%% extraInfo = I1},
+%% #'SigParameter'{sigParameterName = N2,
+%% value = V2,
+%% extraInfo = I2}) ->
+%% validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+%% validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+%% chk_SigParameter_extraInfo(I1, I2),
+%% ok;
+%% chk_SigParameter(P1, P2) ->
+%% wrong_type('SigParameter', P1, P2).
+
+%% chk_SigParameter_extraInfo(EI, EI) ->
+%% chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+%% chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+%% case (is_SigParameter_extraInfo_tag(Tag) and
+%% is_SigParameter_extraInfo_val(Tag, Val1) and
+%% is_SigParameter_extraInfo_val(Tag, Val2)) of
+%% true ->
+%% chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('SigParameter_extraInfo', EI1, EI2)
+%% end;
+%% chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+%% case ((is_SigParameter_extraInfo_tag(Tag1) and
+%% is_SigParameter_extraInfo_val(Tag1, Val1)) and
+%% (is_SigParameter_extraInfo_tag(Tag2) and
+%% is_SigParameter_extraInfo_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('SigParameter_extraInfo', EI1, EI2);
+%% false ->
+%% wrong_type('SigParameter_extraInfo', EI1, EI2)
+%% end;
+%% chk_SigParameter_extraInfo(EI1, EI2) ->
+%% wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+%% chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+%% validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+%% chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+%% chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+%% validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% %% -- RequestID --
+
+%% is_opt_RequestID(asn1_NOVALUE) ->
+%% true;
+%% is_opt_RequestID(V) ->
+%% is_RequestID(V).
+
+%% is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+%% chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_RequestID(V1, V2) ->
+%% chk_RequestID(V1, V2).
+
+%% chk_RequestID(ID, ID) ->
+%% chk_type(fun is_RequestID/1, 'RequestID', ID);
+%% chk_RequestID(ID1, ID2) ->
+%% case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+%% true ->
+%% not_equal('RequestID', ID1, ID2);
+%% false ->
+%% wrong_type('RequestID', ID1, ID2)
+%% end.
+
+
+%% %% -- ModemDescriptor --
+
+%% is_ModemDescriptor(D) when record(D, 'ModemDescriptor') ->
+%% true;
+%% is_ModemDescriptor(_) ->
+%% false.
+
+%% chk_ModemDescriptor(D, D) when record(D, 'ModemDescriptor') ->
+%% ok;
+%% chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+%% mpl = MPL1,
+%% nonStandardData = NSD1},
+%% #'ModemDescriptor'{mtl = MTL2,
+%% mpl = MPL2,
+%% nonStandardData = NSD2}) ->
+%% chk_ModemDescriptor_mtl(MTL1, MTL2),
+%% chk_ModemDescriptor_mpl(MPL1, MPL2),
+%% chk_opt_NonStandardData(NSD1, NSD2),
+%% ok;
+%% chk_ModemDescriptor(D1, D2) ->
+%% wrong_type('ModemDescriptor', D1, D2).
+
+%% chk_ModemDescriptor_mtl([], []) ->
+%% ok;
+%% chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+%% not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+%% chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+%% not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+%% chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+%% case is_ModemType(H) of
+%% true ->
+%% chk_ModemDescriptor_mtl(T1, T2);
+%% false ->
+%% wrong_type('ModemDescriptor_mtl_val', H)
+%% end;
+%% chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+%% chk_ModemDescriptor_mtl(T1, T2);
+%% chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+%% wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+%% chk_ModemDescriptor_mpl([], []) ->
+%% ok;
+%% chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+%% not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+%% chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+%% not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+%% chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+%% case is_PropertyParm(H) of
+%% true ->
+%% chk_ModemDescriptor_mpl(T1, T2);
+%% false ->
+%% wrong_type('ModemDescriptor_mpl_val', H)
+%% end;
+%% chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+%% chk_ModemDescriptor_mpl(T1, T2);
+%% chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+%% wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% %% -- ModemType --
+
+%% chk_ModemType(MT, MT) ->
+%% case is_ModemType(MT) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('ModemType', MT, MT)
+%% end;
+%% chk_ModemType(MT1, MT2) ->
+%% case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+%% true ->
+%% not_equal('ModemType', MT1, MT2);
+%% false ->
+%% wrong_type('ModemType', MT1, MT2)
+%% end.
+
+%% is_ModemType(MT) ->
+%% lists:member(MT,
+%% [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% %% -- DigitMapDescriptor --
+
+%% is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+%% digitMapValue = Val}) ->
+%% is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+%% is_DigitMapDescriptor(_) ->
+%% false.
+
+%% chk_DigitMapDescriptor(D, D) ->
+%% chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+%% chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+%% digitMapValue = Val1},
+%% #'DigitMapDescriptor'{digitMapName = Name2,
+%% digitMapValue = Val2}) ->
+%% d("chk_DigitMapDescriptor -> entry with"
+%% "~n Name1: ~p"
+%% "~n Name2: ~p"
+%% "~n Val1: ~p"
+%% "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+%% validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+%% 'DigitMapDescriptor'),
+%% validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+%% 'DigitMapDescriptor'),
+%% ok;
+%% chk_DigitMapDescriptor(D1, D2) ->
+%% wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% %% -- DigitMapName --
+
+%% is_opt_DigitMapName(asn1_NOVALUE) ->
+%% true;
+%% is_opt_DigitMapName(N) ->
+%% is_DigitMapName(N).
+
+%% is_DigitMapName(N) -> is_Name(N).
+
+%% chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_DigitMapName(N1, N2) ->
+%% chk_DigitMapName(N1, N2).
+
+%% chk_DigitMapName(N, N) ->
+%% chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+%% chk_DigitMapName(N1, N2) ->
+%% case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+%% true ->
+%% not_equal('DigitMapName', N1, N2);
+%% false ->
+%% wrong_type('DigitMapName', N1, N2)
+%% end.
+
+
+%% %% -- DigitMapValue --
+
+%% is_opt_DigitMapValue(V) ->
+%% is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+%% is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+%% shortTimer = Short,
+%% longTimer = Long,
+%% digitMapBody = Body,
+%% durationTimer = Dur}) ->
+%% is_DigitMapValue_startTimer(Start) andalso
+%% is_DigitMapValue_shortTimer(Short) andalso
+%% is_DigitMapValue_longTimer(Long) andalso
+%% is_IA5String(Body) andalso
+%% is_DigitMapValue_durationTimer(Dur);
+%% is_DigitMapValue(_) ->
+%% false.
+
+%% is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+%% is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+%% is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+%% is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+%% is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+%% is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+%% is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+%% is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+%% chk_opt_DigitMapValue(V1, V2) ->
+%% chk_OPTIONAL('DigitMapValue', V1, V2,
+%% fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+%% chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+%% shortTimer = Short1,
+%% longTimer = Long1,
+%% digitMapBody = Body1,
+%% durationTimer = Dur1},
+%% #'DigitMapValue'{startTimer = Start2,
+%% shortTimer = Short2,
+%% longTimer = Long2,
+%% digitMapBody = Body2,
+%% durationTimer = Dur2}) ->
+%% d("chk_DigitMapValue -> entry with"
+%% "~n Start1: ~p"
+%% "~n Start2: ~p"
+%% "~n Short1: ~p"
+%% "~n Short2: ~p"
+%% "~n Long1: ~p"
+%% "~n Long2: ~p"
+%% "~n Body1: ~p"
+%% "~n Body2: ~p"
+%% "~n Dur1: ~p"
+%% "~n Dur2: ~p", [Start1, Start2,
+%% Short1, Short2,
+%% Long1, Long2,
+%% Body1, Body2,
+%% Dur1, Dur2]),
+%% chk_DigitMapValue_startTimer(Start1, Start2),
+%% chk_DigitMapValue_shortTimer(Short1, Short2),
+%% chk_DigitMapValue_longTimer(Long1, Long2),
+%% chk_DigitMapValue_digitMapBody(Body1, Body2),
+%% chk_DigitMapValue_durationTimer(Dur1, Dur2),
+%% ok;
+%% chk_DigitMapValue(V1, V2) ->
+%% wrong_type('DigitMapValue', V1, V2).
+
+%% chk_DigitMapValue_startTimer(T, T) ->
+%% chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+%% chk_DigitMapValue_startTimer(T1, T2) ->
+%% case (is_DigitMapValue_startTimer(T1) andalso
+%% is_DigitMapValue_startTimer(T2)) of
+%% true ->
+%% not_equal('DigitMapValue_startTimer', T1, T2);
+%% false ->
+%% wrong_type('DigitMapValue_startTimer', T1, T2)
+%% end.
+
+%% chk_DigitMapValue_shortTimer(T, T) ->
+%% chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+%% chk_DigitMapValue_shortTimer(T1, T2) ->
+%% case (is_DigitMapValue_shortTimer(T1) andalso
+%% is_DigitMapValue_shortTimer(T2)) of
+%% true ->
+%% not_equal('DigitMapValue_shortTimer', T1, T2);
+%% false ->
+%% wrong_type('DigitMapValue_shortTimer', T1, T2)
+%% end.
+
+%% chk_DigitMapValue_longTimer(T, T) ->
+%% chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+%% chk_DigitMapValue_longTimer(T1, T2) ->
+%% case (is_DigitMapValue_longTimer(T1) andalso
+%% is_DigitMapValue_longTimer(T2)) of
+%% true ->
+%% not_equal('DigitMapValue_longTimer', T1, T2);
+%% false ->
+%% wrong_type('DigitMapValue_longTimer', T1, T2)
+%% end.
+
+%% chk_DigitMapValue_durationTimer(T, T) ->
+%% chk_type(fun is_DigitMapValue_durationTimer/1,
+%% 'DigitMapValue_durationTimer', T);
+%% chk_DigitMapValue_durationTimer(T1, T2) ->
+%% case (is_DigitMapValue_durationTimer(T1) andalso
+%% is_DigitMapValue_durationTimer(T2)) of
+%% true ->
+%% not_equal('DigitMapValue_durationTimer', T1, T2);
+%% false ->
+%% wrong_type('DigitMapValue_durationTimer', T1, T2)
+%% end.
+
+%% chk_DigitMapValue_digitMapBody(B, B) ->
+%% d("chk_DigitMapValue_digitMapBody -> entry with"
+%% "~n B: ~p", [B]),
+%% chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+%% chk_DigitMapValue_digitMapBody(B1, B2) ->
+%% d("chk_DigitMapValue_digitMapBody -> entry with"
+%% "~n B1: ~p"
+%% "~n B2: ~p", [B1, B2]),
+%% case (is_IA5String(B1) andalso is_IA5String(B2)) of
+%% true ->
+%% %% If they are different it could be because
+%% %% of trailing tab's and newline's.
+%% case compare_strings(B1, B2) of
+%% {[], []} ->
+%% ok;
+%% {Str1, []} ->
+%% case strip_tab_and_newline(Str1) of
+%% [] ->
+%% ok;
+%% _ ->
+%% not_equal('DigitMapValue_digitMapBody', B1, B2)
+%% end;
+%% {[], Str2} ->
+%% case strip_tab_and_newline(Str2) of
+%% [] ->
+%% ok;
+%% _ ->
+%% not_equal('DigitMapValue_digitMapBody', B1, B2)
+%% end;
+%% _ ->
+%% not_equal('DigitMapValue_digitMapBody', B1, B2)
+%% end;
+%% false ->
+%% wrong_type('DigitMapValue_digitMapBody', B1, B2)
+%% end.
+
+%% %% -- ServiceChangeParm --
+
+%% is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+%% serviceChangeAddress = A,
+%% serviceChangeVersion = V,
+%% serviceChangeProfile = P,
+%% serviceChangeReason = R,
+%% serviceChangeDelay = D,
+%% serviceChangeMgcId = Id,
+%% timeStamp = TS,
+%% nonStandardData = NSD,
+%% serviceChangeInfo = I}) ->
+%% is_ServiceChangeMethod(M) andalso
+%% is_opt_ServiceChangeAddress(A) andalso
+%% is_opt_INTEGER(V, {range, 0, 99}) andalso
+%% is_opt_ServiceChangeProfile(P) andalso
+%% is_Value(R) andalso
+%% is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+%% is_opt_MId(Id) andalso
+%% is_opt_TimeNotation(TS) andalso
+%% is_opt_NonStandardData(NSD) andalso
+%% is_opt_AuditDescriptor(I);
+%% is_ServiceChangeParm(_) ->
+%% false.
+
+%% chk_ServiceChangeParm(P, P) ->
+%% chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+%% chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+%% serviceChangeAddress = A1,
+%% serviceChangeVersion = V1,
+%% serviceChangeProfile = P1,
+%% serviceChangeReason = R1,
+%% serviceChangeDelay = D1,
+%% serviceChangeMgcId = Id1,
+%% timeStamp = TS1,
+%% nonStandardData = NSD1,
+%% serviceChangeInfo = I1},
+%% #'ServiceChangeParm'{serviceChangeMethod = M2,
+%% serviceChangeAddress = A2,
+%% serviceChangeVersion = V2,
+%% serviceChangeProfile = P2,
+%% serviceChangeReason = R2,
+%% serviceChangeDelay = D2,
+%% serviceChangeMgcId = Id2,
+%% timeStamp = TS2,
+%% nonStandardData = NSD2,
+%% serviceChangeInfo = I2}) ->
+%% validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_Value(R1, R2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_MId(Id1, Id2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+%% 'ServiceChangeParm'),
+%% validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+%% 'ServiceChangeParm'),
+%% ok;
+%% chk_ServiceChangeParm(P1, P2) ->
+%% wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% %% -- ServiceChangeAddress --
+
+%% is_opt_ServiceChangeAddress(A) ->
+%% is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+%% is_ServiceChangeAddress({Tag, Val}) ->
+%% is_ServiceChangeAddress_tag(Tag) andalso
+%% is_ServiceChangeAddress_val(Tag, Val);
+%% is_ServiceChangeAddress(_) ->
+%% false.
+
+%% is_ServiceChangeAddress_tag(Tag) ->
+%% Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+%% mtpAddress],
+%% lists:member(Tag, Tags).
+
+%% is_ServiceChangeAddress_val(portNumber, Val) ->
+%% is_INTEGER(Val, {range, 0, 65535});
+%% is_ServiceChangeAddress_val(ip4Address, Val) ->
+%% is_IP4Address(Val);
+%% is_ServiceChangeAddress_val(ip6Address, Val) ->
+%% is_IP6Address(Val);
+%% is_ServiceChangeAddress_val(domainName, Val) ->
+%% is_DomainName(Val);
+%% is_ServiceChangeAddress_val(deviceName, Val) ->
+%% is_PathName(Val);
+%% is_ServiceChangeAddress_val(mtpAddress, Val) ->
+%% is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+%% chk_opt_ServiceChangeAddress(A1, A2) ->
+%% chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+%% fun is_ServiceChangeAddress/1,
+%% fun chk_ServiceChangeAddress/2).
+
+%% chk_ServiceChangeAddress(A, A) ->
+%% chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+%% chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+%% case (is_ServiceChangeAddress_tag(Tag) andalso
+%% is_ServiceChangeAddress_val(Tag, Val1) andalso
+%% is_ServiceChangeAddress_val(Tag, Val2)) of
+%% true ->
+%% chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('ServiceChangeAddress', A1, A2)
+%% end;
+%% chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+%% case ((is_ServiceChangeAddress_tag(Tag1) andalso
+%% is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+%% (is_ServiceChangeAddress_tag(Tag2) andalso
+%% is_ServiceChangeAddress_val(Tag2, Val2))) of
+%% true ->
+%% not_equal('ServiceChangeAddress', A1, A2);
+%% false ->
+%% wrong_type('ServiceChangeAddress', A1, A2)
+%% end;
+%% chk_ServiceChangeAddress(A1, A2) ->
+%% wrong_type('ServiceChangeAddress', A1, A2).
+
+%% chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+%% validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+%% 'ServiceChangeAddress');
+%% chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+%% validate(fun() -> chk_IP4Address(Val1, Val2) end,
+%% 'ServiceChangeAddress');
+%% chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+%% validate(fun() -> chk_IP6Address(Val1, Val2) end,
+%% 'ServiceChangeAddress');
+%% chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+%% validate(fun() -> chk_DomainName(Val1, Val2) end,
+%% 'ServiceChangeAddress');
+%% chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+%% validate(fun() -> chk_PathName(Val1, Val2) end,
+%% 'ServiceChangeAddress');
+%% chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+%% validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+%% 'ServiceChangeAddress').
+
+
+%% %% -- ServiceChangeResParm --
+
+%% is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+%% serviceChangeAddress = A,
+%% serviceChangeVersion = V,
+%% serviceChangeProfile = P,
+%% timeStamp = TS}) ->
+%% is_opt_MId(Id) andalso
+%% is_opt_ServiceChangeAddress(A) andalso
+%% is_opt_INTEGER(V, {range, 0, 99}) andalso
+%% is_opt_ServiceChangeProfile(P) andalso
+%% is_opt_TimeNotation(TS);
+%% is_ServiceChangeResParm(_) ->
+%% false.
+
+%% chk_ServiceChangeResParm(P, P) ->
+%% chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+%% chk_ServiceChangeResParm(
+%% #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+%% serviceChangeAddress = A1,
+%% serviceChangeVersion = V1,
+%% serviceChangeProfile = P1,
+%% timeStamp = TS1},
+%% #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+%% serviceChangeAddress = A2,
+%% serviceChangeVersion = V2,
+%% serviceChangeProfile = P2,
+%% timeStamp = TS2}) ->
+%% validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+%% validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+%% 'ServiceChangeResParm'),
+%% validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+%% 'ServiceChangeResParm'),
+%% validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+%% 'ServiceChangeResParm'),
+%% validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+%% 'ServiceChangeResParm'),
+%% ok;
+%% chk_ServiceChangeResParm(P1, P2) ->
+%% wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% %% -- ServiceChangeMethod --
+
+%% is_ServiceChangeMethod(M) ->
+%% Methods = [failover, forced, graceful, restart, disconnected, handOff],
+%% lists:member(M, Methods).
+
+%% chk_ServiceChangeMethod(M, M) ->
+%% chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+%% chk_ServiceChangeMethod(M1, M2) ->
+%% case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+%% true ->
+%% not_equal('ServiceChangeMethod', M1, M2);
+%% false ->
+%% wrong_type('ServiceChangeMethod', M1, M2)
+%% end.
+
+
+%% %% -- ServiceChangeProfile --
+
+%% is_opt_ServiceChangeProfile(P) ->
+%% is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+%% is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+%% is_IA5String(N, {range, 1, 67});
+%% is_ServiceChangeProfile(_) ->
+%% false.
+
+%% chk_opt_ServiceChangeProfile(P1, P2) ->
+%% chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+%% fun is_ServiceChangeProfile/1,
+%% fun chk_ServiceChangeProfile/2).
+
+%% chk_ServiceChangeProfile(P, P) ->
+%% chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+%% chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+%% #'ServiceChangeProfile'{profileName = N2}) ->
+%% validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+%% 'ServiceChangeProfile'),
+%% ok;
+%% chk_ServiceChangeProfile(P1, P2) ->
+%% wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% %% -- PackagesDescriptor --
+
+%% is_PackagesDescriptor([]) ->
+%% true;
+%% is_PackagesDescriptor([H|T]) ->
+%% is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+%% is_PackagesDescriptor(_) ->
+%% false.
+
+%% chk_PackagesDescriptor([], []) ->
+%% ok;
+%% chk_PackagesDescriptor([] = D1, D2) ->
+%% not_equal('PackagesDescriptor', D1, D2);
+%% chk_PackagesDescriptor(D1, [] = D2) ->
+%% not_equal('PackagesDescriptor', D1, D2);
+%% chk_PackagesDescriptor([H|T1], [H|T2]) ->
+%% case is_PackagesItem(H) of
+%% true ->
+%% chk_PackagesDescriptor(T1, T2);
+%% false ->
+%% wrong_type('PackagesDescriptor_val', H)
+%% end;
+%% chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_PackagesItem(H1, H2) end,
+%% 'PackagesDescriptor_val'),
+%% chk_PackagesDescriptor(T1, T2);
+%% chk_PackagesDescriptor(D1, D2) ->
+%% wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% %% -- PackagesItem --
+
+%% is_PackagesItem(#'PackagesItem'{packageName = N,
+%% packageVersion = V}) ->
+%% is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+%% is_PackagesItem(_) ->
+%% false.
+
+%% chk_PackagesItem(I, I) ->
+%% chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+%% chk_PackagesItem(#'PackagesItem'{packageName = N1,
+%% packageVersion = V1},
+%% #'PackagesItem'{packageName = N2,
+%% packageVersion = V2}) ->
+%% validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+%% validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+%% ok;
+%% chk_PackagesItem(I1, I2) ->
+%% wrong_type('PackagesItem', I1, I2).
+
+
+%% %% -- StatisticsDescriptor --
+
+%% is_StatisticsDescriptor([]) ->
+%% true;
+%% is_StatisticsDescriptor([H|T]) ->
+%% is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+%% is_StatisticsDescriptor(_) ->
+%% false.
+
+%% chk_StatisticsDescriptor([], []) ->
+%% ok;
+%% chk_StatisticsDescriptor([] = D1, D2) ->
+%% not_equal('StatisticsDescriptor', D1, D2);
+%% chk_StatisticsDescriptor(D1, [] = D2) ->
+%% not_equal('StatisticsDescriptor', D1, D2);
+%% chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+%% case is_StatisticsParameter(H) of
+%% true ->
+%% chk_StatisticsDescriptor(T1, T2);
+%% false ->
+%% wrong_type('StatisticsDescriptor_val', H)
+%% end;
+%% chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+%% validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+%% 'StatisticsDescriptor_val'),
+%% chk_StatisticsDescriptor(T1, T2);
+%% chk_StatisticsDescriptor(D1, D2) ->
+%% wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% %% -- StatisticsParameter --
+
+%% is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+%% statValue = V}) ->
+%% is_PkgdName(N) andalso is_opt_Value(V);
+%% is_StatisticsParameter(_) ->
+%% false.
+
+%% chk_StatisticsParameter(P, P) ->
+%% chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+%% chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+%% statValue = V1},
+%% #'StatisticsParameter'{statName = N2,
+%% statValue = V2}) ->
+%% validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+%% validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+%% ok;
+%% chk_StatisticsParameter(P1, P2) ->
+%% wrong_type('StatisticsParameter', P1, P2).
+
+
+%% %% -- NonStandardData --
+
+%% is_opt_NonStandardData(asn1_NOVALUE) ->
+%% true;
+%% is_opt_NonStandardData(NSD) ->
+%% is_NonStandardData(NSD).
+
+%% %% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% %% data = D}) ->
+%% %% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% %% is_NonStandardData(_) ->
+%% %% false.
+
+%% is_NonStandardData(_) ->
+%% true.
+
+%% chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+%% true;
+%% chk_opt_NonStandardData(NSD1, NSD2) ->
+%% chk_NonStandardData(NSD1, NSD2).
+
+%% chk_NonStandardData(NSD, NSD) ->
+%% chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% %% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% %% data = D1},
+%% %% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% %% data = D2}) ->
+%% %% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% %% 'NonStandardData'),
+%% %% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% %% ok;
+%% %% chk_NonStandardData(NSD1, NSD2) ->
+%% %% wrong_type('NonStandardData', NSD1, NSD2).
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% %% -- NonStandardIdentifier --
+
+%% %% is_NonStandardIdentifier({Tag, Val}) ->
+%% %% is_NonStandardIdentifier_tag(Tag) andalso
+%% %% is_NonStandardIdentifier_val(Tag, Val);
+%% %% is_NonStandardIdentifier(_) ->
+%% %% false.
+
+%% %% is_NonStandardIdentifier_tag(Tag) ->
+%% %% Tags = [object, h221NonStandard, experimental],
+%% %% lists:member(Tag, Tags).
+
+%% %% is_NonStandardIdentifier_val(object, Val) ->
+%% %% is_OBJECT_IDENTIFIER(Val);
+%% %% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% %% is_H221NonStandard(Val);
+%% %% is_NonStandardIdentifier_val(experimental, Val) ->
+%% %% is_IA5String(Val, {exact, 8}).
+
+%% %% chk_NonStandardIdentifier(Id, Id) ->
+%% %% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% %% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% %% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% %% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% %% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% %% true ->
+%% %% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% %% false ->
+%% %% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% %% end;
+%% %% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% %% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% %% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% %% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% %% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% %% true ->
+%% %% not_equal('NonStandardIdentifier', Id1, Id2);
+%% %% false ->
+%% %% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% %% end;
+%% %% chk_NonStandardIdentifier(Id1, Id2) ->
+%% %% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% %% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% %% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% %% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% %% chk_H221NonStandard(Val1, Val2);
+%% %% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% %% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% %% -- H221NonStandard --
+
+%% %% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% %% t35CountryCode2 = CC2,
+%% %% t35Extension = Ext,
+%% %% manufacturerCode = MC}) ->
+%% %% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% %% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% %% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% %% is_INTEGER(Ext, {range, 0, 65535});
+%% %% is_H221NonStandard(_) ->
+%% %% false.
+
+%% %% chk_H221NonStandard(NS, NS) ->
+%% %% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% %% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% %% t35CountryCode2 = CC21,
+%% %% t35Extension = Ext1,
+%% %% manufacturerCode = MC1},
+%% %% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% %% t35CountryCode2 = CC22,
+%% %% t35Extension = Ext2,
+%% %% manufacturerCode = MC2}) ->
+%% %% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% %% 'H221NonStandard'),
+%% %% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% %% 'H221NonStandard'),
+%% %% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% %% 'H221NonStandard'),
+%% %% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% %% 'H221NonStandard'),
+%% %% ok;
+%% %% chk_H221NonStandard(NS1, NS2) ->
+%% %% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% %% -- TimeNotation --
+
+%% is_opt_TimeNotation(asn1_NOVALUE) ->
+%% true;
+%% is_opt_TimeNotation(TN) ->
+%% is_TimeNotation(TN).
+
+%% is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+%% is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+%% is_TimeNotation(_) ->
+%% false.
+
+%% chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+%% ok;
+%% chk_opt_TimeNotation(TN1, TN2) ->
+%% chk_TimeNotation(TN1, TN2).
+
+%% chk_TimeNotation(TN, TN) ->
+%% chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+%% chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+%% #'TimeNotation'{date = D2, time = T2}) ->
+%% validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+%% validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+%% ok;
+%% chk_TimeNotation(TN1, TN2) ->
+%% wrong_type('TimeNotation', TN1, TN2).
+
+
+%% %% -- Value --
+
+%% is_opt_Value(V) ->
+%% is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+%% chk_opt_Value(V1, V2) ->
+%% chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+%% chk_Value(V, V) ->
+%% case is_Value(V) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type('Value', V, V)
+%% end;
+%% chk_Value(V1, V2) ->
+%% case (is_Value(V1) andalso is_Value(V2)) of
+%% true ->
+%% not_equal('Value', V1, V2);
+%% false ->
+%% wrong_type('Value', V1, V2)
+%% end.
+
+
+%% %% ----------------------------------------------------------------------
+%% %% Basic type check functions
+%% %% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ lists:member(B, [true, false]).
+
+%% chk_opt_BOOLEAN(B1, B2) ->
+%% chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+%% chk_BOOLEAN(B, B) ->
+%% chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+%% chk_BOOLEAN(B1, B2) ->
+%% case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+%% true ->
+%% not_equal('BOOLEAN', B1, B2);
+%% false ->
+%% wrong_type('BOOLEAN', B1, B2)
+%% end.
+
+
+%% is_IA5String(S) when list(S) ->
+%% true;
+%% is_IA5String(_) ->
+%% false.
+
+%% is_IA5String(S, _) when list(S) ->
+%% true;
+%% is_IA5String(_, _) ->
+%% false.
+
+%% %% chk_IA5String(S, S) ->
+%% %% chk_type(fun is_IA5String/1, 'IA5String', S);
+%% %% chk_IA5String(S1, S2) ->
+%% %% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+%% %% true ->
+%% %% not_equal('IA5String', S1, S2);
+%% %% false ->
+%% %% wrong_type('IA5String', S1, S2)
+%% %% end.
+
+%% chk_IA5String(S, S, R) ->
+%% chk_type(fun is_IA5String/2, 'IA5String', S, R);
+%% chk_IA5String(S1, S2, R) ->
+%% case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+%% true ->
+%% not_equal('IA5String', S1, S2);
+%% false ->
+%% wrong_type('IA5String', S1, S2)
+%% end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) andalso (length(L) =:= Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) andalso (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) andalso (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) andalso (Min =< length(L)) andalso (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% %% chk_OCTET_STRING(L1, L2) ->
+%% %% chk_OCTET_STRING(L1, L2, any).
+
+%% chk_OCTET_STRING(L, L, R) ->
+%% chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+%% chk_OCTET_STRING(L1, L2, R) ->
+%% case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+%% true ->
+%% not_equal('OCTET STRING', L1, L2);
+%% false ->
+%% wrong_type('OCTET STRING', L1, L2)
+%% end.
+
+
+%% %% is_OBJECT_IDENTIFIER(_) ->
+%% %% true.
+
+%% %% chk_OBJECT_IDENTIFIER(X, X) ->
+%% %% ok;
+%% %% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% %% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+%% is_opt_NULL(N) ->
+%% is_OPTIONAL(fun is_NULL/1, N).
+
+%% is_NULL('NULL') ->
+%% true;
+%% is_NULL(_) ->
+%% false.
+
+%% chk_opt_NULL(N1, N2) ->
+%% chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+%% chk_NULL(N, N) ->
+%% chk_type(fun is_NULL/1, 'NULL', N);
+%% chk_NULL(N1, N2) ->
+%% case (is_NULL(N1) andalso is_NULL(N2)) of
+%% true ->
+%% not_equal('NULL', N1, N2);
+%% false ->
+%% wrong_type('NULL', N1, N2)
+%% end.
+
+
+is_opt_INTEGER(I, R) ->
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min}) when is_integer(I) andalso is_integer(Min) andalso (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max}) when is_integer(I) andalso is_integer(Max) andalso (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Min =< I) andalso
+ (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+%% chk_opt_INTEGER(I1, I2, R) ->
+%% chk_OPTIONAL('INTEGER', I1, I2,
+%% fun(X) -> is_INTEGER(X, R) end,
+%% fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+%% chk_INTEGER(I, I, R) ->
+%% chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+%% chk_INTEGER(I1, I2, R) ->
+%% case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+%% true ->
+%% not_equal('INTEGER', I1, I2);
+%% false ->
+%% wrong_type('INTEGER', I1, I2)
+%% end.
+
+
+%% %% ----------------------------------------------------------------------
+%% %% Various utility functions
+%% %% ----------------------------------------------------------------------
+
+
+%% to_lower([C|Cs]) when C >= $A, C =< $Z ->
+%% [C+($a-$A)|to_lower(Cs)];
+%% to_lower([C|Cs]) ->
+%% [C|to_lower(Cs)];
+%% to_lower([]) ->
+%% [].
+
+
+%% validate(F, Type) when function(F) ->
+%% case (catch F()) of
+%% {error, Reason} ->
+%% error({Type, Reason});
+%% ok ->
+%% ok
+%% end.
+
+
+%% chk_type(F, T, V) when function(F), atom(T) ->
+%% case F(V) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type(T, V)
+%% end.
+
+%% chk_type(F, T, V1, V2) when function(F), atom(T) ->
+%% case F(V1, V2) of
+%% true ->
+%% ok;
+%% false ->
+%% wrong_type(T, V1)
+%% end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+%% chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+%% ok;
+%% chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when function(IS) ->
+%% case IS(V2) of
+%% true ->
+%% not_equal(Type, V1, V2);
+%% false ->
+%% wrong_type(Type, V1, V2)
+%% end;
+%% chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when function(IS) ->
+%% case IS(V1) of
+%% true ->
+%% not_equal(Type, V1, V2);
+%% false ->
+%% wrong_type(Type, V1, V2)
+%% end;
+%% chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when function(CHK) ->
+%% CHK(V1, V2).
+
+
+%% %% ----------------------------------------------------------------------
+
+%% compare_strings([] = L1, L2) ->
+%% {L1, L2};
+%% compare_strings(L1, [] = L2) ->
+%% {L1, L2};
+%% compare_strings([H|T1], [H|T2]) ->
+%% compare_strings(T1, T2);
+%% compare_strings(L1, L2) ->
+%% {L1, L2}.
+
+%% strip_tab_and_newline([]) ->
+%% [];
+%% strip_tab_and_newline([$\n|T]) ->
+%% strip_tab_and_newline(T);
+%% strip_tab_and_newline([$\t|T]) ->
+%% strip_tab_and_newline(T);
+%% strip_tab_and_newline([H|T]) ->
+%% [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+%% atmost_once(Type, Val) ->
+%% error({atmost_once, {Type, Val}}).
+
+%% wrong_type(Type, Val) ->
+%% error({wrong_type, {Type, Val}}).
+
+%% wrong_type(Type, Val1, Val2) ->
+%% error({wrong_type, {Type, Val1, Val2}}).
+
+%% not_equal(What, Val1, Val2) ->
+%% error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_msg_v2_lib.erl b/lib/megaco/test/megaco_test_msg_v2_lib.erl
new file mode 100644
index 0000000000..b680bc869a
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_v2_lib.erl
@@ -0,0 +1,7037 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_v2_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_v2.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([chk_MegacoMessage/2,
+ cre_MegacoMessage/1, cre_MegacoMessage/2,
+ cre_AuthenticationHeader/3,
+ cre_Message/3,
+ cre_ErrorDescriptor/1, cre_ErrorDescriptor/2,
+ cre_ErrorCode/1,
+ cre_ErrorText/1,
+ cre_ContextID/1,
+ cre_Transaction/1,
+ cre_TransactionId/1,
+ cre_TransactionRequest/2,
+ cre_TransactionPending/1,
+ cre_TransactionReply/2, cre_TransactionReply/3,
+ cre_TransactionAck/1, cre_TransactionAck/2,
+ cre_ActionRequest/2, cre_ActionRequest/3, cre_ActionRequest/4,
+ cre_ActionReply/2, cre_ActionReply/3, cre_ActionReply/4,
+ cre_ContextRequest/0, cre_ContextRequest/1, cre_ContextRequest/2,
+ cre_ContextRequest/3,
+ cre_ContextAttrAuditRequest/0, cre_ContextAttrAuditRequest/3,
+ cre_CommandRequest/1, cre_CommandRequest/2, cre_CommandRequest/3,
+ cre_Command/2,
+ cre_CommandReply/2,
+ cre_TopologyRequest/3, cre_TopologyRequest/4,
+ cre_AmmRequest/2,
+ cre_AmmDescriptor/1,
+ cre_AmmsReply/1, cre_AmmsReply/2,
+ cre_SubtractRequest/1, cre_SubtractRequest/2,
+ cre_AuditRequest/2,
+ cre_AuditReply/1,
+ cre_AuditResult/2,
+ cre_AuditReturnParameter/1,
+ cre_AuditDescriptor/0, cre_AuditDescriptor/1, cre_AuditDescriptor/2,
+ cre_IndAuditParameter/1,
+ cre_IndAudMediaDescriptor/0, cre_IndAudMediaDescriptor/1,
+ cre_IndAudMediaDescriptor/2,
+ cre_IndAudStreamDescriptor/2,
+ cre_IndAudStreamParms/0, cre_IndAudStreamParms/1,
+ cre_IndAudStreamParms/3,
+ cre_IndAudLocalControlDescriptor/0,
+ cre_IndAudLocalControlDescriptor/4,
+ cre_IndAudPropertyParm/1,
+ cre_IndAudLocalRemoteDescriptor/1,
+ cre_IndAudLocalRemoteDescriptor/2,
+ cre_IndAudPropertyGroup/1,
+ cre_IndAudTerminationStateDescriptor/1,
+ cre_IndAudTerminationStateDescriptor/3,
+ cre_IndAudEventsDescriptor/1, cre_IndAudEventsDescriptor/2,
+ cre_IndAudEventsDescriptor/3,
+ cre_IndAudEventBufferDescriptor/1,
+ cre_IndAudEventBufferDescriptor/2,
+ cre_IndAudSignalsDescriptor/1,
+ cre_IndAudSeqSigList/1,
+ cre_IndAudSeqSigList/2,
+ cre_IndAudSignal/1, cre_IndAudSignal/2,
+ cre_IndAudDigitMapDescriptor/0, cre_IndAudDigitMapDescriptor/1,
+ cre_IndAudStatisticsDescriptor/1,
+ cre_IndAudPackagesDescriptor/2,
+ cre_NotifyRequest/2, cre_NotifyRequest/3,
+ cre_NotifyReply/1, cre_NotifyReply/2,
+ cre_ObservedEventsDescriptor/2,
+ cre_ObservedEvent/2, cre_ObservedEvent/3, cre_ObservedEvent/4,
+ cre_EventName/1,
+ cre_EventParameter/2, cre_EventParameter/4,
+ cre_ServiceChangeRequest/2,
+ cre_ServiceChangeReply/2,
+ cre_ServiceChangeResult/1,
+ %% cre_WildcardField/1,
+ cre_TerminationID/2,
+ cre_TerminationIDList/1,
+ cre_MediaDescriptor/0, cre_MediaDescriptor/1, cre_MediaDescriptor/2,
+ cre_StreamDescriptor/2,
+ cre_StreamParms/0, cre_StreamParms/1, cre_StreamParms/2,
+ cre_StreamParms/3,
+ cre_LocalControlDescriptor/1, cre_LocalControlDescriptor/2,
+ cre_LocalControlDescriptor/4,
+ cre_StreamMode/1,
+ cre_PropertyParm/2, cre_PropertyParm/4,
+ cre_Name/1,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+ cre_Relation/1,
+ cre_LocalRemoteDescriptor/1,
+ cre_PropertyGroup/1,
+ cre_TerminationStateDescriptor/1,
+ cre_TerminationStateDescriptor/2,
+ cre_TerminationStateDescriptor/3,
+ cre_EventBufferControl/1,
+ cre_ServiceState/1,
+ cre_MuxDescriptor/2, %% cre_MuxDescriptor/3,
+ cre_MuxType/1,
+ cre_StreamID/1,
+ cre_EventsDescriptor/0, cre_EventsDescriptor/2,
+ cre_RequestedEvent/1,
+ cre_RequestedEvent/2, cre_RequestedEvent/3, cre_RequestedEvent/4,
+ cre_RequestedActions/0,
+ cre_RequestedActions/1, cre_RequestedActions/4,
+ cre_EventDM/1,
+ cre_SecondEventsDescriptor/1, cre_SecondEventsDescriptor/2,
+ cre_SecondRequestedEvent/2, cre_SecondRequestedEvent/3,
+ cre_SecondRequestedEvent/4,
+ cre_SecondRequestedActions/0, cre_SecondRequestedActions/1,
+ cre_SecondRequestedActions/2, cre_SecondRequestedActions/3,
+ cre_EventBufferDescriptor/1,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+ cre_SignalsDescriptor/1,
+ cre_SignalRequest/1,
+ cre_SeqSigList/2,
+ cre_Signal/1, cre_Signal/2, cre_Signal/7,
+ cre_SignalType/1,
+ cre_SignalName/1,
+ cre_NotifyCompletion/1,
+ cre_SigParameter/2, cre_SigParameter/4,
+ cre_RequestID/1,
+ cre_ModemDescriptor/2, %% cre_ModemDescriptor/3,
+ cre_ModemType/1,
+ cre_DigitMapDescriptor/0, cre_DigitMapDescriptor/1,
+ cre_DigitMapDescriptor/2,
+ cre_DigitMapName/1,
+ cre_DigitMapValue/1, cre_DigitMapValue/4, cre_DigitMapValue/5,
+ cre_ServiceChangeParm/2, cre_ServiceChangeParm/4,
+ cre_ServiceChangeParm/9,
+ cre_ServiceChangeAddress/2,
+ cre_ServiceChangeResParm/0, cre_ServiceChangeResParm/2,
+ cre_ServiceChangeResParm/5,
+ cre_ServiceChangeMethod/1,
+ cre_ServiceChangeProfile/1, cre_ServiceChangeProfile/2,
+ cre_PackagesDescriptor/1,
+ cre_PackagesItem/2,
+ cre_StatisticsDescriptor/1,
+ cre_StatisticsParameter/1, cre_StatisticsParameter/2,
+%% cre_NonStandardData/2,
+%% cre_NonStandardIdentifier/1,
+%% cre_H221NonStandard/4,
+ cre_TimeNotation/2,
+ cre_Value/1,
+ cre_BOOLEAN/1
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') andalso
+ is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+cre_AuthenticationHeader(SPI, SN, AD) ->
+ #'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+cre_ErrorDescriptor(EC) when is_integer(EC) ->
+ #'ErrorDescriptor'{errorCode = EC}.
+
+cre_ErrorDescriptor(EC, ET) when is_integer(EC) andalso is_list(ET) ->
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_ErrorCode(C) when is_integer(C) andalso (0 =< C) andalso (C =< 65535) ->
+ C;
+cre_ErrorCode(C) ->
+ exit({invalid_ErrorCode, C}).
+
+cre_ErrorText(T) when is_list(T) ->
+ T.
+
+cre_ContextID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA}.
+
+cre_TransactionId(Val) when (0 =< Val) andalso (Val =< 4294967295) ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs) when is_integer(TransID) andalso is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+cre_TransactionPending(TransID) when is_integer(TransID) ->
+ #'TransactionPending'{transactionId = TransID}.
+
+cre_TransactionReply(TransID, ED)
+ when is_integer(TransID) andalso is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, ARs)
+ when is_integer(TransID) andalso is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionReply(TransID, IAR, ED)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, IAR, ARs)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res}.
+
+cre_TransactionAck(FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck}.
+
+cre_TransactionAck(FirstAck, FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck};
+cre_TransactionAck(FirstAck, LastAck) ->
+ #'TransactionAck'{firstAck = FirstAck,
+ lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) andalso is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) andalso
+ is_record(CAAR, 'ContextAttrAuditRequest') andalso
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_record(CAAR, 'ContextAttrAuditRequest') andalso
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionReply(CtxID, CmdReps)
+ when is_integer(CtxID) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(ED, 'ErrorDescriptor') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ commandReply = CmdReps};
+cre_ActionReply(CtxID, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ is_record(ED, 'ErrorDescriptor') andalso
+ is_record(CtxReq, 'ContextRequest') andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ContextRequest() ->
+ #'ContextRequest'{}.
+
+cre_ContextRequest(Prio) when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) ->
+ #'ContextRequest'{priority = Prio};
+cre_ContextRequest(Em) when (Em =:= true) andalso (Em =:= false) andalso (Em =:= asn1_NOVALUE) ->
+ #'ContextRequest'{emergency = Em};
+cre_ContextRequest(Top) when is_list(Top) ->
+ #'ContextRequest'{topologyReq = Top}.
+
+cre_ContextRequest(Prio, Em)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em};
+cre_ContextRequest(Prio, Top)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) andalso is_list(Top) ->
+ #'ContextRequest'{priority = Prio,
+ topologyReq = Top}.
+
+cre_ContextRequest(Prio, Em, Top)
+ when (is_integer(Prio) and (0 =< Prio) and (Prio =< 15)) and
+ ((Em == true) or (Em == false) or (Em == asn1_NOVALUE)) and
+ is_list(Top) ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top}.
+
+cre_ContextAttrAuditRequest() ->
+ #'ContextAttrAuditRequest'{}.
+
+cre_ContextAttrAuditRequest(Top, Em, Prio)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) ->
+ #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio}.
+
+cre_CommandRequest(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_CommandRequest(Cmd, Opt)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt}.
+
+cre_CommandRequest(Cmd, Opt, WR)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+ ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}.
+
+cre_Command(addReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(moveReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(modReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(subtractReq = Tag, Req)
+ when is_record(Req, 'SubtractRequest') ->
+ {Tag, Req};
+cre_Command(auditCapRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(auditValueRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(notifyReq = Tag, Req)
+ when is_record(Req, 'NotifyRequest') ->
+ {Tag, Req};
+cre_Command(serviceChangeReq = Tag, Req)
+ when is_record(Req, 'ServiceChangeRequest') ->
+ {Tag, Req}.
+
+cre_CommandReply(addReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(moveReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(modReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(subtractReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(auditCapReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(auditValueReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(notifyReply = Tag, Rep)
+ when is_record(Rep, 'NotifyReply') ->
+ {Tag, Rep};
+cre_CommandReply(serviceChangeReply = Tag, Rep)
+ when is_record(Rep, 'ServiceChangeReply') ->
+ {Tag, Rep}.
+
+cre_TopologyRequest(From, To, Dir)
+ when is_record(From, 'TerminationID') and
+ is_record(To, 'TerminationID') and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir}.
+
+cre_TopologyRequest(From, To, Dir, SID)
+ when is_record(From, 'TerminationID') and
+ is_record(To, 'TerminationID') and
+ ((Dir == bothway) or (Dir == isolate) or (Dir == oneway)) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = Dir,
+ streamID = SID}.
+
+cre_AmmRequest(TermIDs, Descs) when is_list(TermIDs) andalso is_list(Descs) ->
+ #'AmmRequest'{terminationID = TermIDs,
+ descriptors = Descs}.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end.
+
+cre_AmmsReply(TermIDs) when is_list(TermIDs) ->
+ #'AmmsReply'{terminationID = TermIDs}.
+
+cre_AmmsReply(TermIDs, TAs) when is_list(TermIDs) andalso is_list(TAs) ->
+ #'AmmsReply'{terminationID = TermIDs,
+ terminationAudit = TAs}.
+
+cre_SubtractRequest(TermIDs) when is_list(TermIDs) ->
+ #'SubtractRequest'{terminationID = TermIDs}.
+
+cre_SubtractRequest(TermIDs, Audit)
+ when is_list(TermIDs) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'SubtractRequest'{terminationID = TermIDs,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TermID, Audit)
+ when is_record(TermID, megaco_term_id) andalso is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TermID,
+ auditDescriptor = Audit}.
+
+cre_AuditReply(TermIDs) when is_list(TermIDs) ->
+ {contextAuditResult, TermIDs};
+cre_AuditReply(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {error, ED};
+cre_AuditReply(Audit) when is_record(Audit, 'AuditResult') ->
+ {auditResult, Audit}.
+
+cre_AuditResult(TermID, TAs)
+ when is_record(TermID, megaco_term_id) andalso is_list(TAs) ->
+ #'AuditResult'{terminationID = TermID,
+ terminationAuditResult = TAs}.
+
+cre_AuditReturnParameter(D) when is_record(D, 'ErrorDescriptor') ->
+ {errorDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'EventSpec') ->
+ {eventBufferDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ObservedEventsDescriptor') ->
+ {observedEventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ {statisticsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'PackagesItem') ->
+ {packagesDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'AuditDescriptor') ->
+ {emptyDescriptors, D};
+cre_AuditReturnParameter([H|_] = D) when is_tuple(H) ->
+ {signalsDescriptor, D}.
+
+cre_AuditDescriptor() ->
+ #'AuditDescriptor'{}.
+
+cre_AuditDescriptor([H|_] = AT) when is_atom(H) ->
+ #'AuditDescriptor'{auditToken = AT};
+cre_AuditDescriptor(APT) ->
+ #'AuditDescriptor'{auditPropertyToken = APT}.
+
+cre_AuditDescriptor(AT, APT) ->
+ #'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}.
+
+cre_IndAuditParameter(D) when is_record(D, 'IndAudMediaDescriptor') ->
+ {indAudMediaDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventsDescriptor') ->
+ {indAudEventsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventBufferDescriptor') ->
+ {indAudEventBufferDescriptor, D};
+cre_IndAuditParameter({signal, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter({seqSigList, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudDigitMapDescriptor') ->
+ {indAudDigitMapDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudStatisticsDescriptor') ->
+ {indAudStatisticsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudPackagesDescriptor') ->
+ {indAudPackagesDescriptor, D}.
+
+cre_IndAudMediaDescriptor() ->
+ #'IndAudMediaDescriptor'{}.
+
+cre_IndAudMediaDescriptor(TSD)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudMediaDescriptor'{termStateDescr = TSD};
+cre_IndAudMediaDescriptor(Parms) when is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{streams = Streams};
+cre_IndAudMediaDescriptor(Descs) when is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{streams = Streams}.
+
+cre_IndAudMediaDescriptor(TSD, Parms)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso
+ is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_IndAudMediaDescriptor(TSD, Descs)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') andalso is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_IndAudStreamDescriptor(SID, Parms)
+ when is_integer(SID) andalso is_record(Parms, 'IndAudStreamParms') ->
+ #'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}.
+
+cre_IndAudStreamParms() ->
+ #'IndAudStreamParms'{}.
+
+cre_IndAudStreamParms(LCD) when is_record(LCD, 'IndAudLocalControlDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD}.
+
+cre_IndAudStreamParms(LCD, L, R)
+ when is_record(LCD, 'IndAudLocalControlDescriptor') andalso
+ is_record(L, 'IndAudLocalRemoteDescriptor') andalso
+ is_record(R, 'IndAudLocalRemoteDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = L,
+ remoteDescriptor = R}.
+
+cre_IndAudLocalControlDescriptor() ->
+ #'IndAudLocalControlDescriptor'{}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_IndAudPropertyParm(PkgdName) when is_list(PkgdName) ->
+ #'IndAudPropertyParm'{name = PkgdName}.
+
+cre_IndAudLocalRemoteDescriptor(Grps)
+ when is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+cre_IndAudLocalRemoteDescriptor(GrpID, Grps)
+ when is_integer(GrpID) andalso (0 =< GrpID) andalso (GrpID =< 65535) andalso is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = GrpID,
+ propGrps = Grps}.
+
+cre_IndAudPropertyGroup([]) ->
+ [];
+cre_IndAudPropertyGroup([H|_] = PG)
+ when is_record(H, 'IndAudPropertyParm') ->
+ PG.
+
+cre_IndAudTerminationStateDescriptor([] = PP) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+cre_IndAudTerminationStateDescriptor([H|_] = PP)
+ when is_record(H, 'IndAudPropertyParm') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}.
+
+cre_IndAudEventsDescriptor(PkgdName)
+ when is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName)
+ when is_integer(RID) andalso is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+cre_IndAudEventsDescriptor(PkgdName, SID)
+ when is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+ when is_integer(RID) andalso is_list(PkgdName) andalso is_integer(SID) ->
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = PkgdName,
+ streamID = SID}.
+
+cre_IndAudEventBufferDescriptor(EventName) when is_list(EventName) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+cre_IndAudEventBufferDescriptor(EventName, SID)
+ when is_list(EventName) andalso is_integer(SID) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSignal') ->
+ {signal, S};
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSeqSigList') ->
+ {seqSigList, S}.
+
+cre_IndAudSeqSigList(ID) when is_integer(ID) andalso (0=< ID) andalso (ID =< 65535) ->
+ #'IndAudSeqSigList'{id = ID}.
+
+cre_IndAudSeqSigList(ID, S)
+ when is_integer(ID) andalso
+ (0 =< ID) andalso (ID =< 65535) andalso
+ is_record(S, 'IndAudSignal') ->
+ #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+cre_IndAudSignal(SigName) when is_list(SigName) ->
+ #'IndAudSignal'{signalName = SigName}.
+
+cre_IndAudSignal(SigName, SID) when is_list(SigName) andalso is_integer(SID) ->
+ #'IndAudSignal'{signalName = SigName, streamID = SID}.
+
+cre_IndAudDigitMapDescriptor() ->
+ #'IndAudDigitMapDescriptor'{}.
+
+cre_IndAudDigitMapDescriptor(DMN) when is_list(DMN) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+cre_IndAudStatisticsDescriptor(StatName) when is_list(StatName) ->
+ #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+cre_IndAudPackagesDescriptor(N, V)
+ when is_list(N) andalso
+ is_integer(V) andalso
+ (0 =< V) andalso
+ (V =< 99) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+cre_NotifyRequest(TermIDs, D)
+ when is_list(TermIDs) andalso is_record(D, 'ObservedEventsDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D}.
+
+cre_NotifyRequest(TermIDs, D, ED)
+ when is_list(TermIDs) andalso
+ is_record(D, 'ObservedEventsDescriptor') andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D,
+ errorDescriptor = ED}.
+
+cre_NotifyReply(TermIDs) when is_list(TermIDs) ->
+ #'NotifyReply'{terminationID = TermIDs}.
+
+cre_NotifyReply(TermIDs, ED)
+ when is_list(TermIDs) andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyReply'{terminationID = TermIDs,
+ errorDescriptor = ED}.
+
+cre_ObservedEventsDescriptor(RID, [H|_] = L)
+ when is_integer(RID) andalso is_record(H, 'ObservedEvent') ->
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = L}.
+
+cre_ObservedEvent(EN, EPL)
+ when is_list(EN) andalso is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL};
+cre_ObservedEvent(EN, TN)
+ when is_list(EN) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL)
+ when is_list(EN) andalso
+ is_integer(SID) andalso
+ is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL};
+cre_ObservedEvent(EN, EPL, TN)
+ when is_list(EN) andalso
+ is_list(EPL) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL, TN)
+ when is_list(EN) andalso
+ is_integer(SID) andalso
+ is_list(EPL) andalso
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+cre_ServiceChangeRequest(TermIDs, SCP)
+ when is_list(TermIDs) andalso
+ is_record(SCP, 'ServiceChangeParm') ->
+ #'ServiceChangeRequest'{terminationID = TermIDs,
+ serviceChangeParms = SCP}.
+
+cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+ when is_list(TermIDs) andalso is_atom(Tag) andalso is_tuple(R) ->
+ #'ServiceChangeReply'{terminationID = TermIDs,
+ serviceChangeResult = SCR}.
+
+cre_ServiceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED};
+cre_ServiceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP}.
+
+%% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+cre_TerminationID(W, ID)
+ when is_list(W) andalso
+ is_list(ID) andalso (1 =< length(ID)) andalso (length(ID) =< 8) ->
+ #'TerminationID'{wildcard = W,
+ id = ID}.
+
+cre_TerminationIDList(L) when is_list(L) ->
+ L.
+
+cre_MediaDescriptor() ->
+ #'MediaDescriptor'{}.
+
+cre_MediaDescriptor(TSD) when is_record(TSD, 'TerminationStateDescriptor') ->
+ #'MediaDescriptor'{termStateDescr = TSD};
+cre_MediaDescriptor(SP) when is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{streams = Streams};
+cre_MediaDescriptor([H|_] = SDs) when is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{streams = Streams}.
+
+cre_MediaDescriptor(TSD, SP)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_MediaDescriptor(TSD, [H|_] = SDs)
+ when is_record(TSD, 'TerminationStateDescriptor') andalso
+ is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_StreamDescriptor(SID, SP) when is_integer(SID) andalso is_record(SP, 'StreamParms') ->
+ #'StreamDescriptor'{streamID = SID,
+ streamParms = SP}.
+
+cre_StreamParms() ->
+ #'StreamParms'{}.
+
+cre_StreamParms(LCD) when is_record(LCD, 'LocalControlDescriptor') ->
+ #'StreamParms'{localControlDescriptor = LCD};
+cre_StreamParms(LD) when is_record(LD, 'LocalRemoteDescriptor') ->
+ #'StreamParms'{localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD, RD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}.
+
+cre_LocalControlDescriptor(SM) when is_atom(SM) ->
+ #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+cre_LocalControlDescriptor([H|_] = PP) when is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, [H|_] = PP)
+ when is_atom(SM) andalso is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+ when is_atom(SM) and
+ ((RV == true) or (RV == false) or (RV == asn1_NOVALUE)) and
+ ((RG == true) or (RG == false) or (RG == asn1_NOVALUE)) and
+ is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_StreamMode(sendOnly = M) ->
+ M;
+cre_StreamMode(recvOnly = M) ->
+ M;
+cre_StreamMode(sendRecv = M) ->
+ M;
+cre_StreamMode(inactive = M) ->
+ M;
+cre_StreamMode(loopBack = M) ->
+ M.
+
+cre_PropertyParm(N, [H|_] = V) when is_list(N) andalso is_list(H) ->
+ #'PropertyParm'{name = N, value = V}.
+
+cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+ when is_list(N) andalso is_list(H) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+ when is_list(N) andalso is_list(H) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+cre_Name(N) when is_list(N) andalso (length(N) =:= 2) ->
+ N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) and (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) and (length(PackageName) =< 64)) and
+ (is_list(ItemID) and (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+cre_Relation(greaterThan = R) ->
+ R;
+cre_Relation(smallerThan = R) ->
+ R;
+cre_Relation(unequalTo = R) ->
+ R.
+
+cre_LocalRemoteDescriptor([H|_] = PGs) when is_list(H) ->
+ #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+cre_PropertyGroup([H|_] = PG) when is_record(H, 'PropertyParm') ->
+ PG.
+
+cre_TerminationStateDescriptor([H|_] = PPs) when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+ when is_record(H, 'PropertyParm') andalso
+ ((EMC == off) or (EMC == lockStep)) and
+ ((SS == test) or (SS == outOfSvc) or (SS == inSvc)) ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EMC,
+ serviceState = SS}.
+
+cre_EventBufferControl(off = EBC) ->
+ EBC;
+cre_EventBufferControl(lockStep = EBC) ->
+ EBC.
+
+cre_ServiceState(test = SS) ->
+ SS;
+cre_ServiceState(outOfSvc = SS) ->
+ SS;
+cre_ServiceState(inSvc = SS) ->
+ SS.
+
+cre_MuxDescriptor(MT, [H|_] = TL)
+ when is_atom(MT) andalso is_record(H, 'TerminationID') ->
+ #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+cre_MuxType(h221 = MT) ->
+ MT;
+cre_MuxType(h223 = MT) ->
+ MT;
+cre_MuxType(h226 = MT) ->
+ MT;
+cre_MuxType(v76 = MT) ->
+ MT;
+cre_MuxType(nx64k = MT) ->
+ MT.
+
+cre_StreamID(Val) when 0 =< Val, Val =< 65535 ->
+ Val;
+cre_StreamID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+%% RequestID must be present if eventList is non empty
+cre_EventsDescriptor() ->
+ #'EventsDescriptor'{eventList = []}.
+
+cre_EventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'RequestedEvent') ->
+ #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_RequestedEvent(N) ->
+ #'RequestedEvent'{pkgdName = N}.
+
+cre_RequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_RequestedEvent(N, EA)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions')->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA}.
+
+
+cre_RequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_RequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'RequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedActions() ->
+ #'RequestedActions'{}.
+
+cre_RequestedActions(KA)
+ when (KA == true) or (KA == true) or (KA == asn1_NOVALUE) ->
+ #'RequestedActions'{keepActive = KA};
+cre_RequestedActions(SE)
+ when is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE) ->
+ #'RequestedActions'{secondEvent = SE};
+cre_RequestedActions(SD)
+ when is_list(SD) or (SD == asn1_NOVALUE) ->
+ #'RequestedActions'{signalsDescriptor = SD};
+cre_RequestedActions({Tag, _} = EDM)
+ when is_atom(Tag) or (EDM == asn1_NOVALUE) ->
+ #'RequestedActions'{eventDM = EDM}.
+
+cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}.
+
+cre_EventDM(N) when is_list(N) ->
+ {digitMapName, N};
+cre_EventDM(V) when is_record(V, 'DigitMapValue') ->
+ {digitMapValue, V}.
+
+cre_SecondEventsDescriptor([H|_] = EL)
+ when is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{eventList = EL}.
+
+cre_SecondEventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) andalso is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_SecondRequestedEvent(N, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, EA, [H|_] = EPL)
+ when is_list(N) andalso
+ is_integer(SID) andalso
+ is_record(EA, 'SecondRequestedActions') andalso
+ is_record(H, 'EventParameter') ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedActions() ->
+ #'SecondRequestedActions'{}.
+
+cre_SecondRequestedActions(KA)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA};
+cre_SecondRequestedActions(SD) when is_list(SD) ->
+ #'SecondRequestedActions'{signalsDescriptor = SD};
+cre_SecondRequestedActions({Tag, _} = EDM) when is_atom(Tag) ->
+ #'SecondRequestedActions'{eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, {Tag, _} = EDM)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) ->
+ #'SecondRequestedActions'{keepActive = KA, eventDM = EDM}.
+
+cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag),
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}.
+
+cre_EventBufferDescriptor([H|_] = D) when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL) when is_list(N) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) andalso is_integer(SID) andalso is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+cre_SignalsDescriptor(D) when is_list(D) ->
+ D.
+
+cre_SignalRequest(S) when is_record(S, 'Signal') ->
+ {signal, S};
+cre_SignalRequest(S) when is_record(S, 'SeqSigList') ->
+ {seqSigList, S}.
+
+cre_SeqSigList(ID, [H|_] = SL)
+ when is_integer(ID) andalso (0 =< ID) andalso (ID =< 65535) andalso is_record(H, 'Signal') ->
+ #'SeqSigList'{id = ID, signalList = SL}.
+
+cre_Signal(N) when is_list(N) ->
+ #'Signal'{signalName = N}.
+
+cre_Signal(N, [H|_] = SPL) when is_list(N) andalso is_record(H, 'SigParameter') ->
+ #'Signal'{signalName = N,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, [H|_] = SPL)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asm1_NOVALUE)) and
+ is_list(NC) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_record(H, 'SigParameter') ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}.
+
+cre_SignalType(brief = ST) ->
+ ST;
+cre_SignalType(onOff = ST) ->
+ ST;
+cre_SignalType(timeOut = ST) ->
+ ST.
+
+cre_SignalName(N) ->
+ cre_PkgdName(N).
+
+cre_NotifyCompletion(L) when is_list(L) ->
+ Vals = [onTimeOut, onInterruptByEvent,
+ onInterruptByNewSignalDescr, otherReason],
+ F = fun(E) -> case lists:member(E, Vals) of
+ true ->
+ ok;
+ false ->
+ exit({invalid_NotifyCompletion, E})
+ end
+ end,
+ lists:foreach(F, L),
+ L.
+
+cre_SigParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'SigParameter'{sigParameterName = N, value = V}.
+
+cre_SigParameter(N, V, relation = Tag, R)
+ when is_list(N) andalso is_list(V) andalso is_atom(R) ->
+ EI = {Tag, R},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, range = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, sublist = Tag, B)
+ when is_list(N) andalso is_list(V) andalso is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+cre_RequestID(Val) when 0 =< Val, Val =< 4294967295 ->
+ Val;
+cre_RequestID(Val) ->
+ exit({invalid_RequestID, Val}).
+
+cre_ModemDescriptor(MTL, MPL) when is_list(MTL) andalso is_list(MPL) ->
+ #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemDescriptor(MTL, MPL, NSD)
+%% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+cre_ModemType(v18 = MT) ->
+ MT;
+cre_ModemType(v22 = MT) ->
+ MT;
+cre_ModemType(v22bis = MT) ->
+ MT;
+cre_ModemType(v32 = MT) ->
+ MT;
+cre_ModemType(v32bis = MT) ->
+ MT;
+cre_ModemType(v34 = MT) ->
+ MT;
+cre_ModemType(v90 = MT) ->
+ MT;
+cre_ModemType(v91 = MT) ->
+ MT;
+cre_ModemType(synchISDN = MT) ->
+ MT.
+
+cre_DigitMapDescriptor() ->
+ #'DigitMapDescriptor'{}.
+
+cre_DigitMapDescriptor(N) when is_list(N) ->
+ #'DigitMapDescriptor'{digitMapName = N};
+cre_DigitMapDescriptor(V) when is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = V}.
+
+cre_DigitMapDescriptor(N, V) when is_list(N) andalso is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+cre_DigitMapName(N) ->
+ cre_Name(N).
+
+cre_DigitMapValue(DMB) when is_list(DMB) ->
+ #'DigitMapValue'{digitMapBody = DMB}.
+
+cre_DigitMapValue(Start, Short, Long, DMB) ->
+ cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+ when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+ (Start == asn1_NOVALUE)) and
+ ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+ (Short == asn1_NOVALUE)) and
+ ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+ (Long == asn1_NOVALUE)) and
+ is_list(DMB) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+ (Dur == asn1_NOVALUE)) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = DMB,
+ durationTimer = Dur}.
+
+cre_ServiceChangeParm(M, R) when is_atom(M) andalso is_list(R) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R}.
+
+cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+ cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE).
+
+%% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I)
+ when is_atom(M) and
+ ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ is_list(R) and
+ ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+ (D == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+ (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Mid,
+ timeStamp = TS,
+ serviceChangeInfo = I};
+ _ ->
+ exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeAddress(portNumber = Tag, P)
+ when is_integer(P) andalso (0 =< P) andalso (P =< 65535) ->
+ {Tag, P};
+cre_ServiceChangeAddress(ip4Address = Tag, A) when is_record(A, 'IP4Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(ip6Address = Tag, A) when is_record(A, 'IP6Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(domainName = Tag, N) when is_record(N, 'DomainName') ->
+ {Tag, N};
+cre_ServiceChangeAddress(deviceName = Tag, N) when is_list(N) ->
+ {Tag, N};
+cre_ServiceChangeAddress(mtpAddress = Tag, A) when is_list(A) ->
+ {Tag, A}.
+
+cre_ServiceChangeResParm() ->
+ #'ServiceChangeResParm'{}.
+cre_ServiceChangeResParm(Addr, Prof) ->
+ cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+ Prof, asn1_NOVALUE).
+cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+ when ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ timeStamp = TS};
+ _ ->
+ exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeMethod(failover = M) ->
+ M;
+cre_ServiceChangeMethod(forced = M) ->
+ M;
+cre_ServiceChangeMethod(graceful = M) ->
+ M;
+cre_ServiceChangeMethod(restart = M) ->
+ M;
+cre_ServiceChangeMethod(disconnected = M) ->
+ M;
+cre_ServiceChangeMethod(handOff = M) ->
+ M.
+
+%% The version field is added to make it look more like ABNF
+cre_ServiceChangeProfile(N) ->
+ cre_ServiceChangeProfile(N, 1).
+
+cre_ServiceChangeProfile(N, V)
+ when is_list(N) andalso is_integer(V) andalso (0 =< V) andalso (V =< 99) ->
+ #'ServiceChangeProfile'{profileName = N, version = V}.
+
+cre_PackagesDescriptor([H|_] = D) when is_record(H, 'PackagesItem') ->
+ D.
+
+cre_PackagesItem(N, Ver)
+ when is_list(N) andalso
+ is_integer(Ver) andalso
+ (0 =< Ver) andalso (Ver =< 99) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = Ver}.
+
+cre_StatisticsDescriptor([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ D.
+
+cre_StatisticsParameter(N) when is_list(N) ->
+ #'StatisticsParameter'{statName = N}.
+
+cre_StatisticsParameter(N, V) when is_list(N) andalso is_list(V) ->
+ #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% {h221NonStandard, H221};
+%% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% {object, Obj};
+%% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% {experimental, Exp}.
+
+%% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}.
+
+cre_TimeNotation(D, T)
+ when is_list(D) andalso (length(D) =:= 8) andalso is_list(T) andalso (length(T) =:= 8) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_Value([H|_] = V) when is_list(H) ->
+ V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% -- MegacoMessage --
+
+is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}) ->
+ is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+is_MegacoMessage(_) ->
+ false.
+
+
+chk_MegacoMessage(M, M) ->
+ chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type('MegacoMessage', M1, M2).
+
+
+%% -- AuthenticationHeader --
+
+is_opt_AuthenticationHeader(AH) ->
+ is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}) ->
+ is_SecurityParmIndex(SPI) andalso
+ is_SequenceNum(SN) andalso
+ is_AuthData(AD);
+is_AuthenticationHeader(_) ->
+ false.
+
+%% This stuff is not really used, so make it simple...
+chk_opt_AuthenticationHeader(A1, A2) ->
+ chk_OPTIONAL('AuthenticationHeader', A1, A2,
+ fun is_AuthenticationHeader/1,
+ fun chk_AuthenticationHeader/2).
+
+chk_AuthenticationHeader(A, A) ->
+ chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+chk_AuthenticationHeader(A1, A2) ->
+ case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+ true ->
+ not_equal('AuthenticationHeader', A1, A2);
+ false ->
+ wrong_type('AuthenticationHeader', A1, A2)
+ end.
+
+
+%% -- SecurityParmIndex --
+
+is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- SequenceNum --
+
+is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- AuthData --
+
+is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% -- Message --
+
+is_Message(#'Message'{version = V,
+ mId = MID,
+ messageBody = Body}) ->
+ is_INTEGER(V, {range, 0, 99}) andalso
+ is_MId(MID) andalso
+ is_Message_messageBody(Body);
+is_Message(_) ->
+ false.
+
+chk_Message(M,M) when is_record(M,'Message') ->
+ ok;
+chk_Message(#'Message'{version = V1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = V2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'Message'),
+ validate(fun() -> chk_MId(MID1, MID2) end, 'Message'),
+ chk_Message_messageBody(Body1, Body2),
+ ok;
+chk_Message(M1, M2) ->
+ wrong_type('Message', M1, M2).
+
+
+is_Message_messageBody({Tag, Val}) ->
+ is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val);
+is_Message_messageBody(_) ->
+ false.
+
+is_Message_messageBody_tag(Tag) ->
+ Tags = [messageError, transactions],
+ lists:member(Tag, Tags).
+
+is_Message_messageBody_val(messageError, Val) ->
+ is_ErrorDescriptor(Val);
+is_Message_messageBody_val(transactions, Val) ->
+ is_Message_messageBody_transactions(Val).
+
+is_Message_messageBody_transactions([]) ->
+ true;
+is_Message_messageBody_transactions([H|T]) ->
+ is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+is_Message_messageBody_transactions(_) ->
+ false.
+
+chk_Message_messageBody(B, B) ->
+ chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+ case (is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val1) andalso
+ is_Message_messageBody_val(Tag, Val2)) of
+ true ->
+ chk_Message_messageBody_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+ case ((is_Message_messageBody_tag(Tag1) andalso
+ is_Message_messageBody_val(Tag1, Val1)) andalso
+ (is_Message_messageBody_tag(Tag2) andalso
+ is_Message_messageBody_val(Tag2, Val2))) of
+ true ->
+ not_equal('Message_messageBody', B1, B2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody(B1, B2) ->
+ wrong_type('Message_messageBody', B1, B2).
+
+chk_Message_messageBody_val(messageError, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'Message_messageBody');
+chk_Message_messageBody_val(transactions, Val1, Val2) ->
+ chk_Message_messageBody_transactions(Val1, Val2).
+
+chk_Message_messageBody_transactions([], []) ->
+ ok;
+chk_Message_messageBody_transactions([] = T1, T2) ->
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions(T1, [] = T2) ->
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+ case is_Transaction(H) of
+ true ->
+ chk_Message_messageBody_transactions(T1, T2);
+ false ->
+ wrong_type('Message_messageBody_transactions_val', H)
+ end;
+chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Transaction(H1, H2) end,
+ 'Message_messageBody_transactions_val'),
+ chk_Message_messageBody_transactions(T1, T2);
+chk_Message_messageBody_transactions(T1, T2) ->
+ wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% -- MId --
+
+is_opt_MId(M) ->
+ is_OPTIONAL(fun is_MId/1, M).
+
+is_MId({Tag, Val}) ->
+ is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+is_MId(_) ->
+ false.
+
+is_MId_tag(Tag) ->
+ Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+ lists:member(Tag, Tags).
+
+is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+is_MId_val(domainName, Val) -> is_DomainName(Val);
+is_MId_val(deviceName, Val) -> is_PathName(Val);
+is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+chk_opt_MId(M1, M2) ->
+ chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+chk_MId(M, M) ->
+ chk_type(fun is_MId/1, 'MId', M);
+chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+ case (is_MId_tag(Tag) andalso
+ is_MId_val(Tag, Val1) andalso
+ is_MId_val(Tag, Val2)) of
+ true ->
+ chk_MId_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+ case ((is_MId_tag(Tag1) andalso
+ is_MId_val(Tag1, Val1)) andalso
+ (is_MId_tag(Tag2) andalso
+ is_MId_val(Tag2, Val2))) of
+ true ->
+ not_equal('MId', M1, M2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId(M1, M2) ->
+ wrong_type('MId', M1, M2).
+
+chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% -- DomainName --
+
+is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+ is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+is_DomainName(_) ->
+ false.
+
+chk_DomainName(N, N) ->
+ ok;
+chk_DomainName(N1, N2) ->
+ not_equal('DomainName', N1, N2).
+
+
+%% -- IP4Address --
+
+is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 4}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP4Address(_) ->
+ false.
+
+chk_IP4Address(A, A) ->
+ ok;
+chk_IP4Address(A1, A2) ->
+ not_equal('IP4Address', A1, A2).
+
+
+%% -- IP6Address --
+
+is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 16}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP6Address(_) ->
+ false.
+
+chk_IP6Address(A, A) ->
+ ok;
+chk_IP6Address(A1, A2) ->
+ not_equal('IP6Address', A1, A2).
+
+
+%% -- PathName --
+
+is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+chk_PathName(N, N) ->
+ ok;
+chk_PathName(N1, N2) ->
+ not_equal('PathName', N1, N2).
+
+
+%% -- Transaction --
+
+is_Transaction({Tag, Val}) ->
+ is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+is_Transaction(_) ->
+ false.
+
+is_Transaction_tag(Tag) ->
+ Tags = [transactionRequest,
+ transactionPending,
+ transactionReply,
+ transactionResponseAck],
+ lists:member(Tag, Tags).
+
+is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+chk_Transaction({Tag, Val} = Trans, {Tag, Val}) ->
+ case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Transaction', Trans, Trans)
+ end;
+chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+ case (is_Transaction_tag(Tag) and
+ is_Transaction_val(Tag, Val1) and
+ is_Transaction_val(Tag, Val2)) of
+ true ->
+ chk_Transaction_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+ case ((is_Transaction_tag(Tag1) andalso
+ is_Transaction_val(Tag1, Val1)) andalso
+ (is_Transaction_tag(Tag2) andalso
+ is_Transaction_val(Tag2, Val2))) of
+ true ->
+ not_equal('Transaction', Trans1, Trans2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction(Trans1, Trans2) ->
+ wrong_type('Transaction', Trans1, Trans2).
+
+chk_Transaction_val(transactionRequest, T1, T2) ->
+ chk_TransactionRequest(T1, T2);
+chk_Transaction_val(transactionPending, T1, T2) ->
+ chk_TransactionPending(T1, T2);
+chk_Transaction_val(transactionReply, T1, T2) ->
+ chk_TransactionReply(T1,T2);
+chk_Transaction_val(transactionResponseAck, T1, T2) ->
+ chk_TransactionResponseAck(T1, T2).
+
+
+%% -- TransactionId --
+
+is_opt_TransactionId(TID) ->
+ is_OPTIONAL(fun is_TransactionId/1, TID).
+
+is_TransactionId(TID) -> is_INTEGER(TID, {range, 0, 4294967295}).
+
+chk_opt_TransactionId(TID1, TID2) ->
+ chk_OPTIONAL('TransactionId', TID1, TID2,
+ fun is_TransactionId/1, fun chk_TransactionId/2).
+
+chk_TransactionId(TID, TID) ->
+ chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+chk_TransactionId(TID1, TID2) ->
+ case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+ true ->
+ not_equal('TransactionId', TID1, TID2);
+ false ->
+ wrong_type('TransactionId', TID1, TID2)
+ end.
+
+
+%% -- TransactionRequest --
+
+is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+ actions = Acts}) ->
+ is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+is_TransactionRequest(_) ->
+ false.
+
+chk_TransactionRequest(T, T) ->
+ chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+ actions = Acts1},
+ #'TransactionRequest'{transactionId = TID2,
+ actions = Acts2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+ chk_TransactionRequest_actions(Acts1, Acts2),
+ ok;
+chk_TransactionRequest(T1, T2) ->
+ wrong_type('TransactionRequest', T1, T2).
+
+is_TransactionRequest_actions([]) ->
+ true;
+is_TransactionRequest_actions([H|T]) ->
+ is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+is_TransactionRequest_actions(_) ->
+ false.
+
+chk_TransactionRequest_actions([], []) ->
+ ok;
+chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+ case is_ActionRequest(H) of
+ true ->
+ chk_TransactionRequest_actions(T1, T2);
+ false ->
+ wrong_type('TransactionRequest_actions_val', H)
+ end;
+chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionRequest(H1, H2) end,
+ 'TransactionRequest_actions_val'),
+ chk_TransactionRequest_actions(T1, T2);
+chk_TransactionRequest_actions(Acts1, Acts2) ->
+ wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% -- TransactionPending --
+
+is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+ is_TransactionId(TID);
+is_TransactionPending(_) ->
+ false.
+
+chk_TransactionPending(T, T) ->
+ chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+ #'TransactionPending'{transactionId = TID2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+ ok;
+chk_TransactionPending(T1, T2) ->
+ wrong_type('TransactionPending', T1, T2).
+
+
+%% -- TransactionReply --
+
+is_TransactionReply(#'TransactionReply'{transactionId = TID,
+ immAckRequired = IAR,
+ transactionResult = TR}) ->
+ is_TransactionId(TID) andalso
+ is_opt_NULL(IAR) andalso
+ is_TransactionReply_transactionResult(TR);
+is_TransactionReply(_) ->
+ false.
+
+chk_TransactionReply(T, T) ->
+ chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+ immAckRequired = IAR1,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TID2,
+ immAckRequired = IAR2,
+ transactionResult = TR2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+ validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+ chk_TransactionReply_transactionResult(TR1, TR2),
+ ok;
+chk_TransactionReply(T1, T2) ->
+ wrong_type('TransactionReply', T1, T2).
+
+is_TransactionReply_transactionResult({Tag, Val}) ->
+ is_TransactionReply_transactionResult_tag(Tag) andalso
+ is_TransactionReply_transactionResult_val(Tag, Val);
+is_TransactionReply_transactionResult(_) ->
+ false.
+
+is_TransactionReply_transactionResult_tag(T) ->
+ lists:member(T, [transactionError, actionReplies]).
+
+is_TransactionReply_transactionResult_val(transactionError, V) ->
+ is_ErrorDescriptor(V);
+is_TransactionReply_transactionResult_val(actionReplies, V) ->
+ is_TransactionReply_actionReplies(V).
+
+chk_TransactionReply_transactionResult(Res, Res) ->
+ chk_type(fun is_TransactionReply_transactionResult/1,
+ 'TransactionReply_transactionResult', Res);
+chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+ {Tag, Val2} = Res2) ->
+ case (is_TransactionReply_transactionResult_tag(Tag) and
+ is_TransactionReply_transactionResult_val(Tag, Val1) and
+ is_TransactionReply_transactionResult_val(Tag, Val2)) of
+ true ->
+ chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+ {Tag2, Val2} = Res2) ->
+ case ((is_TransactionReply_transactionResult_tag(Tag1) and
+ is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+ (is_TransactionReply_transactionResult_tag(Tag2) and
+ is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('TransactionReply_transactionResult', Res1, Res2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult(Res1, Res2) ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+ validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+ 'TransactionReply_transactionResult');
+chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+ validate(fun() -> chk_TransactionReply_actionReplies(R1, R2) end,
+ 'TransactionReply_transactionResult').
+
+is_TransactionReply_actionReplies([]) ->
+ true;
+is_TransactionReply_actionReplies([H|T]) ->
+ is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+is_TransactionReply_actionReplies(_) ->
+ false.
+
+chk_TransactionReply_actionReplies([], []) ->
+ ok;
+chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+ case is_ActionReply(H) of
+ true ->
+ chk_TransactionReply_actionReplies(T1, T2);
+ false ->
+ wrong_type('TransactionReply_actionReplies_val', H)
+ end;
+chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionReply(H1, H2) end,
+ 'TransactionReply_actionReplies_val'),
+ chk_TransactionReply_actionReplies(T1, T2);
+chk_TransactionReply_actionReplies(AR1, AR2) ->
+ wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% -- TransactionResponseAck --
+
+is_TransactionResponseAck([]) ->
+ true;
+is_TransactionResponseAck([H|T]) ->
+ is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+is_TransactionResponseAck(_) ->
+ false.
+
+chk_TransactionResponseAck([], []) ->
+ ok;
+chk_TransactionResponseAck([] = AR1, AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck(AR1, [] = AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck([H|T1], [H|T2]) ->
+ case is_TransactionAck(H) of
+ true ->
+ chk_TransactionResponseAck(T1, T2);
+ false ->
+ wrong_type('TransactionResponseAck_val', H)
+ end;
+chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TransactionAck(H1, H2) end,
+ 'TransactionResponseAck'),
+ chk_TransactionResponseAck(T1, T2);
+chk_TransactionResponseAck(AR1, AR2) ->
+ wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% -- TransactionAck --
+
+is_TransactionAck(#'TransactionAck'{firstAck = F,
+ lastAck = L}) ->
+ is_TransactionId(F) andalso is_opt_TransactionId(L);
+is_TransactionAck(_) ->
+ false.
+
+chk_TransactionAck(T, T) ->
+ chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+ validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+ ok;
+chk_TransactionAck(T1, T2) ->
+ wrong_type('TransactionAck', T1, T2).
+
+
+%% -- ErrorDescriptor --
+
+is_opt_ErrorDescriptor(V) ->
+ is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text}) ->
+ is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+is_ErrorDescriptor(_) ->
+ false.
+
+chk_opt_ErrorDescriptor(E1, E2) ->
+ chk_OPTIONAL('ErrorDescriptor', E1, E2,
+ fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+chk_ErrorDescriptor(E, E) ->
+ chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1},
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2}) ->
+ chk_ErrorCode(Code1, Code2),
+ chk_opt_ErrorText(Text1, Text2),
+ ok;
+chk_ErrorDescriptor(E1, E2) ->
+ wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% -- ErrorCode --
+
+is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+chk_ErrorCode(C, C) ->
+ case is_ErrorCode(C) of
+ true ->
+ ok;
+ false ->
+ wrong_type(errorCode, C, C)
+ end;
+chk_ErrorCode(C1, C2) ->
+ case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+ true ->
+ not_equal(errorCode, C1, C2);
+ false ->
+ wrong_type(errorCode, C1, C2)
+ end.
+
+
+%% -- ErrorText --
+
+is_opt_ErrorText(V) ->
+ is_OPTIONAL(fun is_ErrorText/1, V).
+
+is_ErrorText(V) -> is_IA5String(V).
+
+chk_opt_ErrorText(T1, T2) ->
+ chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+chk_ErrorText(T, T) ->
+ chk_type(fun is_ErrorText/1, 'ErrorText', T);
+chk_ErrorText(T1, T2) ->
+ case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+ true ->
+ case {to_lower(T1), to_lower(T2)} of
+ {T, T} ->
+ ok;
+ _ ->
+ not_equal('ErrorText', T1, T2)
+ end;
+ false ->
+ wrong_type('ErrorText', T1, T2)
+ end.
+
+
+%% -- ContextID --
+
+is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+chk_ContextID(Id, Id) ->
+ chk_type(fun is_ContextID/1, 'ContextID', Id);
+chk_ContextID(Id1, Id2) ->
+ case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+ true ->
+ not_equal('ContextID', Id1, Id2);
+ false ->
+ wrong_type('ContextID', Id1, Id2)
+ end.
+
+
+%% -- ActionRequest --
+
+is_ActionRequest(#'ActionRequest'{contextId = Id,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = AuditReq,
+ commandRequests = CmdReqs}) ->
+ is_ContextID(Id) andalso
+ is_opt_ContextRequest(CtxReq) andalso
+ is_opt_ContextAttrAuditRequest(AuditReq) andalso
+ is_ActionRequest_commandRequests(CmdReqs);
+is_ActionRequest(_) ->
+ false.
+
+chk_ActionRequest(A, A) ->
+ chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+ validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+ validate(fun() ->
+ chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+ end,
+ 'ActionRequest'),
+ chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+ ok.
+
+
+is_ActionRequest_commandRequests([]) ->
+ true;
+is_ActionRequest_commandRequests([H|T]) ->
+ is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+is_ActionRequest_commandRequests(_) ->
+ false.
+
+chk_ActionRequest_commandRequests([], []) ->
+ ok;
+chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+ case is_CommandRequest(H) of
+ true ->
+ chk_ActionRequest_commandRequests(T1, T2);
+ false ->
+ wrong_type('ActionRequest_commandRequest_val', H)
+ end;
+chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandRequest(H1, H2) end,
+ 'ActionRequest_commandRequests_val'),
+ chk_ActionRequest_commandRequests(T1, T2);
+chk_ActionRequest_commandRequests(R1, R2) ->
+ wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% -- ActionReply --
+
+is_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep}) ->
+ is_ContextID(Id) andalso
+ is_opt_ErrorDescriptor(ED) andalso
+ is_opt_ContextRequest(CtxRep) andalso
+ is_ActionReply_commandReply(CmdRep);
+is_ActionReply(_) ->
+ false.
+
+is_ActionReply_commandReply([]) ->
+ true;
+is_ActionReply_commandReply([H|T]) ->
+ is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+is_ActionReply_commandReply(_) ->
+ false.
+
+chk_ActionReply(A, A) ->
+ chk_type(fun is_ActionReply/1, 'ActionReply', A);
+chk_ActionReply(#'ActionReply'{contextId = Id1,
+ errorDescriptor = ED1,
+ contextReply = CtxRep1,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = Id2,
+ errorDescriptor = ED2,
+ contextReply = CtxRep2,
+ commandReply = CmdRep2}) ->
+ chk_ContextID(Id1, Id2),
+ chk_opt_ErrorDescriptor(ED1, ED2),
+ chk_opt_ContextRequest(CtxRep1, CtxRep2),
+ chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+chk_ActionReply_commandReply([], []) ->
+ ok;
+chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+ case is_CommandReply(H) of
+ true ->
+ chk_ActionReply_commandReply(T1, T2);
+ false ->
+ wrong_type('ActionReply_commandReply_val', H)
+ end;
+chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandReply(H1, H2) end,
+ 'ActionReply_commandReply_val'),
+ chk_ActionReply_commandReply(T1, T2);
+chk_ActionReply_commandReply(R1, R2) ->
+ wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% -- ContextRequest --
+
+is_opt_ContextRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextRequest(V) ->
+ is_ContextRequest(V).
+
+is_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReq}) ->
+ is_ContextRequest_priority(Prio) andalso
+ is_ContextRequest_emergency(Em) andalso
+ is_ContextRequest_topologyReq(TopReq);
+is_ContextRequest(_) ->
+ false.
+
+is_ContextRequest_priority(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_priority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextRequest_emergency(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_emergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_topologyReq([]) ->
+ true;
+is_ContextRequest_topologyReq([H|T]) ->
+ is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+is_ContextRequest_topologyReq(_) ->
+ false.
+
+chk_opt_ContextRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextRequest(R, R) ->
+ chk_ContextRequest(R, R).
+
+chk_ContextRequest(R, R) ->
+ chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1},
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2}) ->
+ chk_ContextRequest_priority(Prio1, Prio2),
+ chk_ContextRequest_emergency(Em1, Em2),
+ chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+ ok;
+chk_ContextRequest(R1, R2) ->
+ wrong_type('ContextRequest', R1, R2).
+
+
+chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_priority(P, P) ->
+ chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+chk_ContextRequest_priority(P1, P2) ->
+ case (is_ContextRequest_priority(P1) andalso
+ is_ContextRequest_priority(P2)) of
+ true ->
+ not_equal('ContextRequest_priority', P1, P2);
+ false ->
+ wrong_type(contextRequest_priority, P1, P2)
+ end.
+
+
+chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_emergency(E, E) ->
+ chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+chk_ContextRequest_emergency(E1, E2) ->
+ case (is_ContextRequest_emergency(E1) andalso
+ is_ContextRequest_emergency(E2)) of
+ true ->
+ not_equal('ContextRequest_emergency', E1, E2);
+ false ->
+ wrong_type('ContextRequest_emergency', E1, E2)
+ end.
+
+chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_topologyReq([], []) ->
+ ok;
+chk_ContextRequest_topologyReq([] = T1, T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq(T1, [] = T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+ case is_TopologyRequest(H) of
+ true ->
+ chk_ContextRequest_topologyReq(T1, T2);
+ false ->
+ wrong_type('ContextRequest_topologyReq_val', H)
+ end;
+chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TopologyRequest(H1, H2) end,
+ 'ContextRequest_topologyReq_val'),
+ chk_ContextRequest_topologyReq(T1, T2);
+chk_ContextRequest_topologyReq(T1, T2) ->
+ wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+%% -- ContextAttrAuditRequest --
+
+is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextAttrAuditRequest(V) ->
+ is_ContextAttrAuditRequest(V).
+
+is_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T,
+ emergency = E,
+ priority = P}) ->
+ is_opt_NULL(T) andalso is_opt_NULL(E) andalso is_opt_NULL(P);
+is_ContextAttrAuditRequest(_) ->
+ false.
+
+chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextAttrAuditRequest(R1, R2) ->
+ chk_ContextAttrAuditRequest(R1, R2).
+
+chk_ContextAttrAuditRequest(R, R) ->
+ chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+chk_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1},
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2}) ->
+ validate(fun() -> chk_opt_NULL(T1, T2) end,
+ 'ContextAttrAuditRequest_topology'),
+ validate(fun() -> chk_opt_NULL(E1, E2) end,
+ 'ContextAttrAuditRequest_emergency'),
+ validate(fun() -> chk_opt_NULL(P1, P2) end,
+ 'ContextAttrAuditRequest_priority'),
+ ok.
+
+
+%% -- CommandRequest --
+
+is_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}) ->
+ is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+is_CommandRequest(_) ->
+ false.
+
+chk_CommandRequest(C, C) ->
+ chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+ optional = Opt1,
+ wildcardReturn = WR1},
+ #'CommandRequest'{command = Cmd2,
+ optional = Opt2,
+ wildcardReturn = WR2}) ->
+ validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+ ok;
+chk_CommandRequest(R1, R2) ->
+ wrong_type('CommandRequest', R1, R2).
+
+
+%% -- Command --
+
+is_Command({Tag, Val}) ->
+ is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+is_Command(_) ->
+ false.
+
+is_Command_tag(Tag) ->
+ Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+ auditValueRequest, notifyReq, serviceChangeReq],
+ lists:member(Tag, Tags).
+
+is_Command_val(addReq, V) -> is_AmmRequest(V);
+is_Command_val(moveReq, V) -> is_AmmRequest(V);
+is_Command_val(modReq, V) -> is_AmmRequest(V);
+is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+chk_Command(Cmd, Cmd) ->
+ chk_type(fun is_Command/1, 'Command', Cmd);
+chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_Command_tag(Tag) andalso
+ is_Command_val(Tag, Val1) andalso
+ is_Command_val(Tag, Val2)) of
+ true ->
+ chk_Command_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+ (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+ true ->
+ not_equal('Command', Cmd1, Cmd2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command(Cmd1, Cmd2) ->
+ wrong_type('Command', Cmd1, Cmd2).
+
+
+chk_Command_val(addReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+chk_Command_val(moveReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+chk_Command_val(modReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+chk_Command_val(subtractReq, R1, R2) ->
+ validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+chk_Command_val(auditCapRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+chk_Command_val(auditValueRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end,
+ 'Command_auditValueRequest');
+chk_Command_val(notifyReq, R1, R2) ->
+ validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+chk_Command_val(serviceChangeReq, R1, R2) ->
+ validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+ 'Command_serviceChangeReq').
+
+
+%% -- CommandReply --
+
+is_CommandReply({Tag, Val}) ->
+ is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+is_CommandReply(_) ->
+ false.
+
+is_CommandReply_tag(Tag) ->
+ Tags = [addReply, moveReply, modReply, subtractReply,
+ auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+ lists:member(Tag, Tags).
+
+is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+ case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('CommandReply', Cmd)
+ end;
+chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_CommandReply_tag(Tag) andalso
+ is_CommandReply_val(Tag, Val1) andalso
+ is_CommandReply_val(Tag, Val2)) of
+ true ->
+ chk_CommandReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_CommandReply_tag(Tag1) andalso
+ is_CommandReply_val(Tag1, Val1)) andalso
+ (is_CommandReply_tag(Tag2) andalso
+ is_CommandReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('CommandReply', Cmd1, Cmd2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply(Cmd1, Cmd2) ->
+ wrong_type('CommandReply', Cmd1, Cmd2).
+
+chk_CommandReply_val(addReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+chk_CommandReply_val(moveReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+chk_CommandReply_val(modReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+chk_CommandReply_val(subtractReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+chk_CommandReply_val(auditCapReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditCapReply');
+chk_CommandReply_val(auditValueReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditValueReply');
+chk_CommandReply_val(notifyReply, V1, V2) ->
+ validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+ validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+ 'CommandReply_serviceChangeReply').
+
+
+%% -- TopologyRequest --
+
+is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+ terminationTo = T,
+ topologyDirection = D,
+ streamID = S}) ->
+ is_TerminationID(F) andalso
+ is_TerminationID(T) andalso
+ is_TopologyRequest_topologyDirection(D) andalso
+ is_opt_StreamID(S);
+is_TopologyRequest(_) ->
+ false.
+
+is_TopologyRequest_topologyDirection(D) ->
+ lists:member(D, [bothway, isolate, oneway]).
+
+
+chk_TopologyRequest(T, T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = D1,
+ streamID = S1},
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = D2,
+ streamID = S2}) ->
+ validate(fun() -> chk_TerminationID(F1, F2) end,
+ 'TopologyRequest_terminationFrom'),
+ validate(fun() -> chk_TerminationID(T1, T2) end,
+ 'TopologyRequest_terminationTo'),
+ chk_TopologyRequest_topologyDirection(D1,D2),
+ validate(fun() -> chk_StreamID(S1, S2) end, 'TopologyRequest_streamID'),
+ ok.
+
+chk_TopologyRequest_topologyDirection(D, D) ->
+ case is_TopologyRequest_topologyDirection(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D)
+ end;
+chk_TopologyRequest_topologyDirection(D1, D2) ->
+ case (is_TopologyRequest_topologyDirection(D1) andalso
+ is_TopologyRequest_topologyDirection(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirection', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D1, D2)
+ end.
+
+
+%% -- AmmRequest --
+
+is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+ descriptors = Descs}) ->
+ d("is_AmmRequest -> entry with"
+ "~n Tids: ~p", [Tids]),
+ is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+is_AmmRequest(_) ->
+ false.
+
+is_AmmRequest_descriptors(Descs) ->
+ is_AmmRequest_descriptors(Descs, []).
+
+is_AmmRequest_descriptors([], _) ->
+ true;
+is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+ d("is_AmmRequest_descriptors -> entry with"
+ "~n Tag: ~p"
+ "~n FoundDescs: ~p", [Tag, FoundDescs]),
+ case lists:member(Tag, FoundDescs) of
+ true ->
+ atmost_once('AmmRequest_descriptors', Tag);
+ false ->
+ case is_AmmDescriptor(Desc) of
+ true ->
+ is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+ false ->
+ wrong_type('AmmRequest_descriptors', Desc)
+ end
+ end;
+is_AmmRequest_descriptors(Descs, _) ->
+ d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+ "~n Descs: ~p", [Descs]),
+ wrong_type('AmmRequest_descriptors', Descs).
+
+
+chk_AmmRequest(R, R) when is_record(R, 'AmmRequest') ->
+ d("chk_AmmRequest -> entry when equal"),
+ chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = Descs1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = Descs2}) ->
+ d("chk_AmmRequest -> entry with not equal"
+ "~n Tids1: ~p"
+ "~n Tids2: ~p", [Tids1, Tids2]),
+ validate(
+ fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'AmmRequest'),
+ validate(
+ fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+ 'AmmRequest'),
+ ok.
+
+
+chk_AmmRequest_descriptors([], []) ->
+ d("chk_AmmRequest_descriptors -> done when OK"),
+ ok;
+chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when equal"),
+ case is_AmmDescriptor(H) of
+ true ->
+ chk_AmmRequest_descriptors(T1, T2);
+ false ->
+ wrong_type('AmmRequest_descriptors_val', H)
+ end;
+chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when not equal"),
+ validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+ 'AmmRequest_descriptors_val'),
+ chk_AmmRequest_descriptors(T1, T2);
+chk_AmmRequest_descriptors(Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% -- AmmDescriptor --
+
+is_AmmDescriptor({Tag, Val}) ->
+ d("is_AmmDescriptor -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p",[Tag, Val]),
+ is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+is_AmmDescriptor(_) ->
+ false.
+
+is_AmmDescriptor_tag(Tag) ->
+ Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+ eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+ auditDescriptor],
+ lists:member(Tag, Tags).
+
+is_AmmDescriptor_val(mediaDescriptor, D) ->
+ is_MediaDescriptor(D);
+is_AmmDescriptor_val(modemDescriptor, D) ->
+ is_ModemDescriptor(D);
+is_AmmDescriptor_val(muxDescriptor, D) ->
+ is_MuxDescriptor(D);
+is_AmmDescriptor_val(eventsDescriptor, D) ->
+ is_EventsDescriptor(D);
+is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+ is_EventBufferDescriptor(D);
+is_AmmDescriptor_val(signalsDescriptor, D) ->
+ is_SignalsDescriptor(D);
+is_AmmDescriptor_val(digitMapDescriptor, D) ->
+ is_DigitMapDescriptor(D);
+is_AmmDescriptor_val(auditDescriptor, D) ->
+ is_AuditDescriptor(D).
+
+chk_AmmDescriptor(D, D) ->
+ chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_AmmDescriptor_tag(Tag) andalso
+ is_AmmDescriptor_val(Tag, Val1) andalso
+ is_AmmDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_AmmDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_AmmDescriptor_tag(Tag1) andalso
+ is_AmmDescriptor_val(Tag1, Val1)) andalso
+ (is_AmmDescriptor_tag(Tag2) andalso
+ is_AmmDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('AmmDescriptor', Cmd1, Cmd2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor(Cmd1, Cmd2) ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+ validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+ validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+ validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+ validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+ validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+ validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% -- AmmsReply --
+
+is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+ terminationAudit = TA}) ->
+ is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+is_AmmsReply(_) ->
+ false.
+
+chk_AmmsReply(R, R) ->
+ is_AmmsReply(R);
+chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = TID2,
+ terminationAudit = TA2}) ->
+ validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+ validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+ ok;
+chk_AmmsReply(R1, R2) ->
+ wrong_type('AmmsReply', R1, R2).
+
+
+%% -- SubtractRequest --
+
+is_SubtractRequest(#'SubtractRequest'{terminationID = Tids,
+ auditDescriptor = AD}) ->
+ is_TerminationIDList(Tids) andalso is_opt_AuditDescriptor(AD);
+is_SubtractRequest(_) ->
+ false.
+
+chk_SubtractRequest(R, R) ->
+ chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'SubtractRequest'),
+ validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+ 'SubtractRequest'),
+ ok;
+chk_SubtractRequest(SR1, SR2) ->
+ wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% -- AuditRequest --
+
+is_AuditRequest(#'AuditRequest'{terminationID = Tid,
+ auditDescriptor = AD}) ->
+ is_TerminationID(Tid) andalso is_AuditDescriptor(AD);
+is_AuditRequest(_) ->
+ false.
+
+chk_AuditRequest(R, R) ->
+ chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+chk_AuditRequest(#'AuditRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'AuditRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationID(Tids1, Tids2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+ 'AuditRequest'),
+ ok;
+chk_AuditRequest(AR1, AR2) ->
+ wrong_type('AuditRequest', AR1, AR2).
+
+
+%% -- AuditReply --
+
+is_AuditReply({Tag, Val}) ->
+ is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+is_AuditReply(_) ->
+ false.
+
+is_AuditReply_tag(Tag) ->
+ Tags = [contextAuditResult, error, auditResult],
+ lists:member(Tag, Tags).
+
+is_AuditReply_val(contextAuditResult, Val) ->
+ is_TerminationIDList(Val);
+is_AuditReply_val(error, Val) ->
+ is_ErrorDescriptor(Val);
+is_AuditReply_val(auditResult, Val) ->
+ is_AuditResult(Val).
+
+chk_AuditReply(R, R) ->
+ chk_type(fun is_AuditReply/1, 'AuditReply', R);
+chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_AuditReply_tag(Tag) andalso
+ is_AuditReply_val(Tag, Val1)andalso
+ is_AuditReply_val(Tag, Val2)) of
+ true ->
+ chk_AuditReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_AuditReply_tag(Tag1) andalso
+ is_AuditReply_val(Tag1, Val1)) andalso
+ (is_AuditReply_tag(Tag2) andalso
+ is_AuditReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReply', R1, R2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply(AR1, AR2) ->
+ wrong_type('AuditReply', AR1, AR2).
+
+chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+ chk_TerminationIDList(Val1, Val2);
+chk_AuditReply_val(error, Val1, Val2) ->
+ chk_ErrorDescriptor(Val1, Val2);
+chk_AuditReply_val(auditResult, Val1, Val2) ->
+ chk_AuditResult(Val1, Val2).
+
+
+%% -- AuditResult --
+
+is_AuditResult(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}) ->
+ is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+is_AuditResult(_) ->
+ false.
+
+chk_AuditResult(R, R) ->
+ chk_type(fun is_AuditResult/1, 'AuditResult', R);
+chk_AuditResult(#'AuditResult'{terminationID = TID1,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = TID2,
+ terminationAuditResult = TAR2}) ->
+ validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+ ok;
+chk_AuditResult(AR1, AR2) ->
+ wrong_type('AuditResult', AR1, AR2).
+
+
+%% -- TerminationAudit --
+
+is_opt_TerminationAudit(TA) ->
+ is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+is_TerminationAudit([]) ->
+ true;
+is_TerminationAudit([H|T]) ->
+ is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+is_TerminationAudit(_) ->
+ false.
+
+chk_opt_TerminationAudit(TA1, TA2) ->
+ chk_OPTIONAL('TerminationAudit', TA1, TA2,
+ fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+chk_TerminationAudit([], []) ->
+ ok;
+chk_TerminationAudit([] = TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit(TA1, [] = TA2) ->
+ not_equal('TerminationAudit', TA1, TA2);
+chk_TerminationAudit([H|T1], [H|T2]) ->
+ case is_AuditReturnParameter(H) of
+ true ->
+ chk_TerminationAudit(T1, T2);
+ false ->
+ wrong_type('TerminationAudit', H)
+ end;
+chk_TerminationAudit([H1|_], [H2|_]) ->
+ chk_AuditReturnParameter(H1, H2),
+ not_equal('TerminationAudit_val', H1, H2);
+chk_TerminationAudit(TA1, TA2) ->
+ not_equal('TerminationAudit', TA1, TA2).
+
+
+%% -- AuditReturnParameter --
+
+is_AuditReturnParameter({Tag, Val}) ->
+ is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val);
+is_AuditReturnParameter(_) ->
+ false.
+
+is_AuditReturnParameter_tag(Tag) ->
+ Tags = [errorDescriptor,
+ mediaDescriptor,
+ modemDescriptor,
+ muxDescriptor,
+ eventsDescriptor,
+ eventBufferDescriptor,
+ signalsDescriptor,
+ digitMapDescriptor,
+ observedEventsDescriptor,
+ statisticsDescriptor,
+ packagesDescriptor,
+ emptyDescriptors],
+ lists:member(Tag, Tags).
+
+is_AuditReturnParameter_val(errorDescriptor, V) ->
+ is_ErrorDescriptor(V);
+is_AuditReturnParameter_val(mediaDescriptor, V) ->
+ is_MediaDescriptor(V);
+is_AuditReturnParameter_val(modemDescriptor, V) ->
+ is_ModemDescriptor(V);
+is_AuditReturnParameter_val(muxDescriptor, V) ->
+ is_MuxDescriptor(V);
+is_AuditReturnParameter_val(eventsDescriptor, V) ->
+ is_EventsDescriptor(V);
+is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+ is_EventBufferDescriptor(V);
+is_AuditReturnParameter_val(signalsDescriptor, V) ->
+ is_SignalsDescriptor(V);
+is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+ is_DigitMapDescriptor(V);
+is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+ is_ObservedEventsDescriptor(V);
+is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+ is_StatisticsDescriptor(V);
+is_AuditReturnParameter_val(packagesDescriptor, V) ->
+ is_PackagesDescriptor(V);
+is_AuditReturnParameter_val(emptyDescriptors, V) ->
+ is_AuditDescriptor(V).
+
+chk_AuditReturnParameter(ARP, ARP) ->
+ chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+ case (is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val1) andalso
+ is_AuditReturnParameter_val(Tag, Val2)) of
+ true ->
+ chk_AuditReturnParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+ case ((is_AuditReturnParameter_tag(Tag1) andalso
+ is_AuditReturnParameter_val(Tag1, Val1)) andalso
+ (is_AuditReturnParameter_tag(Tag2) andalso
+ is_AuditReturnParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReturnParameter', ARP1, ARP2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter(ARP1, ARP2) ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+ validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+ validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+ validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+ validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+ validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+ validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+ validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+ validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+ validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+ 'AuditReturnParameter').
+
+
+%% -- AuditDescriptor --
+
+is_opt_AuditDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_AuditDescriptor(V) ->
+ is_AuditDescriptor(V).
+
+is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}) ->
+ is_AuditDescriptor_auditToken(AT) andalso
+ is_AuditDescriptor_auditPropertyToken(APT);
+is_AuditDescriptor(_) ->
+ false.
+
+is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditToken([]) ->
+ true;
+is_AuditDescriptor_auditToken([H|T]) ->
+ is_AuditDescriptor_auditToken_val(H) andalso
+ is_AuditDescriptor_auditToken(T);
+is_AuditDescriptor_auditToken(_) ->
+ false.
+
+is_AuditDescriptor_auditToken_val(V) ->
+ Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, observedEventsToken,
+ packagesToken, eventBufferToken],
+ lists:member(V, Toks).
+
+is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([]) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([H|T]) ->
+ is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+is_AuditDescriptor_auditPropertyToken(_) ->
+ false.
+
+chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(AD1, AD2) ->
+ chk_AuditDescriptor(AD1, AD2).
+
+chk_AuditDescriptor(AD, AD) ->
+ chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = AT2,
+ auditPropertyToken = APT2}) ->
+ chk_AuditDescriptor_auditToken(AT1, AT2),
+ chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+ ok;
+chk_AuditDescriptor(AD1, AD2) ->
+ wrong_type('AuditDescriptor', AD1, AD2).
+
+chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+ case is_AuditDescriptor_auditToken_val(H) of
+ true ->
+ chk_AuditDescriptor_auditToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H)
+ end;
+chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+ case (is_AuditDescriptor_auditToken_val(H1) andalso
+ is_AuditDescriptor_auditToken_val(H2)) of
+ true ->
+ not_equal('AuditDescriptor_auditToken_val', H1, H2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+ end;
+chk_AuditDescriptor_auditToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+ case is_IndAuditParameter(H) of
+ true ->
+ chk_AuditDescriptor_auditPropertyToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+ end;
+chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+ chk_IndAuditParameter(H1, H2),
+ not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% -- IndAuditParameter --
+
+is_IndAuditParameter({Tag, Val}) ->
+ is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+is_IndAuditParameter(_) ->
+ false.
+
+is_IndAuditParameter_tag(Tag) ->
+ Tags = [indAudMediaDescriptor,
+ indAudEventsDescriptor,
+ indAudEventBufferDescriptor,
+ indAudSignalsDescriptor,
+ indAudDigitMapDescriptor,
+ indAudStatisticsDescriptor,
+ indAudPackagesDescriptor],
+ lists:member(Tag, Tags).
+
+is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+ is_IndAudMediaDescriptor(Val);
+is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+ is_IndAudEventsDescriptor(Val);
+is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+ is_IndAudEventBufferDescriptor(Val);
+is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+ is_IndAudSignalsDescriptor(Val);
+is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+ is_IndAudDigitMapDescriptor(Val);
+is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+ is_IndAudStatisticsDescriptor(Val);
+is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+ is_IndAudPackagesDescriptor(Val).
+
+chk_IndAuditParameter(IAP, IAP) ->
+ chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+ case (is_IndAuditParameter_tag(Tag) andalso
+ is_IndAuditParameter_val(Tag, Val1) andalso
+ is_IndAuditParameter_val(Tag, Val2)) of
+ true ->
+ chk_IndAuditParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+ case ((is_IndAuditParameter_tag(Tag1) andalso
+ is_IndAuditParameter_val(Tag1, Val1)) andalso
+ (is_IndAuditParameter_tag(Tag2) andalso
+ is_IndAuditParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAuditParameter', IAP1, IAP2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter(IAP1, IAP2) ->
+ wrong_type('IndAuditParameter', IAP1, IAP2).
+
+chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+ 'IndAuditParameter').
+
+
+%% -- IndAudMediaDescriptor --
+
+is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+ is_IndAudMediaDescriptor_streams(S);
+is_IndAudMediaDescriptor(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+ is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val);
+is_IndAudMediaDescriptor_streams(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+ is_IndAudStreamParms(Val);
+is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+ is_IndAudMediaDescriptor_multiStream(Val).
+
+is_IndAudMediaDescriptor_multiStream([]) ->
+ true;
+is_IndAudMediaDescriptor_multiStream([H|T]) ->
+ is_IndAudStreamDescriptor(H) andalso
+ is_IndAudMediaDescriptor_multiStream(T);
+is_IndAudMediaDescriptor_multiStream(_) ->
+ false.
+
+chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+ chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+ 'IndAudMediaDescriptor'),
+ validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+ 'IndAudMediaDescriptor'),
+ ok;
+chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+ wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+ {Tag, Val2} = S2) ->
+ case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+ true ->
+ chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+ {Tag2, Val2} = S2) ->
+ case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+ (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudMediaDescriptor_streams', S1, S2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams(S1, S2) ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams');
+chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams').
+
+chk_IndAudMediaDescriptor_multiStream([], []) ->
+ ok;
+chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_IndAudStreamDescriptor(H) of
+ true ->
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+ end;
+chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+ 'IndAudMediaDescriptor_multiStream_val'),
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% -- IndAudStreamDescriptor --
+
+is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+is_IndAudStreamDescriptor(_) ->
+ false.
+
+chk_IndAudStreamDescriptor(D, D) ->
+ chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'IndAudStreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+ validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+ 'IndAudStreamDescriptor'),
+ ok;
+chk_IndAudStreamDescriptor(D1, D2) ->
+ wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% -- IndAudStreamParms --
+
+is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ is_opt_IndAudLocalControlDescriptor(LCD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(RD);
+is_IndAudStreamParms(_) ->
+ false.
+
+chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+ 'IndAudStreamParms'),
+ ok;
+chk_IndAudStreamParms(D1, D2) ->
+ wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% -- IndAudLocalControlDescriptor --
+
+is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalControlDescriptor(D) ->
+ is_IndAudLocalControlDescriptor(D).
+
+is_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs}) ->
+ is_opt_NULL(SM) andalso is_opt_NULL(RV) andalso is_opt_NULL(RG) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(PPs);
+is_IndAudLocalControlDescriptor(_) ->
+ false.
+
+is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([]) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(T);
+is_IndAudLocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PPs1},
+ #'IndAudLocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PPs2}) ->
+ chk_opt_NULL(SM1, SM2),
+ chk_opt_NULL(RV1, RV2),
+ chk_opt_NULL(RG1, RG2),
+ chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+ ok;
+chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudLocalControlDescriptor_propertyParms_val'),
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+
+%% -- IndAudPropertyParm --
+
+is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name}) ->
+ is_PkgdName(Name);
+is_IndAudPropertyParm(_) ->
+ false.
+
+chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1},
+ #'IndAudPropertyParm'{name = Name2}) ->
+ chk_PkgdName(Name1, Name2),
+ ok;
+chk_IndAudPropertyParm(P1, P2) ->
+ wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% -- IndAudLocalRemoteDescriptor --
+
+is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalRemoteDescriptor(D) ->
+ is_IndAudLocalRemoteDescriptor(D).
+
+is_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps}) ->
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+ is_IndAudPropertyGroup(Grps);
+is_IndAudLocalRemoteDescriptor(_) ->
+ false.
+
+is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+ chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+chk_IndAudLocalRemoteDescriptor(D, D) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+ 'IndAudLocalRemoteDescriptor', D);
+chk_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+ propGrps = Grps1},
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+ propGrps = Grps2}) ->
+ chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+ chk_IndAudPropertyGroup(Grps1, Grps2),
+ ok;
+chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+ 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+ case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+ true ->
+ not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+ false ->
+ wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+ end.
+
+
+%% -- IndAudPropertyGroup --
+
+is_IndAudPropertyGroup([]) ->
+ true;
+is_IndAudPropertyGroup([H|T]) ->
+ is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+is_IndAudPropertyGroup(_) ->
+ false.
+
+chk_IndAudPropertyGroup([], []) ->
+ ok;
+chk_IndAudPropertyGroup([] = PG1, PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudPropertyGroup(T1, T2);
+ false ->
+ wrong_type('IndAudPropertyGroup_val', H)
+ end;
+chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudPropertyGroup_val'),
+ chk_IndAudPropertyGroup(T1, T2);
+chk_IndAudPropertyGroup(P1, P2) ->
+ wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% -- IndAudTerminationStateDescriptor --
+
+is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudTerminationStateDescriptor(D) ->
+ is_IndAudTerminationStateDescriptor(D).
+
+is_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+ is_opt_NULL(EBC) andalso is_opt_NULL(SS);
+is_IndAudTerminationStateDescriptor(_) ->
+ false.
+
+is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudTerminationStateDescriptor_propertyParms(T);
+is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+ chk_IndAudTerminationStateDescriptor(D1, D2).
+
+chk_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+ validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+ 'IndAudTerminationStateDescriptor'),
+ validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+ 'IndAudTerminationStateDescriptor'),
+ ok;
+chk_IndAudTerminationStateDescriptor(D1, D2) ->
+ wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+ end;
+chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudTerminationStateDescriptor_propertyParms'),
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- IndAudEventsDescriptor --
+
+is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = SID}) ->
+ is_opt_RequestID(RID) andalso
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID);
+is_IndAudEventsDescriptor(_) ->
+ false.
+
+chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+ pkgdName = Name1,
+ streamID = SID1},
+ #'IndAudEventsDescriptor'{requestID = RID2,
+ pkgdName = Name2,
+ streamID = SID2}) ->
+ chk_opt_RequestID(RID1, RID2),
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventsDescriptor(D1, D2) ->
+ wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% -- IndAudEventBufferDescriptor --
+
+is_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudEventBufferDescriptor(_) ->
+ false.
+
+chk_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name1,
+ streamID = SID1},
+ #'IndAudEventBufferDescriptor'{eventName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventBufferDescriptor(D1, D2) ->
+ wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% -- IndAudSignalsDescriptor --
+
+is_IndAudSignalsDescriptor({Tag, Val}) ->
+ is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val);
+is_IndAudSignalsDescriptor(_) ->
+ false.
+
+is_IndAudSignalsDescriptor_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_IndAudSignalsDescriptor_val(signal, Val) ->
+ is_IndAudSignal(Val);
+is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+ is_IndAudSeqSigList(Val).
+
+chk_IndAudSignalsDescriptor(D, D) ->
+ chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+ case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+ case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+ is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+ (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+ is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudSignalsDescriptor', D1, D2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor(D1, D2) ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+ chk_IndAudSignal(Val1, Val2);
+chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+ chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% -- IndAudSeqSigList --
+
+is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+is_IndAudSeqSigList(_) ->
+ false.
+
+is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+chk_IndAudSeqSigList(L, L) ->
+ chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+ signalList = SL1},
+ #'IndAudSeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ chk_IndAudSeqSigList_id(ID1, ID2),
+ chk_opt_IndAudSignal(SL1, SL2),
+ ok;
+chk_IndAudSeqSigList(L1, L2) ->
+ wrong_type('IndAudSeqSigList', L1, L2).
+
+chk_IndAudSeqSigList_id(ID, ID) ->
+ chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+chk_IndAudSeqSigList_id(ID1, ID2) ->
+ case (is_IndAudSeqSigList_id(ID1) andalso
+ is_IndAudSeqSigList_id(ID2)) of
+ true ->
+ not_equal('IndAudSeqSigList_id', ID1, ID2);
+ false ->
+ wrong_type('IndAudSeqSigList_id', ID1, ID2)
+ end.
+
+
+%% -- IndAudSignal --
+
+is_opt_IndAudSignal(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudSignal(V) ->
+ is_IndAudSignal(V).
+
+is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudSignal(_) ->
+ false.
+
+chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudSignal(S1, S2) ->
+ chk_IndAudSignal(S1, S2).
+
+chk_IndAudSignal(S, S) ->
+ chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+ streamID = SID1},
+ #'IndAudSignal'{signalName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudSignal(S1, S2) ->
+ wrong_type('IndAudSignal', S1, S2).
+
+
+%% -- IndAudDigitMapDescriptor --
+
+is_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+ is_opt_DigitMapName(Name);
+is_IndAudDigitMapDescriptor(_) ->
+ false.
+
+chk_IndAudDigitMapDescriptor(D, D) ->
+ chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+chk_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+ #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'IndAudDigitMapDescriptor'),
+ ok;
+chk_IndAudDigitMapDescriptor(D1, D2) ->
+ wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% -- IndAudStatisticsDescriptor --
+
+is_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name}) ->
+ is_PkgdName(Name);
+is_IndAudStatisticsDescriptor(_) ->
+ false.
+
+chk_IndAudStatisticsDescriptor(D, D) ->
+ chk_type(fun is_IndAudStatisticsDescriptor/1,
+ 'IndAudStatisticsDescriptor', D);
+chk_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name1},
+ #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudStatisticsDescriptor'),
+ ok;
+chk_IndAudStatisticsDescriptor(D1, D2) ->
+ wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% -- IndAudPackagesDescriptor --
+
+is_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = Ver}) ->
+ is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+is_IndAudPackagesDescriptor(_) ->
+ false.
+
+is_IndAudPackagesDescriptor_packageVersion(V) ->
+ is_INTEGER(V, {range, 0, 99}).
+
+chk_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name1,
+ packageVersion = Ver1},
+ #'IndAudPackagesDescriptor'{packageName = Name2,
+ packageVersion = Ver2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+ chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+ ok;
+chk_IndAudPackagesDescriptor(D1, D2) ->
+ wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+ chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+ 'IndAudPackagesDescriptor_packageVersion', V);
+chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+ case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+ is_IndAudPackagesDescriptor_packageVersion(V2)) of
+ true ->
+ not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+ false ->
+ wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+ end.
+
+
+%% -- NotifyRequest --
+
+is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso
+ is_ObservedEventsDescriptor(OED) andalso
+ is_opt_ErrorDescriptor(ED);
+is_NotifyRequest(_) ->
+ false.
+
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = OED1,
+ errorDescriptor = ED1},
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = OED2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+ 'NotifyRequest'),
+ ok;
+chk_NotifyRequest(NR1, NR2) ->
+ wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% -- NotifyReply --
+
+is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+is_NotifyReply(_) ->
+ false.
+
+chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+ errorDescriptor = ED1},
+ #'NotifyReply'{terminationID = Tids2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+ ok;
+chk_NotifyReply(NR1, NR2) ->
+ wrong_type('NotifyReply', NR1, NR2).
+
+
+%% -- ObservedEventsDescriptor --
+
+is_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}) ->
+ is_RequestID(RID) andalso
+ is_ObservedEventsDescriptor_observedEventLst(OEL);
+is_ObservedEventsDescriptor(_) ->
+ false.
+
+is_ObservedEventsDescriptor_observedEventLst([]) ->
+ true;
+is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+ is_ObservedEvent(H) andalso
+ is_ObservedEventsDescriptor_observedEventLst(T);
+is_ObservedEventsDescriptor_observedEventLst(_) ->
+ false.
+
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID1,
+ observedEventLst = OEL1},
+ #'ObservedEventsDescriptor'{requestId = RID2,
+ observedEventLst = OEL2}) ->
+ validate(fun() -> chk_RequestID(RID1, RID2) end,
+ 'ObservedEventsDescriptor'),
+ validate(
+ fun() ->
+ chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+ end,
+ 'ObservedEventsDescriptor'),
+ ok;
+chk_ObservedEventsDescriptor(D1, D2) ->
+ wrong_type('ObservedEventsDescriptor', D1, D2).
+
+chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+ ok;
+chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+ case is_ObservedEvent(H) of
+ true ->
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+ false ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+ end;
+chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ObservedEvent(H1, H2) end,
+ 'ObservedEventsDescriptor_observedEventLst_val'),
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% -- ObservedEvent --
+
+is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}) ->
+ is_EventName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_ObservedEvent_eventParList(EPL) andalso
+ is_opt_TimeNotation(TN);
+is_ObservedEvent(_) ->
+ false.
+
+is_ObservedEvent_eventParList([]) ->
+ true;
+is_ObservedEvent_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+is_ObservedEvent_eventParList(_) ->
+ false.
+
+chk_ObservedEvent(E, E) ->
+ chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+ streamID = SID1,
+ eventParList = EPL1,
+ timeNotation = TN1},
+ #'ObservedEvent'{eventName = Name2,
+ streamID = SID2,
+ eventParList = EPL2,
+ timeNotation = TN2}) ->
+ validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+ chk_ObservedEvent_eventParList(EPL1, EPL2),
+ validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+ ok;
+chk_ObservedEvent(E1, E2) ->
+ wrong_type('ObservedEvent', E1, E2).
+
+chk_ObservedEvent_eventParList([], []) ->
+ ok;
+chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_ObservedEvent_eventParList(T1, T2);
+ false ->
+ wrong_type('ObservedEvent_eventParList_val', H)
+ end;
+chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'ObservedEvent_eventParList'),
+ chk_ObservedEvent_eventParList(T1, T2);
+chk_ObservedEvent_eventParList(L1, L2) ->
+ wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+chk_EventName(N, N) ->
+ chk_type(fun is_EventName/1, 'EventName', N);
+chk_EventName(N1, N2) ->
+ case (is_EventName(N1) andalso is_EventName(N2)) of
+ true ->
+ not_equal('EventName', N1, N2);
+ false ->
+ wrong_type('EventName', N1, N2)
+ end.
+
+
+%% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+ value = Val1,
+ extraInfo = EI1},
+ #'EventParameter'{eventParameterName = Name2,
+ value = Val2,
+ extraInfo = EI2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+ validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+ chk_EventParameter_extraInfo(EI1, EI2),
+ ok;
+chk_EventParameter(P1, P2) ->
+ wrong_type('EventParameter', P1, P2).
+
+chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_EventParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_EventParameter_extraInfo/1,
+ 'EventParameter_extraInfo', EI);
+chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val1) andalso
+ is_EventParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+ is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+ (is_EventParameter_extraInfo_tag(Tag2) andalso
+ is_EventParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo(EI1, EI2) ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val').
+
+
+%% -- ServiceChangeRequest --
+
+is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+ serviceChangeParms = Parms}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+is_ServiceChangeRequest(_) ->
+ false.
+
+chk_ServiceChangeRequest(R, R) ->
+ chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+chk_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = Parms1},
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = Parms2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeRequest'),
+ validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+ 'ServiceChangeRequest'),
+ ok;
+chk_ServiceChangeRequest(R1, R2) ->
+ wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% -- ServiceChangeReply --
+
+is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+ serviceChangeResult = Res}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+is_ServiceChangeReply(_) ->
+ false.
+
+chk_ServiceChangeReply(R, R) ->
+ chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+chk_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = Tids1,
+ serviceChangeResult = Res1},
+ #'ServiceChangeReply'{terminationID = Tids2,
+ serviceChangeResult = Res2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeReply'),
+ validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+ 'ServiceChangeReply'),
+ ok;
+chk_ServiceChangeReply(R1, R2) ->
+ wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% -- ServiceChangeResult --
+
+is_ServiceChangeResult({Tag, Val}) ->
+ is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val);
+is_ServiceChangeResult(_) ->
+ false.
+
+is_ServiceChangeResult_tag(Tag) ->
+ Tags = [errorDescriptor, serviceChangeResParms],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeResult_val(errorDescriptor, Val) ->
+ is_ErrorDescriptor(Val);
+is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+ is_ServiceChangeResParm(Val).
+
+chk_ServiceChangeResult(Res, Res) ->
+ chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+ case (is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val1) andalso
+ is_ServiceChangeResult_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+ case ((is_ServiceChangeResult_tag(Tag1) andalso
+ is_ServiceChangeResult_val(Tag1, Val1)) andalso
+ (is_ServiceChangeResult_tag(Tag2) andalso
+ is_ServiceChangeResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeResult', Res1, Res2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult(Res1, Res2) ->
+ wrong_type('ServiceChangeResult', Res1, Res2).
+
+chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'ServiceChangeResult');
+chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+ validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+ 'ServiceChangeResult').
+
+
+%% -- WildcardField --
+
+is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+chk_WildcardField(WF, WF) ->
+ case is_WildcardField(WF) of
+ true ->
+ ok;
+ false ->
+ wrong_type('WildcardField', WF)
+ end;
+chk_WildcardField(WF1, WF2) ->
+ case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+ true ->
+ not_equal('WildcardField', WF1, WF2);
+ false ->
+ wrong_type('WildcardField', WF1, WF2)
+ end.
+
+
+%% -- TerminationID --
+
+is_TerminationID(#'TerminationID'{wildcard = W,
+ id = ID}) ->
+ is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+ id = _ID}) ->
+ true; % What are the types?
+is_TerminationID(_) ->
+ false.
+
+is_TerminationID_wildcard([]) ->
+ true;
+is_TerminationID_wildcard([H|T]) ->
+ is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+is_TerminationID_wildcard(_) ->
+ false.
+
+is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+chk_TerminationID(Id,Id) ->
+ chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+chk_TerminationID(#'TerminationID'{wildcard = W1,
+ id = I1},
+ #'TerminationID'{wildcard = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+ id = I1},
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2}) ->
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(Tid1, Tid2) ->
+ wrong_type('TerminationID', Tid1, Tid2).
+
+chk_TerminationID_wildcard([], []) ->
+ ok;
+chk_TerminationID_wildcard([] = WF1, WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard(WF1, [] = WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+ case is_WildcardField(H) of
+ true ->
+ chk_TerminationID_wildcard(T1, T2);
+ false ->
+ wrong_type('TerminationID_wildcard_val', H)
+ end;
+chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_WildcardField(H1, H2) end,
+ 'TerminationID_wildcard_val'),
+ chk_TerminationID_wildcard(T1, T2);
+chk_TerminationID_wildcard(WF1,WF2) ->
+ not_equal('TerminationId_wildcard', WF1, WF2).
+
+chk_TerminationID_id(Id, Id) ->
+ case is_OCTET_STRING(Id, {range, 1, 8}) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TerminationID_id', Id, Id)
+ end;
+chk_TerminationID_id(Id1, Id2) ->
+ not_equal(terminationId_id, Id1, Id2).
+
+
+%% -- TerminationIDList --
+
+is_TerminationIDList([]) ->
+ true;
+is_TerminationIDList([H|T]) ->
+ is_TerminationID(H) andalso is_TerminationIDList(T);
+is_TerminationIDList(_) ->
+ false.
+
+chk_TerminationIDList([], []) ->
+ ok;
+chk_TerminationIDList([] = L1, L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList(L1, [] = L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_TerminationIDList(T1, T2);
+ false ->
+ wrong_type('TerminationIDList', H)
+ end;
+chk_TerminationIDList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+ chk_TerminationIDList(T1, T2);
+chk_TerminationIDList(L1, L2) ->
+ wrong_type('TerminationIDList', L1, L2).
+
+
+%% -- MediaDescriptor --
+
+is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ is_opt_TerminationStateDescriptor(TSD) andalso
+ is_MediaDescriptor_streams(S);
+is_MediaDescriptor(_) ->
+ false.
+
+is_MediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_MediaDescriptor_streams({Tag, Val}) ->
+ is_MediaDescriptor_streams_tag(Tag) andalso
+ is_MediaDescriptor_streams_val(Tag, Val);
+is_MediaDescriptor_streams(_) ->
+ false.
+
+is_MediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_MediaDescriptor_streams_val(oneStream, SP) ->
+ is_StreamParms(SP);
+is_MediaDescriptor_streams_val(multiStream, SDL) ->
+ is_MediaDescriptor_multiStream(SDL).
+
+is_MediaDescriptor_multiStream([]) ->
+ true;
+is_MediaDescriptor_multiStream([H|T]) ->
+ is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+is_MediaDescriptor_multiStream(_) ->
+ false.
+
+chk_MediaDescriptor(D, D) ->
+ chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'MediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(
+ fun() ->
+ chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+ end,
+ 'MediaDescriptor'),
+ validate(
+ fun() ->
+ chk_MediaDescriptor_streams(S1, S2)
+ end,
+ 'MediaDescriptor'),
+ ok;
+chk_MediaDescriptor(D1, D2) ->
+ wrong_type('MediaDescriptor', D1, D2).
+
+
+chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+ validate(fun() ->
+ chk_StreamParms(SP1, SP2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+ validate(fun() ->
+ chk_MediaDescriptor_multiStream(SDs1, SDs2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams(S1, S2) ->
+ wrong_type('MediaDescriptor_streams', S1, S2).
+
+chk_MediaDescriptor_multiStream([], []) ->
+ ok;
+chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_StreamDescriptor(H) of
+ true ->
+ chk_MediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('MediaDescriptor_multiStream_val', H)
+ end;
+chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+ 'MediaDescriptor_multiStream_val'),
+ chk_MediaDescriptor_multiStream(T1, T2);
+chk_MediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% -- StreamDescriptor --
+
+is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ is_StreamID(SID) andalso is_StreamParms(Parms);
+is_StreamDescriptor(_) ->
+ false.
+
+chk_StreamDescriptor(D, D) ->
+ chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+ validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+ ok;
+chk_StreamDescriptor(D1, D2) ->
+ wrong_type('StreamDescriptor', D1, D2).
+
+
+%% -- StreamParms --
+
+is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ is_opt_LocalControlDescriptor(LCD) andalso
+ is_opt_LocalRemoteDescriptor(LD) andalso
+ is_opt_LocalRemoteDescriptor(RD);
+is_StreamParms(_) ->
+ false.
+
+chk_StreamParms(SP, SP) ->
+ chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ chk_opt_LocalControlDescriptor(LCD1, LCD2),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+ localDescriptor),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+ remoteDescriptor),
+ ok;
+chk_StreamParms(P1, P2) ->
+ wrong_type('StreamParms', P1, P2).
+
+
+%% -- LocalControlDescriptor --
+
+is_opt_LocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_LocalControlDescriptor(D) ->
+ is_LocalControlDescriptor(D).
+
+is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}) ->
+ is_opt_StreamMode(SM) andalso
+ is_opt_BOOLEAN(RV) andalso
+ is_opt_BOOLEAN(RG) andalso
+ is_LocalControlDescriptor_propertyParms(PP);
+is_LocalControlDescriptor(_) ->
+ false.
+
+is_LocalControlDescriptor_propertyParms([]) ->
+ true;
+is_LocalControlDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+is_LocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_LocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+ chk_LocalControlDescriptor(LCD1, LCD2).
+
+chk_LocalControlDescriptor(LCD, LCD) ->
+ chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PP1},
+ #'LocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PP2}) ->
+ validate(
+ fun() -> chk_opt_StreamMode(SM1, SM2) end,
+ 'LocalControlDescriptor'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+ 'LocalControlDescriptor_reserveValue'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+ 'LocalControlDescriptor_reserveGroup'),
+ chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+ ok;
+chk_LocalControlDescriptor(LCD1, LCD2) ->
+ wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+chk_LocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('LocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'LocalControlDescriptor_propertyParms_val'),
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- StreamMode --
+
+is_opt_StreamMode(asn1_NOVALUE) ->
+ true;
+is_opt_StreamMode(SM) ->
+ is_StreamMode(SM).
+
+is_StreamMode(SM) ->
+ lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamMode(SM1, SM2) ->
+ chk_StreamMode(SM1, SM2).
+
+chk_StreamMode(SM, SM) ->
+ chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+chk_StreamMode(SM1, SM2) ->
+ case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+ true ->
+ not_equal('StreamMode', SM1, SM2);
+ false ->
+ wrong_type('StreamMode', SM1, SM2)
+ end.
+
+
+%% -- PropertyParm --
+
+is_PropertyParm(#'PropertyParm'{name = N,
+ value = V,
+ extraInfo = I}) ->
+ is_PkgdName(N) andalso
+ is_PropertyParm_value(V) andalso
+ is_PropertyParm_extraInfo(I);
+is_PropertyParm(_) ->
+ false.
+
+is_PropertyParm_value([]) ->
+ true;
+is_PropertyParm_value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+is_PropertyParm_value(_) ->
+ false.
+
+is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+ true;
+is_PropertyParm_extraInfo({Tag, Val}) ->
+ is_PropertyParm_extraInfo_tag(Tag) andalso
+ is_PropertyParm_extraInfo_val(Tag, Val);
+is_PropertyParm_extraInfo(_) ->
+ false.
+
+is_PropertyParm_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_PropertyParm_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_PropertyParm_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_PropertyParm_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_PropertyParm(P, P) ->
+ chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+chk_PropertyParm(#'PropertyParm'{name = N1,
+ value = V1,
+ extraInfo = I1},
+ #'PropertyParm'{name = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+ chk_PropertyParm_value(V1, V2),
+ chk_PropertyParm_extraInfo(I1, I2),
+ ok;
+chk_PropertyParm(P1, P2) ->
+ wrong_type('PropertyParm', P1, P2).
+
+chk_PropertyParm_value([], []) ->
+ ok;
+chk_PropertyParm_value([] = V1, V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value(V1, [] = V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value([H|T1], [H|T2]) ->
+ case is_OCTET_STRING(H) of
+ true ->
+ chk_PropertyParm_value(T1, T2);
+ false ->
+ wrong_type('PropertyParm_value_val', H)
+ end;
+chk_PropertyParm_value([H1|_], [H2|_]) ->
+ case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+ true ->
+ not_equal('PropertyParm_value_val', H1, H2);
+ false ->
+ wrong_type('PropertyParm_value_val', H1, H2)
+ end;
+chk_PropertyParm_value(V1, V2) ->
+ wrong_type('PropertyParm_value', V1, V2).
+
+chk_PropertyParm_extraInfo(EI, EI) ->
+ chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_PropertyParm_extraInfo_tag(Tag) and
+ is_PropertyParm_extraInfo_val(Tag, Val1) and
+ is_PropertyParm_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_PropertyParm_extraInfo_tag(Tag1) and
+ is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+ (is_PropertyParm_extraInfo_tag(Tag2) and
+ is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('PropertyParm_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo(EI1, EI2) ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $z, $a =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $Z, $A =< H ->
+ is_NAME2(T);
+is_NAME2([H|T]) when H =< $9, $0 =< H ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+chk_Name(N, N) ->
+ chk_type(fun is_Name/1, 'Name', N);
+chk_Name(N1, N2) ->
+ case (is_Name(N1) andalso is_Name(N2)) of
+ true ->
+ not_equal('Name', N1, N2);
+ false ->
+ wrong_type('Name', N1, N2)
+ end.
+
+
+%% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+chk_PkgdName(N, N) ->
+ case is_PkgdName(N) of
+ true ->
+ ok;
+ false ->
+ wrong_type('PkgdName', N, N)
+ end;
+chk_PkgdName(N1, N2) ->
+ case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+ true ->
+ not_equal('PkgdName', N1, N2);
+ false ->
+ wrong_type('PkgdName', N1, N2)
+ end.
+
+
+%% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+chk_Relation(R, R) ->
+ chk_type(fun is_Relation/1, 'Relation', R);
+chk_Relation(R1, R2) ->
+ case (is_Relation(R1) andalso is_Relation(R2)) of
+ true ->
+ not_equal('Relation', R1, R2);
+ false ->
+ wrong_type('Relation', R1, R2)
+ end.
+
+
+%% -- LocalRemoteDescriptor --
+
+is_opt_LocalRemoteDescriptor(D) ->
+ is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+ is_LocalRemoteDescriptor_propGrps(PGs);
+is_LocalRemoteDescriptor(_) ->
+ false.
+
+is_LocalRemoteDescriptor_propGrps([]) ->
+ true;
+is_LocalRemoteDescriptor_propGrps([H|T]) ->
+ is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+is_LocalRemoteDescriptor_propGrps(_) ->
+ false.
+
+chk_opt_LocalRemoteDescriptor(D1, D2) ->
+ chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+ fun is_LocalRemoteDescriptor/1,
+ fun chk_LocalRemoteDescriptor/2).
+
+chk_LocalRemoteDescriptor(LRD, LRD) ->
+ chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+ #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+ chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+ ok;
+chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+ wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+chk_LocalRemoteDescriptor_propGrps([], []) ->
+ ok;
+chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+ case is_PropertyGroup(H) of
+ true ->
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+ false ->
+ wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+ end;
+chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyGroup(H1, H2) end,
+ 'LocalRemoteDescriptor_propGrps_val'),
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+ wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% -- PropertyGroup --
+
+is_PropertyGroup([]) ->
+ true;
+is_PropertyGroup([H|T]) ->
+ is_PropertyParm(H) andalso is_PropertyGroup(T);
+is_PropertyGroup(_) ->
+ false.
+
+chk_PropertyGroup([], []) ->
+ ok;
+chk_PropertyGroup([] = PG1, PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup(PG1, [] = PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_PropertyGroup(T1, T2);
+ false ->
+ wrong_type('PropertyGroup_val', H)
+ end;
+chk_PropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+ chk_PropertyGroup(T1, T2);
+chk_PropertyGroup(PG1, PG2) ->
+ wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% -- TerminationStateDescriptor --
+
+is_opt_TerminationStateDescriptor(D) ->
+ is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+is_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_TerminationStateDescriptor_propertyParms(PP) andalso
+ is_opt_EventBufferControl(EBC) andalso
+ is_opt_ServiceState(SS);
+is_TerminationStateDescriptor(_) ->
+ false.
+
+is_TerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_TerminationStateDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+is_TerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_TerminationStateDescriptor(D1, D2) ->
+ chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+ fun is_TerminationStateDescriptor/1,
+ fun chk_TerminationStateDescriptor/2).
+
+chk_TerminationStateDescriptor(D, D) ->
+ chk_type(fun is_TerminationStateDescriptor/1,
+ 'TerminationStateDescriptor', D);
+chk_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'TerminationStateDescriptor'{propertyParms = PP2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+ validate(
+ fun() ->
+ chk_opt_EventBufferControl(EBC1, EBC2)
+ end,
+ 'TerminationStateDescriptor'),
+ validate(
+ fun() ->
+ chk_opt_ServiceState(SS1, SS2)
+ end,
+ 'TerminationStateDescriptor'),
+ ok;
+chk_TerminationStateDescriptor(D1, D2) ->
+ wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+chk_TerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_TerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+ end;
+chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+ case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+ true ->
+ not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+ end;
+chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+ wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% -- EventBufferControl --
+
+is_opt_EventBufferControl(asn1_NOVALUE) ->
+ true;
+is_opt_EventBufferControl(EBC) ->
+ is_EventBufferControl(EBC).
+
+is_EventBufferControl(EBC) ->
+ lists:member(EBC, [off, lockStep]).
+
+chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_EventBufferControl(EBC1, EBC2) ->
+ chk_EventBufferControl(EBC1, EBC2).
+
+chk_EventBufferControl(EBC, EBC) ->
+ chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+chk_EventBufferControl(EBC1, EBC2) ->
+ case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+ true ->
+ not_equal('EventBufferControl', EBC1, EBC2);
+ false ->
+ wrong_type('EventBufferControl', EBC1, EBC2)
+ end.
+
+
+%% -- ServiceState --
+
+is_opt_ServiceState(asn1_NOVALUE) ->
+ true;
+is_opt_ServiceState(SS) ->
+ is_ServiceState(SS).
+
+is_ServiceState(SS) ->
+ lists:member(SS, [test, outOfSvc, inSvc]).
+
+chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ServiceState(SS1, SS2) ->
+ chk_ServiceState(SS1, SS2).
+
+chk_ServiceState(SS, SS) ->
+ chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+chk_ServiceState(SS1, SS2) ->
+ case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+ true ->
+ not_equal('ServiceState', SS1, SS2);
+ false ->
+ wrong_type('ServiceState', SS1, SS2)
+ end.
+
+
+%% -- MuxDescriptor --
+
+is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+ termList = TL,
+ nonStandardData = NSD}) ->
+ is_MuxType(MT) andalso
+ is_MuxDescriptor_termList(TL) andalso
+ is_NonStandardData(NSD);
+is_MuxDescriptor(_) ->
+ false.
+
+is_MuxDescriptor_termList([]) ->
+ true;
+is_MuxDescriptor_termList([H|T]) ->
+ is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+is_MuxDescriptor_termList(_) ->
+ false.
+
+chk_MuxDescriptor(D, D) ->
+ chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+ termList = TL1,
+ nonStandardData = NSD1},
+ #'MuxDescriptor'{muxType = MT2,
+ termList = TL2,
+ nonStandardData = NSD2}) ->
+ validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+ chk_MuxDescriptor_termList(TL1, TL2),
+ validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+ ok;
+chk_MuxDescriptor(D1, D2) ->
+ wrong_type('MuxDescriptor', D1, D2).
+
+chk_MuxDescriptor_termList([], []) ->
+ ok;
+chk_MuxDescriptor_termList([] = TL1, TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_MuxDescriptor_termList(T1, T2);
+ false ->
+ wrong_type('MuxDescriptor_termList_val', H)
+ end;
+chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end,
+ 'MuxDescriptor_termList_val'),
+ chk_MuxDescriptor_termList(T1, T2);
+chk_MuxDescriptor_termList(TL1, TL2) ->
+ wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% -- MuxType --
+
+is_MuxType(MT) ->
+ lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+chk_MuxType(MT, MT) ->
+ chk_type(fun is_MuxType/1, 'MuxType', MT);
+chk_MuxType(MT1, MT2) ->
+ case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+ true ->
+ not_equal('MuxType', MT1, MT2);
+ false ->
+ wrong_type('MuxType', MT1, MT2)
+ end.
+
+
+%% -- StreamID --
+
+is_opt_StreamID(asn1_NOVALUE) ->
+ true;
+is_opt_StreamID(V) ->
+ is_StreamID(V).
+
+is_StreamID(V) -> is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_StreamID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamID(V1, V2) ->
+ chk_StreamID(V1, V2).
+
+chk_StreamID(ID, ID) ->
+ chk_type(fun is_StreamID/1, 'StreamID', ID);
+chk_StreamID(ID1, ID2) ->
+ case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+ true ->
+ not_equal('StreamID', ID1, ID2);
+ false ->
+ wrong_type('StreamID', ID1, ID2)
+ end.
+
+
+%% -- EventsDescriptor --
+
+is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = EVL}) ->
+ d("is_EventsDescriptor -> entry with"
+ "~n RID: ~p"
+ "~n EVL: ~p", [RID, EVL]),
+ is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+is_EventsDescriptor(_) ->
+ false.
+
+is_EventsDescriptor_eventList([]) ->
+ true;
+is_EventsDescriptor_eventList([H|T]) ->
+ is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+is_EventsDescriptor_eventList(_) ->
+ false.
+
+chk_EventsDescriptor(D, D) ->
+ chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+ eventList = EVL1},
+ #'EventsDescriptor'{requestID = RID2,
+ eventList = EVL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+ chk_EventsDescriptor_eventList(EVL1, EVL2),
+ ok;
+chk_EventsDescriptor(D1, D2) ->
+ wrong_type('EventsDescriptor', D1, D2).
+
+chk_EventsDescriptor_eventList([], []) ->
+ ok;
+chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_RequestedEvent(H) of
+ true ->
+ chk_EventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('EventsDescriptor_eventList_val', H)
+ end;
+chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_RequestedEvent(H1, H2) end,
+ 'EventsDescriptor_eventList_val'),
+ chk_EventsDescriptor_eventList(T1, T2);
+chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+ wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% -- RequestedEvent --
+
+is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ d("is_RequestedEvent -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n EA: ~p"
+ "~n EPL: ~p", [N, SID, EA, EPL]),
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestedActions(EA) andalso
+ is_RequestedEvent_evParList(EPL);
+is_RequestedEvent(_) ->
+ false.
+
+is_RequestedEvent_evParList([]) ->
+ true;
+is_RequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+is_RequestedEvent_evParList(_) ->
+ false.
+
+chk_RequestedEvent(RE, RE) ->
+ chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'RequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+ 'RequestedEvent'),
+ chk_RequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_RequestedEvent(RE1, RE2) ->
+ wrong_type('RequestedEvent', RE1, RE2).
+
+chk_RequestedEvent_evParList([], []) ->
+ ok;
+chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_RequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('RequestedEvent_evParList_val', H)
+ end;
+chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'RequestedEvent_evParList_val'),
+ chk_RequestedEvent_evParList(T1, T2);
+chk_RequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- RequestedActions --
+
+is_opt_RequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_RequestedActions(RA) ->
+ is_RequestedActions(RA).
+
+is_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ d("is_RequestedActions -> entry with"
+ "~n KA: ~p"
+ "~n EDM: ~p"
+ "~n SE: ~p"
+ "~n SD: ~p", [KA, EDM, SE, SD]),
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD);
+is_RequestedActions(_) ->
+ false.
+
+chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestedActions(RA1, RA2) ->
+ chk_RequestedActions(RA1, RA2).
+
+chk_RequestedActions(RA, RA) ->
+ chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ secondEvent = SA1,
+ signalsDescriptor = SD1},
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ secondEvent = SA2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end, 'RequestedActions'),
+ validate(fun() -> chk_opt_SecondEventsDescriptor(SA1, SA2) end,
+ 'RequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'RequestedActions'),
+ ok;
+chk_RequestedActions(RA1, RA2) ->
+ wrong_type('RequestedActions', RA1, RA2).
+
+
+%% -- EventDM --
+
+is_opt_EventDM(EDM) ->
+ is_OPTIONAL(fun is_EventDM/1, EDM).
+
+is_EventDM({Tag, Val}) ->
+ is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+is_EventDM(_) ->
+ false.
+
+is_EventDM_tag(Tag) ->
+ Tags = [digitMapName, digitMapValue],
+ lists:member(Tag, Tags).
+
+is_EventDM_val(digitMapName, Val) ->
+ is_DigitMapName(Val);
+is_EventDM_val(digitMapValue, Val) ->
+ is_DigitMapValue(Val).
+
+chk_opt_EventDM(EDM1, EDM2) ->
+ chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+chk_EventDM(EDM, EDM) ->
+ chk_type(fun is_EventDM/1, 'EventDM', EDM);
+chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+ case (is_EventDM_tag(Tag) andalso
+ is_EventDM_val(Tag, Val1) andalso
+ is_EventDM_val(Tag, Val2)) of
+ true ->
+ chk_EventDM_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+ case ((is_EventDM_tag(Tag1) andalso
+ is_EventDM_val(Tag1, Val1)) andalso
+ (is_EventDM_tag(Tag2) andalso
+ is_EventDM_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventDM', EDM1, EDM2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM(EDM1, EDM2) ->
+ wrong_type('EventDM', EDM1, EDM2).
+
+chk_EventDM_val(digitMapName, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+chk_EventDM_val(digitMapValue, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% -- SecondEventsDescriptor --
+
+is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SecondEventsDescriptor(D) ->
+ is_SecondEventsDescriptor(D).
+
+is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = EL}) ->
+ is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+is_SecondEventsDescriptor(_) ->
+ false.
+
+is_SecondEventsDescriptor_eventList([]) ->
+ true;
+is_SecondEventsDescriptor_eventList([H|T]) ->
+ is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+is_SecondEventsDescriptor_eventList(_) ->
+ false.
+
+chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondEventsDescriptor(D1, D2) ->
+ chk_SecondEventsDescriptor(D1, D2).
+
+chk_SecondEventsDescriptor(D, D) ->
+ chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+ eventList = EL1},
+ #'SecondEventsDescriptor'{requestID = RID2,
+ eventList = EL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+ 'SecondEventsDescriptor'),
+ chk_SecondEventsDescriptor_eventList(EL1, EL2),
+ ok;
+chk_SecondEventsDescriptor(D1, D2) ->
+ wrong_type('SecondEventsDescriptor', D1, D2).
+
+chk_SecondEventsDescriptor_eventList([], []) ->
+ ok;
+chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_SecondRequestedEvent(H) of
+ true ->
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('SecondEventsDescriptor_eventList_val', H)
+ end;
+chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+ 'SecondEventsDescriptor_eventList_val'),
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+chk_SecondEventsDescriptor_eventList(L1, L2) ->
+ wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% -- SecondRequestedEvent --
+
+is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SecondRequestedActions(EA) andalso
+ is_SecondRequestedEvent_evParList(EPL);
+is_SecondRequestedEvent(_) ->
+ false.
+
+is_SecondRequestedEvent_evParList([]) ->
+ true;
+is_SecondRequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+is_SecondRequestedEvent_evParList(_) ->
+ false.
+
+chk_SecondRequestedEvent(RE, RE) ->
+ chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'SecondRequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+ 'SecondRequestedEvent'),
+ chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_SecondRequestedEvent(RE1, RE2) ->
+ wrong_type('SecondRequestedEvent', RE1, RE2).
+
+chk_SecondRequestedEvent_evParList([], []) ->
+ ok;
+chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_SecondRequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('SecondRequestedEvent_evParList_val', H)
+ end;
+chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'SecondRequestedEvent_evParList_val'),
+ chk_SecondRequestedEvent_evParList(T1, T2);
+chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- SecondRequestedActions --
+
+is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_SecondRequestedActions(SRA) ->
+ is_SecondRequestedActions(SRA).
+
+is_SecondRequestedActions(#'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD}) ->
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SignalsDescriptor(SD);
+is_SecondRequestedActions(_) ->
+ false.
+
+chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+ chk_SecondRequestedActions(SRA1, SRA2).
+
+chk_SecondRequestedActions(SRA, SRA) ->
+ chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+chk_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ signalsDescriptor = SD1},
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ signalsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_EventDM(EDM1, EDM2) end,
+ 'SecondRequestedActions'),
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'SecondRequestedActions'),
+ ok;
+chk_SecondRequestedActions(SRA1, SRA2) ->
+ wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+
+%% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor([]) ->
+ true;
+is_EventBufferDescriptor([H|T]) ->
+ is_EventSpec(H) andalso is_EventBufferDescriptor(T);
+is_EventBufferDescriptor(_) ->
+ false.
+
+chk_EventBufferDescriptor([], []) ->
+ ok;
+chk_EventBufferDescriptor([] = D1, D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor(D1, [] = D2) ->
+ not_equal('EventBufferDescriptor', D1, D2);
+chk_EventBufferDescriptor([H|T1], [H|T2]) ->
+ case is_EventSpec(H) of
+ true ->
+ chk_EventBufferDescriptor(T1, T2);
+ false ->
+ wrong_type('EventBufferDescriptor_val', H)
+ end;
+chk_EventBufferDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventSpec(H1, H2) end,
+ 'EventBufferDescriptor_val'),
+ chk_EventBufferDescriptor(T1, T2);
+chk_EventBufferDescriptor(D1, D2) ->
+ wrong_type('EventBufferDescriptor_val', D1, D2).
+
+
+%% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+chk_EventSpec(ES, ES) ->
+ chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = SID1,
+ eventParList = EPL1},
+ #'EventSpec'{eventName = N2,
+ streamID = SID2,
+ eventParList = EPL2}) ->
+ validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+ chk_EventSpec_eventParList(EPL1, EPL2),
+ ok;
+chk_EventSpec(ES1, ES2) ->
+ wrong_type('EventSpec', ES1, ES2).
+
+chk_EventSpec_eventParList([], []) ->
+ ok;
+chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_EventSpec_eventParList(T1, T2);
+ false ->
+ wrong_type('EventSpec_eventParList_val', H)
+ end;
+chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'EventSpec_eventParList_val'),
+ chk_EventSpec_eventParList(T1, T2);
+chk_EventSpec_eventParList(EPL1, EPL2) ->
+ wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% -- SignalsDescriptor --
+
+is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SignalsDescriptor(D) ->
+ is_SignalsDescriptor(D).
+
+is_SignalsDescriptor([]) ->
+ true;
+is_SignalsDescriptor([H|T]) ->
+ is_SignalRequest(H) andalso is_SignalsDescriptor(T);
+is_SignalsDescriptor(_) ->
+ false.
+
+chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalsDescriptor(D1, D2) ->
+ chk_SignalsDescriptor(D1, D2).
+
+chk_SignalsDescriptor([], []) ->
+ ok;
+chk_SignalsDescriptor([] = D1, D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor(D1, [] = D2) ->
+ not_equal('SignalsDescriptor', D1, D2);
+chk_SignalsDescriptor([H|T1], [H|T2]) ->
+ case is_SignalRequest(H) of
+ true ->
+ chk_SignalsDescriptor(T1, T2);
+ false ->
+ wrong_type('SignalsDescriptor_val', H)
+ end;
+chk_SignalsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SignalRequest(H1, H2) end, 'SignalsDescriptor_val'),
+ chk_SignalsDescriptor(T1, T2);
+chk_SignalsDescriptor(D1, D2) ->
+ wrong_type('SignalsDescriptor', D1, D2).
+
+
+%% -- SignalRequest --
+
+is_SignalRequest({Tag, Val}) ->
+ is_SignalRequest_tag(Tag) andalso is_SignalRequest_val(Tag, Val);
+is_SignalRequest(_) ->
+ false.
+
+is_SignalRequest_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_SignalRequest_val(signal, Val) ->
+ is_Signal(Val);
+is_SignalRequest_val(seqSigList, Val) ->
+ is_SeqSigList(Val).
+
+chk_SignalRequest(R, R) ->
+ chk_type(fun is_SignalRequest/1, 'SignalRequest', R);
+chk_SignalRequest({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_SignalRequest_tag(Tag) andalso
+ is_SignalRequest_val(Tag, Val1) andalso
+ is_SignalRequest_val(Tag, Val2)) of
+ true ->
+ chk_SignalRequest_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_SignalRequest_tag(Tag1) andalso
+ is_SignalRequest_val(Tag1, Val1)) andalso
+ (is_SignalRequest_tag(Tag2) andalso
+ is_SignalRequest_val(Tag2, Val2))) of
+ true ->
+ not_equal('SignalRequest', R1, R2);
+ false ->
+ wrong_type('SignalRequest', R1, R2)
+ end;
+chk_SignalRequest(R1, R2) ->
+ wrong_type('SignalRequest', R1, R2).
+
+chk_SignalRequest_val(signal, Val1, Val2) ->
+ validate(fun() -> chk_Signal(Val1, Val2) end, 'SignalRequest');
+chk_SignalRequest_val(seqSigList, Val1, Val2) ->
+ validate(fun() -> chk_SeqSigList(Val1, Val2) end, 'SignalRequest').
+
+
+%% -- SeqSigList --
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+chk_SeqSigList(L, L) ->
+ chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+chk_SeqSigList(#'SeqSigList'{id = ID1,
+ signalList = SL1},
+ #'SeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+ 'SeqSigList'),
+ chk_SeqSigList_signalList(SL1, SL2),
+ ok;
+chk_SeqSigList(L1, L2) ->
+ wrong_type('SeqSigList', L1, L2).
+
+chk_SeqSigList_signalList([], []) ->
+ ok;
+chk_SeqSigList_signalList([] = L1, L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList(L1, [] = L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+ case is_Signal(H) of
+ true ->
+ chk_SeqSigList_signalList(T1, T2);
+ false ->
+ wrong_type('SeqSigList_signalList_val', H)
+ end;
+chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Signal(H1, H2) end,
+ 'SeqSigList_signalList_val'),
+ chk_SeqSigList_signalList(T1, T2);
+chk_SeqSigList_signalList(L1, L2) ->
+ wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}) ->
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+chk_Signal(S, S) ->
+ chk_type(fun is_Signal/1, 'Signal', S);
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = SID1,
+ sigType = ST1,
+ duration = Dur1,
+ notifyCompletion = NC1,
+ keepActive = KA1,
+ sigParList = SPL1},
+ #'Signal'{signalName = N2,
+ streamID = SID2,
+ sigType = ST2,
+ duration = Dur2,
+ notifyCompletion = NC2,
+ keepActive = KA2,
+ sigParList = SPL2}) ->
+ validate(fun() -> chk_SignalName(N1, N2) end, 'Signal'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'Signal'),
+ validate(fun() -> chk_opt_SignalType(ST1, ST2) end, 'Signal'),
+ validate(fun() -> chk_opt_INTEGER(Dur1, Dur2, {range, 0, 65535}) end,
+ 'Signal'),
+ validate(fun() -> chk_opt_NotifyCompletion(NC1, NC2) end, 'Signal'),
+ validate(fun() -> chk_opt_BOOLEAN(KA1, KA2) end, 'Signal'),
+ chk_Signal_sigParList(SPL1, SPL2),
+ ok;
+chk_Signal(S1, S2) ->
+ wrong_type('Signal', S1, S2).
+
+chk_Signal_sigParList([], []) ->
+ ok;
+chk_Signal_sigParList([] = L1, L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList(L1, [] = L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList([H|T1], [H|T2]) ->
+ case is_SigParameter(H) of
+ true ->
+ chk_Signal_sigParList(T1, T2);
+ false ->
+ wrong_type('Signal_sigParList_val', H)
+ end;
+chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SigParameter(H1, H2) end,
+ 'Signal_sigParList_val'),
+ chk_Signal_sigParList(T1, T2);
+chk_Signal_sigParList(L1, L2) ->
+ wrong_type('Signal_sigParList', L1, L2).
+
+
+%% -- SignalType --
+
+is_opt_SignalType(asn1_NOVALUE) ->
+ true;
+is_opt_SignalType(T) ->
+ is_SignalType(T).
+
+is_SignalType(T) ->
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+chk_opt_SignalType(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalType(T1, T2) ->
+ chk_SignalType(T1, T2).
+
+chk_SignalType(T, T) ->
+ chk_type(fun is_SignalType/1, 'SignalType', T);
+chk_SignalType(T1, T2) ->
+ case (is_SignalType(T1) andalso is_SignalType(T2)) of
+ true ->
+ not_equal('SignalType', T1, T2);
+ false ->
+ wrong_type('SignalType', T1, T2)
+ end.
+
+
+%% -- SignalName --
+
+is_SignalName(N) -> is_PkgdName(N).
+
+chk_SignalName(N1, N2) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:member(NC, Valids).
+
+chk_opt_NotifyCompletion(NC1, NC2) ->
+ chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+ fun is_NotifyCompletion/1,
+ fun chk_NotifyCompletion/2).
+
+chk_NotifyCompletion(NC, NC) ->
+ chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+chk_NotifyCompletion(NC1, NC2) ->
+ case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+ true ->
+ not_equal('NotifyCompletion', NC1, NC2);
+ false ->
+ wrong_type('NotifyCompletion', NC1, NC2)
+ end.
+
+
+%% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_SigParameter(P, P) ->
+ chk_type(fun is_SigParameter/1, 'SigParameter', P);
+chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = I1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+ validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+ chk_SigParameter_extraInfo(I1, I2),
+ ok;
+chk_SigParameter(P1, P2) ->
+ wrong_type('SigParameter', P1, P2).
+
+chk_SigParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_SigParameter_extraInfo_tag(Tag) and
+ is_SigParameter_extraInfo_val(Tag, Val1) and
+ is_SigParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_SigParameter_extraInfo_tag(Tag1) and
+ is_SigParameter_extraInfo_val(Tag1, Val1)) and
+ (is_SigParameter_extraInfo_tag(Tag2) and
+ is_SigParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('SigParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo(EI1, EI2) ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% -- RequestID --
+
+is_opt_RequestID(asn1_NOVALUE) ->
+ true;
+is_opt_RequestID(V) ->
+ is_RequestID(V).
+
+is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestID(V1, V2) ->
+ chk_RequestID(V1, V2).
+
+chk_RequestID(ID, ID) ->
+ chk_type(fun is_RequestID/1, 'RequestID', ID);
+chk_RequestID(ID1, ID2) ->
+ case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+ true ->
+ not_equal('RequestID', ID1, ID2);
+ false ->
+ wrong_type('RequestID', ID1, ID2)
+ end.
+
+
+%% -- ModemDescriptor --
+
+is_ModemDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ true;
+is_ModemDescriptor(_) ->
+ false.
+
+chk_ModemDescriptor(D, D) when is_record(D, 'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+ mpl = MPL1,
+ nonStandardData = NSD1},
+ #'ModemDescriptor'{mtl = MTL2,
+ mpl = MPL2,
+ nonStandardData = NSD2}) ->
+ chk_ModemDescriptor_mtl(MTL1, MTL2),
+ chk_ModemDescriptor_mpl(MPL1, MPL2),
+ chk_opt_NonStandardData(NSD1, NSD2),
+ ok;
+chk_ModemDescriptor(D1, D2) ->
+ wrong_type('ModemDescriptor', D1, D2).
+
+chk_ModemDescriptor_mtl([], []) ->
+ ok;
+chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+ case is_ModemType(H) of
+ true ->
+ chk_ModemDescriptor_mtl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mtl_val', H)
+ end;
+chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+ chk_ModemDescriptor_mtl(T1, T2);
+chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+ wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+chk_ModemDescriptor_mpl([], []) ->
+ ok;
+chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ModemDescriptor_mpl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mpl_val', H)
+ end;
+chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+ chk_ModemDescriptor_mpl(T1, T2);
+chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+ wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% -- ModemType --
+
+chk_ModemType(MT, MT) ->
+ case is_ModemType(MT) of
+ true ->
+ ok;
+ false ->
+ wrong_type('ModemType', MT, MT)
+ end;
+chk_ModemType(MT1, MT2) ->
+ case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+ true ->
+ not_equal('ModemType', MT1, MT2);
+ false ->
+ wrong_type('ModemType', MT1, MT2)
+ end.
+
+is_ModemType(MT) ->
+ lists:member(MT,
+ [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% -- DigitMapDescriptor --
+
+is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Val}) ->
+ is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+is_DigitMapDescriptor(_) ->
+ false.
+
+chk_DigitMapDescriptor(D, D) ->
+ chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+ digitMapValue = Val1},
+ #'DigitMapDescriptor'{digitMapName = Name2,
+ digitMapValue = Val2}) ->
+ d("chk_DigitMapDescriptor -> entry with"
+ "~n Name1: ~p"
+ "~n Name2: ~p"
+ "~n Val1: ~p"
+ "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'DigitMapDescriptor'),
+ validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+ 'DigitMapDescriptor'),
+ ok;
+chk_DigitMapDescriptor(D1, D2) ->
+ wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% -- DigitMapName --
+
+is_opt_DigitMapName(asn1_NOVALUE) ->
+ true;
+is_opt_DigitMapName(N) ->
+ is_DigitMapName(N).
+
+is_DigitMapName(N) -> is_Name(N).
+
+chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_DigitMapName(N1, N2) ->
+ chk_DigitMapName(N1, N2).
+
+chk_DigitMapName(N, N) ->
+ chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+chk_DigitMapName(N1, N2) ->
+ case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+ true ->
+ not_equal('DigitMapName', N1, N2);
+ false ->
+ wrong_type('DigitMapName', N1, N2)
+ end.
+
+
+%% -- DigitMapValue --
+
+is_opt_DigitMapValue(V) ->
+ is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Dur}) ->
+ is_DigitMapValue_startTimer(Start) andalso
+ is_DigitMapValue_shortTimer(Short) andalso
+ is_DigitMapValue_longTimer(Long) andalso
+ is_IA5String(Body) andalso
+ is_DigitMapValue_durationTimer(Dur);
+is_DigitMapValue(_) ->
+ false.
+
+is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+chk_opt_DigitMapValue(V1, V2) ->
+ chk_OPTIONAL('DigitMapValue', V1, V2,
+ fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1,
+ digitMapBody = Body1,
+ durationTimer = Dur1},
+ #'DigitMapValue'{startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2,
+ digitMapBody = Body2,
+ durationTimer = Dur2}) ->
+ d("chk_DigitMapValue -> entry with"
+ "~n Start1: ~p"
+ "~n Start2: ~p"
+ "~n Short1: ~p"
+ "~n Short2: ~p"
+ "~n Long1: ~p"
+ "~n Long2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p"
+ "~n Dur1: ~p"
+ "~n Dur2: ~p", [Start1, Start2,
+ Short1, Short2,
+ Long1, Long2,
+ Body1, Body2,
+ Dur1, Dur2]),
+ chk_DigitMapValue_startTimer(Start1, Start2),
+ chk_DigitMapValue_shortTimer(Short1, Short2),
+ chk_DigitMapValue_longTimer(Long1, Long2),
+ chk_DigitMapValue_digitMapBody(Body1, Body2),
+ chk_DigitMapValue_durationTimer(Dur1, Dur2),
+ ok;
+chk_DigitMapValue(V1, V2) ->
+ wrong_type('DigitMapValue', V1, V2).
+
+chk_DigitMapValue_startTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+chk_DigitMapValue_startTimer(T1, T2) ->
+ case (is_DigitMapValue_startTimer(T1) andalso
+ is_DigitMapValue_startTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_startTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_startTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_shortTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+chk_DigitMapValue_shortTimer(T1, T2) ->
+ case (is_DigitMapValue_shortTimer(T1) andalso
+ is_DigitMapValue_shortTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_shortTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_shortTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_longTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+chk_DigitMapValue_longTimer(T1, T2) ->
+ case (is_DigitMapValue_longTimer(T1) andalso
+ is_DigitMapValue_longTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_longTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_longTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_durationTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_durationTimer/1,
+ 'DigitMapValue_durationTimer', T);
+chk_DigitMapValue_durationTimer(T1, T2) ->
+ case (is_DigitMapValue_durationTimer(T1) andalso
+ is_DigitMapValue_durationTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_durationTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_durationTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_digitMapBody(B, B) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B: ~p", [B]),
+ chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+chk_DigitMapValue_digitMapBody(B1, B2) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B1: ~p"
+ "~n B2: ~p", [B1, B2]),
+ case (is_IA5String(B1) andalso is_IA5String(B2)) of
+ true ->
+ %% If they are different it could be because
+ %% of trailing tab's and newline's.
+ case compare_strings(B1, B2) of
+ {[], []} ->
+ ok;
+ {Str1, []} ->
+ case strip_tab_and_newline(Str1) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ {[], Str2} ->
+ case strip_tab_and_newline(Str2) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ false ->
+ wrong_type('DigitMapValue_digitMapBody', B1, B2)
+ end.
+
+%% -- ServiceChangeParm --
+
+is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Id,
+ timeStamp = TS,
+ nonStandardData = NSD,
+ serviceChangeInfo = I}) ->
+ is_ServiceChangeMethod(M) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_Value(R) andalso
+ is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+ is_opt_MId(Id) andalso
+ is_opt_TimeNotation(TS) andalso
+ is_opt_NonStandardData(NSD) andalso
+ is_opt_AuditDescriptor(I);
+is_ServiceChangeParm(_) ->
+ false.
+
+chk_ServiceChangeParm(P, P) ->
+ chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Id1,
+ timeStamp = TS1,
+ nonStandardData = NSD1,
+ serviceChangeInfo = I1},
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Id2,
+ timeStamp = TS2,
+ nonStandardData = NSD2,
+ serviceChangeInfo = I2}) ->
+ validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_Value(R1, R2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_MId(Id1, Id2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+ 'ServiceChangeParm'),
+ ok;
+chk_ServiceChangeParm(P1, P2) ->
+ wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% -- ServiceChangeAddress --
+
+is_opt_ServiceChangeAddress(A) ->
+ is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+is_ServiceChangeAddress({Tag, Val}) ->
+ is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val);
+is_ServiceChangeAddress(_) ->
+ false.
+
+is_ServiceChangeAddress_tag(Tag) ->
+ Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+ mtpAddress],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeAddress_val(portNumber, Val) ->
+ is_INTEGER(Val, {range, 0, 65535});
+is_ServiceChangeAddress_val(ip4Address, Val) ->
+ is_IP4Address(Val);
+is_ServiceChangeAddress_val(ip6Address, Val) ->
+ is_IP6Address(Val);
+is_ServiceChangeAddress_val(domainName, Val) ->
+ is_DomainName(Val);
+is_ServiceChangeAddress_val(deviceName, Val) ->
+ is_PathName(Val);
+is_ServiceChangeAddress_val(mtpAddress, Val) ->
+ is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+chk_opt_ServiceChangeAddress(A1, A2) ->
+ chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+ fun is_ServiceChangeAddress/1,
+ fun chk_ServiceChangeAddress/2).
+
+chk_ServiceChangeAddress(A, A) ->
+ chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+ case (is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val1) andalso
+ is_ServiceChangeAddress_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+ case ((is_ServiceChangeAddress_tag(Tag1) andalso
+ is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+ (is_ServiceChangeAddress_tag(Tag2) andalso
+ is_ServiceChangeAddress_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeAddress', A1, A2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress(A1, A2) ->
+ wrong_type('ServiceChangeAddress', A1, A2).
+
+chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+ validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+ validate(fun() -> chk_IP4Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+ validate(fun() -> chk_IP6Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+ validate(fun() -> chk_DomainName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+ validate(fun() -> chk_PathName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+ validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+ 'ServiceChangeAddress').
+
+
+%% -- ServiceChangeResParm --
+
+is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ timeStamp = TS}) ->
+ is_opt_MId(Id) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_opt_TimeNotation(TS);
+is_ServiceChangeResParm(_) ->
+ false.
+
+chk_ServiceChangeResParm(P, P) ->
+ chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+chk_ServiceChangeResParm(
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ timeStamp = TS1},
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ timeStamp = TS2}) ->
+ validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeResParm'),
+ ok;
+chk_ServiceChangeResParm(P1, P2) ->
+ wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% -- ServiceChangeMethod --
+
+is_ServiceChangeMethod(M) ->
+ Methods = [failover, forced, graceful, restart, disconnected, handOff],
+ lists:member(M, Methods).
+
+chk_ServiceChangeMethod(M, M) ->
+ chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+chk_ServiceChangeMethod(M1, M2) ->
+ case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+ true ->
+ not_equal('ServiceChangeMethod', M1, M2);
+ false ->
+ wrong_type('ServiceChangeMethod', M1, M2)
+ end.
+
+
+%% -- ServiceChangeProfile --
+
+is_opt_ServiceChangeProfile(P) ->
+ is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+ is_IA5String(N, {range, 1, 67});
+is_ServiceChangeProfile(_) ->
+ false.
+
+chk_opt_ServiceChangeProfile(P1, P2) ->
+ chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+ fun is_ServiceChangeProfile/1,
+ fun chk_ServiceChangeProfile/2).
+
+chk_ServiceChangeProfile(P, P) ->
+ chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+ #'ServiceChangeProfile'{profileName = N2}) ->
+ validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+ 'ServiceChangeProfile'),
+ ok;
+chk_ServiceChangeProfile(P1, P2) ->
+ wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% -- PackagesDescriptor --
+
+is_PackagesDescriptor([]) ->
+ true;
+is_PackagesDescriptor([H|T]) ->
+ is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+is_PackagesDescriptor(_) ->
+ false.
+
+chk_PackagesDescriptor([], []) ->
+ ok;
+chk_PackagesDescriptor([] = D1, D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor(D1, [] = D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor([H|T1], [H|T2]) ->
+ case is_PackagesItem(H) of
+ true ->
+ chk_PackagesDescriptor(T1, T2);
+ false ->
+ wrong_type('PackagesDescriptor_val', H)
+ end;
+chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PackagesItem(H1, H2) end,
+ 'PackagesDescriptor_val'),
+ chk_PackagesDescriptor(T1, T2);
+chk_PackagesDescriptor(D1, D2) ->
+ wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% -- PackagesItem --
+
+is_PackagesItem(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+is_PackagesItem(_) ->
+ false.
+
+chk_PackagesItem(I, I) ->
+ chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+chk_PackagesItem(#'PackagesItem'{packageName = N1,
+ packageVersion = V1},
+ #'PackagesItem'{packageName = N2,
+ packageVersion = V2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+ ok;
+chk_PackagesItem(I1, I2) ->
+ wrong_type('PackagesItem', I1, I2).
+
+
+%% -- StatisticsDescriptor --
+
+is_StatisticsDescriptor([]) ->
+ true;
+is_StatisticsDescriptor([H|T]) ->
+ is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+is_StatisticsDescriptor(_) ->
+ false.
+
+chk_StatisticsDescriptor([], []) ->
+ ok;
+chk_StatisticsDescriptor([] = D1, D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor(D1, [] = D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+ case is_StatisticsParameter(H) of
+ true ->
+ chk_StatisticsDescriptor(T1, T2);
+ false ->
+ wrong_type('StatisticsDescriptor_val', H)
+ end;
+chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+ 'StatisticsDescriptor_val'),
+ chk_StatisticsDescriptor(T1, T2);
+chk_StatisticsDescriptor(D1, D2) ->
+ wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% -- StatisticsParameter --
+
+is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+ statValue = V}) ->
+ is_PkgdName(N) andalso is_opt_Value(V);
+is_StatisticsParameter(_) ->
+ false.
+
+chk_StatisticsParameter(P, P) ->
+ chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+ statValue = V1},
+ #'StatisticsParameter'{statName = N2,
+ statValue = V2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+ validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+ ok;
+chk_StatisticsParameter(P1, P2) ->
+ wrong_type('StatisticsParameter', P1, P2).
+
+
+%% -- NonStandardData --
+
+is_opt_NonStandardData(asn1_NOVALUE) ->
+ true;
+is_opt_NonStandardData(NSD) ->
+ is_NonStandardData(NSD).
+
+%% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% data = D}) ->
+%% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% is_NonStandardData(_) ->
+%% false.
+
+is_NonStandardData(_) ->
+ true.
+
+chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+ true;
+chk_opt_NonStandardData(NSD1, NSD2) ->
+ chk_NonStandardData(NSD1, NSD2).
+
+chk_NonStandardData(NSD, NSD) ->
+ chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% data = D1},
+%% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% data = D2}) ->
+%% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% 'NonStandardData'),
+%% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% ok;
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% wrong_type('NonStandardData', NSD1, NSD2).
+chk_NonStandardData(NSD1, NSD2) ->
+ not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% -- NonStandardIdentifier --
+
+%% is_NonStandardIdentifier({Tag, Val}) ->
+%% is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val);
+%% is_NonStandardIdentifier(_) ->
+%% false.
+
+%% is_NonStandardIdentifier_tag(Tag) ->
+%% Tags = [object, h221NonStandard, experimental],
+%% lists:member(Tag, Tags).
+
+%% is_NonStandardIdentifier_val(object, Val) ->
+%% is_OBJECT_IDENTIFIER(Val);
+%% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% is_H221NonStandard(Val);
+%% is_NonStandardIdentifier_val(experimental, Val) ->
+%% is_IA5String(Val, {exact, 8}).
+
+%% chk_NonStandardIdentifier(Id, Id) ->
+%% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% true ->
+%% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% true ->
+%% not_equal('NonStandardIdentifier', Id1, Id2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier(Id1, Id2) ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% chk_H221NonStandard(Val1, Val2);
+%% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% -- H221NonStandard --
+
+%% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}) ->
+%% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 65535});
+%% is_H221NonStandard(_) ->
+%% false.
+
+%% chk_H221NonStandard(NS, NS) ->
+%% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% t35CountryCode2 = CC21,
+%% t35Extension = Ext1,
+%% manufacturerCode = MC1},
+%% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% t35CountryCode2 = CC22,
+%% t35Extension = Ext2,
+%% manufacturerCode = MC2}) ->
+%% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% 'H221NonStandard'),
+%% ok;
+%% chk_H221NonStandard(NS1, NS2) ->
+%% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% -- TimeNotation --
+
+is_opt_TimeNotation(asn1_NOVALUE) ->
+ true;
+is_opt_TimeNotation(TN) ->
+ is_TimeNotation(TN).
+
+is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+ is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+is_TimeNotation(_) ->
+ false.
+
+chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(TN1, TN2) ->
+ chk_TimeNotation(TN1, TN2).
+
+chk_TimeNotation(TN, TN) ->
+ chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+ #'TimeNotation'{date = D2, time = T2}) ->
+ validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+ validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+ ok;
+chk_TimeNotation(TN1, TN2) ->
+ wrong_type('TimeNotation', TN1, TN2).
+
+
+%% -- Value --
+
+is_opt_Value(V) ->
+ is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+chk_opt_Value(V1, V2) ->
+ chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+chk_Value(V, V) ->
+ case is_Value(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Value', V, V)
+ end;
+chk_Value(V1, V2) ->
+ case (is_Value(V1) andalso is_Value(V2)) of
+ true ->
+ not_equal('Value', V1, V2);
+ false ->
+ wrong_type('Value', V1, V2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Basic type check functions
+%% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ lists:member(B, [true, false]).
+
+chk_opt_BOOLEAN(B1, B2) ->
+ chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+chk_BOOLEAN(B, B) ->
+ chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+chk_BOOLEAN(B1, B2) ->
+ case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+ true ->
+ not_equal('BOOLEAN', B1, B2);
+ false ->
+ wrong_type('BOOLEAN', B1, B2)
+ end.
+
+
+is_IA5String(S) when is_list(S) ->
+ true;
+is_IA5String(_) ->
+ false.
+
+is_IA5String(S, _) when is_list(S) ->
+ true;
+is_IA5String(_, _) ->
+ false.
+
+%% chk_IA5String(S, S) ->
+%% chk_type(fun is_IA5String/1, 'IA5String', S);
+%% chk_IA5String(S1, S2) ->
+%% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+%% true ->
+%% not_equal('IA5String', S1, S2);
+%% false ->
+%% wrong_type('IA5String', S1, S2)
+%% end.
+
+chk_IA5String(S, S, R) ->
+ chk_type(fun is_IA5String/2, 'IA5String', S, R);
+chk_IA5String(S1, S2, R) ->
+ case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+ true ->
+ not_equal('IA5String', S1, S2);
+ false ->
+ wrong_type('IA5String', S1, S2)
+ end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) andalso (length(L) =:= Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) andalso (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) andalso (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) andalso (Min =< length(L)) andalso (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% chk_OCTET_STRING(L1, L2) ->
+%% chk_OCTET_STRING(L1, L2, any).
+
+chk_OCTET_STRING(L, L, R) ->
+ chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+chk_OCTET_STRING(L1, L2, R) ->
+ case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+ true ->
+ not_equal('OCTET STRING', L1, L2);
+ false ->
+ wrong_type('OCTET STRING', L1, L2)
+ end.
+
+
+%% is_OBJECT_IDENTIFIER(_) ->
+%% true.
+
+%% chk_OBJECT_IDENTIFIER(X, X) ->
+%% ok;
+%% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+is_opt_NULL(N) ->
+ is_OPTIONAL(fun is_NULL/1, N).
+
+is_NULL('NULL') ->
+ true;
+is_NULL(_) ->
+ false.
+
+chk_opt_NULL(N1, N2) ->
+ chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+chk_NULL(N, N) ->
+ chk_type(fun is_NULL/1, 'NULL', N);
+chk_NULL(N1, N2) ->
+ case (is_NULL(N1) andalso is_NULL(N2)) of
+ true ->
+ not_equal('NULL', N1, N2);
+ false ->
+ wrong_type('NULL', N1, N2)
+ end.
+
+
+is_opt_INTEGER(I, R) ->
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min}) when is_integer(I) andalso is_integer(Min) andalso (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max}) when is_integer(I) andalso is_integer(Max) andalso (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) andalso
+ is_integer(Min) andalso
+ is_integer(Max) andalso
+ (Min =< I) andalso
+ (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+chk_opt_INTEGER(I1, I2, R) ->
+ chk_OPTIONAL('INTEGER', I1, I2,
+ fun(X) -> is_INTEGER(X, R) end,
+ fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+chk_INTEGER(I, I, R) ->
+ chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+chk_INTEGER(I1, I2, R) ->
+ case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+ true ->
+ not_equal('INTEGER', I1, I2);
+ false ->
+ wrong_type('INTEGER', I1, I2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Various utility functions
+%% ----------------------------------------------------------------------
+
+
+to_lower([C|Cs]) when C >= $A, C =< $Z ->
+ [C+($a-$A)|to_lower(Cs)];
+to_lower([C|Cs]) ->
+ [C|to_lower(Cs)];
+to_lower([]) ->
+ [].
+
+
+validate(F, Type) when is_function(F) ->
+ case (catch F()) of
+ {error, Reason} ->
+ error({Type, Reason});
+ ok ->
+ ok
+ end.
+
+
+chk_type(F, T, V) when is_function(F) andalso is_atom(T) ->
+ case F(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V)
+ end.
+
+chk_type(F, T, V1, V2) when is_function(F) andalso is_atom(T) ->
+ case F(V1, V2) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V1)
+ end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+ ok;
+chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when is_function(IS) ->
+ case IS(V2) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when is_function(IS) ->
+ case IS(V1) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when is_function(CHK) ->
+ CHK(V1, V2).
+
+
+%% ----------------------------------------------------------------------
+
+compare_strings([] = L1, L2) ->
+ {L1, L2};
+compare_strings(L1, [] = L2) ->
+ {L1, L2};
+compare_strings([H|T1], [H|T2]) ->
+ compare_strings(T1, T2);
+compare_strings(L1, L2) ->
+ {L1, L2}.
+
+strip_tab_and_newline([]) ->
+ [];
+strip_tab_and_newline([$\n|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([$\t|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([H|T]) ->
+ [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+atmost_once(Type, Val) ->
+ error({atmost_once, {Type, Val}}).
+
+wrong_type(Type, Val) ->
+ error({wrong_type, {Type, Val}}).
+
+wrong_type(Type, Val1, Val2) ->
+ error({wrong_type, {Type, Val1, Val2}}).
+
+not_equal(What, Val1, Val2) ->
+ error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_msg_v3_lib.erl b/lib/megaco/test/megaco_test_msg_v3_lib.erl
new file mode 100644
index 0000000000..7b0d4f7d37
--- /dev/null
+++ b/lib/megaco/test/megaco_test_msg_v3_lib.erl
@@ -0,0 +1,8724 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for creating the megaco types
+%%----------------------------------------------------------------------
+
+-module(megaco_test_msg_v3_lib).
+
+%% ----
+
+-include_lib("megaco/include/megaco_message_v3.hrl").
+-include_lib("megaco/include/megaco.hrl").
+
+%% ----
+
+-export([chk_MegacoMessage/2,
+
+ cre_MegacoMessage/1,
+ cre_MegacoMessage/2,
+
+ cre_ActionReply/2,
+ cre_ActionReply/3,
+ cre_ActionReply/4,
+ cre_ActionRequest/2,
+ cre_ActionRequest/3,
+ cre_ActionRequest/4,
+ cre_AmmDescriptor/1,
+ cre_AmmRequest/2,
+ cre_AmmsReply/1,
+ cre_AmmsReply/2,
+ cre_AuditDescriptor/0,
+ cre_AuditDescriptor/1,
+ cre_AuditDescriptor/2,
+ cre_AuditReply/1,
+ cre_AuditRequest/2,
+ cre_AuditRequest/3,
+ cre_AuditResult/2,
+ cre_AuditReturnParameter/1,
+ cre_AuthenticationHeader/3,
+ cre_BOOLEAN/1,
+ cre_Command/2,
+ cre_CommandReply/2,
+ cre_CommandRequest/1,
+ cre_CommandRequest/2,
+ cre_CommandRequest/3,
+ cre_ContextAttrAuditRequest/0,
+ cre_ContextAttrAuditRequest/3,
+ cre_ContextAttrAuditRequest/4,
+ cre_ContextAttrAuditRequest/5,
+ cre_ContextAttrAuditRequest/6,
+ cre_ContextAttrAuditRequest/7,
+ cre_ContextAttrAuditRequest/8,
+ cre_ContextAttrAuditRequest/9,
+ cre_ContextID/1,
+ cre_ContextRequest/0,
+ cre_ContextRequest/1,
+ cre_ContextRequest/2,
+ cre_ContextRequest/3,
+ cre_ContextRequest/4,
+ cre_ContextRequest/5,
+ cre_ContextRequest/6,
+ cre_DigitMapDescriptor/0,
+ cre_DigitMapDescriptor/1,
+ cre_DigitMapDescriptor/2,
+ cre_DigitMapName/1,
+ cre_DigitMapValue/1,
+ cre_DigitMapValue/4,
+ cre_DigitMapValue/5,
+ cre_ErrorCode/1,
+ cre_ErrorDescriptor/1,
+ cre_ErrorDescriptor/2,
+ cre_ErrorText/1,
+ cre_EventBufferControl/1,
+ cre_EventBufferDescriptor/1,
+ cre_EventDM/1,
+ cre_EventName/1,
+ cre_EventParameter/2,
+ cre_EventParameter/4,
+ cre_EventsDescriptor/0,
+ cre_EventsDescriptor/2,
+ cre_EventSpec/2,
+ cre_EventSpec/3,
+ %% cre_H221NonStandard/4,
+ cre_IndAuditParameter/1,
+ cre_IndAudLocalControlDescriptor/0,
+ cre_IndAudLocalControlDescriptor/4,
+ cre_IndAudLocalControlDescriptor/5,
+ cre_IndAudLocalRemoteDescriptor/1,
+ cre_IndAudLocalRemoteDescriptor/2,
+ cre_IndAudMediaDescriptor/0,
+ cre_IndAudMediaDescriptor/1,
+ cre_IndAudMediaDescriptor/2,
+ cre_IndAudPropertyGroup/1,
+ cre_IndAudPropertyParm/1,
+ cre_IndAudPropertyParm/2,
+ cre_IndAudDigitMapDescriptor/0,
+ cre_IndAudDigitMapDescriptor/1,
+ cre_IndAudEventBufferDescriptor/1,
+ cre_IndAudEventBufferDescriptor/2,
+ cre_IndAudEventsDescriptor/1,
+ cre_IndAudEventsDescriptor/2,
+ cre_IndAudEventsDescriptor/3,
+ cre_IndAudPackagesDescriptor/2,
+ cre_IndAudSeqSigList/1,
+ cre_IndAudSeqSigList/2,
+ cre_IndAudSignal/1,
+ cre_IndAudSignal/2,
+ cre_IndAudSignalsDescriptor/1,
+ cre_IndAudStatisticsDescriptor/1,
+ cre_IndAudStreamDescriptor/2,
+ cre_IndAudStreamParms/0,
+ cre_IndAudStreamParms/1,
+ cre_IndAudStreamParms/3,
+ cre_IndAudStreamParms/4,
+ cre_IndAudTerminationStateDescriptor/1,
+ cre_IndAudTerminationStateDescriptor/3,
+ cre_IndAudTerminationStateDescriptor/4,
+ cre_LocalControlDescriptor/1,
+ cre_LocalControlDescriptor/2,
+ cre_LocalControlDescriptor/4,
+ cre_LocalRemoteDescriptor/1,
+ cre_MediaDescriptor/0,
+ cre_MediaDescriptor/1,
+ cre_MediaDescriptor/2,
+ cre_Message/3,
+ cre_ModemDescriptor/2,
+ %% cre_ModemDescriptor/3,
+ cre_ModemType/1,
+ cre_MuxDescriptor/2,
+ %% cre_MuxDescriptor/3,
+ cre_MuxType/1,
+ cre_Name/1,
+ %% cre_NonStandardData/2,
+ %% cre_NonStandardIdentifier/1,
+ cre_NotifyBehaviour/2,
+ cre_NotifyCompletion/1,
+ cre_NotifyReply/1,
+ cre_NotifyReply/2,
+ cre_NotifyRequest/2,
+ cre_NotifyRequest/3,
+ cre_ObservedEvent/2,
+ cre_ObservedEvent/3,
+ cre_ObservedEvent/4,
+ cre_ObservedEventsDescriptor/2,
+ cre_PackagesDescriptor/1,
+ cre_PackagesItem/2,
+ cre_PkgdName/1,
+ cre_PkgdName/2,
+ cre_PropertyGroup/1,
+ cre_PropertyParm/2,
+ cre_PropertyParm/4,
+ cre_RegulatedEmbeddedDescriptor/0,
+ cre_RegulatedEmbeddedDescriptor/1,
+ cre_RegulatedEmbeddedDescriptor/2,
+ cre_Relation/1,
+ cre_RequestedActions/0,
+ cre_RequestedActions/1,
+ cre_RequestedActions/4,
+ cre_RequestedActions/6,
+ cre_RequestedEvent/1,
+ cre_RequestedEvent/2,
+ cre_RequestedEvent/3,
+ cre_RequestedEvent/4,
+ cre_RequestID/1,
+ cre_SecondEventsDescriptor/1,
+ cre_SecondEventsDescriptor/2,
+ cre_SecondRequestedActions/0,
+ cre_SecondRequestedActions/1,
+ cre_SecondRequestedActions/2,
+ cre_SecondRequestedActions/3,
+ cre_SecondRequestedActions/5,
+ cre_SecondRequestedEvent/2,
+ cre_SecondRequestedEvent/3,
+ cre_SecondRequestedEvent/4,
+ cre_SegmentReply/2,
+ cre_SegmentReply/3,
+ cre_SelectLogic/1,
+ cre_SeqSigList/2,
+ cre_ServiceChangeAddress/2,
+ cre_ServiceChangeRequest/2,
+ cre_ServiceChangeMethod/1,
+ cre_ServiceChangeParm/2,
+ cre_ServiceChangeParm/4,
+ cre_ServiceChangeParm/9,
+ cre_ServiceChangeParm/10,
+ cre_ServiceChangeProfile/1,
+ cre_ServiceChangeProfile/2,
+ cre_ServiceChangeReply/2,
+ cre_ServiceChangeResParm/0,
+ cre_ServiceChangeResParm/2,
+ cre_ServiceChangeResParm/5,
+ cre_ServiceChangeResult/1,
+ cre_ServiceState/1,
+ cre_Signal/1,
+ cre_Signal/2,
+ cre_Signal/7,
+ cre_Signal/9,
+ cre_Signal/10,
+ cre_SignalDirection/1,
+ cre_SignalName/1,
+ cre_SignalRequest/1,
+ cre_SignalsDescriptor/1,
+ cre_SignalType/1,
+ cre_SigParameter/2,
+ cre_SigParameter/4,
+ cre_StatisticsDescriptor/1,
+ cre_StatisticsParameter/1,
+ cre_StatisticsParameter/2,
+ cre_StreamDescriptor/2,
+ cre_StreamID/1,
+ cre_StreamMode/1,
+ cre_StreamParms/0,
+ cre_StreamParms/1,
+ cre_StreamParms/2,
+ cre_StreamParms/3,
+ cre_StreamParms/4,
+ cre_SubtractRequest/1,
+ cre_SubtractRequest/2,
+ cre_TopologyRequest/3,
+ cre_TopologyRequest/4,
+ cre_TerminationAudit/1,
+ cre_TerminationID/2,
+ cre_TerminationIDList/1,
+ cre_TerminationStateDescriptor/1,
+ cre_TerminationStateDescriptor/2,
+ cre_TerminationStateDescriptor/3,
+ cre_TermListAuditResult/2,
+ cre_TimeNotation/2,
+ cre_Transaction/1,
+ cre_TransactionAck/1,
+ cre_TransactionAck/2,
+ cre_TransactionId/1,
+ cre_TransactionPending/1,
+ cre_TransactionReply/2,
+ cre_TransactionReply/3,
+ cre_TransactionReply/4,
+ cre_TransactionReply/5,
+ cre_TransactionRequest/2,
+ cre_Value/1
+ %% cre_WildcardField/1,
+ ]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cre_MegacoMessage(M) when is_record(M, 'Message') ->
+ #'MegacoMessage'{mess = M}.
+
+cre_MegacoMessage(AH, M)
+ when is_record(AH, 'AuthenticationHeader') and
+ is_record(M, 'Message') ->
+ #'MegacoMessage'{authHeader = AH,
+ mess = M}.
+
+cre_AuthenticationHeader(SPI, SN, AD) ->
+ #'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}.
+
+cre_Message(V, Mid, ED) when is_record(ED, 'ErrorDescriptor') ->
+ Body = {errorDescriptor, ED},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, Transactions) when is_list(Transactions) ->
+ Body = {transactions, Transactions},
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {transactions, T} = Body) when is_list(T) ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body};
+cre_Message(V, Mid, {errorDescriptor, ED} = Body)
+ when is_record(ED, 'ErrorDescriptor') ->
+ #'Message'{version = V,
+ mId = Mid,
+ messageBody = Body}.
+
+
+cre_ErrorDescriptor(EC) when is_integer(EC) ->
+ #'ErrorDescriptor'{errorCode = EC}.
+
+cre_ErrorDescriptor(EC, ET) when is_integer(EC) and is_list(ET) ->
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_ErrorCode(C) when is_integer(C) and (0 =< C) and (C =< 65535) ->
+ C;
+cre_ErrorCode(C) ->
+ exit({invalid_ErrorCode, C}).
+
+cre_ErrorText(T) when is_list(T) ->
+ T.
+
+cre_ContextID(Val) when (0 =< Val) and (Val =< 4294967295) ->
+ Val;
+cre_ContextID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+cre_Transaction(TR) when is_record(TR, 'TransactionRequest') ->
+ {transactionRequest, TR};
+cre_Transaction(TP) when is_record(TP, 'TransactionPending') ->
+ {transactionPending, TP};
+cre_Transaction(TR) when is_record(TR, 'TransactionReply') ->
+ {transactionReply, TR};
+cre_Transaction(TRA) when is_list(TRA) ->
+ {transactionResponseAck, TRA};
+cre_Transaction(SR) when is_record(SR, 'SegmentReply') ->
+ {segmentReply, SR}.
+
+cre_TransactionId(Val) when (0 =< Val) and (Val =< 4294967295) ->
+ Val;
+cre_TransactionId(Val) ->
+ exit({invalid_TransactionId, Val}).
+
+cre_TransactionRequest(TransID, ARs)
+ when is_integer(TransID) and is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransID,
+ actions = ARs}.
+
+cre_TransactionPending(TransID) when is_integer(TransID) ->
+ #'TransactionPending'{transactionId = TransID}.
+
+cre_TransactionReply(TransID, ED)
+ when is_integer(TransID) and is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, ARs)
+ when is_integer(TransID) and is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ transactionResult = Res};
+cre_TransactionReply(TransID, Res) ->
+ error({invalid_TransactionReply_values, {TransID, Res}}).
+
+cre_TransactionReply(TransID, IAR, ED)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_record(ED, 'ErrorDescriptor') ->
+ Res = {transactionError, ED},
+ #'TransactionReply'{transactionId = TransID,
+ immAckRequired = IAR,
+ transactionResult = Res};
+cre_TransactionReply(TransID, IAR, ARs)
+ when is_integer(TransID) and
+ ((IAR == 'NULL') or (IAR == asn1_NOVALUE)) and
+ is_list(ARs) ->
+ Res = {actionReplies, ARs},
+ #'TransactionReply'{transactionId = TransID,
+ immAckRequired = IAR,
+ transactionResult = Res};
+cre_TransactionReply(TransID, Res, SN)
+ when (is_integer(SN) and (SN > 0) and (SN =< 65535)) or
+ (SN == asn1_NOVALUE) ->
+ TR = cre_TransactionReply(TransID, Res),
+ TR#'TransactionReply'{segmentNumber = SN};
+cre_TransactionReply(TransID, Res, SN) ->
+ error({invalid_TransactionReply_values, {TransID, Res, SN}}).
+
+cre_TransactionReply(TransID, Res, SN, SC)
+ when is_integer(SN) and ((SC == 'NULL') or (SC == asn1_NOVALUE)) ->
+ TR = cre_TransactionReply(TransID, Res),
+ TR#'TransactionReply'{segmentNumber = SN,
+ segmentationComplete = SC};
+cre_TransactionReply(TransID, IAR, Res, SN) ->
+ cre_TransactionReply(TransID, IAR, Res, SN, asn1_NOVALUE).
+
+cre_TransactionReply(TransID, IAR, Res, SN, SC)
+ when (SN == asn1_NOVALUE) and (SC == asn1_NOVALUE) ->
+ cre_TransactionReply(TransID, IAR, Res);
+cre_TransactionReply(TransID, IAR, Res, SN, SC)
+ when (is_integer(SN) and (SN > 0) and (SN =< 65535)) and
+ ((SC == asn1_NOVALUE) or (SC == 'NULL')) ->
+ TR = cre_TransactionReply(TransID, IAR, Res),
+ TR#'TransactionReply'{segmentNumber = SN,
+ segmentationComplete = SC};
+cre_TransactionReply(TransID, IAR, Res, SN, SC) ->
+ error({invalid_TransactionReply_values, {TransID, IAR, Res, SN, SC}}).
+
+
+cre_SegmentReply(TransID, SN)
+ when is_integer(TransID) and
+ is_integer(SN) and (SN > 0) and (SN =< 65535) ->
+ #'SegmentReply'{transactionId = TransID,
+ segmentNumber = SN}.
+
+cre_SegmentReply(TransID, SN, SC)
+ when is_integer(TransID) and
+ is_integer(SN) and (SN > 0) and (SN =< 65535) and
+ ((SC == 'NULL') or (SC == asn1_NOVALUE)) ->
+ #'SegmentReply'{transactionId = TransID,
+ segmentNumber = SN,
+ segmentationComplete = SC}.
+
+cre_TransactionAck(FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck}.
+
+cre_TransactionAck(FirstAck, FirstAck) ->
+ #'TransactionAck'{firstAck = FirstAck};
+cre_TransactionAck(FirstAck, LastAck) ->
+ #'TransactionAck'{firstAck = FirstAck,
+ lastAck = LastAck}.
+
+cre_ActionRequest(CtxID, CmdReqs)
+ when is_integer(CtxID) and is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ commandRequests = CmdReqs};
+cre_ActionRequest(CtxID, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ is_record(CAAR, 'ContextAttrAuditRequest') and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionRequest(CtxID, CtxReq, CAAR, CmdReqs)
+ when is_integer(CtxID) and
+ (is_record(CtxReq, 'ContextRequest') or
+ (CtxReq == asn1_NOVALUE)) and
+ (is_record(CAAR, 'ContextAttrAuditRequest') or
+ (CAAR == asn1_NOVALUE)) and
+ is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxID,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = CAAR,
+ commandRequests = CmdReqs}.
+
+cre_ActionReply(CtxID, CmdReps)
+ when is_integer(CtxID) and
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CmdReps)
+ when is_integer(CtxID) and
+ is_record(ED, 'ErrorDescriptor') and
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ commandReply = CmdReps};
+cre_ActionReply(CtxID, CtxReq, CmdReps)
+ when is_integer(CtxID) and
+ is_record(CtxReq, 'ContextRequest') and
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ActionReply(CtxID, ED, CtxReq, CmdReps)
+ when is_integer(CtxID) andalso
+ (is_record(ED, 'ErrorDescriptor') orelse (ED =:= asn1_NOVALUE)) andalso
+ (is_record(CtxReq, 'ContextRequest') orelse (CtxReq =:= asn1_NOVALUE)) andalso
+ is_list(CmdReps) ->
+ #'ActionReply'{contextId = CtxID,
+ errorDescriptor = ED,
+ contextReply = CtxReq,
+ commandReply = CmdReps}.
+
+cre_ContextRequest() ->
+ strip_ContextRequest(#'ContextRequest'{}).
+
+cre_ContextRequest(Prio)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) ->
+ strip_ContextRequest(#'ContextRequest'{priority = Prio});
+cre_ContextRequest(Em)
+ when (Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE) ->
+ strip_ContextRequest(#'ContextRequest'{emergency = Em});
+cre_ContextRequest(Top) when is_list(Top) ->
+ strip_ContextRequest(#'ContextRequest'{topologyReq = Top}).
+
+cre_ContextRequest(Prio, Em)
+ when (is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Top)
+ when is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15) andalso is_list(Top) ->
+ CR = #'ContextRequest'{priority = Prio,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top)
+ when (is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) andalso
+ (is_list(Top) orelse (Top == asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top},
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps)
+ when (is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) andalso
+ (is_list(Top) orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= true) orelse (Ieps =:= false)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps},
+ strip_ContextRequest(CR);
+cre_ContextRequest(Prio, Em, Top, Ctx)
+ when ((is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) or
+ (Prio =:= asn1_NOVALUE)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) andalso
+ (is_list(Top) orelse (Top =:= asn1_NOVALUE)) andalso
+ (is_list(Ctx)) ->
+ CR =
+ case context_list_or_prop(Ctx) of
+ contextProp ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextProp = Ctx};
+ contextList ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ contextList = Ctx}
+ end,
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, Ctx)
+ when ((is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) orelse
+ (Prio =:= asn1_NOVALUE)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) andalso
+ (is_list(Top) orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= true) orelse (Ieps =:= false) orelse (Ieps =:= asn1_NOVALUE)) andalso
+ (is_list(Ctx)) ->
+ CR =
+ case context_list_or_prop(Ctx) of
+ contextProp ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Ctx};
+ contextList ->
+ #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextList = Ctx}
+ end,
+ strip_ContextRequest(CR).
+
+cre_ContextRequest(Prio, Em, Top, Ieps, CtxProp, CtxList)
+ when ((is_integer(Prio) andalso (0 =< Prio) andalso (Prio =< 15)) orelse
+ (Prio =:= asn1_NOVALUE)) andalso
+ ((Em =:= true) orelse (Em =:= false) orelse (Em =:= asn1_NOVALUE)) andalso
+ (is_list(Top) orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= true) orelse (Ieps =:= false) orelse (Ieps =:= asn1_NOVALUE)) andalso
+ (is_list(CtxProp) orelse (CtxProp =:= asn1_NOVALUE)) andalso
+ (is_list(CtxList) orelse (CtxList =:= asn1_NOVALUE)) ->
+ CR = #'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = CtxProp,
+ contextList = CtxList},
+ strip_ContextRequest(CR).
+
+context_list_or_prop(asn1_NOVALUE) ->
+ contextProp;
+context_list_or_prop([]) ->
+ contextProp;
+context_list_or_prop([H|T]) ->
+ case is_ContextID(H) of
+ true ->
+ context_list_or_prop(T, contextList);
+ false ->
+ context_list_or_prop(T, contextProp)
+ end.
+
+context_list_or_prop([], What) ->
+ What;
+context_list_or_prop([H|T], What) ->
+ case is_ContextID(H) of
+ true when (What =:= contextList) ->
+ context_list_or_prop(T, What);
+ false when (What =:= contextProp) ->
+ context_list_or_prop(T, What);
+ _ ->
+ error({invalid_contextListOrProp, H, What})
+ end.
+
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextProp = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextRequest(#'ContextRequest'{priority = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ topologyReq = Top,
+ iepscallind = Ieps,
+ contextProp = Prop} = CR) ->
+ case (((Top == []) or (Top == asn1_NOVALUE)) and
+ ((Ieps == false) or (Ieps == asn1_NOVALUE)) and
+ ((Prop == []) or (Prop == asn1_NOVALUE))) of
+ true ->
+ asn1_NOVALUE;
+ false ->
+ CR
+ end;
+strip_ContextRequest(CR) ->
+ CR.
+
+cre_ContextAttrAuditRequest() ->
+ strip_ContextAttrAuditRequest(#'ContextAttrAuditRequest'{}).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio)
+ when ((Top =:= 'NULL') orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Em =:= 'NULL') orelse (Em =:= asn1_NOVALUE)) andalso
+ ((Prio =:= 'NULL') orelse (Prio =:= asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps)
+ when ((Top =:= 'NULL') orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Em =:= 'NULL') orelse (Em =:= asn1_NOVALUE)) andalso
+ ((Prio =:= 'NULL') orelse (Prio =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= 'NULL') orelse (Ieps =:= asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx)
+ when ((Top =:= 'NULL') orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Em =:= 'NULL') orelse (Em =:= asn1_NOVALUE)) andalso
+ ((Prio =:= 'NULL') orelse (Prio =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= 'NULL') orelse (Ieps =:= asn1_NOVALUE)) andalso
+ (is_list(Ctx) orelse (Ctx =:= asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SelPrio)
+ when ((Top =:= 'NULL') orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Em =:= 'NULL') orelse (Em =:= asn1_NOVALUE)) andalso
+ ((Prio =:= 'NULL') orelse (Prio =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= 'NULL') orelse (Ieps =:= asn1_NOVALUE)) andalso
+ (is_list(Ctx) orelse (Ctx =:= asn1_NOVALUE)) andalso
+ ((is_integer(SelPrio) andalso ((0 =< SelPrio) and (SelPrio =< 15))) orelse
+ (SelPrio =:= asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx, SelPrio, SelLog)
+ when ((Top =:= 'NULL') orelse (Top =:= asn1_NOVALUE)) andalso
+ ((Em =:= 'NULL') orelse (Em =:= asn1_NOVALUE)) andalso
+ ((Prio =:= 'NULL') orelse (Prio =:= asn1_NOVALUE)) andalso
+ ((Ieps =:= 'NULL') orelse (Ieps =:= asn1_NOVALUE)) andalso
+ (is_list(Ctx) orelse (Ctx =:= asn1_NOVALUE)) andalso
+ ((is_integer(SelPrio) andalso ((0 =< SelPrio) andalso (SelPrio =< 15))) orelse
+ (SelPrio =:= asn1_NOVALUE)) ->
+ case ((SelLog =:= asn1_NOVALUE) orelse is_SelectLogic(SelLog)) of
+ true ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectLogic = SelLog},
+ strip_ContextAttrAuditRequest(CAAR);
+ false ->
+ error({invalid_SelectLogic, SelLog,
+ ['ContextAttrAuditRequest',
+ Top, Em, Prio, Ieps, Ctx, SelPrio]})
+ end.
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SelPrio, SelEm, SelIeps)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) and
+ ((SelEm == true) or
+ (SelEm == false) or
+ (SelEm == asn1_NOVALUE)) and
+ ((SelIeps == true) or
+ (SelIeps == false) or
+ (SelIeps == asn1_NOVALUE)) ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectemergency = SelEm,
+ selectiepscallind = SelIeps},
+ strip_ContextAttrAuditRequest(CAAR).
+
+cre_ContextAttrAuditRequest(Top, Em, Prio, Ieps, Ctx,
+ SelPrio, SelEm, SelIeps, SelLog)
+ when ((Top == 'NULL') or (Top == asn1_NOVALUE)) and
+ ((Em == 'NULL') or (Em == asn1_NOVALUE)) and
+ ((Prio == 'NULL') or (Prio == asn1_NOVALUE)) and
+ ((Ieps == 'NULL') or (Ieps == asn1_NOVALUE)) and
+ (is_list(Ctx) or (Ctx == asn1_NOVALUE)) and
+ ((is_integer(SelPrio) and ((0 =< SelPrio) and (SelPrio =< 15))) or
+ (SelPrio == asn1_NOVALUE)) and
+ ((SelEm == true) or
+ (SelEm == false) or
+ (SelEm == asn1_NOVALUE)) and
+ ((SelIeps == true) or
+ (SelIeps == false) or
+ (SelIeps == asn1_NOVALUE)) ->
+ case ((SelLog == asn1_NOVALUE) orelse is_SelectLogic(SelLog)) of
+ true ->
+ CAAR = #'ContextAttrAuditRequest'{topology = Top,
+ emergency = Em,
+ priority = Prio,
+ iepscallind = Ieps,
+ contextPropAud = Ctx,
+ selectpriority = SelPrio,
+ selectemergency = SelEm,
+ selectiepscallind = SelIeps,
+ selectLogic = SelLog},
+ strip_ContextAttrAuditRequest(CAAR);
+ false ->
+ error({invalid_SelectLogic, SelLog})
+ end.
+
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = asn1_NOVALUE}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = asn1_NOVALUE,
+ emergency = asn1_NOVALUE,
+ priority = asn1_NOVALUE,
+ iepscallind = asn1_NOVALUE,
+ contextPropAud = []}) ->
+ asn1_NOVALUE;
+strip_ContextAttrAuditRequest(CAAR) ->
+ CAAR.
+
+
+cre_SelectLogic(andAUDITSelect = SL) ->
+ {SL, 'NULL'};
+cre_SelectLogic(orAUDITSelect = SL) ->
+ {SL, 'NULL'};
+cre_SelectLogic(asn1_NOVALUE) ->
+ asn1_NOVALUE.
+
+
+cre_CommandRequest(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_CommandRequest(Cmd, Opt)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt}.
+
+cre_CommandRequest(Cmd, Opt, WR)
+ when ((Opt == 'NULL') or (Opt == asn1_NOVALUE)) and
+ ((WR == 'NULL') or (WR == asn1_NOVALUE)) ->
+ #'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}.
+
+cre_Command(addReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(moveReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(modReq = Tag, Req)
+ when is_record(Req, 'AmmRequest') ->
+ {Tag, Req};
+cre_Command(subtractReq = Tag, Req)
+ when is_record(Req, 'SubtractRequest') ->
+ {Tag, Req};
+cre_Command(auditCapRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(auditValueRequest = Tag, Req)
+ when is_record(Req, 'AuditRequest') ->
+ {Tag, Req};
+cre_Command(notifyReq = Tag, Req)
+ when is_record(Req, 'NotifyRequest') ->
+ {Tag, Req};
+cre_Command(serviceChangeReq = Tag, Req)
+ when is_record(Req, 'ServiceChangeRequest') ->
+ {Tag, Req}.
+
+cre_CommandReply(addReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(moveReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(modReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(subtractReply = Tag, Rep)
+ when is_record(Rep, 'AmmsReply') ->
+ {Tag, Rep};
+cre_CommandReply(auditCapReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(auditValueReply = Tag, Rep)
+ when is_tuple(Rep) ->
+ {Tag, Rep};
+cre_CommandReply(notifyReply = Tag, Rep)
+ when is_record(Rep, 'NotifyReply') ->
+ {Tag, Rep};
+cre_CommandReply(serviceChangeReply = Tag, Rep)
+ when is_record(Rep, 'ServiceChangeReply') ->
+ {Tag, Rep}.
+
+
+%% -- TopologyRequest --
+
+cre_TopologyRequest(From, To, TD)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TD == bothway) or (TD == isolate) or (TD == oneway)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD};
+cre_TopologyRequest(From, To, TDE)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TDE == onewayexternal) or (TDE == onewayboth)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = oneway,
+ topologyDirectionExtension = TDE}.
+
+cre_TopologyRequest(From, To, TD, SID)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ ((TD == bothway) or (TD == isolate) or (TD == oneway)) and
+ (is_integer(SID)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = TD,
+ streamID = SID};
+cre_TopologyRequest(From, To, SID, TDE)
+ when (is_record(From, 'TerminationID') or
+ is_record(From, megaco_term_id)) and
+ (is_record(To, 'TerminationID') or
+ is_record(To, megaco_term_id)) and
+ (is_integer(SID)) and
+ ((TDE == onewayexternal) or (TDE == onewayboth)) ->
+ #'TopologyRequest'{terminationFrom = From,
+ terminationTo = To,
+ topologyDirection = oneway,
+ streamID = SID,
+ topologyDirectionExtension = TDE}.
+
+cre_AmmRequest(TermIDs, Descs) ->
+ d("cre_AmmRequest -> entry with"
+ "~n TermIDs: ~p"
+ "~n Descs: ~p", [TermIDs, Descs]),
+ case is_TerminationIDList(TermIDs) andalso
+ is_AmmRequest_descriptors(Descs) of
+ true ->
+ #'AmmRequest'{terminationID = TermIDs,
+ descriptors = Descs};
+ false ->
+ error({invalid_AmmRequest, {TermIDs, Descs}})
+ end.
+
+cre_AmmDescriptor(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AmmDescriptor(D) when is_record(D, 'AuditDescriptor') ->
+ {auditDescriptor, D};
+cre_AmmDescriptor(D) when is_list(D) ->
+ case is_EventBufferDescriptor(D) of
+ true ->
+ {eventBufferDescriptor, D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ {signalsDescriptor, D};
+ false ->
+ case is_StatisticsDescriptor(D) of
+ true ->
+ {statisticsDescriptor, D};
+ false ->
+ error({invalid_AmmDescriptor, D})
+ end
+ end
+ end.
+
+cre_AmmsReply(TermIDs) when is_list(TermIDs) ->
+ #'AmmsReply'{terminationID = TermIDs}.
+
+cre_AmmsReply(TermIDs, TAs) when is_list(TermIDs) and is_list(TAs) ->
+ #'AmmsReply'{terminationID = TermIDs,
+ terminationAudit = TAs}.
+
+cre_SubtractRequest(TermIDs) when is_list(TermIDs) ->
+ #'SubtractRequest'{terminationID = TermIDs}.
+
+cre_SubtractRequest(TermIDs, Audit)
+ when is_list(TermIDs) and is_record(Audit, 'AuditDescriptor') ->
+ #'SubtractRequest'{terminationID = TermIDs,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TermID, Audit)
+ when is_record(TermID, megaco_term_id) and
+ is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TermID,
+ auditDescriptor = Audit}.
+
+cre_AuditRequest(TID, Audit, [TID|_] = TIDs)
+ when is_record(TID, megaco_term_id) and
+ is_record(Audit, 'AuditDescriptor') ->
+ #'AuditRequest'{terminationID = TID,
+ auditDescriptor = Audit,
+ terminationIDList = TIDs}.
+
+cre_AuditReply(TermIDs) when is_list(TermIDs) ->
+ {contextAuditResult, TermIDs};
+cre_AuditReply(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {error, ED};
+cre_AuditReply(Audit) when is_record(Audit, 'AuditResult') ->
+ {auditResult, Audit};
+cre_AuditReply(ARTL) when is_record(ARTL, 'TermListAuditResult') ->
+ {auditResultTermList, ARTL}.
+
+cre_AuditResult(TID, TAs)
+ when is_record(TID, megaco_term_id) and is_list(TAs) ->
+ #'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAs}.
+
+cre_TermListAuditResult(TIDs, TA)
+ when is_list(TIDs) and is_list(TA) ->
+ #'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TA}.
+
+cre_TerminationAudit(D) ->
+ true = is_TerminationAudit(D),
+ D.
+
+cre_AuditReturnParameter(D) when is_record(D, 'ErrorDescriptor') ->
+ {errorDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MediaDescriptor') ->
+ {mediaDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ModemDescriptor') ->
+ {modemDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'MuxDescriptor') ->
+ {muxDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'EventsDescriptor') ->
+ {eventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'EventSpec') ->
+ {eventBufferDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'DigitMapDescriptor') ->
+ {digitMapDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'ObservedEventsDescriptor') ->
+ {observedEventsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'StatisticsParameter') ->
+ {statisticsDescriptor, D};
+cre_AuditReturnParameter([H|_] = D) when is_record(H, 'PackagesItem') ->
+ {packagesDescriptor, D};
+cre_AuditReturnParameter(D) when is_record(D, 'AuditDescriptor') ->
+ {emptyDescriptors, D};
+cre_AuditReturnParameter([H|_] = D) when is_tuple(H) ->
+ {signalsDescriptor, D}.
+
+cre_AuditDescriptor() ->
+ #'AuditDescriptor'{}.
+
+cre_AuditDescriptor([H|_] = AT) when is_atom(H) ->
+ #'AuditDescriptor'{auditToken = AT};
+cre_AuditDescriptor(APT) ->
+ #'AuditDescriptor'{auditPropertyToken = APT}.
+
+cre_AuditDescriptor(AT, APT) ->
+ #'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}.
+
+cre_IndAuditParameter(D) when is_record(D, 'IndAudMediaDescriptor') ->
+ {indAudMediaDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventsDescriptor') ->
+ {indAudEventsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudEventBufferDescriptor') ->
+ {indAudEventBufferDescriptor, D};
+cre_IndAuditParameter({signal, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter({seqSigList, _} = D) ->
+ {indAudSignalsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudDigitMapDescriptor') ->
+ {indAudDigitMapDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudStatisticsDescriptor') ->
+ {indAudStatisticsDescriptor, D};
+cre_IndAuditParameter(D) when is_record(D, 'IndAudPackagesDescriptor') ->
+ {indAudPackagesDescriptor, D}.
+
+cre_IndAudMediaDescriptor() ->
+ #'IndAudMediaDescriptor'{}.
+
+cre_IndAudMediaDescriptor(TSD)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') ->
+ #'IndAudMediaDescriptor'{termStateDescr = TSD};
+cre_IndAudMediaDescriptor(Parms) when is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{streams = Streams};
+cre_IndAudMediaDescriptor(Descs) when is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{streams = Streams}.
+
+cre_IndAudMediaDescriptor(TSD, Parms)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') and
+ is_record(Parms, 'IndAudStreamParms') ->
+ Streams = {oneStream, Parms},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_IndAudMediaDescriptor(TSD, Descs)
+ when is_record(TSD, 'IndAudTerminationStateDescriptor') and is_list(Descs) ->
+ Streams = {multiStream, Descs},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_IndAudStreamDescriptor(SID, Parms)
+ when is_integer(SID) and is_record(Parms, 'IndAudStreamParms') ->
+ #'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms};
+cre_IndAudStreamDescriptor(SID, Parms) ->
+ error({invalid_IndAudStreamDescriptor, [SID, Parms]}).
+
+cre_IndAudStreamParms() ->
+ #'IndAudStreamParms'{}.
+
+cre_IndAudStreamParms(LCD)
+ when is_record(LCD, 'IndAudLocalControlDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LCD};
+cre_IndAudStreamParms(SD) when is_record(SD, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{statisticsDescriptor = SD}.
+
+cre_IndAudStreamParms(LC, L, R)
+ when is_record(LC, 'IndAudLocalControlDescriptor') and
+ is_record(L, 'IndAudLocalRemoteDescriptor') and
+ is_record(R, 'IndAudLocalRemoteDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R}.
+
+cre_IndAudStreamParms(LC, L, R, S)
+ when is_record(LC, 'IndAudLocalControlDescriptor') and
+ is_record(L, 'IndAudLocalRemoteDescriptor') and
+ is_record(R, 'IndAudLocalRemoteDescriptor') and
+ is_record(S, 'IndAudStatisticsDescriptor') ->
+ #'IndAudStreamParms'{localControlDescriptor = LC,
+ localDescriptor = L,
+ remoteDescriptor = R,
+ statisticsDescriptor = S}.
+
+cre_IndAudLocalControlDescriptor() ->
+ #'IndAudLocalControlDescriptor'{}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP};
+cre_IndAudLocalControlDescriptor(RV, RG, PP, SMS)
+ when ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) and
+ is_atom(SMS) ->
+ #'IndAudLocalControlDescriptor'{reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS}.
+
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS)
+ when (SM == 'NULL') and
+ (is_atom(SMS) and (SMS =/= asn1_NOVALUE)) ->
+ error({invalid_IndAudLocalControlDescriptor, [SM, RV, RG, PP, SMS]});
+cre_IndAudLocalControlDescriptor(SM, RV, RG, PP, SMS)
+ when ((SM == 'NULL') or (SM == asn1_NOVALUE)) and
+ ((RV == 'NULL') or (RV == asn1_NOVALUE)) and
+ ((RG == 'NULL') or (RG == asn1_NOVALUE)) and
+ (is_list(PP) or (PP == asn1_NOVALUE)) and
+ is_atom(SMS) ->
+ case is_StreamMode(SMS) of
+ true ->
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP,
+ streamModeSel = SMS};
+ false ->
+ error({invalid_IndAudLocalControlDescriptor, SMS})
+ end.
+
+cre_IndAudPropertyParm(PkgdName) when is_list(PkgdName) ->
+ #'IndAudPropertyParm'{name = PkgdName}.
+
+cre_IndAudPropertyParm(PkgdName, PP)
+ when is_list(PkgdName) and is_record(PP, 'PropertyParm') ->
+ #'IndAudPropertyParm'{name = PkgdName, propertyParms = PP}.
+
+cre_IndAudLocalRemoteDescriptor(Grps) when is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGrps = Grps}.
+
+cre_IndAudLocalRemoteDescriptor(GID, Grps)
+ when is_integer(GID) and (0 =< GID) and (GID =< 65535) and is_list(Grps) ->
+ #'IndAudLocalRemoteDescriptor'{propGroupID = GID,
+ propGrps = Grps}.
+
+cre_IndAudPropertyGroup([]) ->
+ [];
+cre_IndAudPropertyGroup([H|_] = PG) when is_record(H, 'IndAudPropertyParm') ->
+ PG.
+
+cre_IndAudTerminationStateDescriptor([] = PP) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP};
+cre_IndAudTerminationStateDescriptor([H|_] = PP)
+ when is_record(H, 'IndAudPropertyParm') ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP}.
+
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}.
+
+cre_IndAudTerminationStateDescriptor(PP, EBC, SS, SSS)
+ when (SS == 'NULL') and
+ ((is_atom(SSS) and (SSS =/= asn1_NOVALUE))) ->
+ error({invalid_IndAudTerminationStateDescriptor, [PP, EBC, SS, SSS]});
+cre_IndAudTerminationStateDescriptor([] = PP, EBC, SS, SSS)
+ when ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) and
+ is_atom(SSS) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS};
+cre_IndAudTerminationStateDescriptor([H|_] = PP, EBC, SS, SSS)
+ when is_record(H, 'IndAudPropertyParm') and
+ ((EBC == 'NULL') or (EBC == asn1_NOVALUE)) and
+ ((SS == 'NULL') or (SS == asn1_NOVALUE)) and
+ is_atom(SSS) ->
+ #'IndAudTerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS}.
+
+cre_IndAudEventsDescriptor(PkgdName)
+ when is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName)
+ when is_integer(RID) and is_list(PkgdName) ->
+ #'IndAudEventsDescriptor'{requestID = RID, pkgdName = PkgdName};
+cre_IndAudEventsDescriptor(PkgdName, SID)
+ when is_list(PkgdName) and is_integer(SID) ->
+ #'IndAudEventsDescriptor'{pkgdName = PkgdName, streamID = SID}.
+
+cre_IndAudEventsDescriptor(RID, PkgdName, SID)
+ when is_integer(RID) and is_list(PkgdName) and is_integer(SID) ->
+ #'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = PkgdName,
+ streamID = SID}.
+
+cre_IndAudEventBufferDescriptor(EventName) when is_list(EventName) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName}.
+
+cre_IndAudEventBufferDescriptor(EventName, SID)
+ when is_list(EventName) and is_integer(SID) ->
+ #'IndAudEventBufferDescriptor'{eventName = EventName, streamID = SID}.
+
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSignal') ->
+ {signal, S};
+cre_IndAudSignalsDescriptor(S) when is_record(S, 'IndAudSeqSigList') ->
+ {seqSigList, S}.
+
+cre_IndAudSeqSigList(ID)
+ when is_integer(ID) and (0=< ID) and (ID =< 65535) ->
+ #'IndAudSeqSigList'{id = ID}.
+
+cre_IndAudSeqSigList(ID, S)
+ when is_integer(ID) and (0=< ID) and (ID =< 65535) and
+ is_record(S, 'IndAudSignal') ->
+ #'IndAudSeqSigList'{id = ID, signalList = S}.
+
+cre_IndAudSignal(SigName) when is_list(SigName) ->
+ #'IndAudSignal'{signalName = SigName}.
+
+cre_IndAudSignal(SigName, RID)
+ when is_list(SigName) and is_integer(RID) ->
+ #'IndAudSignal'{signalName = SigName,
+ signalRequestID = RID}.
+
+cre_IndAudDigitMapDescriptor() ->
+ #'IndAudDigitMapDescriptor'{}.
+
+cre_IndAudDigitMapDescriptor(DMN) when is_list(DMN) ->
+ #'IndAudDigitMapDescriptor'{digitMapName = DMN}.
+
+cre_IndAudStatisticsDescriptor(StatName) when is_list(StatName) ->
+ #'IndAudStatisticsDescriptor'{statName = StatName}.
+
+cre_IndAudPackagesDescriptor(N, V)
+ when is_list(N) and
+ is_integer(V) and (0 =< V) and (V =< 99) ->
+ #'IndAudPackagesDescriptor'{packageName = N,
+ packageVersion = V}.
+
+cre_NotifyRequest(TermIDs, D)
+ when is_list(TermIDs) and is_record(D, 'ObservedEventsDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D}.
+
+cre_NotifyRequest(TermIDs, D, ED)
+ when is_list(TermIDs) andalso
+ is_record(D, 'ObservedEventsDescriptor') andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyRequest'{terminationID = TermIDs,
+ observedEventsDescriptor = D,
+ errorDescriptor = ED}.
+
+cre_NotifyReply(TermIDs) when is_list(TermIDs) ->
+ #'NotifyReply'{terminationID = TermIDs}.
+
+cre_NotifyReply(TermIDs, ED)
+ when is_list(TermIDs) andalso
+ is_record(ED, 'ErrorDescriptor') ->
+ #'NotifyReply'{terminationID = TermIDs,
+ errorDescriptor = ED}.
+
+cre_ObservedEventsDescriptor(RID, [H|_] = L)
+ when is_integer(RID) andalso is_record(H, 'ObservedEvent') ->
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = L}.
+
+cre_ObservedEvent(EN, EPL)
+ when is_list(EN) and is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL};
+cre_ObservedEvent(EN, TN)
+ when is_list(EN) and is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL)
+ when is_list(EN) and is_integer(SID) and is_list(EPL) ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL};
+cre_ObservedEvent(EN, EPL, TN)
+ when is_list(EN) and is_list(EPL) and is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_ObservedEvent(EN, SID, EPL, TN)
+ when is_list(EN) and
+ is_integer(SID) and
+ is_list(EPL) and
+ is_record(TN, 'TimeNotation') ->
+ #'ObservedEvent'{eventName = EN,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}.
+
+cre_EventName(N) when is_list(N) ->
+ N.
+
+cre_EventParameter(N, V) when is_list(N) and is_list(V) ->
+ #'EventParameter'{eventParameterName = N,
+ value = V}.
+
+cre_EventParameter(N, V, relation = Tag, R)
+ when is_list(N) and is_list(V) and is_atom(R) ->
+ EI = {Tag, R},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, range = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI};
+cre_EventParameter(N, V, sublist = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'EventParameter'{eventParameterName = N,
+ value = V,
+ extraInfo = EI}.
+
+cre_ServiceChangeRequest(TermIDs, SCP)
+ when is_list(TermIDs) and
+ is_record(SCP, 'ServiceChangeParm') ->
+ #'ServiceChangeRequest'{terminationID = TermIDs,
+ serviceChangeParms = SCP}.
+
+cre_ServiceChangeReply(TermIDs, {Tag, R} = SCR)
+ when is_list(TermIDs) and is_atom(Tag) and is_tuple(R) ->
+ #'ServiceChangeReply'{terminationID = TermIDs,
+ serviceChangeResult = SCR}.
+
+cre_ServiceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED};
+cre_ServiceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP}.
+
+%% cre_WildcardField(L) when list(L), length(L) == 1 -> L.
+
+cre_TerminationID(W, ID)
+ when is_list(W) andalso
+ is_list(ID) andalso (1 =< length(ID)) andalso (length(ID) =< 8) ->
+ #'TerminationID'{wildcard = W,
+ id = ID}.
+
+cre_TerminationIDList(L) when is_list(L) ->
+ L.
+
+cre_MediaDescriptor() ->
+ #'MediaDescriptor'{}.
+
+cre_MediaDescriptor(TSD) when is_record(TSD, 'TerminationStateDescriptor') ->
+ #'MediaDescriptor'{termStateDescr = TSD};
+cre_MediaDescriptor(SP) when is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{streams = Streams};
+cre_MediaDescriptor([H|_] = SDs) when is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{streams = Streams}.
+
+cre_MediaDescriptor(TSD, SP)
+ when is_record(TSD, 'TerminationStateDescriptor') and
+ is_record(SP, 'StreamParms') ->
+ Streams = {oneStream, SP},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams};
+cre_MediaDescriptor(TSD, [H|_] = SDs)
+ when is_record(TSD, 'TerminationStateDescriptor') and
+ is_record(H, 'StreamDescriptor') ->
+ Streams = {multiStream, SDs},
+ #'MediaDescriptor'{termStateDescr = TSD,
+ streams = Streams}.
+
+cre_StreamDescriptor(SID, SP)
+ when is_integer(SID) and is_record(SP, 'StreamParms') ->
+ #'StreamDescriptor'{streamID = SID,
+ streamParms = SP}.
+
+cre_StreamParms() ->
+ #'StreamParms'{}.
+
+cre_StreamParms(LCD) when is_record(LCD, 'LocalControlDescriptor') ->
+ #'StreamParms'{localControlDescriptor = LCD};
+cre_StreamParms(LD) when is_record(LD, 'LocalRemoteDescriptor') ->
+ #'StreamParms'{localDescriptor = LD};
+cre_StreamParms(SD) when is_list(SD) ->
+ #'StreamParms'{statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD}.
+
+cre_StreamParms(LCD, LD, RD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD};
+cre_StreamParms(LCD, LD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ statisticsDescriptor = SD}.
+
+cre_StreamParms(LCD, LD, RD, SD)
+ when (is_record(LCD, 'LocalControlDescriptor') or (LCD == asn1_NOVALUE)) and
+ (is_record(LD, 'LocalRemoteDescriptor') or (LD == asn1_NOVALUE)) and
+ (is_record(RD, 'LocalRemoteDescriptor') or (RD == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}.
+
+cre_LocalControlDescriptor(SM) when is_atom(SM) ->
+ #'LocalControlDescriptor'{streamMode = SM, propertyParms = []};
+cre_LocalControlDescriptor([H|_] = PP) when is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, [H|_] = PP)
+ when is_atom(SM) and is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ propertyParms = PP}.
+
+cre_LocalControlDescriptor(SM, RV, RG, [H|_] = PP)
+ when is_atom(SM) and
+ ((RV == true) or (RV == false) or (RV == asn1_NOVALUE)) and
+ ((RG == true) or (RG == false) or (RG == asn1_NOVALUE)) and
+ is_record(H, 'PropertyParm') ->
+ #'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}.
+
+cre_StreamMode(sendOnly = M) ->
+ M;
+cre_StreamMode(recvOnly = M) ->
+ M;
+cre_StreamMode(sendRecv = M) ->
+ M;
+cre_StreamMode(inactive = M) ->
+ M;
+cre_StreamMode(loopBack = M) ->
+ M.
+
+cre_PropertyParm(N, [H|_] = V) when is_list(N) and is_list(H) ->
+ #'PropertyParm'{name = N, value = V}.
+
+cre_PropertyParm(N, [H|_] = V, relation = Tag, R)
+ when is_list(N) and is_list(H) and is_atom(R) ->
+ EI = {Tag, R},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, range = Tag, B)
+ when is_list(N) and is_list(H) and is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI};
+cre_PropertyParm(N, [H|_] = V, sublist = Tag, B)
+ when is_list(N) and is_list(H) and is_atom(B) ->
+ EI = {Tag, B},
+ #'PropertyParm'{name = N, value = V, extraInfo = EI}.
+
+
+cre_Name(N) when is_list(N) and (length(N) == 2) ->
+ N.
+
+cre_PkgdName(N) when is_list(N) ->
+ case string:tokens(N, [$\\]) of
+ [_PkgName, _ItemID] ->
+ N;
+ _ ->
+ error({invalid_PkgdName, N})
+ end.
+cre_PkgdName(root, root) ->
+ "*/*";
+cre_PkgdName(PackageName, root)
+ when is_list(PackageName) and (length(PackageName) =< 64) ->
+ PackageName ++ "/*";
+cre_PkgdName(PackageName, ItemID)
+ when ((is_list(PackageName) and (length(PackageName) =< 64)) and
+ (is_list(ItemID) and (length(ItemID) =< 64))) ->
+ PackageName ++ "/" ++ ItemID;
+cre_PkgdName(PackageName, ItemID) ->
+ error({invalid_PkgdName, {PackageName, ItemID}}).
+
+cre_Relation(greaterThan = R) ->
+ R;
+cre_Relation(smallerThan = R) ->
+ R;
+cre_Relation(unequalTo = R) ->
+ R.
+
+cre_LocalRemoteDescriptor([H|_] = PGs) when is_list(H) ->
+ #'LocalRemoteDescriptor'{propGrps = PGs}.
+
+cre_PropertyGroup([H|_] = PG) when is_record(H, 'PropertyParm') ->
+ PG.
+
+cre_TerminationStateDescriptor([H|_] = PPs)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, off = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, lockStep = EBC)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EBC};
+cre_TerminationStateDescriptor([H|_] = PPs, test = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, outOfSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS};
+cre_TerminationStateDescriptor([H|_] = PPs, inSvc = SS)
+ when is_record(H, 'PropertyParm') ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ serviceState = SS}.
+
+cre_TerminationStateDescriptor([H|_] = PPs, EMC, SS)
+ when is_record(H, 'PropertyParm') and
+ ((EMC == off) or (EMC == lockStep)) and
+ ((SS == test) or (SS == outOfSvc) or (SS == inSvc)) ->
+ #'TerminationStateDescriptor'{propertyParms = PPs,
+ eventBufferControl = EMC,
+ serviceState = SS}.
+
+cre_EventBufferControl(off = EBC) ->
+ EBC;
+cre_EventBufferControl(lockStep = EBC) ->
+ EBC.
+
+cre_ServiceState(test = SS) ->
+ SS;
+cre_ServiceState(outOfSvc = SS) ->
+ SS;
+cre_ServiceState(inSvc = SS) ->
+ SS.
+
+cre_MuxDescriptor(MT, [H|_] = TL)
+ when is_atom(MT) and is_record(H, 'TerminationID') ->
+ #'MuxDescriptor'{muxType = MT, termList = TL}.
+
+%% cre_MuxDescriptor(MT, [H|_] = TL, NSD)
+%% when atom(MT), record(H, 'TerminationID'), record(NSD, 'NonStandardData') ->
+%% #'MuxDescriptor'{muxType = MT, termList = TL, nonStandardData = NSD}.
+
+cre_MuxType(h221 = MT) ->
+ MT;
+cre_MuxType(h223 = MT) ->
+ MT;
+cre_MuxType(h226 = MT) ->
+ MT;
+cre_MuxType(v76 = MT) ->
+ MT;
+cre_MuxType(nx64k = MT) ->
+ MT.
+
+cre_StreamID(Val) when (0 =< Val) and (Val =< 65535) ->
+ Val;
+cre_StreamID(Val) ->
+ exit({invalid_ContextID, Val}).
+
+%% RequestID must be present if eventList is non empty
+cre_EventsDescriptor() ->
+ #'EventsDescriptor'{eventList = []}.
+
+cre_EventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) and is_record(H, 'RequestedEvent') ->
+ #'EventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_RequestedEvent(N) ->
+ #'RequestedEvent'{pkgdName = N}.
+
+cre_RequestedEvent(N, EPL)
+ when is_list(N) and is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_RequestedEvent(N, EA)
+ when is_list(N) and is_record(EA, 'RequestedActions')->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA}.
+
+
+cre_RequestedEvent(N, SID, EPL)
+ when is_list(N) and is_integer(SID) and is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_RequestedEvent(N, EA, EPL)
+ when is_list(N) and is_record(EA, 'RequestedActions') and is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RequestedEvent(N, SID, EA, EPL)
+ when is_list(N) and
+ is_integer(SID) and
+ is_record(EA, 'RequestedActions') and
+ is_list(EPL) ->
+ #'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_RegulatedEmbeddedDescriptor() ->
+ #'RegulatedEmbeddedDescriptor'{}.
+
+cre_RegulatedEmbeddedDescriptor(D) ->
+ case is_SecondEventsDescriptor(D) of
+ true ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = D};
+ false ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ #'RegulatedEmbeddedDescriptor'{signalsDescriptor = D};
+ false ->
+ error({invalid_RegulatedEmbeddedDescriptor, D})
+ end
+ end.
+
+cre_RegulatedEmbeddedDescriptor(SED, SD)
+ when ((SED == asn1_NOVALUE) or is_record(SED, 'SecondEventsDescriptor')) and
+ ((SD == asn1_NOVALUE) or is_list(SD)) ->
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SED,
+ signalsDescriptor = SD}.
+
+cre_NotifyBehaviour(notifyImmediate = Tag, 'NULL' = Val) ->
+ {Tag, Val};
+cre_NotifyBehaviour(notifyRegulated = Tag, Val)
+ when is_record(Val, 'RegulatedEmbeddedDescriptor') ->
+ {Tag, Val};
+cre_NotifyBehaviour(neverNotify = Tag, 'NULL' = Val) ->
+ {Tag, Val};
+cre_NotifyBehaviour(Tag, Val) ->
+ error({invalid_NotifyBehaviour, [Tag, Val]}).
+
+cre_RequestedActions() ->
+ #'RequestedActions'{}.
+
+cre_RequestedActions(KA)
+ when (KA == true) or (KA == true) ->
+ #'RequestedActions'{keepActive = KA};
+cre_RequestedActions(SE)
+ when is_record(SE, 'SecondEventsDescriptor') ->
+ #'RequestedActions'{secondEvent = SE};
+cre_RequestedActions(SD)
+ when is_list(SD) ->
+ #'RequestedActions'{signalsDescriptor = SD};
+cre_RequestedActions({Tag, _} = EDM)
+ when is_atom(Tag) ->
+ #'RequestedActions'{eventDM = EDM}.
+
+cre_RequestedActions(KA, {Tag, _} = EDM, SE, SD)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(Tag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD}.
+
+cre_RequestedActions(KA, {EDMTag, _} = EDM, SE, SD, {NBTag, _} = NB, RED)
+ when ((KA == true) or (KA == true) or (KA == asn1_NOVALUE)) and
+ (is_atom(EDMTag) or (EDM == asn1_NOVALUE)) and
+ (is_record(SE, 'SecondEventsDescriptor') or (SE == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) and
+ (is_atom(NBTag) or (NB == asn1_NOVALUE)) and
+ ((RED == 'NULL') or (RED == asn1_NOVALUE)) ->
+ #'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}.
+
+cre_EventDM(N) when is_list(N) ->
+ {digitMapName, N};
+cre_EventDM(V) when is_record(V, 'DigitMapValue') ->
+ {digitMapValue, V}.
+
+cre_SecondEventsDescriptor([H|_] = EL)
+ when is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{eventList = EL}.
+
+cre_SecondEventsDescriptor(RID, [H|_] = EL)
+ when is_integer(RID) and is_record(H, 'SecondRequestedEvent') ->
+ #'SecondEventsDescriptor'{requestID = RID, eventList = EL}.
+
+cre_SecondRequestedEvent(N, EPL)
+ when is_list(N) and is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EPL) ->
+ error({invalid_SecondRequestedEvent, [N, EPL]}).
+
+cre_SecondRequestedEvent(N, SID, EPL)
+ when is_list(N) and is_integer(SID) and is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ evParList = EPL};
+cre_SecondRequestedEvent(N, EA, EPL)
+ when is_list(N) and
+ is_record(EA, 'SecondRequestedActions') and
+ is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedEvent(N, SID, EA, EPL)
+ when is_list(N) and
+ is_integer(SID) and
+ is_record(EA, 'SecondRequestedActions') and
+ is_list(EPL) ->
+ #'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}.
+
+cre_SecondRequestedActions() ->
+ #'SecondRequestedActions'{}.
+
+cre_SecondRequestedActions(KA)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA};
+cre_SecondRequestedActions(SD) when is_list(SD) ->
+ #'SecondRequestedActions'{signalsDescriptor = SD};
+cre_SecondRequestedActions({Tag, _} = Val) when is_atom(Tag) ->
+ case is_EventDM(Val) of
+ true ->
+ #'SecondRequestedActions'{eventDM = Val};
+ false ->
+ case is_NotifyBehaviour(Val) of
+ true ->
+ #'SecondRequestedActions'{notifyBehaviour = Val};
+ false ->
+ error({invalid_SecondRequestedActions, Val})
+ end
+ end;
+cre_SecondRequestedActions('NULL' = RED) ->
+ #'SecondRequestedActions'{resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA, signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, {Tag, _} = Val)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) ->
+ case is_EventDM(Val) of
+ true ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = Val};
+ false ->
+ case is_NotifyBehaviour(Val) of
+ true ->
+ #'SecondRequestedActions'{keepActive = KA,
+ notifyBehaviour = Val};
+ false ->
+ error({invalid_SecondRequestedActions, Val})
+ end
+ end;
+cre_SecondRequestedActions(KA, 'NULL' = RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, {Tag, _} = EDM, SD)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_atom(Tag) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD};
+cre_SecondRequestedActions(KA, SD, {Tag, _} = NB)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) and
+ is_atom(Tag) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB};
+cre_SecondRequestedActions(KA, SD, 'NULL' = RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SD) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ signalsDescriptor = SD,
+ resetEventsDescriptor = RED}.
+
+cre_SecondRequestedActions(KA, {EDMTag, _} = EDM, SD,
+ {NBTag, _} = NB, RED)
+ when ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ (is_atom(EDMTag) or (EDM == asn1_NOVALUE)) and
+ (is_list(SD) or (SD == asn1_NOVALUE)) and
+ (is_atom(NBTag) or (NB == asn1_NOVALUE)) and
+ ((RED == 'NULL') or (RED == asn1_NOVALUE)) ->
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}.
+
+cre_EventBufferDescriptor([H|_] = D) when is_record(H, 'EventSpec') ->
+ D.
+
+cre_EventSpec(N, [H|_] = EPL)
+ when is_list(N) and is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, eventParList = EPL}.
+
+cre_EventSpec(N, SID, [H|_] = EPL)
+ when is_list(N) and is_integer(SID) and is_record(H, 'EventParameter') ->
+ #'EventSpec'{eventName = N, streamID = SID, eventParList = EPL}.
+
+cre_SignalsDescriptor(D) ->
+ case is_SignalsDescriptor(D) of
+ true ->
+ D;
+ false ->
+ error({invalid_SignalsDescriptor, D})
+ end.
+
+cre_SignalRequest(S) when is_record(S, 'Signal') ->
+ {signal, S};
+cre_SignalRequest(S) when is_record(S, 'SeqSigList') ->
+ {seqSigList, S}.
+
+cre_SeqSigList(ID, [H|_] = SL)
+ when is_integer(ID) and (0 =< ID) and (ID =< 65535) and
+ is_record(H, 'Signal') ->
+ #'SeqSigList'{id = ID, signalList = SL}.
+
+cre_Signal(N) when is_list(N) ->
+ #'Signal'{signalName = N}.
+
+cre_Signal(N, SPL) when is_list(N) and is_list(SPL) ->
+ #'Signal'{signalName = N,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID}.
+
+cre_Signal(N, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISIG)
+ when is_list(N) and
+ (is_integer(SID) or (SID == asn1_NOVALUE)) and
+ ((ST == brief) or (ST == onOff) or (ST == timeOut) or
+ (ST == asn1_NOVALUE)) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 65535)) or
+ (Dur == asn1_NOVALUE)) and
+ (is_list(NC) or (NC == asn1_NOVALUE)) and
+ ((KA == true) or (KA == false) or (KA == asn1_NOVALUE)) and
+ is_list(SPL) and
+ ((Dir == internal) or (Dir == external) or (Dir == both) or
+ (Dir == asn1_NOVALUE)) and
+ (is_integer(RID) or (RID == asn1_NOVALUE)) and
+ (is_integer(ISIG) or (ISIG == asn1_NOVALUE)) ->
+ #'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ISIG}.
+
+cre_SignalType(brief = ST) ->
+ ST;
+cre_SignalType(onOff = ST) ->
+ ST;
+cre_SignalType(timeOut = ST) ->
+ ST.
+
+cre_SignalDirection(internal = SD) ->
+ SD;
+cre_SignalDirection(external = SD) ->
+ SD;
+cre_SignalDirection(both = SD) ->
+ SD.
+
+cre_SignalName(N) ->
+ cre_PkgdName(N).
+
+cre_NotifyCompletion(L) when is_list(L) ->
+ Vals = [onTimeOut, onInterruptByEvent,
+ onInterruptByNewSignalDescr, otherReason],
+ F = fun(E) -> case lists:member(E, Vals) of
+ true ->
+ ok;
+ false ->
+ exit({invalid_NotifyCompletion, E})
+ end
+ end,
+ lists:foreach(F, L),
+ L.
+
+cre_SigParameter(N, V) when is_list(N) and is_list(V) ->
+ #'SigParameter'{sigParameterName = N, value = V}.
+
+cre_SigParameter(N, V, relation = Tag, R)
+ when is_list(N) and is_list(V) and is_atom(R) ->
+ EI = {Tag, R},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, range = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI};
+cre_SigParameter(N, V, sublist = Tag, B)
+ when is_list(N) and is_list(V) and is_atom(B) ->
+ EI = {Tag, B},
+ #'SigParameter'{sigParameterName = N, value = V, extraInfo = EI}.
+
+cre_RequestID(Val) when (0 =< Val) and (Val =< 4294967295) ->
+ Val;
+cre_RequestID(Val) ->
+ exit({invalid_RequestID, Val}).
+
+cre_ModemDescriptor(MTL, MPL) when is_list(MTL) and is_list(MPL) ->
+ #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+%% cre_ModemDescriptor(MTL, MPL, NSD)
+%% when list(MTL), list(MPL), record(NSD, 'NonStandardData') ->
+%% #'ModemDescriptor'{mtl = MTL, mpl = MPL}.
+
+cre_ModemType(v18 = MT) ->
+ MT;
+cre_ModemType(v22 = MT) ->
+ MT;
+cre_ModemType(v22bis = MT) ->
+ MT;
+cre_ModemType(v32 = MT) ->
+ MT;
+cre_ModemType(v32bis = MT) ->
+ MT;
+cre_ModemType(v34 = MT) ->
+ MT;
+cre_ModemType(v90 = MT) ->
+ MT;
+cre_ModemType(v91 = MT) ->
+ MT;
+cre_ModemType(synchISDN = MT) ->
+ MT.
+
+cre_DigitMapDescriptor() ->
+ #'DigitMapDescriptor'{}.
+
+cre_DigitMapDescriptor(N) when is_list(N) ->
+ #'DigitMapDescriptor'{digitMapName = N};
+cre_DigitMapDescriptor(V) when is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapValue = V}.
+
+cre_DigitMapDescriptor(N, V)
+ when is_list(N) and is_record(V, 'DigitMapValue') ->
+ #'DigitMapDescriptor'{digitMapName = N, digitMapValue = V}.
+
+cre_DigitMapName(N) ->
+ cre_Name(N).
+
+cre_DigitMapValue(DMB) when is_list(DMB) ->
+ #'DigitMapValue'{digitMapBody = DMB}.
+
+cre_DigitMapValue(Start, Short, Long, DMB) ->
+ cre_DigitMapValue(Start, Short, Long, DMB, asn1_NOVALUE).
+
+cre_DigitMapValue(Start, Short, Long, DMB, Dur)
+ when ((is_integer(Start) and (0 =< Start) and (Start =< 99)) or
+ (Start == asn1_NOVALUE)) and
+ ((is_integer(Short) and (0 =< Short) and (Short =< 99)) or
+ (Short == asn1_NOVALUE)) and
+ ((is_integer(Long) and (0 =< Long) and (Long =< 99)) or
+ (Long == asn1_NOVALUE)) and
+ is_list(DMB) and
+ ((is_integer(Dur) and (0 =< Dur) and (Dur =< 99)) or
+ (Dur == asn1_NOVALUE)) ->
+ #'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = DMB,
+ durationTimer = Dur}.
+
+cre_ServiceChangeParm(M, R) when is_atom(M) and is_list(R) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R}.
+
+cre_ServiceChangeParm(M, Addr, Prof, Reason) ->
+ cre_ServiceChangeParm(M, Addr, asn1_NOVALUE, Prof, Reason, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE,
+ asn1_NOVALUE, asn1_NOVALUE).
+
+%% Addr = asn1_NOVALUE | {AddrTag, AddrVal}
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I) ->
+ cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, asn1_NOVALUE).
+
+cre_ServiceChangeParm(M, Addr, Ver, Prof, R, D, Mid, TS, I, IF)
+ when is_atom(M) and
+ ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ is_list(R) and
+ ((is_integer(D) and (0 =< D) and (D =< 4294967295)) or
+ (D == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) and
+ (is_record(I, 'AuditDescriptor') or (I == asn1_NOVALUE)) and
+ ((IF == 'NULL') or (IF == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Mid,
+ timeStamp = TS,
+ serviceChangeInfo = I,
+ serviceChangeIncompleteFlag = IF};
+ _ ->
+ exit({invalid_ServiceChangeParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeAddress(portNumber = Tag, P)
+ when is_integer(P) and (0 =< P) and (P =< 65535) ->
+ {Tag, P};
+cre_ServiceChangeAddress(ip4Address = Tag, A)
+ when is_record(A, 'IP4Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(ip6Address = Tag, A)
+ when is_record(A, 'IP6Address') ->
+ {Tag, A};
+cre_ServiceChangeAddress(domainName = Tag, N)
+ when is_record(N, 'DomainName') ->
+ {Tag, N};
+cre_ServiceChangeAddress(deviceName = Tag, N) when is_list(N) ->
+ {Tag, N};
+cre_ServiceChangeAddress(mtpAddress = Tag, A) when is_list(A) ->
+ {Tag, A}.
+
+cre_ServiceChangeResParm() ->
+ #'ServiceChangeResParm'{}.
+cre_ServiceChangeResParm(Addr, Prof) ->
+ cre_ServiceChangeResParm(asn1_NOVALUE, Addr, asn1_NOVALUE,
+ Prof, asn1_NOVALUE).
+cre_ServiceChangeResParm(Mid, Addr, Ver, Prof, TS)
+ when ((is_integer(Ver) and (0 =< Ver) and (Ver =< 99)) or
+ (Ver == asn1_NOVALUE)) and
+ (is_record(Prof, 'ServiceChangeProfile') or (Prof == asn1_NOVALUE)) and
+ (is_record(TS, 'TimeNotation') or (TS == asn1_NOVALUE)) ->
+ F = fun(A) ->
+ (A == asn1_NOVALUE) orelse
+ (is_tuple(A)
+ andalso is_atom(element(1, A)))
+ end,
+ case (F(Addr) andalso F(Mid)) of
+ true ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid,
+ serviceChangeAddress = Addr,
+ serviceChangeVersion = Ver,
+ serviceChangeProfile = Prof,
+ timeStamp = TS};
+ _ ->
+ exit({invalid_ServiceChangeResParm_args, {Addr, Mid}})
+ end.
+
+cre_ServiceChangeMethod(failover = M) ->
+ M;
+cre_ServiceChangeMethod(forced = M) ->
+ M;
+cre_ServiceChangeMethod(graceful = M) ->
+ M;
+cre_ServiceChangeMethod(restart = M) ->
+ M;
+cre_ServiceChangeMethod(disconnected = M) ->
+ M;
+cre_ServiceChangeMethod(handOff = M) ->
+ M.
+
+%% The version field is added to make it look more like ABNF
+cre_ServiceChangeProfile(N) ->
+ cre_ServiceChangeProfile(N, 1).
+
+cre_ServiceChangeProfile(N, V)
+ when is_list(N) and is_integer(V) and (0 =< V) and (V =< 99) ->
+ #'ServiceChangeProfile'{profileName = N, version = V}.
+
+cre_PackagesDescriptor([H|_] = D) when is_record(H, 'PackagesItem') ->
+ D.
+
+cre_PackagesItem(N, Ver)
+ when is_list(N) and
+ is_integer(Ver) and (0 =< Ver) and (Ver =< 99) ->
+ #'PackagesItem'{packageName = N,
+ packageVersion = Ver}.
+
+cre_StatisticsDescriptor(D) ->
+ true = is_StatisticsDescriptor(D),
+ D.
+
+cre_StatisticsParameter(N) when is_list(N) ->
+ #'StatisticsParameter'{statName = N}.
+
+cre_StatisticsParameter(N, V) when is_list(N) and is_list(V) ->
+ #'StatisticsParameter'{statName = N, statValue = V}.
+
+%% cre_NonStandardData({Tag, _} = Id, Data) when atom(Tag), list(Data) ->
+%% #'NonStandardData'{nonStandardIdentifier = Id, data = Data}.
+
+%% cre_NonStandardIdentifier(H221) when record(H221, 'H221NonStandard') ->
+%% {h221NonStandard, H221};
+%% cre_NonStandardIdentifier(Obj) when tuple(Obj) ->
+%% {object, Obj};
+%% cre_NonStandardIdentifier(Exp) when list(Exp), length(Exp) == 8 ->
+%% {experimental, Exp}.
+
+%% cre_H221NonStandard(CC1, CC2, Ext, MC)
+%% when (is_integer(CC1) and (0 =< CC1) and (CC1 =< 255)) and
+%% (is_integer(CC2) and (0 =< CC2) and (CC2 =< 255)) and
+%% (is_integer(Ext) and (0 =< Ext) and (Ext =< 255)) and
+%% (is_integer(MC) and (0 =< MC) and (MC =< 255)) ->
+%% #'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}.
+
+cre_TimeNotation(D, T)
+ when is_list(D) and (length(D) == 8) and
+ is_list(T) and (length(T) == 8) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_Value([H|_] = V) when is_list(H) ->
+ V.
+
+cre_BOOLEAN(true = B) ->
+ B;
+cre_BOOLEAN(false = B) ->
+ B.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% -- MegacoMessage --
+
+is_MegacoMessage(#'MegacoMessage'{authHeader = Auth,
+ mess = Mess}) ->
+ d("is_MegacoMessage -> entry"),
+ is_opt_AuthenticationHeader(Auth) andalso is_Message(Mess);
+is_MegacoMessage(_) ->
+ false.
+
+
+chk_MegacoMessage(M, M) ->
+ d("chk_MegacoMessage -> entry (1)"),
+ chk_type(fun is_MegacoMessage/1, 'MegacoMessage', M);
+chk_MegacoMessage(#'MegacoMessage'{authHeader = Auth1,
+ mess = Mess1},
+ #'MegacoMessage'{authHeader = Auth2,
+ mess = Mess2}) ->
+ d("chk_MegacoMessage -> entry (2)"),
+ chk_opt_AuthenticationHeader(Auth1,Auth2),
+ chk_Message(Mess1,Mess2),
+ ok;
+chk_MegacoMessage(M1, M2) ->
+ wrong_type('MegacoMessage', M1, M2).
+
+
+%% -- AuthenticationHeader --
+
+is_opt_AuthenticationHeader(AH) ->
+ is_OPTIONAL(fun is_AuthenticationHeader/1, AH).
+
+is_AuthenticationHeader(#'AuthenticationHeader'{secParmIndex = SPI,
+ seqNum = SN,
+ ad = AD}) ->
+ is_SecurityParmIndex(SPI) andalso
+ is_SequenceNum(SN) andalso
+ is_AuthData(AD);
+is_AuthenticationHeader(_) ->
+ false.
+
+%% This stuff is not really used, so make it simple...
+chk_opt_AuthenticationHeader(A1, A2) ->
+ chk_OPTIONAL('AuthenticationHeader', A1, A2,
+ fun is_AuthenticationHeader/1,
+ fun chk_AuthenticationHeader/2).
+
+chk_AuthenticationHeader(A, A) ->
+ chk_type(fun is_AuthenticationHeader/1, 'AuthenticationHeader', A);
+chk_AuthenticationHeader(A1, A2) ->
+ case (is_AuthenticationHeader(A1) andalso is_AuthenticationHeader(A2)) of
+ true ->
+ not_equal('AuthenticationHeader', A1, A2);
+ false ->
+ wrong_type('AuthenticationHeader', A1, A2)
+ end.
+
+
+%% -- SecurityParmIndex --
+
+is_SecurityParmIndex(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- SequenceNum --
+
+is_SequenceNum(V) -> is_OCTET_STRING(V, {exact, 4}).
+
+
+%% -- AuthData --
+
+is_AuthData(V) -> is_OCTET_STRING(V, {range, 12, 32}).
+
+
+%% -- Message --
+
+is_Message(#'Message'{version = V,
+ mId = MID,
+ messageBody = Body}) ->
+ d("is_Message -> entry"),
+ is_INTEGER(V, {range, 0, 99}) andalso
+ is_MId(MID) andalso
+ is_Message_messageBody(Body);
+is_Message(_) ->
+ false.
+
+chk_Message(M, M) ->
+ d("chk_Message -> entry (1)"),
+ chk_type(fun is_Message/1, 'Message', M);
+chk_Message(#'Message'{version = V1,
+ mId = MID1,
+ messageBody = Body1},
+ #'Message'{version = V2,
+ mId = MID2,
+ messageBody = Body2}) ->
+ d("chk_Message -> entry with"
+ "~n V1: ~p"
+ "~n V2: ~p"
+ "~n MID1: ~p"
+ "~n MID2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p",
+ [V1, V2, MID1, MID2, Body1, Body2]),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'Message_version'),
+ validate(fun() -> chk_MId(MID1, MID2) end, 'Message_mId'),
+ chk_Message_messageBody(Body1, Body2),
+ ok;
+chk_Message(M1, M2) ->
+ wrong_type('Message', M1, M2).
+
+
+is_Message_messageBody({Tag, Val}) ->
+ d("is_Message_messageBody -> entry"),
+ is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val);
+is_Message_messageBody(_) ->
+ false.
+
+is_Message_messageBody_tag(Tag) ->
+ Tags = [messageError, transactions],
+ lists:member(Tag, Tags).
+
+is_Message_messageBody_val(messageError, Val) ->
+ is_ErrorDescriptor(Val);
+is_Message_messageBody_val(transactions, Val) ->
+ is_Message_messageBody_transactions(Val).
+
+is_Message_messageBody_transactions([]) ->
+ d("is_Message_messageBody_transactions -> entry when done"),
+ true;
+is_Message_messageBody_transactions([H|T]) ->
+ d("is_Message_messageBody_transactions -> entry"),
+ is_Transaction(H) andalso is_Message_messageBody_transactions(T);
+is_Message_messageBody_transactions(_) ->
+ false.
+
+chk_Message_messageBody(B, B) ->
+ d("chk_Message_messageBody -> entry (1)"),
+ chk_type(fun is_Message_messageBody/1, 'Message_messageBody', B);
+chk_Message_messageBody({Tag, Val1} = B1, {Tag, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (2)"),
+ case (is_Message_messageBody_tag(Tag) andalso
+ is_Message_messageBody_val(Tag, Val1) andalso
+ is_Message_messageBody_val(Tag, Val2)) of
+ true ->
+ chk_Message_messageBody_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody({Tag1, Val1} = B1, {Tag2, Val2} = B2) ->
+ d("chk_Message_messageBody -> entry (3)"),
+ case ((is_Message_messageBody_tag(Tag1) andalso
+ is_Message_messageBody_val(Tag1, Val1)) andalso
+ (is_Message_messageBody_tag(Tag2) andalso
+ is_Message_messageBody_val(Tag2, Val2))) of
+ true ->
+ not_equal('Message_messageBody', B1, B2);
+ false ->
+ wrong_type('Message_messageBody', B1, B2)
+ end;
+chk_Message_messageBody(B1, B2) ->
+ wrong_type('Message_messageBody', B1, B2).
+
+chk_Message_messageBody_val(messageError, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'Message_messageBody');
+chk_Message_messageBody_val(transactions, Val1, Val2) ->
+ chk_Message_messageBody_transactions(lists:sort(Val1),
+ lists:sort(Val2)).
+
+chk_Message_messageBody_transactions([], []) ->
+ d("chk_Message_messageBody_transactions -> entry - ok (1)"),
+ ok;
+chk_Message_messageBody_transactions([] = T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (2)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions(T1, [] = T2) ->
+ d("chk_Message_messageBody_transactions -> entry - not-equal (3)"),
+ not_equal('Message_messageBody_transactions', T1, T2);
+chk_Message_messageBody_transactions([H|T1], [H|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (4)"),
+ case is_Transaction(H) of
+ true ->
+ chk_Message_messageBody_transactions(T1, T2);
+ false ->
+ wrong_type('Message_messageBody_transactions_val', H)
+ end;
+chk_Message_messageBody_transactions([H1|T1], [H2|T2]) ->
+ d("chk_Message_messageBody_transactions -> entry (5)"),
+ validate(fun() -> chk_Transaction(H1, H2) end,
+ 'Message_messageBody_transactions_val'),
+ chk_Message_messageBody_transactions(T1, T2);
+chk_Message_messageBody_transactions(T1, T2) ->
+ d("chk_Message_messageBody_transactions -> entry - wrong-type (6)"),
+ wrong_type('Message_messageBody_transactions', T1, T2).
+
+
+%% -- MId --
+
+is_opt_MId(M) ->
+ is_OPTIONAL(fun is_MId/1, M).
+
+is_MId({Tag, Val}) ->
+ is_MId_tag(Tag) andalso is_MId_val(Tag, Val);
+is_MId(_) ->
+ false.
+
+is_MId_tag(Tag) ->
+ Tags = [ip4Address, ip6Address, domainName, deviceName, mtpAddress],
+ lists:member(Tag, Tags).
+
+is_MId_val(ip4Address, Val) -> is_IP4Address(Val);
+is_MId_val(ip6Address, Val) -> is_IP6Address(Val);
+is_MId_val(domainName, Val) -> is_DomainName(Val);
+is_MId_val(deviceName, Val) -> is_PathName(Val);
+is_MId_val(mtpAddress, Val) -> is_OCTET_STRING(Val, {range, 2, 4}).
+
+chk_opt_MId(M1, M2) ->
+ chk_OPTIONAL('MId', M1, M2, fun is_MId/1, fun chk_MId/2).
+
+chk_MId(M, M) ->
+ chk_type(fun is_MId/1, 'MId', M);
+chk_MId({Tag, Val1} = M1, {Tag, Val2} = M2) ->
+ case (is_MId_tag(Tag) andalso
+ is_MId_val(Tag, Val1) andalso
+ is_MId_val(Tag, Val2)) of
+ true ->
+ chk_MId_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId({Tag1, Val1} = M1, {Tag2, Val2} = M2) ->
+ case ((is_MId_tag(Tag1) andalso
+ is_MId_val(Tag1, Val1)) andalso
+ (is_MId_tag(Tag2) andalso
+ is_MId_val(Tag2, Val2))) of
+ true ->
+ not_equal('MId', M1, M2);
+ false ->
+ wrong_type('MId', M1, M2)
+ end;
+chk_MId(M1, M2) ->
+ wrong_type('MId', M1, M2).
+
+chk_MId_val(ip4Address, M1, M2) -> chk_IP4Address(M1, M2);
+chk_MId_val(ip6Address, M1, M2) -> chk_IP6Address(M1, M2);
+chk_MId_val(domainName, M1, M2) -> chk_DomainName(M1, M2);
+chk_MId_val(deviceName, M1, M2) -> chk_PathName(M1, M2);
+chk_MId_val(mtpAddress, M1, M2) -> chk_OCTET_STRING(M1, M2, {range, 2, 4}).
+
+
+%% -- DomainName --
+
+is_DomainName(#'DomainName'{name = N, portNumber = PN}) ->
+ is_IA5String(N) andalso is_opt_INTEGER(PN, {range, 0, 65535});
+is_DomainName(_) ->
+ false.
+
+chk_DomainName(N, N) ->
+ ok;
+chk_DomainName(N1, N2) ->
+ not_equal('DomainName', N1, N2).
+
+
+%% -- IP4Address --
+
+is_IP4Address(#'IP4Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 4}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP4Address(_) ->
+ false.
+
+chk_IP4Address(A, A) ->
+ ok;
+chk_IP4Address(A1, A2) ->
+ not_equal('IP4Address', A1, A2).
+
+
+%% -- IP6Address --
+
+is_IP6Address(#'IP6Address'{address = A, portNumber = PN}) ->
+ is_OCTET_STRING(A, {exact, 16}) andalso
+ is_opt_INTEGER(PN, {range, 0, 65535});
+is_IP6Address(_) ->
+ false.
+
+chk_IP6Address(A, A) ->
+ ok;
+chk_IP6Address(A1, A2) ->
+ not_equal('IP6Address', A1, A2).
+
+
+%% -- PathName --
+
+is_PathName(N) -> is_IA5String(N, {range, 1, 64}).
+
+chk_PathName(N, N) ->
+ ok;
+chk_PathName(N1, N2) ->
+ not_equal('PathName', N1, N2).
+
+
+%% -- Transaction --
+
+is_Transaction({Tag, Val}) ->
+ d("is_Transaction -> entry"),
+ is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val);
+is_Transaction(_) ->
+ false.
+
+is_Transaction_tag(Tag) ->
+ Tags = [transactionRequest,
+ transactionPending,
+ transactionReply,
+ transactionResponseAck],
+ lists:member(Tag, Tags).
+
+is_Transaction_val(transactionRequest, V) -> is_TransactionRequest(V);
+is_Transaction_val(transactionPending, V) -> is_TransactionPending(V);
+is_Transaction_val(transactionReply, V) -> is_TransactionReply(V);
+is_Transaction_val(transactionResponseAck, V) -> is_TransactionResponseAck(V).
+
+
+chk_Transaction({Tag, Val} = Trans, Trans) ->
+ d("chk_Transaction -> entry (1)"),
+ case (is_Transaction_tag(Tag) andalso is_Transaction_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Transaction', Trans, Trans)
+ end;
+chk_Transaction({Tag, Val1} = Trans1, {Tag, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (2)"),
+ case (is_Transaction_tag(Tag) and
+ is_Transaction_val(Tag, Val1) and
+ is_Transaction_val(Tag, Val2)) of
+ true ->
+ chk_Transaction_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction({Tag1, Val1} = Trans1, {Tag2, Val2} = Trans2) ->
+ d("chk_Transaction -> entry (3)"),
+ case ((is_Transaction_tag(Tag1) andalso
+ is_Transaction_val(Tag1, Val1)) andalso
+ (is_Transaction_tag(Tag2) andalso
+ is_Transaction_val(Tag2, Val2))) of
+ true ->
+ not_equal('Transaction', Trans1, Trans2);
+ false ->
+ wrong_type('Transaction', Trans1, Trans2)
+ end;
+chk_Transaction(Trans1, Trans2) ->
+ d("chk_Transaction -> entry - wrong-type - (4)"),
+ wrong_type('Transaction', Trans1, Trans2).
+
+chk_Transaction_val(transactionRequest, T1, T2) ->
+ chk_TransactionRequest(T1, T2);
+chk_Transaction_val(transactionPending, T1, T2) ->
+ chk_TransactionPending(T1, T2);
+chk_Transaction_val(transactionReply, T1, T2) ->
+ chk_TransactionReply(T1,T2);
+chk_Transaction_val(transactionResponseAck, T1, T2) ->
+ chk_TransactionResponseAck(T1, T2).
+
+
+%% -- TransactionId --
+
+is_opt_TransactionId(TID) ->
+ is_OPTIONAL(fun is_TransactionId/1, TID).
+
+is_TransactionId(TID) ->
+ d("is_TransactionId -> entry"),
+ is_INTEGER(TID, {range, 0, 4294967295}).
+
+chk_opt_TransactionId(TID1, TID2) ->
+ chk_OPTIONAL('TransactionId', TID1, TID2,
+ fun is_TransactionId/1, fun chk_TransactionId/2).
+
+chk_TransactionId(TID, TID) ->
+ chk_type(fun is_TransactionId/1, 'TransactionId', TID);
+chk_TransactionId(TID1, TID2) ->
+ case (is_TransactionId(TID1) andalso is_TransactionId(TID2)) of
+ true ->
+ not_equal('TransactionId', TID1, TID2);
+ false ->
+ wrong_type('TransactionId', TID1, TID2)
+ end.
+
+
+%% -- TransactionRequest --
+
+is_TransactionRequest(#'TransactionRequest'{transactionId = TID,
+ actions = Acts}) ->
+ d("is_TransactionRequest -> entry"),
+ is_TransactionId(TID) andalso is_TransactionRequest_actions(Acts);
+is_TransactionRequest(_) ->
+ false.
+
+chk_TransactionRequest(T, T) ->
+ chk_type(fun is_TransactionRequest/1, 'TransactionRequest', T);
+chk_TransactionRequest(#'TransactionRequest'{transactionId = TID1,
+ actions = Acts1},
+ #'TransactionRequest'{transactionId = TID2,
+ actions = Acts2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionRequest'),
+ chk_TransactionRequest_actions(lists:sort(Acts1),
+ lists:sort(Acts2)),
+ ok;
+chk_TransactionRequest(T1, T2) ->
+ wrong_type('TransactionRequest', T1, T2).
+
+is_TransactionRequest_actions([]) ->
+ d("is_TransactionRequest_actions -> entry when done"),
+ true;
+is_TransactionRequest_actions([H|T]) ->
+ d("is_TransactionRequest_actions -> entry"),
+ is_ActionRequest(H) andalso is_TransactionRequest_actions(T);
+is_TransactionRequest_actions(_) ->
+ false.
+
+chk_TransactionRequest_actions([], []) ->
+ ok;
+chk_TransactionRequest_actions([] = Acts1, Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions(Acts1, [] = Acts2) ->
+ not_equal('TransactionRequest_actions', Acts1, Acts2);
+chk_TransactionRequest_actions([H|T1], [H|T2]) ->
+ case is_ActionRequest(H) of
+ true ->
+ chk_TransactionRequest_actions(T1, T2);
+ false ->
+ wrong_type('TransactionRequest_actions_val', H)
+ end;
+chk_TransactionRequest_actions([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionRequest(H1, H2) end,
+ 'TransactionRequest_actions_val'),
+ chk_TransactionRequest_actions(T1, T2);
+chk_TransactionRequest_actions(Acts1, Acts2) ->
+ wrong_type('TransactionRequest_actions', Acts1, Acts2).
+
+
+%% -- TransactionPending --
+
+is_TransactionPending(#'TransactionPending'{transactionId = TID}) ->
+ d("is_TransactionPending -> entry"),
+ is_TransactionId(TID);
+is_TransactionPending(_) ->
+ false.
+
+chk_TransactionPending(T, T) ->
+ chk_type(fun is_TransactionPending/1, 'TransactionPending', T);
+chk_TransactionPending(#'TransactionPending'{transactionId = TID1},
+ #'TransactionPending'{transactionId = TID2}) ->
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionPending'),
+ ok;
+chk_TransactionPending(T1, T2) ->
+ wrong_type('TransactionPending', T1, T2).
+
+
+%% -- TransactionReply --
+
+is_TransactionReply(#'TransactionReply'{transactionId = TID,
+ immAckRequired = IAR,
+ transactionResult = TR}) ->
+ d("is_TransactionReply -> entry"),
+ is_TransactionId(TID) andalso
+ is_opt_NULL(IAR) andalso
+ is_TransactionReply_transactionResult(TR);
+is_TransactionReply(_) ->
+ false.
+
+chk_TransactionReply(T, T) ->
+ d("chk_TransactionReply -> entry (2)"),
+ chk_type(fun is_TransactionReply/1, 'TransactionReply', T);
+chk_TransactionReply(#'TransactionReply'{transactionId = TID1,
+ immAckRequired = IAR1,
+ transactionResult = TR1},
+ #'TransactionReply'{transactionId = TID2,
+ immAckRequired = IAR2,
+ transactionResult = TR2}) ->
+ d("chk_TransactionReply -> entry (2)"),
+ validate(fun() -> chk_TransactionId(TID1, TID2) end, 'TransactionReply'),
+ validate(fun() -> chk_opt_NULL(IAR1, IAR2) end, 'TransactionReply'),
+ chk_TransactionReply_transactionResult(TR1, TR2),
+ ok;
+chk_TransactionReply(T1, T2) ->
+ d("chk_TransactionReply -> entry (3)"),
+ wrong_type('TransactionReply', T1, T2).
+
+is_TransactionReply_transactionResult({Tag, Val}) ->
+ d("is_TransactionReply_transactionResult -> entry"),
+ is_TransactionReply_transactionResult_tag(Tag) andalso
+ is_TransactionReply_transactionResult_val(Tag, Val);
+is_TransactionReply_transactionResult(_) ->
+ false.
+
+is_TransactionReply_transactionResult_tag(T) ->
+ lists:member(T, [transactionError, actionReplies]).
+
+is_TransactionReply_transactionResult_val(transactionError, V) ->
+ is_ErrorDescriptor(V);
+is_TransactionReply_transactionResult_val(actionReplies, V) ->
+ is_TransactionReply_actionReplies(V).
+
+chk_TransactionReply_transactionResult(Res, Res) ->
+ chk_type(fun is_TransactionReply_transactionResult/1,
+ 'TransactionReply_transactionResult', Res);
+chk_TransactionReply_transactionResult({Tag, Val1} = Res1,
+ {Tag, Val2} = Res2) ->
+ case (is_TransactionReply_transactionResult_tag(Tag) and
+ is_TransactionReply_transactionResult_val(Tag, Val1) and
+ is_TransactionReply_transactionResult_val(Tag, Val2)) of
+ true ->
+ chk_TransactionReply_transactionResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult({Tag1, Val1} = Res1,
+ {Tag2, Val2} = Res2) ->
+ case ((is_TransactionReply_transactionResult_tag(Tag1) and
+ is_TransactionReply_transactionResult_val(Tag1, Val1)) and
+ (is_TransactionReply_transactionResult_tag(Tag2) and
+ is_TransactionReply_transactionResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('TransactionReply_transactionResult', Res1, Res2);
+ false ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2)
+ end;
+chk_TransactionReply_transactionResult(Res1, Res2) ->
+ wrong_type('TransactionReply_transactionResult', Res1, Res2).
+
+chk_TransactionReply_transactionResult_val(transactionError, E1, E2) ->
+ validate(fun() -> chk_ErrorDescriptor(E1, E2) end,
+ 'TransactionReply_transactionResult');
+chk_TransactionReply_transactionResult_val(actionReplies, R1, R2) ->
+ validate(fun() ->
+ chk_TransactionReply_actionReplies(lists:sort(R1),
+ lists:sort(R2))
+ end,
+ 'TransactionReply_transactionResult').
+
+is_TransactionReply_actionReplies([]) ->
+ d("is_TransactionReply_actionReplies -> entry when done"),
+ true;
+is_TransactionReply_actionReplies([H|T]) ->
+ d("is_TransactionReply_actionReplies -> entry"),
+ is_ActionReply(H) andalso is_TransactionReply_actionReplies(T);
+is_TransactionReply_actionReplies(_) ->
+ false.
+
+chk_TransactionReply_actionReplies([], []) ->
+ ok;
+chk_TransactionReply_actionReplies([] = AR1, AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies(AR1, [] = AR2) ->
+ not_equal('TransactionReply_actionReplies', AR1, AR2);
+chk_TransactionReply_actionReplies([H|T1], [H|T2]) ->
+ case is_ActionReply(H) of
+ true ->
+ chk_TransactionReply_actionReplies(T1, T2);
+ false ->
+ wrong_type('TransactionReply_actionReplies_val', H)
+ end;
+chk_TransactionReply_actionReplies([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ActionReply(H1, H2) end,
+ 'TransactionReply_actionReplies_val'),
+ chk_TransactionReply_actionReplies(T1, T2);
+chk_TransactionReply_actionReplies(AR1, AR2) ->
+ wrong_type('TransactionReply_actionReplies', AR1, AR2).
+
+
+%% -- TransactionResponseAck --
+
+is_TransactionResponseAck([]) ->
+ d("is_TransactionResponseAck -> entry when done"),
+ true;
+is_TransactionResponseAck([H|T]) ->
+ d("is_TransactionResponseAck -> entry"),
+ is_TransactionAck(H) andalso is_TransactionResponseAck(T);
+is_TransactionResponseAck(_) ->
+ false.
+
+chk_TransactionResponseAck([], []) ->
+ ok;
+chk_TransactionResponseAck([] = AR1, AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck(AR1, [] = AR2) ->
+ not_equal('TransactionResponseAck', AR1, AR2);
+chk_TransactionResponseAck([H|T1], [H|T2]) ->
+ case is_TransactionAck(H) of
+ true ->
+ chk_TransactionResponseAck(T1, T2);
+ false ->
+ wrong_type('TransactionResponseAck_val', H)
+ end;
+chk_TransactionResponseAck([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TransactionAck(H1, H2) end,
+ 'TransactionResponseAck'),
+ chk_TransactionResponseAck(T1, T2);
+chk_TransactionResponseAck(AR1, AR2) ->
+ wrong_type('TransactionResponseAck', AR1, AR2).
+
+
+%% -- TransactionAck --
+
+is_TransactionAck(#'TransactionAck'{firstAck = F,
+ lastAck = L}) ->
+ d("is_TransactionAck -> entry"),
+ is_TransactionId(F) andalso is_opt_TransactionId(L);
+is_TransactionAck(_) ->
+ false.
+
+chk_TransactionAck(T, T) ->
+ chk_type(fun is_TransactionAck/1, 'TransactionAck', T);
+chk_TransactionAck(#'TransactionAck'{firstAck = F1,
+ lastAck = L1},
+ #'TransactionAck'{firstAck = F2,
+ lastAck = L2}) ->
+ validate(fun() -> chk_TransactionId(F1, F2) end, 'TransactionAck'),
+ validate(fun() -> chk_opt_TransactionId(L1, L2) end, 'TransactionAck'),
+ ok;
+chk_TransactionAck(T1, T2) ->
+ wrong_type('TransactionAck', T1, T2).
+
+
+%% -- ErrorDescriptor --
+
+is_opt_ErrorDescriptor(V) ->
+ is_OPTIONAL(fun is_ErrorDescriptor/1, V).
+
+is_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code,
+ errorText = Text}) ->
+ d("is_ErrorDescriptor -> entry"),
+ is_ErrorCode(Code) andalso is_opt_ErrorText(Text);
+is_ErrorDescriptor(_) ->
+ false.
+
+chk_opt_ErrorDescriptor(E1, E2) ->
+ chk_OPTIONAL('ErrorDescriptor', E1, E2,
+ fun is_ErrorDescriptor/1, fun chk_ErrorDescriptor/2).
+
+chk_ErrorDescriptor(E, E) ->
+ chk_type(fun is_ErrorDescriptor/1, 'ErrorDescriptor', E);
+chk_ErrorDescriptor(#'ErrorDescriptor'{errorCode = Code1,
+ errorText = Text1},
+ #'ErrorDescriptor'{errorCode = Code2,
+ errorText = Text2}) ->
+ chk_ErrorCode(Code1, Code2),
+ chk_opt_ErrorText(Text1, Text2),
+ ok;
+chk_ErrorDescriptor(E1, E2) ->
+ wrong_type('ErrorDescriptor', E1, E2).
+
+
+%% -- ErrorCode --
+
+is_ErrorCode(C) -> is_INTEGER(C, {range, 0, 65535}).
+
+chk_ErrorCode(C, C) ->
+ case is_ErrorCode(C) of
+ true ->
+ ok;
+ false ->
+ wrong_type(errorCode, C, C)
+ end;
+chk_ErrorCode(C1, C2) ->
+ case (is_ErrorCode(C1) andalso is_ErrorCode(C2)) of
+ true ->
+ not_equal(errorCode, C1, C2);
+ false ->
+ wrong_type(errorCode, C1, C2)
+ end.
+
+
+%% -- ErrorText --
+
+is_opt_ErrorText(V) ->
+ is_OPTIONAL(fun is_ErrorText/1, V).
+
+is_ErrorText(V) -> is_IA5String(V).
+
+chk_opt_ErrorText(T1, T2) ->
+ chk_OPTIONAL('ErrorText', T1, T2, fun is_ErrorText/1, fun chk_ErrorText/2).
+
+chk_ErrorText(T, T) ->
+ chk_type(fun is_ErrorText/1, 'ErrorText', T);
+chk_ErrorText(T1, T2) ->
+ case (is_ErrorText(T1) andalso is_ErrorText(T2)) of
+ true ->
+ case {to_lower(T1), to_lower(T2)} of
+ {T, T} ->
+ ok;
+ _ ->
+ not_equal('ErrorText', T1, T2)
+ end;
+ false ->
+ wrong_type('ErrorText', T1, T2)
+ end.
+
+
+%% -- ContextID --
+
+is_ContextID(Id) -> is_INTEGER(Id, {range, 0, 4294967295}).
+
+chk_ContextID(Id, Id) ->
+ chk_type(fun is_ContextID/1, 'ContextID', Id);
+chk_ContextID(Id1, Id2) ->
+ case (is_ContextID(Id1) andalso is_ContextID(Id2)) of
+ true ->
+ not_equal('ContextID', Id1, Id2);
+ false ->
+ wrong_type('ContextID', Id1, Id2)
+ end.
+
+
+%% -- ActionRequest --
+
+is_ActionRequest(#'ActionRequest'{contextId = Id,
+ contextRequest = CtxReq,
+ contextAttrAuditReq = AuditReq,
+ commandRequests = CmdReqs}) ->
+ d("is_ActionRequest -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ContextRequest(CtxReq) andalso
+ is_opt_ContextAttrAuditRequest(AuditReq) andalso
+ is_ActionRequest_commandRequests(CmdReqs);
+is_ActionRequest(_) ->
+ false.
+
+chk_ActionRequest(A, A) ->
+ chk_type(fun is_ActionRequest/1, 'ActionRequest', A);
+chk_ActionRequest(#'ActionRequest'{contextId = Id1,
+ contextRequest = Req1,
+ contextAttrAuditReq = AuditReq1,
+ commandRequests = CmdReqs1},
+ #'ActionRequest'{contextId = Id2,
+ contextRequest = Req2,
+ contextAttrAuditReq = AuditReq2,
+ commandRequests = CmdReqs2}) ->
+ validate(fun() -> chk_ContextID(Id1, Id2) end, 'ActionRequest'),
+ validate(fun() -> chk_opt_ContextRequest(Req1, Req2) end, 'ActionRequest'),
+ validate(fun() ->
+ chk_opt_ContextAttrAuditRequest(AuditReq1, AuditReq2)
+ end,
+ 'ActionRequest'),
+ chk_ActionRequest_commandRequests(CmdReqs1, CmdReqs2),
+ ok.
+
+
+is_ActionRequest_commandRequests([]) ->
+ d("is_ActionRequest_commandRequests -> entry when done"),
+ true;
+is_ActionRequest_commandRequests([H|T]) ->
+ d("is_ActionRequest_commandRequests -> entry"),
+ is_CommandRequest(H) andalso is_ActionRequest_commandRequests(T);
+is_ActionRequest_commandRequests(_) ->
+ false.
+
+chk_ActionRequest_commandRequests([], []) ->
+ ok;
+chk_ActionRequest_commandRequests([] = CmdReqs1, CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests(CmdReqs1, [] = CmdReqs2) ->
+ not_equal('ActionRequest_commandRequests', CmdReqs1, CmdReqs2);
+chk_ActionRequest_commandRequests([H|T1], [H|T2]) ->
+ case is_CommandRequest(H) of
+ true ->
+ chk_ActionRequest_commandRequests(T1, T2);
+ false ->
+ wrong_type('ActionRequest_commandRequest_val', H)
+ end;
+chk_ActionRequest_commandRequests([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandRequest(H1, H2) end,
+ 'ActionRequest_commandRequests_val'),
+ chk_ActionRequest_commandRequests(T1, T2);
+chk_ActionRequest_commandRequests(R1, R2) ->
+ wrong_type('ActionRequest_commandRequests', R1, R2).
+
+
+%% -- ActionReply --
+
+is_ActionReply(#'ActionReply'{contextId = Id,
+ errorDescriptor = ED,
+ contextReply = CtxRep,
+ commandReply = CmdRep}) ->
+ d("is_ActionReply -> entry"),
+ is_ContextID(Id) andalso
+ is_opt_ErrorDescriptor(ED) andalso
+ is_opt_ContextRequest(CtxRep) andalso
+ is_ActionReply_commandReply(CmdRep);
+is_ActionReply(_) ->
+ false.
+
+is_ActionReply_commandReply([]) ->
+ d("is_ActionReply_commandReply -> entry when done"),
+ true;
+is_ActionReply_commandReply([H|T]) ->
+ d("is_ActionReply_commandReply -> entry"),
+ is_CommandReply(H) andalso is_ActionReply_commandReply(T);
+is_ActionReply_commandReply(_) ->
+ false.
+
+chk_ActionReply(A, A) ->
+ d("chk_ActionReply -> entry (1)"),
+ chk_type(fun is_ActionReply/1, 'ActionReply', A);
+chk_ActionReply(#'ActionReply'{contextId = Id1,
+ errorDescriptor = ED1,
+ contextReply = CtxRep1,
+ commandReply = CmdRep1},
+ #'ActionReply'{contextId = Id2,
+ errorDescriptor = ED2,
+ contextReply = CtxRep2,
+ commandReply = CmdRep2}) ->
+ d("chk_ActionReply -> entry (2)"),
+ chk_ContextID(Id1, Id2),
+ chk_opt_ErrorDescriptor(ED1, ED2),
+ chk_opt_ContextRequest(CtxRep1, CtxRep2),
+ chk_ActionReply_commandReply(CmdRep1, CmdRep2).
+
+chk_ActionReply_commandReply([], []) ->
+ ok;
+chk_ActionReply_commandReply([] = Reps1, Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply(Reps1, [] = Reps2) ->
+ not_equal('ActionReply_commandReply', Reps1, Reps2);
+chk_ActionReply_commandReply([H|T1], [H|T2]) ->
+ case is_CommandReply(H) of
+ true ->
+ chk_ActionReply_commandReply(T1, T2);
+ false ->
+ wrong_type('ActionReply_commandReply_val', H)
+ end;
+chk_ActionReply_commandReply([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_CommandReply(H1, H2) end,
+ 'ActionReply_commandReply_val'),
+ chk_ActionReply_commandReply(T1, T2);
+chk_ActionReply_commandReply(R1, R2) ->
+ wrong_type('ActionReply_commandReply', R1, R2).
+
+
+%% -- ContextRequest --
+
+is_opt_ContextRequest(V) ->
+ is_OPTIONAL(fun is_ContextRequest/1, V).
+
+is_ContextRequest(#'ContextRequest'{priority = Prio,
+ emergency = Em,
+ topologyReq = TopReq,
+ iepscallind = Ieps,
+ contextProp = CtxProp,
+ contextList = CtxList}) ->
+ d("is_ContextRequest -> entry"),
+ is_ContextRequest_priority(Prio) andalso
+ is_ContextRequest_emergency(Em) andalso
+ is_ContextRequest_topologyReq(TopReq) andalso
+ is_ContextRequest_iepscallind(Ieps) andalso
+ is_ContextRequest_contextProp(CtxProp) andalso
+ is_ContextRequest_contextList(CtxList);
+is_ContextRequest(_) ->
+ false.
+
+is_ContextRequest_priority(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_priority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextRequest_emergency(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_emergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_topologyReq(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_topologyReq([]) ->
+ true;
+is_ContextRequest_topologyReq([H|T]) ->
+ is_TopologyRequest(H) andalso is_ContextRequest_topologyReq(T);
+is_ContextRequest_topologyReq(_) ->
+ false.
+
+is_ContextRequest_iepscallind(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_iepscallind(V) ->
+ is_BOOLEAN(V).
+
+is_ContextRequest_contextProp(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextProp([]) ->
+ true;
+is_ContextRequest_contextProp([H|T]) ->
+ is_PropertyParm(H) andalso is_ContextRequest_contextProp(T);
+is_ContextRequest_contextProp(_) ->
+ false.
+
+is_ContextRequest_contextList(asn1_NOVALUE) ->
+ true;
+is_ContextRequest_contextList([]) ->
+ true;
+is_ContextRequest_contextList([H|T]) ->
+ is_ContextID(H) andalso is_ContextRequest_contextList(T);
+is_ContextRequest_contextList(_) ->
+ false.
+
+chk_opt_ContextRequest(R1, R2) ->
+ chk_OPTIONAL('ContextRequest', R1, R2,
+ fun is_ContextRequest/1, fun chk_ContextRequest/2).
+
+chk_ContextRequest(R, R) ->
+ chk_type(fun is_ContextRequest/1, 'ContextRequest', R);
+chk_ContextRequest(#'ContextRequest'{priority = Prio1,
+ emergency = Em1,
+ topologyReq = TopReq1,
+ iepscallind = Ieps1,
+ contextProp = CtxProp1,
+ contextList = CtxList1},
+ #'ContextRequest'{priority = Prio2,
+ emergency = Em2,
+ topologyReq = TopReq2,
+ iepscallind = Ieps2,
+ contextProp = CtxProp2,
+ contextList = CtxList2}) ->
+ chk_ContextRequest_priority(Prio1, Prio2),
+ chk_ContextRequest_emergency(Em1, Em2),
+ chk_ContextRequest_topologyReq(TopReq1, TopReq2),
+ chk_ContextRequest_iepscallind(Ieps1, Ieps2),
+ chk_ContextRequest_contextProp(CtxProp1, CtxProp2),
+ chk_ContextRequest_contextList(CtxList1, CtxList2),
+ ok;
+chk_ContextRequest(R1, R2) ->
+ wrong_type('ContextRequest', R1, R2).
+
+
+chk_ContextRequest_priority(asn1_NOVALUE,asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_priority(P, P) ->
+ chk_type(fun is_ContextRequest_priority/1, 'ContextRequest_priority', P);
+chk_ContextRequest_priority(P1, P2) ->
+ case (is_ContextRequest_priority(P1) andalso
+ is_ContextRequest_priority(P2)) of
+ true ->
+ not_equal('ContextRequest_priority', P1, P2);
+ false ->
+ wrong_type(contextRequest_priority, P1, P2)
+ end.
+
+
+chk_ContextRequest_emergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_emergency(E, E) ->
+ chk_type(fun is_ContextRequest_emergency/1, 'ContextRequest_emergency', E);
+chk_ContextRequest_emergency(E1, E2) ->
+ case (is_ContextRequest_emergency(E1) andalso
+ is_ContextRequest_emergency(E2)) of
+ true ->
+ not_equal('ContextRequest_emergency', E1, E2);
+ false ->
+ wrong_type('ContextRequest_emergency', E1, E2)
+ end.
+
+chk_ContextRequest_topologyReq(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_topologyReq([], []) ->
+ ok;
+chk_ContextRequest_topologyReq([] = T1, T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq(T1, [] = T2) ->
+ not_equal('ContextRequest_topologyReq', T1, T2);
+chk_ContextRequest_topologyReq([H|T1], [H|T2]) ->
+ case is_TopologyRequest(H) of
+ true ->
+ chk_ContextRequest_topologyReq(T1, T2);
+ false ->
+ wrong_type('ContextRequest_topologyReq_val', H)
+ end;
+chk_ContextRequest_topologyReq([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TopologyRequest(H1, H2) end,
+ 'ContextRequest_topologyReq_val'),
+ chk_ContextRequest_topologyReq(T1, T2);
+chk_ContextRequest_topologyReq(T1, T2) ->
+ wrong_type('ContextRequest_topologyReq', T1, T2).
+
+
+chk_ContextRequest_iepscallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_iepscallind(E, E) ->
+ chk_type(fun is_ContextRequest_iepscallind/1,
+ 'ContextRequest_iepscallind', E);
+chk_ContextRequest_iepscallind(E1, E2) ->
+ case (is_ContextRequest_iepscallind(E1) andalso
+ is_ContextRequest_iepscallind(E2)) of
+ true ->
+ case (((E1 == false) and (E2 == asn1_NOVALUE)) or
+ ((E1 == asn1_NOVALUE) and (E2 == false))) of
+ true ->
+ ok;
+ false ->
+ not_equal('ContextRequest_iepscallind', E1, E2)
+ end;
+
+ false ->
+ wrong_type('ContextRequest_iepscallind', E1, E2)
+ end.
+
+chk_ContextRequest_contextProp(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextProp([], []) ->
+ ok;
+chk_ContextRequest_contextProp([] = T1, T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp(T1, [] = T2) ->
+ not_equal('ContextRequest_contextProp', T1, T2);
+chk_ContextRequest_contextProp([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ContextRequest_contextProp(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextProp_val', H)
+ end;
+chk_ContextRequest_contextProp([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextRequest_contextProp_val'),
+ chk_ContextRequest_contextProp(T1, T2);
+chk_ContextRequest_contextProp(T1, T2) ->
+ wrong_type('ContextRequest_contextProp', T1, T2).
+
+chk_ContextRequest_contextList(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextRequest_contextList([], []) ->
+ ok;
+chk_ContextRequest_contextList([] = T1, T2) ->
+ not_equal('ContextRequest_contextList', T1, T2);
+chk_ContextRequest_contextList(T1, [] = T2) ->
+ not_equal('ContextRequest_contextList', T1, T2);
+chk_ContextRequest_contextList([H|T1], [H|T2]) ->
+ case is_ContextID(H) of
+ true ->
+ chk_ContextRequest_contextList(T1, T2);
+ false ->
+ wrong_type('ContextRequest_contextList_val', H)
+ end;
+chk_ContextRequest_contextList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ContextID(H1, H2) end,
+ 'ContextRequest_contextList_val'),
+ chk_ContextRequest_contextList(T1, T2);
+chk_ContextRequest_contextList(T1, T2) ->
+ wrong_type('ContextRequest_contextList', T1, T2).
+
+
+%% -- ContextAttrAuditRequest --
+
+is_opt_ContextAttrAuditRequest(asn1_NOVALUE) ->
+ true;
+is_opt_ContextAttrAuditRequest(V) ->
+ is_ContextAttrAuditRequest(V).
+
+is_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = T,
+ emergency = E,
+ priority = P,
+ iepscallind = I,
+ contextPropAud = A,
+ selectpriority = SP,
+ selectemergency = SE,
+ selectiepscallind = SI,
+ selectLogic = SL}) ->
+ d("is_ContextAttrAuditRequest -> entry"),
+ is_opt_NULL(T) andalso
+ is_opt_NULL(E) andalso
+ is_opt_NULL(P) andalso
+ is_opt_NULL(I) andalso
+ is_ContextAttrAuditRequest_contextPropAud(A) andalso
+ is_ContextAttrAuditRequest_selectpriority(SP) andalso
+ is_ContextAttrAuditRequest_selectemergency(SE) andalso
+ is_ContextAttrAuditRequest_selectiepscallind(SI) andalso
+ is_opt_SelectLogic(SL);
+is_ContextAttrAuditRequest(_) ->
+ false.
+
+is_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([]) ->
+ true;
+is_ContextAttrAuditRequest_contextPropAud([H|T]) ->
+ d("is_ContextAttrAuditRequest_contextPropAud -> entry"),
+ is_IndAudPropertyParm(H) andalso
+ is_ContextAttrAuditRequest_contextPropAud(T).
+
+is_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectpriority(V) ->
+ is_INTEGER(V, {range, 1, 15}).
+
+is_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectemergency(V) ->
+ is_BOOLEAN(V).
+
+is_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE) ->
+ true;
+is_ContextAttrAuditRequest_selectiepscallind(V) ->
+ is_BOOLEAN(V).
+
+
+chk_opt_ContextAttrAuditRequest(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ContextAttrAuditRequest(R1, R2) ->
+ chk_ContextAttrAuditRequest(R1, R2).
+
+chk_ContextAttrAuditRequest(R, R) ->
+ chk_type(fun is_ContextAttrAuditRequest/1, 'ContextAttrAuditRequest', R);
+chk_ContextAttrAuditRequest(
+ #'ContextAttrAuditRequest'{topology = T1,
+ emergency = E1,
+ priority = P1,
+ iepscallind = I1,
+ contextPropAud = A1,
+ selectpriority = SP1,
+ selectemergency = SE1,
+ selectiepscallind = SI1,
+ selectLogic = SL1},
+ #'ContextAttrAuditRequest'{topology = T2,
+ emergency = E2,
+ priority = P2,
+ iepscallind = I2,
+ contextPropAud = A2,
+ selectpriority = SP2,
+ selectemergency = SE2,
+ selectiepscallind = SI2,
+ selectLogic = SL2}) ->
+ validate(fun() -> chk_opt_NULL(T1, T2) end,
+ 'ContextAttrAuditRequest_topology'),
+ validate(fun() -> chk_opt_NULL(E1, E2) end,
+ 'ContextAttrAuditRequest_emergency'),
+ validate(fun() -> chk_opt_NULL(P1, P2) end,
+ 'ContextAttrAuditRequest_priority'),
+ validate(fun() -> chk_opt_NULL(I1, I2) end,
+ 'ContextAttrAuditRequest_iepscallind'),
+ chk_ContextAttrAuditRequest_contextPropAud(lists:sort(A1),
+ lists:sort(A2)),
+ chk_ContextAttrAuditRequest_selectpriority(SP1, SP2),
+ chk_ContextAttrAuditRequest_selectemergency(SE1, SE2),
+ chk_ContextAttrAuditRequest_selectiepscallind(SI1, SI2),
+ chk_ContextAttrAuditRequest_selectLogic(SL1, SL2),
+ ok.
+
+chk_ContextAttrAuditRequest_contextPropAud(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_contextPropAud/1,
+ 'ContextAttrAuditRequest_contextPropAud', A);
+chk_ContextAttrAuditRequest_contextPropAud([], []) ->
+ ok;
+chk_ContextAttrAuditRequest_contextPropAud([] = T1, T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, [] = T2) ->
+ not_equal('ContextAttrAuditRequest_contextPropAud', T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud_val', H)
+ end;
+chk_ContextAttrAuditRequest_contextPropAud([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'ContextAttrAuditRequest_contextPropAud_val'),
+ chk_ContextAttrAuditRequest_contextPropAud(T1, T2);
+chk_ContextAttrAuditRequest_contextPropAud(T1, T2) ->
+ wrong_type('ContextAttrAuditRequest_contextPropAud', T1, T2).
+
+chk_ContextAttrAuditRequest_selectpriority(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectpriority(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectpriority/1,
+ 'ContextAttrAuditRequest_selectpriority', A);
+chk_ContextAttrAuditRequest_selectpriority(SP1, SP2) ->
+ case (is_ContextAttrAuditRequest_selectpriority(SP1) andalso
+ is_ContextAttrAuditRequest_selectpriority(SP2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectpriority', SP1, SP2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectpriority', SP1, SP2)
+ end.
+
+chk_ContextAttrAuditRequest_selectemergency(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectemergency(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectemergency/1,
+ 'ContextAttrAuditRequest_selectemergency', A);
+chk_ContextAttrAuditRequest_selectemergency(SE1, SE2) ->
+ case (is_ContextAttrAuditRequest_selectemergency(SE1) andalso
+ is_ContextAttrAuditRequest_selectemergency(SE2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectemergency', SE1, SE2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectemergency', SE1, SE2)
+ end.
+
+chk_ContextAttrAuditRequest_selectiepscallind(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_ContextAttrAuditRequest_selectiepscallind(A, A) ->
+ chk_type(fun is_ContextAttrAuditRequest_selectiepscallind/1,
+ 'ContextAttrAuditRequest_selectiepscallind', A);
+chk_ContextAttrAuditRequest_selectiepscallind(SI1, SI2) ->
+ case (is_ContextAttrAuditRequest_selectiepscallind(SI1) andalso
+ is_ContextAttrAuditRequest_selectiepscallind(SI2)) of
+ true ->
+ not_equal('ContextAttrAuditRequest_selectiepscallind', SI1, SI2);
+ false ->
+ wrong_type('ContextAttrAuditRequest_selectiepscallind', SI1, SI2)
+ end.
+
+chk_ContextAttrAuditRequest_selectLogic(SL1, SL2) ->
+ validate(fun() -> chk_opt_SelectLogic(SL1, SL2) end,
+ 'ContextAttrAuditRequest_selectLogic').
+
+
+%% -- SelectLogic --
+
+is_opt_SelectLogic(asn1_NOVALUE) ->
+ true;
+is_opt_SelectLogic(SL) ->
+ is_SelectLogic(SL).
+
+is_SelectLogic({Tag, Val}) ->
+ d("is_SelectLogic -> entry"),
+ is_SelectLogic_tag(Tag) andalso is_SelectLogic_val(Tag, Val);
+is_SelectLogic(_) ->
+ false.
+
+is_SelectLogic_tag(Tag) ->
+ Tags = [andAUDITSelect, orAUDITSelect],
+ lists:member(Tag, Tags).
+
+is_SelectLogic_val(andAUDITSelect, 'NULL') -> true;
+is_SelectLogic_val(orAUDITSelect, 'NULL') -> true;
+is_SelectLogic_val(_, _) -> false.
+
+chk_opt_SelectLogic(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SelectLogic(SL1, SL2) ->
+ chk_SelectLogic(SL1, SL2).
+
+chk_SelectLogic(SL, SL) ->
+ chk_type(fun is_SelectLogic/1, 'SelectLogic', SL);
+chk_SelectLogic(asn1_NOVALUE, {andAUDITSelect, 'NULL'}) ->
+ ok; % AND is default
+chk_SelectLogic({andAUDITSelect, 'NULL'}, asn1_NOVALUE) ->
+ ok; % AND is default
+chk_SelectLogic({Tag, Val1} = SL1, {Tag, Val2} = SL2) ->
+ case (is_SelectLogic_tag(Tag) andalso
+ is_SelectLogic_val(Tag, Val1) andalso
+ is_SelectLogic_val(Tag, Val2)) of
+ true ->
+ chk_SelectLogic_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SelectLogic', SL1, SL2)
+ end;
+chk_SelectLogic({Tag1, Val1} = SL1, {Tag2, Val2} = SL2) ->
+ case ((is_SelectLogic_tag(Tag1) andalso
+ is_SelectLogic_val(Tag1, Val1)) andalso
+ (is_SelectLogic_tag(Tag2) andalso
+ is_SelectLogic_val(Tag2, Val2))) of
+ true ->
+ not_equal('SelectLogic', SL1, SL2);
+ false ->
+ wrong_type('SelectLogic', SL1, SL2)
+ end;
+chk_SelectLogic(SL1, SL2) ->
+ wrong_type('SelectLogic', SL1, SL2).
+
+chk_SelectLogic_val(andAUDITSelect, SL1, SL2) ->
+ validate(fun() -> chk_NULL(SL1, SL2) end, 'SelectLogic_andAUDITSelect');
+chk_SelectLogic_val(orAUDITSelect, SL1, SL2) ->
+ validate(fun() -> chk_NULL(SL1, SL2) end, 'SelectLogic_orAUDITSelect').
+
+
+%% -- CommandRequest --
+
+is_CommandRequest(#'CommandRequest'{command = Cmd,
+ optional = Opt,
+ wildcardReturn = WR}) ->
+ d("is_CommandRequest -> entry with"
+ "~n Cmd: ~p"
+ "~n Opt: ~p"
+ "~n WR: ~p", [Cmd, Opt, WR]),
+ is_Command(Cmd) andalso is_opt_NULL(Opt) andalso is_opt_NULL(WR);
+is_CommandRequest(_) ->
+ false.
+
+chk_CommandRequest(C, C) ->
+ chk_type(fun is_CommandRequest/1, 'CommandRequest', C);
+chk_CommandRequest(#'CommandRequest'{command = Cmd1,
+ optional = Opt1,
+ wildcardReturn = WR1},
+ #'CommandRequest'{command = Cmd2,
+ optional = Opt2,
+ wildcardReturn = WR2}) ->
+ validate(fun() -> chk_Command(Cmd1, Cmd2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(Opt1, Opt2) end, 'CommandRequest'),
+ validate(fun() -> chk_opt_NULL(WR1, WR2) end, 'CommandRequest'),
+ ok;
+chk_CommandRequest(R1, R2) ->
+ wrong_type('CommandRequest', R1, R2).
+
+
+%% -- Command --
+
+is_Command({Tag, Val}) ->
+ d("is_Command -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_Command_tag(Tag) andalso is_Command_val(Tag, Val);
+is_Command(_) ->
+ false.
+
+is_Command_tag(Tag) ->
+ Tags = [addReq, moveReq, modReq, subtractReq, auditCapRequest,
+ auditValueRequest, notifyReq, serviceChangeReq],
+ lists:member(Tag, Tags).
+
+is_Command_val(addReq, V) -> is_AmmRequest(V);
+is_Command_val(moveReq, V) -> is_AmmRequest(V);
+is_Command_val(modReq, V) -> is_AmmRequest(V);
+is_Command_val(subtractReq, V) -> is_SubtractRequest(V);
+is_Command_val(auditCapRequest, V) -> is_AuditRequest(V);
+is_Command_val(auditValueRequest, V) -> is_AuditRequest(V);
+is_Command_val(notifyReq, V) -> is_NotifyRequest(V);
+is_Command_val(serviceChangeReq, V) -> is_ServiceChangeRequest(V).
+
+chk_Command(Cmd, Cmd) ->
+ chk_type(fun is_Command/1, 'Command', Cmd);
+chk_Command({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_Command_tag(Tag) andalso
+ is_Command_val(Tag, Val1) andalso
+ is_Command_val(Tag, Val2)) of
+ true ->
+ chk_Command_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_Command_tag(Tag1) andalso is_Command_val(Tag1, Val1)) andalso
+ (is_Command_tag(Tag2) andalso is_Command_val(Tag2, Val2))) of
+ true ->
+ not_equal('Command', Cmd1, Cmd2);
+ false ->
+ wrong_type('Command', Cmd1, Cmd2)
+ end;
+chk_Command(Cmd1, Cmd2) ->
+ wrong_type('Command', Cmd1, Cmd2).
+
+
+chk_Command_val(addReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_addReq');
+chk_Command_val(moveReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_moveReq');
+chk_Command_val(modReq, R1, R2) ->
+ validate(fun() -> chk_AmmRequest(R1, R2) end, 'Command_modReq');
+chk_Command_val(subtractReq, R1, R2) ->
+ validate(fun() -> chk_SubtractRequest(R1, R2) end, 'Command_subtractReq');
+chk_Command_val(auditCapRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end, 'Command_auditCapRequest');
+chk_Command_val(auditValueRequest, R1, R2) ->
+ validate(fun() -> chk_AuditRequest(R1, R2) end,
+ 'Command_auditValueRequest');
+chk_Command_val(notifyReq, R1, R2) ->
+ validate(fun() -> chk_NotifyRequest(R1, R2) end, 'Command_notifyReq');
+chk_Command_val(serviceChangeReq, R1, R2) ->
+ validate(fun() -> chk_ServiceChangeRequest(R1, R2) end,
+ 'Command_serviceChangeReq').
+
+
+%% -- CommandReply --
+
+is_CommandReply({Tag, Val}) ->
+ d("is_CommandReply -> entry"),
+ is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val);
+is_CommandReply(_) ->
+ false.
+
+is_CommandReply_tag(Tag) ->
+ Tags = [addReply, moveReply, modReply, subtractReply,
+ auditCapReply, auditValueReply, notifyReply, serviceChangeReply],
+ lists:member(Tag, Tags).
+
+is_CommandReply_val(addReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(moveReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(modReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(subtractReply, V) -> is_AmmsReply(V);
+is_CommandReply_val(auditCapReply, V) -> is_AuditReply(V);
+is_CommandReply_val(auditValueReply, V) -> is_AuditReply(V);
+is_CommandReply_val(notifyReply, V) -> is_NotifyReply(V);
+is_CommandReply_val(serviceChangeReply, V) -> is_ServiceChangeReply(V).
+
+chk_CommandReply({Tag, Val} = Cmd, Cmd) ->
+ case (is_CommandReply_tag(Tag) andalso is_CommandReply_val(Tag, Val)) of
+ true ->
+ ok;
+ false ->
+ wrong_type('CommandReply', Cmd)
+ end;
+chk_CommandReply({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_CommandReply_tag(Tag) andalso
+ is_CommandReply_val(Tag, Val1) andalso
+ is_CommandReply_val(Tag, Val2)) of
+ true ->
+ chk_CommandReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_CommandReply_tag(Tag1) andalso
+ is_CommandReply_val(Tag1, Val1)) andalso
+ (is_CommandReply_tag(Tag2) andalso
+ is_CommandReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('CommandReply', Cmd1, Cmd2);
+ false ->
+ wrong_type('CommandReply', Cmd1, Cmd2)
+ end;
+chk_CommandReply(Cmd1, Cmd2) ->
+ wrong_type('CommandReply', Cmd1, Cmd2).
+
+chk_CommandReply_val(addReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_addReply');
+chk_CommandReply_val(moveReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_moveReply');
+chk_CommandReply_val(modReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_modReply');
+chk_CommandReply_val(subtractReply, V1, V2) ->
+ validate(fun() -> chk_AmmsReply(V1, V2) end, 'CommandReply_subtractReply');
+chk_CommandReply_val(auditCapReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditCapReply');
+chk_CommandReply_val(auditValueReply, V1, V2) ->
+ validate(fun() -> chk_AuditReply(V1, V2) end,
+ 'CommandReply_auditValueReply');
+chk_CommandReply_val(notifyReply, V1, V2) ->
+ validate(fun() -> chk_NotifyReply(V1, V2) end, 'CommandReply_notifyReply');
+chk_CommandReply_val(serviceChangeReply, V1, V2) ->
+ validate(fun() -> chk_ServiceChangeReply(V1, V2) end,
+ 'CommandReply_serviceChangeReply').
+
+
+%% -- TopologyRequest --
+
+is_TopologyRequest(#'TopologyRequest'{terminationFrom = F,
+ terminationTo = T,
+ topologyDirection = TD,
+ streamID = S,
+ topologyDirectionExtension = TDE}) ->
+ d("is_TopologyRequest -> entry"),
+ is_TerminationID(F) andalso
+ is_TerminationID(T) andalso
+ is_TopologyRequest_topologyDirection(TD) andalso
+ is_opt_StreamID(S) andalso
+ is_TopologyRequest_topologyDirectionExtension(TDE);
+is_TopologyRequest(_) ->
+ false.
+
+is_TopologyRequest_topologyDirection(D) ->
+ lists:member(D, [bothway, isolate, oneway]).
+
+is_TopologyRequest_topologyDirectionExtension(asn1_NOVALUE) ->
+ true;
+is_TopologyRequest_topologyDirectionExtension(D) ->
+ lists:member(D, [onewayexternal, onewayboth]).
+
+
+chk_TopologyRequest(T, T) when is_record(T,'TopologyRequest') ->
+ ok;
+chk_TopologyRequest(#'TopologyRequest'{terminationFrom = F1,
+ terminationTo = T1,
+ topologyDirection = TD1,
+ streamID = S1,
+ topologyDirectionExtension = TDE1},
+ #'TopologyRequest'{terminationFrom = F2,
+ terminationTo = T2,
+ topologyDirection = TD2,
+ streamID = S2,
+ topologyDirectionExtension = TDE2}) ->
+ validate(fun() -> chk_TerminationID(F1, F2) end,
+ 'TopologyRequest_terminationFrom'),
+ validate(fun() -> chk_TerminationID(T1, T2) end,
+ 'TopologyRequest_terminationTo'),
+ chk_TopologyRequest_topologyDirection(TD1, TD2),
+ validate(fun() -> chk_opt_StreamID(S1, S2) end,
+ 'TopologyRequest_streamID'),
+ chk_TopologyRequest_topologyDirectionExtension(TDE1, TDE2),
+ ok.
+
+chk_TopologyRequest_topologyDirection(D, D) ->
+ case is_TopologyRequest_topologyDirection(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D)
+ end;
+chk_TopologyRequest_topologyDirection(D1, D2) ->
+ case (is_TopologyRequest_topologyDirection(D1) andalso
+ is_TopologyRequest_topologyDirection(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirection', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirection', D1, D2)
+ end.
+
+chk_TopologyRequest_topologyDirectionExtension(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_TopologyRequest_topologyDirectionExtension(D, D) ->
+ case is_TopologyRequest_topologyDirectionExtension(D) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TopologyRequest_topologyDirectionExtension', D)
+ end;
+chk_TopologyRequest_topologyDirectionExtension(D1, D2) ->
+ case (is_TopologyRequest_topologyDirectionExtension(D1) andalso
+ is_TopologyRequest_topologyDirectionExtension(D1)) of
+ true ->
+ not_equal('TopologyRequest_topologyDirectionExtension', D1, D2);
+ false ->
+ wrong_type('TopologyRequest_topologyDirectionExtension', D1, D2)
+ end.
+
+
+%% -- AmmRequest --
+
+is_AmmRequest(#'AmmRequest'{terminationID = Tids,
+ descriptors = Descs}) ->
+ d("is_AmmRequest -> entry with"
+ "~n Tids: ~p", [Tids]),
+ is_TerminationIDList(Tids) andalso is_AmmRequest_descriptors(Descs);
+is_AmmRequest(_) ->
+ false.
+
+is_AmmRequest_descriptors(Descs) ->
+ d("is_AmmRequest_descriptors -> entry"),
+ is_AmmRequest_descriptors(Descs, []).
+
+is_AmmRequest_descriptors([], _) ->
+ true;
+is_AmmRequest_descriptors([{Tag, _} = Desc|Descs], FoundDescs) ->
+ d("is_AmmRequest_descriptors -> entry with"
+ "~n Tag: ~p"
+ "~n FoundDescs: ~p", [Tag, FoundDescs]),
+ case lists:member(Tag, FoundDescs) of
+ true ->
+ atmost_once('AmmRequest_descriptors', Tag);
+ false ->
+ case is_AmmDescriptor(Desc) of
+ true ->
+ is_AmmRequest_descriptors(Descs, [Tag|FoundDescs]);
+ false ->
+ wrong_type('AmmRequest_descriptors', Desc)
+ end
+ end;
+is_AmmRequest_descriptors(Descs, _) ->
+ d("is_AmmRequest_descriptors -> entry with WRONG TYPE"
+ "~n Descs: ~p", [Descs]),
+ wrong_type('AmmRequest_descriptors', Descs).
+
+
+chk_AmmRequest(R, R) when is_record(R, 'AmmRequest') ->
+ d("chk_AmmRequest -> entry when equal"),
+ chk_type(fun is_AmmRequest/1, 'AmmRequest', R);
+chk_AmmRequest(#'AmmRequest'{terminationID = Tids1,
+ descriptors = Descs1},
+ #'AmmRequest'{terminationID = Tids2,
+ descriptors = Descs2}) ->
+ d("chk_AmmRequest -> entry with not equal"
+ "~n Tids1: ~p"
+ "~n Tids2: ~p", [Tids1, Tids2]),
+ validate(
+ fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'AmmRequest'),
+ validate(
+ fun() -> chk_AmmRequest_descriptors(Descs1, Descs2) end,
+ 'AmmRequest'),
+ ok.
+
+
+chk_AmmRequest_descriptors([], []) ->
+ d("chk_AmmRequest_descriptors -> done when OK"),
+ ok;
+chk_AmmRequest_descriptors([] = Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors(Descs1, [] = Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when NOT EQUAL:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ not_equal('AmmRequest_descriptors', Descs1, Descs2);
+chk_AmmRequest_descriptors([H|T1], [H|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when equal"),
+ case is_AmmDescriptor(H) of
+ true ->
+ chk_AmmRequest_descriptors(T1, T2);
+ false ->
+ wrong_type('AmmRequest_descriptors_val', H)
+ end;
+chk_AmmRequest_descriptors([H1|T1], [H2|T2]) ->
+ d("chk_AmmRequest_descriptors -> entry when not equal"),
+ validate(fun() -> chk_AmmDescriptor(H1, H2) end,
+ 'AmmRequest_descriptors_val'),
+ chk_AmmRequest_descriptors(T1, T2);
+chk_AmmRequest_descriptors(Descs1, Descs2) ->
+ d("chk_AmmRequest_descriptors -> done when WRONG TYPE:"
+ "~n Descs1: ~p"
+ "~n Descs1: ~p", [Descs1, Descs2]),
+ wrong_type('AmmRequest_descriptors', Descs1, Descs2).
+
+
+%% -- AmmDescriptor --
+
+is_AmmDescriptor({Tag, Val}) ->
+ d("is_AmmDescriptor -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p",[Tag, Val]),
+ is_AmmDescriptor_tag(Tag) andalso is_AmmDescriptor_val(Tag, Val);
+is_AmmDescriptor(_) ->
+ false.
+
+is_AmmDescriptor_tag(Tag) ->
+ Tags = [mediaDescriptor, modemDescriptor, muxDescriptor, eventsDescriptor,
+ eventBufferDescriptor, signalsDescriptor, digitMapDescriptor,
+ auditDescriptor, statisticsDescriptor],
+ lists:member(Tag, Tags).
+
+is_AmmDescriptor_val(mediaDescriptor, D) ->
+ is_MediaDescriptor(D);
+is_AmmDescriptor_val(modemDescriptor, D) ->
+ is_ModemDescriptor(D);
+is_AmmDescriptor_val(muxDescriptor, D) ->
+ is_MuxDescriptor(D);
+is_AmmDescriptor_val(eventsDescriptor, D) ->
+ is_EventsDescriptor(D);
+is_AmmDescriptor_val(eventBufferDescriptor, D) ->
+ is_EventBufferDescriptor(D);
+is_AmmDescriptor_val(signalsDescriptor, D) ->
+ is_SignalsDescriptor(D);
+is_AmmDescriptor_val(digitMapDescriptor, D) ->
+ is_DigitMapDescriptor(D);
+is_AmmDescriptor_val(auditDescriptor, D) ->
+ is_AuditDescriptor(D);
+is_AmmDescriptor_val(statisticsDescriptor, D) ->
+ is_StatisticsDescriptor(D).
+
+chk_AmmDescriptor(D, D) ->
+ chk_type(fun is_AmmDescriptor_tag/1, 'AmmDescriptor', D);
+chk_AmmDescriptor({Tag, Val1} = Cmd1, {Tag, Val2} = Cmd2) ->
+ case (is_AmmDescriptor_tag(Tag) andalso
+ is_AmmDescriptor_val(Tag, Val1) andalso
+ is_AmmDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_AmmDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor({Tag1, Val1} = Cmd1, {Tag2, Val2} = Cmd2) ->
+ case ((is_AmmDescriptor_tag(Tag1) andalso
+ is_AmmDescriptor_val(Tag1, Val1)) andalso
+ (is_AmmDescriptor_tag(Tag2) andalso
+ is_AmmDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('AmmDescriptor', Cmd1, Cmd2);
+ false ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2)
+ end;
+chk_AmmDescriptor(Cmd1, Cmd2) ->
+ wrong_type('AmmDescriptor', Cmd1, Cmd2).
+
+chk_AmmDescriptor_val(mediaDescriptor, D1, D2) ->
+ validate(fun() -> chk_MediaDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(modemDescriptor, D1, D2) ->
+ validate(fun() -> chk_ModemDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(muxDescriptor, D1, D2) ->
+ validate(fun() -> chk_MuxDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventsDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(eventBufferDescriptor, D1, D2) ->
+ validate(fun() -> chk_EventBufferDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(signalsDescriptor, D1, D2) ->
+ validate(fun() -> chk_SignalsDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(digitMapDescriptor, D1, D2) ->
+ validate(fun() -> chk_DigitMapDescriptor(D1, D2) end, 'AmmDescriptor');
+chk_AmmDescriptor_val(auditDescriptor, D1, D2) ->
+ validate(fun() -> chk_AuditDescriptor(D1, D2) end, 'AmmDescriptor').
+
+
+%% -- AmmsReply --
+
+is_AmmsReply(#'AmmsReply'{terminationID = Tids,
+ terminationAudit = TA}) ->
+ is_TerminationIDList(Tids) andalso is_opt_TerminationAudit(TA);
+is_AmmsReply(_) ->
+ false.
+
+chk_AmmsReply(R, R) ->
+ is_AmmsReply(R);
+chk_AmmsReply(#'AmmsReply'{terminationID = TID1,
+ terminationAudit = TA1},
+ #'AmmsReply'{terminationID = TID2,
+ terminationAudit = TA2}) ->
+ validate(fun() -> chk_TerminationIDList(TID1, TID2) end, 'AmmsReply'),
+ validate(fun() -> chk_opt_TerminationAudit(TA1, TA2) end, 'AmmsReply'),
+ ok;
+chk_AmmsReply(R1, R2) ->
+ wrong_type('AmmsReply', R1, R2).
+
+
+%% -- SubtractRequest --
+
+is_SubtractRequest(#'SubtractRequest'{terminationID = TID,
+ auditDescriptor = AD}) ->
+ d("is_SubtractDescriptor -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p",[TID, AD]),
+ is_TerminationIDList(TID) andalso is_opt_AuditDescriptor(AD);
+is_SubtractRequest(_) ->
+ false.
+
+chk_SubtractRequest(R, R) ->
+ chk_type(fun is_SubtractRequest/1, 'SubtractRequest', R);
+chk_SubtractRequest(#'SubtractRequest'{terminationID = Tids1,
+ auditDescriptor = AD1},
+ #'SubtractRequest'{terminationID = Tids2,
+ auditDescriptor = AD2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'SubtractRequest'),
+ validate(fun() -> chk_opt_AuditDescriptor(AD1, AD2) end,
+ 'SubtractRequest'),
+ ok;
+chk_SubtractRequest(SR1, SR2) ->
+ wrong_type('SubtractRequest', SR1, SR2).
+
+
+%% -- AuditRequest --
+
+is_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = asn1_NOVALUE}) ->
+ d("is_AuditRequest -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p",[TID, AD]),
+ is_TerminationID(TID) andalso
+ is_AuditDescriptor(AD);
+is_AuditRequest(#'AuditRequest'{terminationID = TID,
+ auditDescriptor = AD,
+ terminationIDList = [TID|_] = TIDs}) ->
+ d("is_AuditRequest -> entry with"
+ "~n TID: ~p"
+ "~n AD: ~p"
+ "~n TIDs: ~p",[TID, AD, TIDs]),
+ is_TerminationID(TID) andalso
+ is_AuditDescriptor(AD) andalso
+ is_TerminationIDList(TIDs);
+is_AuditRequest(_) ->
+ false.
+
+chk_AuditRequest(R, R) ->
+ chk_type(fun is_AuditRequest/1, 'AuditRequest', R);
+chk_AuditRequest(#'AuditRequest'{terminationID = TID1,
+ auditDescriptor = AD1,
+ terminationIDList = [TID1|_] = TIDs1},
+ #'AuditRequest'{terminationID = TID2,
+ auditDescriptor = AD2,
+ terminationIDList = [TID2|_] = TIDs2}) ->
+ validate(fun() -> chk_TerminationID(TID1, TID2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_AuditDescriptor(AD1, AD2) end,
+ 'AuditRequest'),
+ validate(fun() -> chk_opt_TerminationIDList(TIDs1, TIDs2) end,
+ 'AuditRequest'),
+ ok;
+chk_AuditRequest(AR1, AR2) ->
+ wrong_type('AuditRequest', AR1, AR2).
+
+
+%% -- AuditReply --
+
+is_AuditReply({Tag, Val}) ->
+ is_AuditReply_tag(Tag) andalso is_AuditReply_val(Tag, Val);
+is_AuditReply(_) ->
+ false.
+
+is_AuditReply_tag(Tag) ->
+ Tags = [contextAuditResult, error, auditResult, auditResultTermList],
+ lists:member(Tag, Tags).
+
+is_AuditReply_val(contextAuditResult, Val) ->
+ is_TerminationIDList(Val);
+is_AuditReply_val(error, Val) ->
+ is_ErrorDescriptor(Val);
+is_AuditReply_val(auditResult, Val) ->
+ is_AuditResult(Val);
+is_AuditReply_val(auditResultTermList, Val) ->
+ is_TermListAuditResult(Val).
+
+chk_AuditReply(R, R) ->
+ chk_type(fun is_AuditReply/1, 'AuditReply', R);
+chk_AuditReply({Tag, Val1} = R1, {Tag, Val2} = R2) ->
+ case (is_AuditReply_tag(Tag) andalso
+ is_AuditReply_val(Tag, Val1)andalso
+ is_AuditReply_val(Tag, Val2)) of
+ true ->
+ chk_AuditReply_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply({Tag1, Val1} = R1, {Tag2, Val2} = R2) ->
+ case ((is_AuditReply_tag(Tag1) andalso
+ is_AuditReply_val(Tag1, Val1)) andalso
+ (is_AuditReply_tag(Tag2) andalso
+ is_AuditReply_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReply', R1, R2);
+ false ->
+ wrong_type('AuditReply', R1, R2)
+ end;
+chk_AuditReply(AR1, AR2) ->
+ wrong_type('AuditReply', AR1, AR2).
+
+chk_AuditReply_val(contextAuditResult, Val1, Val2) ->
+ chk_TerminationIDList(Val1, Val2);
+chk_AuditReply_val(error, Val1, Val2) ->
+ chk_ErrorDescriptor(Val1, Val2);
+chk_AuditReply_val(auditResult, Val1, Val2) ->
+ chk_AuditResult(Val1, Val2);
+chk_AuditReply_val(auditResultTermList, Val1, Val2) ->
+ chk_TermListAuditResult(Val1, Val2).
+
+
+%% -- AuditResult --
+
+is_AuditResult(#'AuditResult'{terminationID = TID,
+ terminationAuditResult = TAR}) ->
+ is_TerminationID(TID) andalso is_TerminationAudit(TAR);
+is_AuditResult(_) ->
+ false.
+
+chk_AuditResult(R, R) ->
+ d("chk_AuditResult -> entry (1)"),
+ chk_type(fun is_AuditResult/1, 'AuditResult', R);
+chk_AuditResult(#'AuditResult'{terminationID = TID1,
+ terminationAuditResult = TAR1},
+ #'AuditResult'{terminationID = TID2,
+ terminationAuditResult = TAR2}) ->
+ d("chk_AuditResult -> entry (2)"),
+ validate(fun() -> chk_TerminationID(TID1, TID2) end, 'AuditResult'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end, 'AuditResult'),
+ ok;
+chk_AuditResult(AR1, AR2) ->
+ d("chk_AuditResult -> entry (3)"),
+ wrong_type('AuditResult', AR1, AR2).
+
+
+%% -- TermListAuditResult --
+
+is_TermListAuditResult(#'TermListAuditResult'{terminationIDList = TIDs,
+ terminationAuditResult = TAR}) ->
+ is_TerminationIDList(TIDs) andalso is_TerminationAudit(TAR);
+is_TermListAuditResult(_) ->
+ false.
+
+chk_TermListAuditResult(TLAR, TLAR) ->
+ d("chk_TermListAuditResult(1) -> entry with"
+ "~n TLAR: ~p", [TLAR]),
+ chk_type(fun is_TermListAuditResult/1, 'TermListAuditResult', TLAR);
+chk_TermListAuditResult(
+ #'TermListAuditResult'{terminationIDList = TIDs1,
+ terminationAuditResult = TAR1},
+ #'TermListAuditResult'{terminationIDList = TIDs2,
+ terminationAuditResult = TAR2}) ->
+ d("chk_TermListAuditResult(2) -> entry with"
+ "~n TIDs1: ~p"
+ "~n TAR1: ~p"
+ "~n TIDs2: ~p"
+ "~n TAR2: ~p", [TIDs1, TAR1, TIDs2, TAR2]),
+ validate(fun() -> chk_TerminationIDList(TIDs1, TIDs2) end,
+ 'TermListAuditResult_terminationIDList'),
+ validate(fun() -> chk_TerminationAudit(TAR1, TAR2) end,
+ 'TermListAuditResult_terminationAuditResult'),
+ ok;
+chk_TermListAuditResult(TLAR1, TLAR2) ->
+ d("chk_TermListAuditResult(3) -> entry with"
+ "~n TLAR1: ~p"
+ "~n TLAR2: ~p", [TLAR1, TLAR2]),
+ wrong_type('TermListAuditResult', TLAR1, TLAR2).
+
+
+%% -- TerminationAudit --
+
+is_opt_TerminationAudit(TA) ->
+ is_OPTIONAL(fun is_TerminationAudit/1, TA).
+
+is_TerminationAudit([]) ->
+ true;
+is_TerminationAudit([H|T]) ->
+ is_AuditReturnParameter(H) andalso is_TerminationAudit(T);
+is_TerminationAudit(_) ->
+ false.
+
+chk_opt_TerminationAudit(TA1, TA2) ->
+ d("chk_opt_TerminationAudit -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ chk_OPTIONAL('TerminationAudit',
+ strip_TerminationAudit(TA1),
+ strip_TerminationAudit(TA2),
+ fun is_TerminationAudit/1, fun chk_TerminationAudit/2).
+
+strip_TerminationAudit(L) when is_list(L) ->
+ d("strip_TerminationAudit(1) -> entry with"
+ "~n L: ~p", [L]),
+ %% Drop all empty emptyDescriptor's
+ F = fun({emptyDescriptors, AD}) ->
+ case AD of
+ #'AuditDescriptor'{auditToken = asn1_NOVALUE,
+ auditPropertyToken = asn1_NOVALUE} ->
+ true;
+ _ ->
+ false
+ end;
+ (_) ->
+ false
+ end,
+ lists:dropwhile(F, L);
+strip_TerminationAudit(asn1_NOVALUE) ->
+ d("strip_TerminationAudit(2) -> entry"),
+ [];
+strip_TerminationAudit(X) ->
+ d("strip_TerminationAudit(3) -> entry with"
+ "~n X: ~p", [X]),
+ X.
+
+chk_TerminationAudit(TA1, TA2) ->
+ d("chk_TerminationAudit -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ do_chk_TerminationAudit(strip_TerminationAudit(TA1),
+ strip_TerminationAudit(TA2)).
+
+do_chk_TerminationAudit([], []) ->
+ d("do_chk_TerminationAudit(1) -> entry"),
+ ok;
+do_chk_TerminationAudit([], asn1_NOVALUE) ->
+ d("do_chk_TerminationAudit(2) -> entry"),
+ ok;
+do_chk_TerminationAudit(asn1_NOVALUE, []) ->
+ d("do_chk_TerminationAudit(3) -> entry"),
+ ok;
+do_chk_TerminationAudit([] = TA1, TA2) ->
+ d("do_chk_TerminationAudit(4) -> entry with"
+ "~n TA2: ~p", [TA2]),
+ not_equal('TerminationAudit', TA1, TA2);
+do_chk_TerminationAudit(TA1, [] = TA2) ->
+ d("do_chk_TerminationAudit(5) -> entry with"
+ "~n TA1: ~p", [TA1]),
+ not_equal('TerminationAudit', TA1, TA2);
+do_chk_TerminationAudit([H|T1], [H|T2]) ->
+ d("do_chk_TerminationAudit(6) -> entry with"
+ "~n H: ~p", [H]),
+ case is_AuditReturnParameter(H) of
+ true ->
+ do_chk_TerminationAudit(T1, T2);
+ false ->
+ wrong_type('TerminationAudit', H)
+ end;
+do_chk_TerminationAudit([H1|T1], [H2|T2]) ->
+ d("do_chk_TerminationAudit(7) -> entry with"
+ "~n H1: ~p"
+ "~n H2: ~p", [H1, H2]),
+ chk_AuditReturnParameter(H1, H2),
+ do_chk_TerminationAudit(T1, T2);
+do_chk_TerminationAudit(TA1, TA2) ->
+ d("do_chk_TerminationAudit(8) -> entry with"
+ "~n TA1: ~p"
+ "~n TA2: ~p", [TA1, TA2]),
+ not_equal('TerminationAudit', TA1, TA2).
+
+
+%% -- AuditReturnParameter --
+
+is_AuditReturnParameter({Tag, Val}) ->
+ is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val);
+is_AuditReturnParameter(_) ->
+ false.
+
+is_AuditReturnParameter_tag(Tag) ->
+ Tags = [errorDescriptor,
+ mediaDescriptor,
+ modemDescriptor,
+ muxDescriptor,
+ eventsDescriptor,
+ eventBufferDescriptor,
+ signalsDescriptor,
+ digitMapDescriptor,
+ observedEventsDescriptor,
+ statisticsDescriptor,
+ packagesDescriptor,
+ emptyDescriptors],
+ lists:member(Tag, Tags).
+
+is_AuditReturnParameter_val(errorDescriptor, V) ->
+ is_ErrorDescriptor(V);
+is_AuditReturnParameter_val(mediaDescriptor, V) ->
+ is_MediaDescriptor(V);
+is_AuditReturnParameter_val(modemDescriptor, V) ->
+ is_ModemDescriptor(V);
+is_AuditReturnParameter_val(muxDescriptor, V) ->
+ is_MuxDescriptor(V);
+is_AuditReturnParameter_val(eventsDescriptor, V) ->
+ is_EventsDescriptor(V);
+is_AuditReturnParameter_val(eventBufferDescriptor, V) ->
+ is_EventBufferDescriptor(V);
+is_AuditReturnParameter_val(signalsDescriptor, V) ->
+ is_SignalsDescriptor(V);
+is_AuditReturnParameter_val(digitMapDescriptor, V) ->
+ is_DigitMapDescriptor(V);
+is_AuditReturnParameter_val(observedEventsDescriptor, V) ->
+ is_ObservedEventsDescriptor(V);
+is_AuditReturnParameter_val(statisticsDescriptor, V) ->
+ is_StatisticsDescriptor(V);
+is_AuditReturnParameter_val(packagesDescriptor, V) ->
+ is_PackagesDescriptor(V);
+is_AuditReturnParameter_val(emptyDescriptors, V) ->
+ is_AuditDescriptor(V).
+
+chk_AuditReturnParameter(ARP, ARP) ->
+ chk_type(fun is_AuditReturnParameter/1, 'AuditReturnParameter', ARP);
+chk_AuditReturnParameter({Tag, Val1} = ARP1, {Tag, Val2} = ARP2) ->
+ case (is_AuditReturnParameter_tag(Tag) andalso
+ is_AuditReturnParameter_val(Tag, Val1) andalso
+ is_AuditReturnParameter_val(Tag, Val2)) of
+ true ->
+ chk_AuditReturnParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter({Tag1, Val1} = ARP1, {Tag2, Val2} = ARP2) ->
+ case ((is_AuditReturnParameter_tag(Tag1) andalso
+ is_AuditReturnParameter_val(Tag1, Val1)) andalso
+ (is_AuditReturnParameter_tag(Tag2) andalso
+ is_AuditReturnParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('AuditReturnParameter', ARP1, ARP2);
+ false ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2)
+ end;
+chk_AuditReturnParameter(ARP1, ARP2) ->
+ wrong_type('AuditReturnParameter', ARP1, ARP2).
+
+chk_AuditReturnParameter_val(errorDescriptor, V1, V2) ->
+ validate(fun() -> chk_ErrorDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(mediaDescriptor, V1, V2) ->
+ validate(fun() -> chk_MediaDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(modemDescriptor, V1, V2) ->
+ validate(fun() -> chk_ModemDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(muxDescriptor, V1, V2) ->
+ validate(fun() -> chk_MuxDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(eventBufferDescriptor, V1, V2) ->
+ validate(fun() -> chk_EventBufferDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(signalsDescriptor, V1, V2) ->
+ validate(fun() -> chk_SignalsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(digitMapDescriptor, V1, V2) ->
+ validate(fun() -> chk_DigitMapDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(observedEventsDescriptor, V1, V2) ->
+ validate(fun() -> chk_ObservedEventsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(statisticsDescriptor, V1, V2) ->
+ validate(fun() -> chk_StatisticsDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(packagesDescriptor, V1, V2) ->
+ validate(fun() -> chk_PackagesDescriptor(V1, V2) end,
+ 'AuditReturnParameter');
+chk_AuditReturnParameter_val(emptyDescriptors, V1, V2) ->
+ validate(fun() -> chk_AuditDescriptor(V1, V2) end,
+ 'AuditReturnParameter').
+
+
+%% -- AuditDescriptor --
+
+is_opt_AuditDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_AuditDescriptor(V) ->
+ is_AuditDescriptor(V).
+
+is_AuditDescriptor(#'AuditDescriptor'{auditToken = AT,
+ auditPropertyToken = APT}) ->
+ d("is_AuditDescriptor -> entry with"
+ "~n AT: ~p"
+ "~n APT: ~p", [AT, APT]),
+ is_AuditDescriptor_auditToken(AT) andalso
+ is_AuditDescriptor_auditPropertyToken(APT);
+is_AuditDescriptor(_) ->
+ false.
+
+is_AuditDescriptor_auditToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditToken([]) ->
+ true;
+is_AuditDescriptor_auditToken([H|T]) ->
+ is_AuditDescriptor_auditToken_val(H) andalso
+ is_AuditDescriptor_auditToken(T);
+is_AuditDescriptor_auditToken(_) ->
+ false.
+
+is_AuditDescriptor_auditToken_val(V) ->
+ Toks = [muxToken, modemToken, mediaToken, eventsToken, signalsToken,
+ digitMapToken, statsToken, observedEventsToken,
+ packagesToken, eventBufferToken],
+ lists:member(V, Toks).
+
+is_AuditDescriptor_auditPropertyToken(asn1_NOVALUE) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([]) ->
+ true;
+is_AuditDescriptor_auditPropertyToken([H|T]) ->
+ d("is_AuditDescriptor_auditPropertyToken -> entry with"
+ "~n H: ~p", [H]),
+ is_IndAuditParameter(H) andalso is_AuditDescriptor_auditPropertyToken(T);
+is_AuditDescriptor_auditPropertyToken(_) ->
+ false.
+
+chk_opt_AuditDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_AuditDescriptor(AD1, AD2) ->
+ chk_AuditDescriptor(AD1, AD2).
+
+chk_AuditDescriptor(AD, AD) ->
+ chk_type(fun is_AuditDescriptor/1, 'AuditDescriptor', AD);
+chk_AuditDescriptor(#'AuditDescriptor'{auditToken = AT1,
+ auditPropertyToken = APT1},
+ #'AuditDescriptor'{auditToken = AT2,
+ auditPropertyToken = APT2}) ->
+ chk_AuditDescriptor_auditToken(maybe_sort(AT1), maybe_sort(AT2)),
+ chk_AuditDescriptor_auditPropertyToken(APT1, APT2),
+ ok;
+chk_AuditDescriptor(AD1, AD2) ->
+ wrong_type('AuditDescriptor', AD1, AD2).
+
+chk_AuditDescriptor_auditToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditToken', AT1, AT2);
+chk_AuditDescriptor_auditToken([H|T1], [H|T2]) ->
+ case is_AuditDescriptor_auditToken_val(H) of
+ true ->
+ chk_AuditDescriptor_auditToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H)
+ end;
+chk_AuditDescriptor_auditToken([H1|_T1], [H2|_T2]) ->
+ case (is_AuditDescriptor_auditToken_val(H1) andalso
+ is_AuditDescriptor_auditToken_val(H2)) of
+ true ->
+ not_equal('AuditDescriptor_auditToken_val', H1, H2);
+ false ->
+ wrong_type('AuditDescriptor_auditToken_val', H1, H2)
+ end;
+chk_AuditDescriptor_auditToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditToken', AT1, AT2).
+
+chk_AuditDescriptor_auditPropertyToken(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([], []) ->
+ ok;
+chk_AuditDescriptor_auditPropertyToken([] = AT1, AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken(AT1, [] = AT2) ->
+ not_equal('AuditDescriptor_auditPropertyToken', AT1, AT2);
+chk_AuditDescriptor_auditPropertyToken([H|T1], [H|T2]) ->
+ case is_IndAuditParameter(H) of
+ true ->
+ chk_AuditDescriptor_auditPropertyToken(T1, T2);
+ false ->
+ wrong_type('AuditDescriptor_auditPropertyToken_val', H)
+ end;
+chk_AuditDescriptor_auditPropertyToken([H1|_], [H2|_]) ->
+ chk_IndAuditParameter(H1, H2),
+ not_equal('AuditDescriptor_auditPropertyToken_val', H1, H2);
+chk_AuditDescriptor_auditPropertyToken(AT1, AT2) ->
+ wrong_type('AuditDescriptor_auditPropertyToken', AT1, AT2).
+
+
+%% -- IndAuditParameter --
+
+is_IndAuditParameter({Tag, Val}) ->
+ is_IndAuditParameter_tag(Tag) andalso is_IndAuditParameter_val(Tag, Val);
+is_IndAuditParameter(_) ->
+ false.
+
+is_IndAuditParameter_tag(Tag) ->
+ Tags = [indAudMediaDescriptor,
+ indAudEventsDescriptor,
+ indAudEventBufferDescriptor,
+ indAudSignalsDescriptor,
+ indAudDigitMapDescriptor,
+ indAudStatisticsDescriptor,
+ indAudPackagesDescriptor],
+ lists:member(Tag, Tags).
+
+is_IndAuditParameter_val(indAudMediaDescriptor, Val) ->
+ is_IndAudMediaDescriptor(Val);
+is_IndAuditParameter_val(indAudEventsDescriptor, Val) ->
+ is_IndAudEventsDescriptor(Val);
+is_IndAuditParameter_val(indAudEventBufferDescriptor, Val) ->
+ is_IndAudEventBufferDescriptor(Val);
+is_IndAuditParameter_val(indAudSignalsDescriptor, Val) ->
+ is_IndAudSignalsDescriptor(Val);
+is_IndAuditParameter_val(indAudDigitMapDescriptor, Val) ->
+ is_IndAudDigitMapDescriptor(Val);
+is_IndAuditParameter_val(indAudStatisticsDescriptor, Val) ->
+ is_IndAudStatisticsDescriptor(Val);
+is_IndAuditParameter_val(indAudPackagesDescriptor, Val) ->
+ is_IndAudPackagesDescriptor(Val).
+
+chk_IndAuditParameter(IAP, IAP) ->
+ chk_type(fun is_IndAuditParameter/1, 'IndAuditParameter', IAP);
+chk_IndAuditParameter({Tag, Val1} = IAP1, {Tag, Val2} = IAP2) ->
+ case (is_IndAuditParameter_tag(Tag) andalso
+ is_IndAuditParameter_val(Tag, Val1) andalso
+ is_IndAuditParameter_val(Tag, Val2)) of
+ true ->
+ chk_IndAuditParameter_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter({Tag1, Val1} = IAP1, {Tag2, Val2} = IAP2) ->
+ case ((is_IndAuditParameter_tag(Tag1) andalso
+ is_IndAuditParameter_val(Tag1, Val1)) andalso
+ (is_IndAuditParameter_tag(Tag2) andalso
+ is_IndAuditParameter_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAuditParameter', IAP1, IAP2);
+ false ->
+ wrong_type('IndAuditParameter', IAP1, IAP2)
+ end;
+chk_IndAuditParameter(IAP1, IAP2) ->
+ wrong_type('IndAuditParameter', IAP1, IAP2).
+
+chk_IndAuditParameter_val(indAudMediaDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudEventBufferDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudEventBufferDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudSignalsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudSignalsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudDigitMapDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudDigitMapDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudStatisticsDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStatisticsDescriptor(Val1, Val2) end,
+ 'IndAuditParameter');
+chk_IndAuditParameter_val(indAudPackagesDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_IndAudPackagesDescriptor(Val1, Val2) end,
+ 'IndAuditParameter').
+
+
+%% -- IndAudMediaDescriptor --
+
+is_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_IndAudMediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_IndAudTerminationStateDescriptor(TSD) andalso
+ is_IndAudMediaDescriptor_streams(S);
+is_IndAudMediaDescriptor(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_IndAudMediaDescriptor_streams({Tag, Val}) ->
+ d("is_IndAudMediaDescriptor_streams -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val);
+is_IndAudMediaDescriptor_streams(_) ->
+ false.
+
+is_IndAudMediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_IndAudMediaDescriptor_streams_val(oneStream, Val) ->
+ d("is_IndAudMediaDescriptor_streams_val(oneStream) -> entry with"
+ "~n Val: ~p", [Val]),
+ is_IndAudStreamParms(Val);
+is_IndAudMediaDescriptor_streams_val(multiStream, Val) ->
+ d("is_IndAudMediaDescriptor_streams_val(multiStream) -> entry with"
+ "~n Val: ~p", [Val]),
+ is_IndAudMediaDescriptor_multiStream(Val).
+
+is_IndAudMediaDescriptor_multiStream([]) ->
+ true;
+is_IndAudMediaDescriptor_multiStream([H|T]) ->
+ d("is_IndAudMediaDescriptor_multiStream -> entry with"
+ "~n H: ~p", [H]),
+ is_IndAudStreamDescriptor(H) andalso
+ is_IndAudMediaDescriptor_multiStream(T);
+is_IndAudMediaDescriptor_multiStream(_) ->
+ false.
+
+chk_IndAudMediaDescriptor(IAMD, IAMD) ->
+ chk_type(fun is_IndAudMediaDescriptor/1, 'IndAudMediaDescriptor', IAMD);
+chk_IndAudMediaDescriptor(#'IndAudMediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'IndAudMediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(fun() -> chk_opt_IndAudTerminationStateDescriptor(TSD1, TSD2) end,
+ 'IndAudMediaDescriptor'),
+ validate(fun() -> chk_IndAudMediaDescriptor_streams(S1, S2) end,
+ 'IndAudMediaDescriptor'),
+ ok;
+chk_IndAudMediaDescriptor(IAMD1, IAMD2) ->
+ wrong_type('IndAudMediaDescriptor', IAMD1, IAMD2).
+
+chk_IndAudMediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudMediaDescriptor_streams({Tag, Val1} = S1,
+ {Tag, Val2} = S2) ->
+ case (is_IndAudMediaDescriptor_streams_tag(Tag) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag, Val2)) of
+ true ->
+ chk_IndAudMediaDescriptor_streams_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams({Tag1, Val1} = S1,
+ {Tag2, Val2} = S2) ->
+ case ((is_IndAudMediaDescriptor_streams_tag(Tag1) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag1, Val1)) andalso
+ (is_IndAudMediaDescriptor_streams_tag(Tag2) andalso
+ is_IndAudMediaDescriptor_streams_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudMediaDescriptor_streams', S1, S2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2)
+ end;
+chk_IndAudMediaDescriptor_streams(S1, S2) ->
+ wrong_type('IndAudMediaDescriptor_streams', S1, S2).
+
+chk_IndAudMediaDescriptor_streams_val(oneStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudStreamParms(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams');
+chk_IndAudMediaDescriptor_streams_val(multiStream, Val1, Val2) ->
+ validate(fun() -> chk_IndAudMediaDescriptor_multiStream(Val1, Val2) end,
+ 'IndAudMediaDescriptor_streams').
+
+chk_IndAudMediaDescriptor_multiStream([], []) ->
+ ok;
+chk_IndAudMediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('IndAudMediaDescriptor_multiStream', MS1, MS2);
+chk_IndAudMediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_IndAudStreamDescriptor(H) of
+ true ->
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('IndAudMediaDescriptor_multiStream_val', H)
+ end;
+chk_IndAudMediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudStreamDescriptor(H1, H2) end,
+ 'IndAudMediaDescriptor_multiStream_val'),
+ chk_IndAudMediaDescriptor_multiStream(T1, T2);
+chk_IndAudMediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('IndAudMediaDescriptor_multiStream', MS1, MS2).
+
+
+%% -- IndAudStreamDescriptor --
+
+is_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_IndAudStreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_IndAudStreamParms(Parms);
+is_IndAudStreamDescriptor(_) ->
+ false.
+
+chk_IndAudStreamDescriptor(D, D) ->
+ chk_type(fun is_IndAudStreamDescriptor/1, 'IndAudStreamDescriptor', D);
+chk_IndAudStreamDescriptor(#'IndAudStreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'IndAudStreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'IndAudStreamDescriptor'),
+ validate(fun() -> chk_IndAudStreamParms(Parms1, Parms2) end,
+ 'IndAudStreamDescriptor'),
+ ok;
+chk_IndAudStreamDescriptor(D1, D2) ->
+ wrong_type('IndAudStreamDescriptor', D1, D2).
+
+
+%% -- IndAudStreamParms --
+
+is_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD}) ->
+ d("is_IndAudStreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p", [LCD, LD, RD]),
+ is_opt_IndAudLocalControlDescriptor(LCD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(LD) andalso
+ is_opt_IndAudLocalRemoteDescriptor(RD);
+is_IndAudStreamParms(_) ->
+ false.
+
+chk_IndAudStreamParms(#'IndAudStreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1},
+ #'IndAudStreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2}) ->
+ validate(fun() -> chk_opt_IndAudLocalControlDescriptor(LCD1, LCD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(LD1, LD2) end,
+ 'IndAudStreamParms'),
+ validate(fun() -> chk_opt_IndAudLocalRemoteDescriptor(RD1, RD2) end,
+ 'IndAudStreamParms'),
+ ok;
+chk_IndAudStreamParms(D1, D2) ->
+ wrong_type('IndAudStreamParms', D1, D2).
+
+
+%% -- IndAudLocalControlDescriptor --
+
+is_opt_IndAudLocalControlDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalControlDescriptor(D) ->
+ is_IndAudLocalControlDescriptor(D).
+
+is_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PPs,
+ streamModeSel = SMS}) ->
+ d("is_IndAudLocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PPs: ~p"
+ "~n SMS: ~p", [SM, RV, RG, PPs, SMS]),
+ is_opt_NULL(SM) andalso
+ is_opt_NULL(RV) andalso
+ is_opt_NULL(RG) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(PPs) andalso
+ is_opt_StreamMode(SMS);
+is_IndAudLocalControlDescriptor(_) ->
+ false.
+
+is_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([]) ->
+ true;
+is_IndAudLocalControlDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudLocalControlDescriptor_propertyParms(T);
+is_IndAudLocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudLocalControlDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalControlDescriptor(
+ #'IndAudLocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PPs1,
+ streamModeSel = SMS1},
+ #'IndAudLocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PPs2,
+ streamModeSel = SMS2}) ->
+ chk_IndAudLocalControlDescriptor_streamMode(SM1, SM2),
+ chk_IndAudLocalControlDescriptor_reserveValue(RV1, RV2),
+ chk_IndAudLocalControlDescriptor_reserveGroup(RG1, RG2),
+ chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2),
+ chk_IndAudLocalControlDescriptor_streamModeSel(SMS1, SMS2),
+ ok;
+chk_opt_IndAudLocalControlDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalControlDescriptor', D1, D2).
+
+chk_IndAudLocalControlDescriptor_streamMode(SM1, SM2) ->
+ validate(fun() -> chk_opt_NULL(SM1, SM2) end,
+ 'IndAudLocalControlDescriptor_streamMode').
+
+chk_IndAudLocalControlDescriptor_reserveValue(RV1, RV2) ->
+ validate(fun() -> chk_opt_NULL(RV1, RV2) end,
+ 'IndAudLocalControlDescriptor_reserveValue').
+
+chk_IndAudLocalControlDescriptor_reserveGroup(RG1, RG2) ->
+ validate(fun() -> chk_opt_NULL(RG1, RG2) end,
+ 'IndAudLocalControlDescriptor_reserveGroup').
+
+chk_IndAudLocalControlDescriptor_propertyParms(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudLocalControlDescriptor_propertyParms([] = PPs1, PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, [] = PPs2) ->
+ not_equal('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2);
+chk_IndAudLocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_IndAudLocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudLocalControlDescriptor_propertyParms_val'),
+ chk_IndAudLocalControlDescriptor_propertyParms(T1, T2);
+chk_IndAudLocalControlDescriptor_propertyParms(PPs1, PPs2) ->
+ wrong_type('IndAudLocalControlDescriptor_propertyParms', PPs1, PPs2).
+
+chk_IndAudLocalControlDescriptor_streamModeSel(SMS1, SMS2) ->
+ validate(fun() -> chk_opt_StreamMode(SMS1, SMS2) end,
+ 'IndAudLocalControlDescriptor_streamModeSel').
+
+
+%% -- IndAudPropertyParm --
+
+is_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name,
+ propertyParms = PP}) ->
+ d("is_IndAudPropertyParm -> entry"),
+ is_PkgdName(Name) andalso is_opt_PropertyParm(PP);
+is_IndAudPropertyParm(_) ->
+ false.
+
+chk_IndAudPropertyParm(#'IndAudPropertyParm'{name = Name1,
+ propertyParms = PP1},
+ #'IndAudPropertyParm'{name = Name2,
+ propertyParms = PP2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end, 'IndAudPropertyParm'),
+ validate(fun() -> chk_opt_PropertyParm(PP1, PP2) end,
+ 'IndAudPropertyParm'),
+ ok;
+chk_IndAudPropertyParm(P1, P2) ->
+ wrong_type('IndAudPropertyParm', P1, P2).
+
+
+%% -- IndAudLocalRemoteDescriptor --
+
+is_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudLocalRemoteDescriptor(D) ->
+ is_IndAudLocalRemoteDescriptor(D).
+
+is_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID,
+ propGrps = Grps}) ->
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID) andalso
+ is_IndAudPropertyGroup(Grps);
+is_IndAudLocalRemoteDescriptor(_) ->
+ false.
+
+is_IndAudLocalRemoteDescriptor_propGroupID(asn1_NOVALUE) ->
+ true;
+is_IndAudLocalRemoteDescriptor_propGroupID(V) ->
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_IndAudLocalRemoteDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudLocalRemoteDescriptor(D1, D2) ->
+ chk_IndAudLocalRemoteDescriptor(D1, D2).
+
+chk_IndAudLocalRemoteDescriptor(D, D) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor/1,
+ 'IndAudLocalRemoteDescriptor', D);
+chk_IndAudLocalRemoteDescriptor(
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID1,
+ propGrps = Grps1},
+ #'IndAudLocalRemoteDescriptor'{propGroupID = ID2,
+ propGrps = Grps2}) ->
+ chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2),
+ chk_IndAudPropertyGroup(Grps1, Grps2),
+ ok;
+chk_IndAudLocalRemoteDescriptor(D1, D2) ->
+ wrong_type('IndAudLocalRemoteDescriptor', D1, D2).
+
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID, ID) ->
+ chk_type(fun is_IndAudLocalRemoteDescriptor_propGroupID/1,
+ 'IndAudLocalRemoteDescriptor_propGroupID', ID);
+chk_IndAudLocalRemoteDescriptor_propGroupID(ID1, ID2) ->
+ case (is_IndAudLocalRemoteDescriptor_propGroupID(ID1) andalso
+ is_IndAudLocalRemoteDescriptor_propGroupID(ID2)) of
+ true ->
+ not_equal('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2);
+ false ->
+ wrong_type('IndAudLocalRemoteDescriptor_propGroupID', ID1, ID2)
+ end.
+
+
+%% -- IndAudPropertyGroup --
+
+is_IndAudPropertyGroup([]) ->
+ true;
+is_IndAudPropertyGroup([H|T]) ->
+ is_IndAudPropertyParm(H) andalso is_IndAudPropertyGroup(T);
+is_IndAudPropertyGroup(_) ->
+ false.
+
+chk_IndAudPropertyGroup([], []) ->
+ ok;
+chk_IndAudPropertyGroup([] = PG1, PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup(PG1, [] = PG2) ->
+ not_equal('IndAudPropertyGroup', PG1, PG2);
+chk_IndAudPropertyGroup([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudPropertyGroup(T1, T2);
+ false ->
+ wrong_type('IndAudPropertyGroup_val', H)
+ end;
+chk_IndAudPropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudPropertyGroup_val'),
+ chk_IndAudPropertyGroup(T1, T2);
+chk_IndAudPropertyGroup(P1, P2) ->
+ wrong_type('IndAudPropertyGroup', P1, P2).
+
+
+%% -- IndAudTerminationStateDescriptor --
+
+is_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudTerminationStateDescriptor(D) ->
+ is_IndAudTerminationStateDescriptor(D).
+
+is_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms,
+ eventBufferControl = EBC,
+ serviceState = SS,
+ serviceStateSel = SSS}) ->
+ is_IndAudTerminationStateDescriptor_propertyParms(Parms) andalso
+ is_opt_NULL(EBC) andalso
+ is_opt_NULL(SS) andalso
+ is_opt_ServiceState(SSS);
+is_IndAudTerminationStateDescriptor(_) ->
+ false.
+
+is_IndAudTerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_IndAudTerminationStateDescriptor_propertyParms([H|T]) ->
+ is_IndAudPropertyParm(H) andalso
+ is_IndAudTerminationStateDescriptor_propertyParms(T);
+is_IndAudTerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_IndAudTerminationStateDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudTerminationStateDescriptor(D1, D2) ->
+ chk_IndAudTerminationStateDescriptor(D1, D2).
+
+chk_IndAudTerminationStateDescriptor(
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms1,
+ eventBufferControl = EBC1,
+ serviceState = SS1,
+ serviceStateSel = SSS1},
+ #'IndAudTerminationStateDescriptor'{propertyParms = Parms2,
+ eventBufferControl = EBC2,
+ serviceState = SS2,
+ serviceStateSel = SSS2}) ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(Parms1, Parms2),
+ chk_IndAudTerminationStateDescriptor_eventBufferControl(EBC1, EBC2),
+ chk_IndAudTerminationStateDescriptor_serviceState(SS1, SS2),
+ chk_IndAudTerminationStateDescriptor_serviceStateSel(SSS1, SSS2),
+ ok;
+chk_IndAudTerminationStateDescriptor(D1, D2) ->
+ wrong_type('IndAudTerminationStateDescriptor', D1, D2).
+
+chk_IndAudTerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_IndAudTerminationStateDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2);
+chk_IndAudTerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_IndAudPropertyParm(H) of
+ true ->
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', H)
+ end;
+chk_IndAudTerminationStateDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_IndAudPropertyParm(H1, H2) end,
+ 'IndAudTerminationStateDescriptor_propertyParms'),
+ chk_IndAudTerminationStateDescriptor_propertyParms(T1, T2);
+chk_IndAudTerminationStateDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('IndAudTerminationStateDescriptor_propertyParms', PP1, PP2).
+
+chk_IndAudTerminationStateDescriptor_eventBufferControl(EBC1, EBC2) ->
+ validate(fun() -> chk_opt_NULL(EBC1, EBC2) end,
+ 'IndAudTerminationStateDescriptor_eventBufferControl').
+
+chk_IndAudTerminationStateDescriptor_serviceState(SS1, SS2) ->
+ validate(fun() -> chk_opt_NULL(SS1, SS2) end,
+ 'IndAudTerminationStateDescriptor_serviceState').
+
+chk_IndAudTerminationStateDescriptor_serviceStateSel(SSS1, SSS2) ->
+ validate(fun() -> chk_opt_ServiceState(SSS1, SSS2) end,
+ 'IndAudTerminationStateDescriptor_serviceStateSel').
+
+%% -- IndAudEventsDescriptor --
+
+is_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID,
+ pkgdName = Name,
+ streamID = SID}) ->
+ is_opt_RequestID(RID) andalso
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID);
+is_IndAudEventsDescriptor(_) ->
+ false.
+
+chk_IndAudEventsDescriptor(#'IndAudEventsDescriptor'{requestID = RID1,
+ pkgdName = Name1,
+ streamID = SID1},
+ #'IndAudEventsDescriptor'{requestID = RID2,
+ pkgdName = Name2,
+ streamID = SID2}) ->
+ chk_opt_RequestID(RID1, RID2),
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventsDescriptor(D1, D2) ->
+ wrong_type('IndAudEventsDescriptor', D1, D2).
+
+
+%% -- IndAudEventBufferDescriptor --
+
+is_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name,
+ streamID = SID}) ->
+ is_PkgdName(Name) andalso is_opt_StreamID(SID);
+is_IndAudEventBufferDescriptor(_) ->
+ false.
+
+chk_IndAudEventBufferDescriptor(
+ #'IndAudEventBufferDescriptor'{eventName = Name1,
+ streamID = SID1},
+ #'IndAudEventBufferDescriptor'{eventName = Name2,
+ streamID = SID2}) ->
+ chk_PkgdName(Name1, Name2),
+ chk_opt_StreamID(SID1, SID2),
+ ok;
+chk_IndAudEventBufferDescriptor(D1, D2) ->
+ wrong_type('IndAudEventBufferDescriptor', D1, D2).
+
+
+%% -- IndAudSignalsDescriptor --
+
+is_IndAudSignalsDescriptor({Tag, Val}) ->
+ is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val);
+is_IndAudSignalsDescriptor(_) ->
+ false.
+
+is_IndAudSignalsDescriptor_tag(Tag) ->
+ Tags = [signal, seqSigList],
+ lists:member(Tag, Tags).
+
+is_IndAudSignalsDescriptor_val(signal, Val) ->
+ is_IndAudSignal(Val);
+is_IndAudSignalsDescriptor_val(seqSigList, Val) ->
+ is_IndAudSeqSigList(Val).
+
+chk_IndAudSignalsDescriptor(D, D) ->
+ chk_type(fun is_IndAudSignalsDescriptor/1, 'IndAudSignalsDescriptor', D);
+chk_IndAudSignalsDescriptor({Tag, Val1} = D1, {Tag, Val2} = D2) ->
+ case (is_IndAudSignalsDescriptor_tag(Tag) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val1) andalso
+ is_IndAudSignalsDescriptor_val(Tag, Val2)) of
+ true ->
+ chk_IndAudSignalsDescriptor_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor({Tag1, Val1} = D1, {Tag2, Val2} = D2) ->
+ case ((is_IndAudSignalsDescriptor_tag(Tag1) andalso
+ is_IndAudSignalsDescriptor_val(Tag1, Val1)) andalso
+ (is_IndAudSignalsDescriptor_tag(Tag2) andalso
+ is_IndAudSignalsDescriptor_val(Tag2, Val2))) of
+ true ->
+ not_equal('IndAudSignalsDescriptor', D1, D2);
+ false ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2)
+ end;
+chk_IndAudSignalsDescriptor(D1, D2) ->
+ wrong_type('IndAudSignalsDescriptor', D1, D2).
+
+chk_IndAudSignalsDescriptor_val(signal, Val1, Val2) ->
+ chk_IndAudSignal(Val1, Val2);
+chk_IndAudSignalsDescriptor_val(seqSigList, Val1, Val2) ->
+ chk_IndAudSeqSigList(Val1, Val2).
+
+
+%% -- IndAudSeqSigList --
+
+is_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_IndAudSeqSigList_id(ID) andalso is_opt_IndAudSignal(SL);
+is_IndAudSeqSigList(_) ->
+ false.
+
+is_IndAudSeqSigList_id(ID) -> is_INTEGER(ID, {range, 0, 65535}).
+
+chk_IndAudSeqSigList(L, L) ->
+ chk_type(fun is_IndAudSeqSigList/1, 'IndAudSeqSigList', L);
+chk_IndAudSeqSigList(#'IndAudSeqSigList'{id = ID1,
+ signalList = SL1},
+ #'IndAudSeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ chk_IndAudSeqSigList_id(ID1, ID2),
+ chk_opt_IndAudSignal(SL1, SL2),
+ ok;
+chk_IndAudSeqSigList(L1, L2) ->
+ wrong_type('IndAudSeqSigList', L1, L2).
+
+chk_IndAudSeqSigList_id(ID, ID) ->
+ chk_type(fun is_IndAudSeqSigList_id/1, 'IndAudSeqSigList_id', ID);
+chk_IndAudSeqSigList_id(ID1, ID2) ->
+ case (is_IndAudSeqSigList_id(ID1) andalso
+ is_IndAudSeqSigList_id(ID2)) of
+ true ->
+ not_equal('IndAudSeqSigList_id', ID1, ID2);
+ false ->
+ wrong_type('IndAudSeqSigList_id', ID1, ID2)
+ end.
+
+
+%% -- IndAudSignal --
+
+is_opt_IndAudSignal(asn1_NOVALUE) ->
+ true;
+is_opt_IndAudSignal(V) ->
+ is_IndAudSignal(V).
+
+is_IndAudSignal(#'IndAudSignal'{signalName = Name,
+ streamID = SID,
+ signalRequestID = SRID}) ->
+ is_PkgdName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestID(SRID);
+is_IndAudSignal(_) ->
+ false.
+
+chk_opt_IndAudSignal(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_IndAudSignal(S1, S2) ->
+ chk_IndAudSignal(S1, S2).
+
+chk_IndAudSignal(S, S) ->
+ chk_type(fun is_IndAudSignal/1, 'IndAudSignal', S);
+chk_IndAudSignal(#'IndAudSignal'{signalName = Name1,
+ streamID = SID1,
+ signalRequestID = SRID1},
+ #'IndAudSignal'{signalName = Name2,
+ streamID = SID2,
+ signalRequestID = SRID2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudSignal_signalName'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'IndAudSignal_streamID'),
+ validate(fun() -> chk_opt_RequestID(SRID1, SRID2) end,
+ 'IndAudSignal_signalRequestID'),
+ ok;
+chk_IndAudSignal(S1, S2) ->
+ wrong_type('IndAudSignal', S1, S2).
+
+
+%% -- IndAudDigitMapDescriptor --
+
+is_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name}) ->
+ is_opt_DigitMapName(Name);
+is_IndAudDigitMapDescriptor(_) ->
+ false.
+
+chk_IndAudDigitMapDescriptor(D, D) ->
+ chk_type(fun is_IndAudDigitMapDescriptor/1, 'IndAudDigitMapDescriptor', D);
+chk_IndAudDigitMapDescriptor(
+ #'IndAudDigitMapDescriptor'{digitMapName = Name1},
+ #'IndAudDigitMapDescriptor'{digitMapName = Name2}) ->
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'IndAudDigitMapDescriptor'),
+ ok;
+chk_IndAudDigitMapDescriptor(D1, D2) ->
+ wrong_type('IndAudDigitMapDescriptor', D1, D2).
+
+
+%% -- IndAudStatisticsDescriptor --
+
+is_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name}) ->
+ is_PkgdName(Name);
+is_IndAudStatisticsDescriptor(_) ->
+ false.
+
+chk_IndAudStatisticsDescriptor(D, D) ->
+ chk_type(fun is_IndAudStatisticsDescriptor/1,
+ 'IndAudStatisticsDescriptor', D);
+chk_IndAudStatisticsDescriptor(
+ #'IndAudStatisticsDescriptor'{statName = Name1},
+ #'IndAudStatisticsDescriptor'{statName = Name2}) ->
+ validate(fun() -> chk_PkgdName(Name1, Name2) end,
+ 'IndAudStatisticsDescriptor'),
+ ok;
+chk_IndAudStatisticsDescriptor(D1, D2) ->
+ wrong_type('IndAudStatisticsDescriptor', D1, D2).
+
+
+%% -- IndAudPackagesDescriptor --
+
+is_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name,
+ packageVersion = Ver}) ->
+ is_Name(Name) andalso is_IndAudPackagesDescriptor_packageVersion(Ver);
+is_IndAudPackagesDescriptor(_) ->
+ false.
+
+is_IndAudPackagesDescriptor_packageVersion(V) ->
+ is_INTEGER(V, {range, 0, 99}).
+
+chk_IndAudPackagesDescriptor(
+ #'IndAudPackagesDescriptor'{packageName = Name1,
+ packageVersion = Ver1},
+ #'IndAudPackagesDescriptor'{packageName = Name2,
+ packageVersion = Ver2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'IndAudPackagesDescriptor'),
+ chk_IndAudPackagesDescriptor_packageVersion(Ver1, Ver2),
+ ok;
+chk_IndAudPackagesDescriptor(D1, D2) ->
+ wrong_type('IndAudPackagesDescriptor', D1, D2).
+
+chk_IndAudPackagesDescriptor_packageVersion(V, V) ->
+ chk_type(fun is_IndAudPackagesDescriptor_packageVersion/1,
+ 'IndAudPackagesDescriptor_packageVersion', V);
+chk_IndAudPackagesDescriptor_packageVersion(V1, V2) ->
+ case (is_IndAudPackagesDescriptor_packageVersion(V1) andalso
+ is_IndAudPackagesDescriptor_packageVersion(V2)) of
+ true ->
+ not_equal('IndAudPackagesDescriptor_packageVersion', V1, V2);
+ false ->
+ wrong_type('IndAudPackagesDescriptor_packageVersion', V1, V2)
+ end.
+
+
+%% -- NotifyRequest --
+
+is_NotifyRequest(#'NotifyRequest'{terminationID = Tids,
+ observedEventsDescriptor = OED,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso
+ is_ObservedEventsDescriptor(OED) andalso
+ is_opt_ErrorDescriptor(ED);
+is_NotifyRequest(_) ->
+ false.
+
+chk_NotifyRequest(#'NotifyRequest'{terminationID = Tids1,
+ observedEventsDescriptor = OED1,
+ errorDescriptor = ED1},
+ #'NotifyRequest'{terminationID = Tids2,
+ observedEventsDescriptor = OED2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_ObservedEventsDescriptor(OED1, OED2) end,
+ 'NotifyRequest'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end,
+ 'NotifyRequest'),
+ ok;
+chk_NotifyRequest(NR1, NR2) ->
+ wrong_type('NotifyRequest', NR1, NR2).
+
+
+%% -- NotifyReply --
+
+is_NotifyReply(#'NotifyReply'{terminationID = Tids,
+ errorDescriptor = ED}) ->
+ is_TerminationIDList(Tids) andalso is_opt_ErrorDescriptor(ED);
+is_NotifyReply(_) ->
+ false.
+
+chk_NotifyReply(#'NotifyReply'{terminationID = Tids1,
+ errorDescriptor = ED1},
+ #'NotifyReply'{terminationID = Tids2,
+ errorDescriptor = ED2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end, 'NotifyReply'),
+ validate(fun() -> chk_opt_ErrorDescriptor(ED1, ED2) end, 'NotifyReply'),
+ ok;
+chk_NotifyReply(NR1, NR2) ->
+ wrong_type('NotifyReply', NR1, NR2).
+
+
+%% -- ObservedEventsDescriptor --
+
+is_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID,
+ observedEventLst = OEL}) ->
+ is_RequestID(RID) andalso
+ is_ObservedEventsDescriptor_observedEventLst(OEL);
+is_ObservedEventsDescriptor(_) ->
+ false.
+
+is_ObservedEventsDescriptor_observedEventLst([]) ->
+ true;
+is_ObservedEventsDescriptor_observedEventLst([H|T]) ->
+ is_ObservedEvent(H) andalso
+ is_ObservedEventsDescriptor_observedEventLst(T);
+is_ObservedEventsDescriptor_observedEventLst(_) ->
+ false.
+
+chk_ObservedEventsDescriptor(
+ #'ObservedEventsDescriptor'{requestId = RID1,
+ observedEventLst = OEL1},
+ #'ObservedEventsDescriptor'{requestId = RID2,
+ observedEventLst = OEL2}) ->
+ validate(fun() -> chk_RequestID(RID1, RID2) end,
+ 'ObservedEventsDescriptor'),
+ validate(
+ fun() ->
+ chk_ObservedEventsDescriptor_observedEventLst(OEL1, OEL2)
+ end,
+ 'ObservedEventsDescriptor'),
+ ok;
+chk_ObservedEventsDescriptor(D1, D2) ->
+ wrong_type('ObservedEventsDescriptor', D1, D2).
+
+chk_ObservedEventsDescriptor_observedEventLst([], []) ->
+ ok;
+chk_ObservedEventsDescriptor_observedEventLst([] = L1, L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, [] = L2) ->
+ not_equal('ObservedEventsDescriptor_observedEventLst', L1, L2);
+chk_ObservedEventsDescriptor_observedEventLst([H|T1], [H|T2]) ->
+ case is_ObservedEvent(H) of
+ true ->
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+ false ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst_val', H)
+ end;
+chk_ObservedEventsDescriptor_observedEventLst([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ObservedEvent(H1, H2) end,
+ 'ObservedEventsDescriptor_observedEventLst_val'),
+ chk_ObservedEventsDescriptor_observedEventLst(T1, T2);
+chk_ObservedEventsDescriptor_observedEventLst(L1, L2) ->
+ wrong_type('ObservedEventsDescriptor_observedEventLst', L1, L2).
+
+
+%% -- ObservedEvent --
+
+is_ObservedEvent(#'ObservedEvent'{eventName = Name,
+ streamID = SID,
+ eventParList = EPL,
+ timeNotation = TN}) ->
+ is_EventName(Name) andalso
+ is_opt_StreamID(SID) andalso
+ is_ObservedEvent_eventParList(EPL) andalso
+ is_opt_TimeNotation(TN);
+is_ObservedEvent(_) ->
+ false.
+
+is_ObservedEvent_eventParList([]) ->
+ true;
+is_ObservedEvent_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_ObservedEvent_eventParList(T);
+is_ObservedEvent_eventParList(_) ->
+ false.
+
+chk_ObservedEvent(E, E) ->
+ chk_type(fun is_ObservedEvent/1, 'ObservedEvent', E);
+chk_ObservedEvent(#'ObservedEvent'{eventName = Name1,
+ streamID = SID1,
+ eventParList = EPL1,
+ timeNotation = TN1},
+ #'ObservedEvent'{eventName = Name2,
+ streamID = SID2,
+ eventParList = EPL2,
+ timeNotation = TN2}) ->
+ validate(fun() -> chk_EventName(Name1, Name2) end, 'ObservedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'ObservedEvent'),
+ chk_ObservedEvent_eventParList(EPL1, EPL2),
+ validate(fun() -> chk_opt_TimeNotation(TN1, TN2) end, 'ObservedEvent'),
+ ok;
+chk_ObservedEvent(E1, E2) ->
+ wrong_type('ObservedEvent', E1, E2).
+
+chk_ObservedEvent_eventParList([], []) ->
+ ok;
+chk_ObservedEvent_eventParList([] = EPL1, EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList(EPL1, [] = EPL2) ->
+ not_equal('ObservedEvent_eventParList', EPL1, EPL2);
+chk_ObservedEvent_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_ObservedEvent_eventParList(T1, T2);
+ false ->
+ wrong_type('ObservedEvent_eventParList_val', H)
+ end;
+chk_ObservedEvent_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'ObservedEvent_eventParList'),
+ chk_ObservedEvent_eventParList(T1, T2);
+chk_ObservedEvent_eventParList(L1, L2) ->
+ wrong_type('ObservedEvent_eventParList', L1, L2).
+
+
+%% -- EventName --
+
+is_EventName(N) -> is_PkgdName(N).
+
+chk_EventName(N, N) ->
+ chk_type(fun is_EventName/1, 'EventName', N);
+chk_EventName(N1, N2) ->
+ case (is_EventName(N1) andalso is_EventName(N2)) of
+ true ->
+ not_equal('EventName', N1, N2);
+ false ->
+ wrong_type('EventName', N1, N2)
+ end.
+
+
+%% -- EventParameter --
+
+is_EventParameter(#'EventParameter'{eventParameterName = Name,
+ value = Val,
+ extraInfo = EI}) ->
+ d("is_EventParameter -> entery with"
+ "~n Name: ~p"
+ "~n Val: ~p"
+ "~n EI: ~p", [Name, Val, EI]),
+ is_Name(Name) andalso
+ is_Value(Val) andalso
+ is_EventParameter_extraInfo(EI);
+is_EventParameter(_) ->
+ false.
+
+is_EventParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_EventParameter_extraInfo({Tag, Val}) ->
+ is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val);
+is_EventParameter_extraInfo(_) ->
+ false.
+
+is_EventParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_EventParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_EventParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_EventParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_EventParameter(#'EventParameter'{eventParameterName = Name1,
+ value = Val1,
+ extraInfo = EI1},
+ #'EventParameter'{eventParameterName = Name2,
+ value = Val2,
+ extraInfo = EI2}) ->
+ validate(fun() -> chk_Name(Name1, Name2) end, 'EventParameter'),
+ validate(fun() -> chk_Value(Val1, Val2) end, 'EventParameter'),
+ chk_EventParameter_extraInfo(EI1, EI2),
+ ok;
+chk_EventParameter(P1, P2) ->
+ wrong_type('EventParameter', P1, P2).
+
+chk_EventParameter_extraInfo(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_EventParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_EventParameter_extraInfo/1,
+ 'EventParameter_extraInfo', EI);
+chk_EventParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_EventParameter_extraInfo_tag(Tag) andalso
+ is_EventParameter_extraInfo_val(Tag, Val1) andalso
+ is_EventParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_EventParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_EventParameter_extraInfo_tag(Tag1) andalso
+ is_EventParameter_extraInfo_val(Tag1, Val1)) andalso
+ (is_EventParameter_extraInfo_tag(Tag2) andalso
+ is_EventParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2)
+ end;
+chk_EventParameter_extraInfo(EI1, EI2) ->
+ wrong_type('EventParameter_extraInfo', EI1, EI2).
+
+chk_EventParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val');
+chk_EventParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end,
+ 'EventParameter_extraInfo_val').
+
+
+%% -- ServiceChangeRequest --
+
+is_ServiceChangeRequest(#'ServiceChangeRequest'{terminationID = Tids,
+ serviceChangeParms = Parms}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeParm(Parms);
+is_ServiceChangeRequest(_) ->
+ false.
+
+chk_ServiceChangeRequest(R, R) ->
+ chk_type(fun is_ServiceChangeRequest/1, 'ServiceChangeRequest', R);
+chk_ServiceChangeRequest(
+ #'ServiceChangeRequest'{terminationID = Tids1,
+ serviceChangeParms = Parms1},
+ #'ServiceChangeRequest'{terminationID = Tids2,
+ serviceChangeParms = Parms2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeRequest'),
+ validate(fun() -> chk_ServiceChangeParm(Parms1, Parms2) end,
+ 'ServiceChangeRequest'),
+ ok;
+chk_ServiceChangeRequest(R1, R2) ->
+ wrong_type('ServiceChangeRequest', R1, R2).
+
+
+%% -- ServiceChangeReply --
+
+is_ServiceChangeReply(#'ServiceChangeReply'{terminationID = Tids,
+ serviceChangeResult = Res}) ->
+ is_TerminationIDList(Tids) andalso is_ServiceChangeResult(Res);
+is_ServiceChangeReply(_) ->
+ false.
+
+chk_ServiceChangeReply(R, R) ->
+ chk_type(fun is_ServiceChangeReply/1, 'ServiceChangeReply', R);
+chk_ServiceChangeReply(
+ #'ServiceChangeReply'{terminationID = Tids1,
+ serviceChangeResult = Res1},
+ #'ServiceChangeReply'{terminationID = Tids2,
+ serviceChangeResult = Res2}) ->
+ validate(fun() -> chk_TerminationIDList(Tids1, Tids2) end,
+ 'ServiceChangeReply'),
+ validate(fun() -> chk_ServiceChangeResult(Res1, Res2) end,
+ 'ServiceChangeReply'),
+ ok;
+chk_ServiceChangeReply(R1, R2) ->
+ wrong_type('ServiceChangeReply', R1, R2).
+
+
+%% -- ServiceChangeResult --
+
+is_ServiceChangeResult({Tag, Val}) ->
+ is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val);
+is_ServiceChangeResult(_) ->
+ false.
+
+is_ServiceChangeResult_tag(Tag) ->
+ Tags = [errorDescriptor, serviceChangeResParms],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeResult_val(errorDescriptor, Val) ->
+ is_ErrorDescriptor(Val);
+is_ServiceChangeResult_val(serviceChangeResParms, Val) ->
+ is_ServiceChangeResParm(Val).
+
+chk_ServiceChangeResult(Res, Res) ->
+ chk_type(fun is_ServiceChangeResult/1, 'ServiceChangeResult', Res);
+chk_ServiceChangeResult({Tag, Val1} = Res1, {Tag, Val2} = Res2) ->
+ case (is_ServiceChangeResult_tag(Tag) andalso
+ is_ServiceChangeResult_val(Tag, Val1) andalso
+ is_ServiceChangeResult_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeResult_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult({Tag1, Val1} = Res1, {Tag2, Val2} = Res2) ->
+ case ((is_ServiceChangeResult_tag(Tag1) andalso
+ is_ServiceChangeResult_val(Tag1, Val1)) andalso
+ (is_ServiceChangeResult_tag(Tag2) andalso
+ is_ServiceChangeResult_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeResult', Res1, Res2);
+ false ->
+ wrong_type('ServiceChangeResult', Res1, Res2)
+ end;
+chk_ServiceChangeResult(Res1, Res2) ->
+ wrong_type('ServiceChangeResult', Res1, Res2).
+
+chk_ServiceChangeResult_val(errorDescriptor, Val1, Val2) ->
+ validate(fun() -> chk_ErrorDescriptor(Val1, Val2) end,
+ 'ServiceChangeResult');
+chk_ServiceChangeResult_val(serviceChangeResParms, Val1, Val2) ->
+ validate(fun() -> chk_ServiceChangeResParm(Val1, Val2) end,
+ 'ServiceChangeResult').
+
+
+%% -- WildcardField --
+
+is_WildcardField(WF) -> is_OCTET_STRING(WF, {exact, 1}).
+
+chk_WildcardField(WF, WF) ->
+ case is_WildcardField(WF) of
+ true ->
+ ok;
+ false ->
+ wrong_type('WildcardField', WF)
+ end;
+chk_WildcardField(WF1, WF2) ->
+ case (is_WildcardField(WF1) andalso is_WildcardField(WF2)) of
+ true ->
+ not_equal('WildcardField', WF1, WF2);
+ false ->
+ wrong_type('WildcardField', WF1, WF2)
+ end.
+
+
+%% -- TerminationID --
+
+is_TerminationID(#'TerminationID'{wildcard = W,
+ id = ID}) ->
+ is_TerminationID_wildcard(W) andalso is_TerminationID_id(ID);
+is_TerminationID(#megaco_term_id{contains_wildcards = _W,
+ id = _ID}) ->
+ true; % What are the types?
+is_TerminationID(_) ->
+ false.
+
+is_TerminationID_wildcard([]) ->
+ true;
+is_TerminationID_wildcard([H|T]) ->
+ is_WildcardField(H) andalso is_TerminationID_wildcard(T);
+is_TerminationID_wildcard(_) ->
+ false.
+
+is_TerminationID_id(ID) -> is_OCTET_STRING(ID, {range, 1, 8}).
+
+chk_TerminationID(Id,Id) ->
+ d("chk_TerminationID(1) -> entry with"
+ "~n Id: ~p", [Id]),
+ chk_type(fun is_TerminationID/1, 'TerminationID', Id);
+chk_TerminationID(#'TerminationID'{wildcard = W1,
+ id = I1},
+ #'TerminationID'{wildcard = W2,
+ id = I2}) ->
+ d("chk_TerminationID(2) -> entry with"
+ "~n W1: ~p"
+ "~n W2: ~p"
+ "~n I1: ~p"
+ "~n I2: ~p", [W1, W2, I1, I2]),
+ chk_TerminationID_wildcard(W1, W2),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(#megaco_term_id{contains_wildcards = W1,
+ id = I1},
+ #megaco_term_id{contains_wildcards = W2,
+ id = I2}) ->
+ d("chk_TerminationID(3) -> entry with"
+ "~n W1: ~p"
+ "~n W2: ~p"
+ "~n I1: ~p"
+ "~n I2: ~p", [W1, W2, I1, I2]),
+ validate(fun() -> chk_BOOLEAN(W1, W2) end, 'TerminationID_wildcard'),
+ chk_TerminationID_id(I1, I2),
+ ok;
+chk_TerminationID(Tid1, Tid2) ->
+ d("chk_TerminationID(4) -> entry with"
+ "~n Tid1: ~p"
+ "~n Tid2: ~p", [Tid1, Tid2]),
+ wrong_type('TerminationID', Tid1, Tid2).
+
+chk_TerminationID_wildcard([], []) ->
+ ok;
+chk_TerminationID_wildcard([] = WF1, WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard(WF1, [] = WF2) ->
+ not_equal('TerminationID_wildcard', WF1, WF2);
+chk_TerminationID_wildcard([H|T1], [H|T2]) ->
+ case is_WildcardField(H) of
+ true ->
+ chk_TerminationID_wildcard(T1, T2);
+ false ->
+ wrong_type('TerminationID_wildcard_val', H)
+ end;
+chk_TerminationID_wildcard([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_WildcardField(H1, H2) end,
+ 'TerminationID_wildcard_val'),
+ chk_TerminationID_wildcard(T1, T2);
+chk_TerminationID_wildcard(WF1,WF2) ->
+ not_equal('TerminationId_wildcard', WF1, WF2).
+
+chk_TerminationID_id(Id, Id) ->
+ case is_OCTET_STRING(Id, {range, 1, 8}) of
+ true ->
+ ok;
+ false ->
+ wrong_type('TerminationID_id', Id, Id)
+ end;
+chk_TerminationID_id(Id1, Id2) ->
+ Id12 = flatten_TerminationID_id(Id1, []),
+ Id22 = flatten_TerminationID_id(Id2, []),
+ case Id12 == Id22 of
+ true ->
+ ok;
+ false ->
+ not_equal(terminationId_id, Id1, Id2)
+ end.
+
+flatten_TerminationID_id([], Acc) ->
+ lists:flatten(lists:reverse(Acc));
+flatten_TerminationID_id([H|T], Acc) ->
+ flatten_TerminationID_id(T, [string:tokens(H, [$/])|Acc]).
+
+%% -- TerminationIDList --
+
+%% is_opt_TerminationIDList(asn1_NOVALUE) ->
+%% true;
+%% is_opt_TerminationIDList(TIDs) ->
+%% is_TerminationIDList(TIDs).
+
+is_TerminationIDList([]) ->
+ true;
+is_TerminationIDList([H|T]) ->
+ is_TerminationID(H) andalso is_TerminationIDList(T);
+is_TerminationIDList(_) ->
+ false.
+
+chk_opt_TerminationIDList(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TerminationIDList(TIDs1, TIDs2) ->
+ chk_TerminationIDList(TIDs1, TIDs2).
+
+chk_TerminationIDList([], []) ->
+ ok;
+chk_TerminationIDList([] = L1, L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList(L1, [] = L2) ->
+ not_equal('TerminationIDList', L1, L2);
+chk_TerminationIDList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_TerminationIDList(T1, T2);
+ false ->
+ wrong_type('TerminationIDList', H)
+ end;
+chk_TerminationIDList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end, 'TerminationIDList'),
+ chk_TerminationIDList(T1, T2);
+chk_TerminationIDList(L1, L2) ->
+ wrong_type('TerminationIDList', L1, L2).
+
+
+%% -- MediaDescriptor --
+
+is_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD,
+ streams = S}) ->
+ d("is_MediaDescriptor -> entry with"
+ "~n TSD: ~p"
+ "~n S: ~p", [TSD, S]),
+ is_opt_TerminationStateDescriptor(TSD) andalso
+ is_MediaDescriptor_streams(S);
+is_MediaDescriptor(_) ->
+ false.
+
+is_MediaDescriptor_streams(asn1_NOVALUE) ->
+ true;
+is_MediaDescriptor_streams({Tag, Val}) ->
+ is_MediaDescriptor_streams_tag(Tag) andalso
+ is_MediaDescriptor_streams_val(Tag, Val);
+is_MediaDescriptor_streams(_) ->
+ false.
+
+is_MediaDescriptor_streams_tag(Tag) ->
+ Tags = [oneStream, multiStream],
+ lists:member(Tag, Tags).
+
+is_MediaDescriptor_streams_val(oneStream, SP) ->
+ is_StreamParms(SP);
+is_MediaDescriptor_streams_val(multiStream, SDL) ->
+ is_MediaDescriptor_multiStream(SDL).
+
+is_MediaDescriptor_multiStream([]) ->
+ true;
+is_MediaDescriptor_multiStream([H|T]) ->
+ is_StreamDescriptor(H) andalso is_MediaDescriptor_multiStream(T);
+is_MediaDescriptor_multiStream(_) ->
+ false.
+
+chk_MediaDescriptor(D, D) ->
+ chk_type(fun is_MediaDescriptor/1, 'MediaDescriptor', D);
+chk_MediaDescriptor(#'MediaDescriptor'{termStateDescr = TSD1,
+ streams = S1},
+ #'MediaDescriptor'{termStateDescr = TSD2,
+ streams = S2}) ->
+ validate(
+ fun() ->
+ chk_opt_TerminationStateDescriptor(TSD1, TSD2)
+ end,
+ 'MediaDescriptor'),
+ validate(
+ fun() ->
+ chk_MediaDescriptor_streams(S1, S2)
+ end,
+ 'MediaDescriptor'),
+ ok;
+chk_MediaDescriptor(D1, D2) ->
+ wrong_type('MediaDescriptor', D1, D2).
+
+
+chk_MediaDescriptor_streams(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_MediaDescriptor_streams({oneStream, SP1}, {oneStream, SP2}) ->
+ validate(fun() ->
+ chk_StreamParms(SP1, SP2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams({multiStream, SDs1}, {multiStream, SDs2}) ->
+ validate(fun() ->
+ chk_MediaDescriptor_multiStream(SDs1, SDs2)
+ end,
+ 'MediaDescriptor_streams');
+chk_MediaDescriptor_streams(S1, S2) ->
+ wrong_type('MediaDescriptor_streams', S1, S2).
+
+chk_MediaDescriptor_multiStream([], []) ->
+ ok;
+chk_MediaDescriptor_multiStream([] = MS1, MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream(MS1, [] = MS2) ->
+ not_equal('MediaDescriptor_multiStream', MS1, MS2);
+chk_MediaDescriptor_multiStream([H|T1], [H|T2]) ->
+ case is_StreamDescriptor(H) of
+ true ->
+ chk_MediaDescriptor_multiStream(T1, T2);
+ false ->
+ wrong_type('MediaDescriptor_multiStream_val', H)
+ end;
+chk_MediaDescriptor_multiStream([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StreamDescriptor(H1, H2) end,
+ 'MediaDescriptor_multiStream_val'),
+ chk_MediaDescriptor_multiStream(T1, T2);
+chk_MediaDescriptor_multiStream(MS1, MS2) ->
+ wrong_type('MediaDescriptor_multiStream_val', MS1, MS2).
+
+
+%% -- StreamDescriptor --
+
+is_StreamDescriptor(#'StreamDescriptor'{streamID = SID,
+ streamParms = Parms}) ->
+ d("is_StreamDescriptor -> entry with"
+ "~n SID: ~p"
+ "~n Parms: ~p", [SID, Parms]),
+ is_StreamID(SID) andalso is_StreamParms(Parms);
+is_StreamDescriptor(X) ->
+ d("is_StreamDescriptor -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamDescriptor(D, D) ->
+ chk_type(fun is_StreamDescriptor/1, 'StreamDescriptor', D);
+chk_StreamDescriptor(#'StreamDescriptor'{streamID = SID1,
+ streamParms = Parms1},
+ #'StreamDescriptor'{streamID = SID2,
+ streamParms = Parms2}) ->
+ validate(fun() -> chk_StreamID(SID1, SID2) end, 'StreamDescriptor'),
+ validate(fun() -> chk_StreamParms(Parms1, Parms2) end, 'StreamDescriptor'),
+ ok;
+chk_StreamDescriptor(D1, D2) ->
+ wrong_type('StreamDescriptor', D1, D2).
+
+
+%% -- StreamParms --
+
+is_StreamParms(#'StreamParms'{localControlDescriptor = LCD,
+ localDescriptor = LD,
+ remoteDescriptor = RD,
+ statisticsDescriptor = SD}) ->
+ d("is_StreamParms -> entry with"
+ "~n LCD: ~p"
+ "~n LD: ~p"
+ "~n RD: ~p"
+ "~n SD: ~p", [LCD, LD, RD, SD]),
+ is_opt_LocalControlDescriptor(LCD) andalso
+ is_opt_LocalRemoteDescriptor(LD) andalso
+ is_opt_LocalRemoteDescriptor(RD) andalso
+ is_opt_StatisticsDescriptor(SD);
+is_StreamParms(X) ->
+ d("is_StreamParms -> entry when ERROR with"
+ "~n X: ~p", [X]),
+ false.
+
+chk_StreamParms(SP, SP) ->
+ chk_type(fun is_StreamParms/1, 'StreamParms', SP);
+chk_StreamParms(#'StreamParms'{localControlDescriptor = LCD1,
+ localDescriptor = LD1,
+ remoteDescriptor = RD1,
+ statisticsDescriptor = SD1},
+ #'StreamParms'{localControlDescriptor = LCD2,
+ localDescriptor = LD2,
+ remoteDescriptor = RD2,
+ statisticsDescriptor = SD2}) ->
+ validate(fun() -> chk_opt_LocalControlDescriptor(LCD1, LCD2) end,
+ 'StreamParms_localControlDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(LD1, LD2) end,
+ 'StreamParms_localDescriptor'),
+ validate(fun() -> chk_opt_LocalRemoteDescriptor(RD1, RD2) end,
+ 'StreamParms_remoteDescriptor'),
+ validate(fun() -> chk_opt_StatisticsDescriptor(SD1, SD2) end,
+ 'StreamParms_statisticsDescriptor'),
+ ok;
+chk_StreamParms(P1, P2) ->
+ wrong_type('StreamParms', P1, P2).
+
+
+%% -- LocalControlDescriptor --
+
+is_opt_LocalControlDescriptor(D) ->
+ d("is_opt_LocalControlDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalControlDescriptor/1, D).
+
+is_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM,
+ reserveValue = RV,
+ reserveGroup = RG,
+ propertyParms = PP}) ->
+ d("is_LocalControlDescriptor -> entry with"
+ "~n SM: ~p"
+ "~n RV: ~p"
+ "~n RG: ~p"
+ "~n PP: ~p", [SM, RV, RG, PP]),
+ is_opt_StreamMode(SM) andalso
+ is_opt_BOOLEAN(RV) andalso
+ is_opt_BOOLEAN(RG) andalso
+ is_LocalControlDescriptor_propertyParms(PP);
+is_LocalControlDescriptor(_) ->
+ false.
+
+is_LocalControlDescriptor_propertyParms([]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry when done"),
+ true;
+is_LocalControlDescriptor_propertyParms([H|T]) ->
+ d("is_LocalControlDescriptor_propertyParms -> entry with"
+ "~n H: ~p"
+ "~n T: ~p", [H, T]),
+ is_PropertyParm(H) andalso is_LocalControlDescriptor_propertyParms(T);
+is_LocalControlDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_LocalControlDescriptor(LCD1, LCD2) ->
+ chk_OPTIONAL('LocalControlDescriptor', LCD1, LCD2,
+ fun is_LocalControlDescriptor/1,
+ fun chk_LocalControlDescriptor/2).
+
+chk_LocalControlDescriptor(LCD, LCD) ->
+ chk_type(fun is_LocalControlDescriptor/1, 'LocalControlDescriptor', LCD);
+chk_LocalControlDescriptor(#'LocalControlDescriptor'{streamMode = SM1,
+ reserveValue = RV1,
+ reserveGroup = RG1,
+ propertyParms = PP1},
+ #'LocalControlDescriptor'{streamMode = SM2,
+ reserveValue = RV2,
+ reserveGroup = RG2,
+ propertyParms = PP2}) ->
+ validate(
+ fun() -> chk_opt_StreamMode(SM1, SM2) end,
+ 'LocalControlDescriptor'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RV1, RV2) end,
+ 'LocalControlDescriptor_reserveValue'),
+ validate(
+ fun() -> chk_opt_BOOLEAN(RG1, RG2) end,
+ 'LocalControlDescriptor_reserveGroup'),
+ chk_LocalControlDescriptor_propertyParms(PP1, PP2),
+ ok;
+chk_LocalControlDescriptor(LCD1, LCD2) ->
+ wrong_type('LocalControlDescriptor', LCD1, LCD2).
+
+
+chk_LocalControlDescriptor_propertyParms([], []) ->
+ ok;
+chk_LocalControlDescriptor_propertyParms([] = PP1, PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms(PP1, [] = PP2) ->
+ not_equal('LocalControlDescriptor_propertyParms', PP1, PP2);
+chk_LocalControlDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('LocalControlDescriptor_propertyParms_val', H)
+ end;
+chk_LocalControlDescriptor_propertyParms([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end,
+ 'LocalControlDescriptor_propertyParms_val'),
+ chk_LocalControlDescriptor_propertyParms(T1, T2);
+chk_LocalControlDescriptor_propertyParms(PP1, PP2) ->
+ wrong_type('LocalControlDescriptor_propertyParms', PP1, PP2).
+
+
+%% -- StreamMode --
+
+is_opt_StreamMode(asn1_NOVALUE) ->
+ true;
+is_opt_StreamMode(SM) ->
+ is_StreamMode(SM).
+
+is_StreamMode(SM) ->
+ lists:member(SM, [sendOnly, recvOnly, sendRecv, inactive, loopBack]).
+
+chk_opt_StreamMode(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_StreamMode(SM1, SM2) ->
+ chk_StreamMode(SM1, SM2).
+
+chk_StreamMode(SM, SM) ->
+ chk_type(fun is_StreamMode/1, 'StreamMode', SM);
+chk_StreamMode(SM1, SM2) ->
+ case (is_StreamMode(SM1) andalso is_StreamMode(SM2)) of
+ true ->
+ not_equal('StreamMode', SM1, SM2);
+ false ->
+ wrong_type('StreamMode', SM1, SM2)
+ end.
+
+
+%% -- PropertyParm --
+
+is_opt_PropertyParm(asn1_NOVALUE) ->
+ true;
+is_opt_PropertyParm(PP) ->
+ is_PropertyParm(PP).
+
+is_PropertyParm(#'PropertyParm'{name = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_PropertyParm -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_PkgdName(N) andalso
+ is_PropertyParm_value(V) andalso
+ is_PropertyParm_extraInfo(I);
+is_PropertyParm(_) ->
+ false.
+
+is_PropertyParm_value([]) ->
+ d("is_PropertyParm_value -> entry when done"),
+ true;
+is_PropertyParm_value([H|T]) ->
+ d("is_PropertyParm_value -> entry with"
+ "~n H: ~p", [H]),
+ is_OCTET_STRING(H) andalso is_PropertyParm_value(T);
+is_PropertyParm_value(_) ->
+ false.
+
+is_PropertyParm_extraInfo(asn1_NOVALUE) ->
+ true;
+is_PropertyParm_extraInfo({Tag, Val}) ->
+ d("is_PropertyParm_extraInfo -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_PropertyParm_extraInfo_tag(Tag) andalso
+ is_PropertyParm_extraInfo_val(Tag, Val);
+is_PropertyParm_extraInfo(_) ->
+ false.
+
+is_PropertyParm_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_PropertyParm_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_PropertyParm_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_PropertyParm_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+
+chk_opt_PropertyParm(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_PropertyParm(P1, P2) ->
+ chk_PropertyParm(P1, P2).
+
+chk_PropertyParm(P, P) ->
+ chk_type(fun is_PropertyParm/1, 'PropertyParm', P);
+chk_PropertyParm(#'PropertyParm'{name = N1,
+ value = V1,
+ extraInfo = I1},
+ #'PropertyParm'{name = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'PropertyParm'),
+ chk_PropertyParm_value(V1, V2),
+ chk_PropertyParm_extraInfo(I1, I2),
+ ok;
+chk_PropertyParm(P1, P2) ->
+ wrong_type('PropertyParm', P1, P2).
+
+chk_PropertyParm_value([], []) ->
+ ok;
+chk_PropertyParm_value([] = V1, V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value(V1, [] = V2) ->
+ not_equal('PropertyParm_value', V1, V2);
+chk_PropertyParm_value([H|T1], [H|T2]) ->
+ case is_OCTET_STRING(H) of
+ true ->
+ chk_PropertyParm_value(T1, T2);
+ false ->
+ wrong_type('PropertyParm_value_val', H)
+ end;
+chk_PropertyParm_value([H1|_], [H2|_]) ->
+ case (is_OCTET_STRING(H1) andalso is_OCTET_STRING(H2)) of
+ true ->
+ not_equal('PropertyParm_value_val', H1, H2);
+ false ->
+ wrong_type('PropertyParm_value_val', H1, H2)
+ end;
+chk_PropertyParm_value(V1, V2) ->
+ wrong_type('PropertyParm_value', V1, V2).
+
+chk_PropertyParm_extraInfo(EI, EI) ->
+ chk_type(fun is_PropertyParm_extraInfo/1, 'PropertyParm_extraInfo', EI);
+chk_PropertyParm_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_PropertyParm_extraInfo_tag(Tag) and
+ is_PropertyParm_extraInfo_val(Tag, Val1) and
+ is_PropertyParm_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_PropertyParm_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_PropertyParm_extraInfo_tag(Tag1) and
+ is_PropertyParm_extraInfo_val(Tag1, Val1)) and
+ (is_PropertyParm_extraInfo_tag(Tag2) and
+ is_PropertyParm_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('PropertyParm_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2)
+ end;
+chk_PropertyParm_extraInfo(EI1, EI2) ->
+ wrong_type('PropertyParm_extraInfo', EI1, EI2).
+
+chk_PropertyParm_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo');
+chk_PropertyParm_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'PropertyParm_extraInfo').
+
+
+%% -- Name --
+
+is_Name(N) ->
+ %% Binary: is_OCTET_STRING(N, {exact, 2}).
+ case is_OCTET_STRING(N, {range, 1, 64}) of
+ true ->
+ is_NAME(N);
+ false ->
+ false
+ end.
+
+is_NAME([H|T]) when (H =< $z) and ($a =< H) ->
+ is_NAME2(T);
+is_NAME([H|T]) when (H =< $Z) and ($A =< H) ->
+ is_NAME2(T);
+is_NAME(_) ->
+ false.
+
+is_NAME2([]) ->
+ true;
+is_NAME2([$_|T]) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when (H =< $z) and ($a =< H) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when (H =< $Z) and ($A =< H) ->
+ is_NAME2(T);
+is_NAME2([H|T]) when (H =< $9) and ($0 =< H) ->
+ is_NAME2(T);
+is_NAME2(_) ->
+ false.
+
+
+
+chk_Name(N, N) ->
+ chk_type(fun is_Name/1, 'Name', N);
+chk_Name(N1, N2) ->
+ case (is_Name(N1) andalso is_Name(N2)) of
+ true ->
+ not_equal('Name', N1, N2);
+ false ->
+ wrong_type('Name', N1, N2)
+ end.
+
+
+%% -- PkgdName --
+
+%% PkgdName is either "AB/CD" or just plain "ABCD"
+%% Note that in ASN.1 the parts is exactly 2 char
+%% each, unless you don't use the native config
+%% option. In text and in binary without the native
+%% option, it is 63 + 1 chars for each.
+is_PkgdName(N) ->
+ d("is_PkgdName -> entry with"
+ "~n N: ~p", [N]),
+ case string:tokens(N, "/") of
+ ["*" = PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (0): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ true;
+ [PackageName, "*" = ItemID] ->
+ d("is_PkgdName -> tokenized (1): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName);
+ [PackageName, ItemID] ->
+ d("is_PkgdName -> tokenized (2): "
+ "~n PackageName: ~p"
+ "~n ItemID: ~p", [PackageName, ItemID]),
+ is_Name(PackageName) andalso is_Name(ItemID);
+ _ ->
+ is_Name(N)
+ end.
+
+chk_PkgdName(N, N) ->
+ case is_PkgdName(N) of
+ true ->
+ ok;
+ false ->
+ wrong_type('PkgdName', N, N)
+ end;
+chk_PkgdName(N1, N2) ->
+ case (is_PkgdName(N1) andalso is_PkgdName(N2)) of
+ true ->
+ not_equal('PkgdName', N1, N2);
+ false ->
+ wrong_type('PkgdName', N1, N2)
+ end.
+
+
+%% -- Relation --
+
+is_Relation(R) ->
+ lists:member(R, [greaterThan, smallerThan, unequalTo]).
+
+chk_Relation(R, R) ->
+ chk_type(fun is_Relation/1, 'Relation', R);
+chk_Relation(R1, R2) ->
+ case (is_Relation(R1) andalso is_Relation(R2)) of
+ true ->
+ not_equal('Relation', R1, R2);
+ false ->
+ wrong_type('Relation', R1, R2)
+ end.
+
+
+%% -- LocalRemoteDescriptor --
+
+is_opt_LocalRemoteDescriptor(D) ->
+ d("is_LocalRemoteDescriptor -> entry"),
+ is_OPTIONAL(fun is_LocalRemoteDescriptor/1, D).
+
+is_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PGs}) ->
+ d("is_LocalRemoteDescriptor -> entry with"
+ "~n PGs: ~p", [PGs]),
+ is_LocalRemoteDescriptor_propGrps(PGs);
+is_LocalRemoteDescriptor(_) ->
+ false.
+
+is_LocalRemoteDescriptor_propGrps([]) ->
+ true;
+is_LocalRemoteDescriptor_propGrps([H|T]) ->
+ is_PropertyGroup(H) andalso is_LocalRemoteDescriptor_propGrps(T);
+is_LocalRemoteDescriptor_propGrps(_) ->
+ false.
+
+chk_opt_LocalRemoteDescriptor(D1, D2) ->
+ chk_OPTIONAL('LocalRemoteDescriptor', D1, D2,
+ fun is_LocalRemoteDescriptor/1,
+ fun chk_LocalRemoteDescriptor/2).
+
+chk_LocalRemoteDescriptor(LRD, LRD) ->
+ chk_type(fun is_LocalRemoteDescriptor/1, 'LocalRemoteDescriptor', LRD);
+chk_LocalRemoteDescriptor(#'LocalRemoteDescriptor'{propGrps = PG1},
+ #'LocalRemoteDescriptor'{propGrps = PG2}) ->
+ chk_LocalRemoteDescriptor_propGrps(PG1, PG2),
+ ok;
+chk_LocalRemoteDescriptor(LRD1, LRD2) ->
+ wrong_type('LocalRemoteDescriptor', LRD1, LRD2).
+
+chk_LocalRemoteDescriptor_propGrps([], []) ->
+ ok;
+chk_LocalRemoteDescriptor_propGrps([] = PG1, PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps(PG1, [] = PG2) ->
+ not_equal('LocalRemoteDescriptor_propGrps', PG1, PG2);
+chk_LocalRemoteDescriptor_propGrps([H|T1], [H|T2]) ->
+ case is_PropertyGroup(H) of
+ true ->
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+ false ->
+ wrong_type('LocalRemoteDescriptor_propGrps_val', H)
+ end;
+chk_LocalRemoteDescriptor_propGrps([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyGroup(H1, H2) end,
+ 'LocalRemoteDescriptor_propGrps_val'),
+ chk_LocalRemoteDescriptor_propGrps(T1, T2);
+chk_LocalRemoteDescriptor_propGrps(PG1, PG2) ->
+ wrong_type('LocalRemoteDescriptor_propGrps', PG1, PG2).
+
+
+%% -- PropertyGroup --
+
+is_PropertyGroup([]) ->
+ true;
+is_PropertyGroup([H|T]) ->
+ is_PropertyParm(H) andalso is_PropertyGroup(T);
+is_PropertyGroup(_) ->
+ false.
+
+chk_PropertyGroup([], []) ->
+ ok;
+chk_PropertyGroup([] = PG1, PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup(PG1, [] = PG2) ->
+ not_equal('PropertyGroup', PG1, PG2);
+chk_PropertyGroup([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_PropertyGroup(T1, T2);
+ false ->
+ wrong_type('PropertyGroup_val', H)
+ end;
+chk_PropertyGroup([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'PropertyGroup_val'),
+ chk_PropertyGroup(T1, T2);
+chk_PropertyGroup(PG1, PG2) ->
+ wrong_type('PropertyGroup', PG1, PG2).
+
+
+%% -- TerminationStateDescriptor --
+
+is_opt_TerminationStateDescriptor(D) ->
+ is_OPTIONAL(fun is_TerminationStateDescriptor/1, D).
+
+is_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP,
+ eventBufferControl = EBC,
+ serviceState = SS}) ->
+ is_TerminationStateDescriptor_propertyParms(PP) andalso
+ is_opt_EventBufferControl(EBC) andalso
+ is_opt_ServiceState(SS);
+is_TerminationStateDescriptor(_) ->
+ false.
+
+is_TerminationStateDescriptor_propertyParms([]) ->
+ true;
+is_TerminationStateDescriptor_propertyParms([H|T]) ->
+ is_PropertyParm(H) andalso is_TerminationStateDescriptor_propertyParms(T);
+is_TerminationStateDescriptor_propertyParms(_) ->
+ false.
+
+chk_opt_TerminationStateDescriptor(D1, D2) ->
+ chk_OPTIONAL('TerminationStateDescriptor', D1, D2,
+ fun is_TerminationStateDescriptor/1,
+ fun chk_TerminationStateDescriptor/2).
+
+chk_TerminationStateDescriptor(D, D) ->
+ chk_type(fun is_TerminationStateDescriptor/1,
+ 'TerminationStateDescriptor', D);
+chk_TerminationStateDescriptor(
+ #'TerminationStateDescriptor'{propertyParms = PP1,
+ eventBufferControl = EBC1,
+ serviceState = SS1},
+ #'TerminationStateDescriptor'{propertyParms = PP2,
+ eventBufferControl = EBC2,
+ serviceState = SS2}) ->
+ chk_TerminationStateDescriptor_propertyParms(PP1, PP2),
+ validate(
+ fun() ->
+ chk_opt_EventBufferControl(EBC1, EBC2)
+ end,
+ 'TerminationStateDescriptor'),
+ validate(
+ fun() ->
+ chk_opt_ServiceState(SS1, SS2)
+ end,
+ 'TerminationStateDescriptor'),
+ ok;
+chk_TerminationStateDescriptor(D1, D2) ->
+ wrong_type('TerminationStateDescriptor', D1, D2).
+
+
+chk_TerminationStateDescriptor_propertyParms([], []) ->
+ ok;
+chk_TerminationStateDescriptor_propertyParms([] = P1, P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms(P1, [] = P2) ->
+ not_equal('TerminationStateDescriptor_propertyParms', P1, P2);
+chk_TerminationStateDescriptor_propertyParms([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_TerminationStateDescriptor_propertyParms(T1, T2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H)
+ end;
+chk_TerminationStateDescriptor_propertyParms([H1|_], [H2|_]) ->
+ case (is_PropertyParm(H1) andalso is_PropertyParm(H2)) of
+ true ->
+ not_equal('TerminationStateDescriptor_propertyParms_val', H1, H2);
+ false ->
+ wrong_type('TerminationStateDescriptor_propertyParms_val', H1, H2)
+ end;
+chk_TerminationStateDescriptor_propertyParms(P1, P2) ->
+ wrong_type('TerminationStateDescriptor_propertyParms', P1, P2).
+
+
+%% -- EventBufferControl --
+
+is_opt_EventBufferControl(asn1_NOVALUE) ->
+ true;
+is_opt_EventBufferControl(EBC) ->
+ is_EventBufferControl(EBC).
+
+is_EventBufferControl(EBC) ->
+ lists:member(EBC, [off, lockStep]).
+
+chk_opt_EventBufferControl(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_EventBufferControl(EBC1, EBC2) ->
+ chk_EventBufferControl(EBC1, EBC2).
+
+chk_EventBufferControl(EBC, EBC) ->
+ chk_type(fun is_EventBufferControl/1, 'EventBufferControl', EBC);
+chk_EventBufferControl(EBC1, EBC2) ->
+ case (is_EventBufferControl(EBC1) andalso is_EventBufferControl(EBC2)) of
+ true ->
+ not_equal('EventBufferControl', EBC1, EBC2);
+ false ->
+ wrong_type('EventBufferControl', EBC1, EBC2)
+ end.
+
+
+%% -- ServiceState --
+
+is_opt_ServiceState(asn1_NOVALUE) ->
+ true;
+is_opt_ServiceState(SS) ->
+ is_ServiceState(SS).
+
+is_ServiceState(SS) ->
+ lists:member(SS, [test, outOfSvc, inSvc]).
+
+chk_opt_ServiceState(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_ServiceState(SS1, SS2) ->
+ chk_ServiceState(SS1, SS2).
+
+chk_ServiceState(SS, SS) ->
+ chk_type(fun is_ServiceState/1, 'ServiceState', SS);
+chk_ServiceState(SS1, SS2) ->
+ case (is_ServiceState(SS1) andalso is_ServiceState(SS2)) of
+ true ->
+ not_equal('ServiceState', SS1, SS2);
+ false ->
+ wrong_type('ServiceState', SS1, SS2)
+ end.
+
+
+%% -- MuxDescriptor --
+
+is_MuxDescriptor(#'MuxDescriptor'{muxType = MT,
+ termList = TL,
+ nonStandardData = NSD}) ->
+ is_MuxType(MT) andalso
+ is_MuxDescriptor_termList(TL) andalso
+ is_NonStandardData(NSD);
+is_MuxDescriptor(_) ->
+ false.
+
+is_MuxDescriptor_termList([]) ->
+ true;
+is_MuxDescriptor_termList([H|T]) ->
+ is_TerminationID(H) andalso is_MuxDescriptor_termList(T);
+is_MuxDescriptor_termList(_) ->
+ false.
+
+chk_MuxDescriptor(D, D) ->
+ chk_type(fun is_MuxDescriptor/1, 'MuxDescriptor', D);
+chk_MuxDescriptor(#'MuxDescriptor'{muxType = MT1,
+ termList = TL1,
+ nonStandardData = NSD1},
+ #'MuxDescriptor'{muxType = MT2,
+ termList = TL2,
+ nonStandardData = NSD2}) ->
+ validate(fun() -> chk_MuxType(MT1, MT2) end, 'MuxDescriptor'),
+ chk_MuxDescriptor_termList(TL1, TL2),
+ validate(fun() -> chk_NonStandardData(NSD1, NSD2) end, 'MuxDescriptor'),
+ ok;
+chk_MuxDescriptor(D1, D2) ->
+ wrong_type('MuxDescriptor', D1, D2).
+
+chk_MuxDescriptor_termList([], []) ->
+ ok;
+chk_MuxDescriptor_termList([] = TL1, TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList(TL1, [] = TL2) ->
+ not_equal('MuxDescriptor_termList', TL1, TL2);
+chk_MuxDescriptor_termList([H|T1], [H|T2]) ->
+ case is_TerminationID(H) of
+ true ->
+ chk_MuxDescriptor_termList(T1, T2);
+ false ->
+ wrong_type('MuxDescriptor_termList_val', H)
+ end;
+chk_MuxDescriptor_termList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_TerminationID(H1, H2) end,
+ 'MuxDescriptor_termList_val'),
+ chk_MuxDescriptor_termList(T1, T2);
+chk_MuxDescriptor_termList(TL1, TL2) ->
+ wrong_type('MuxDescriptor_termList', TL1, TL2).
+
+
+%% -- MuxType --
+
+is_MuxType(MT) ->
+ lists:member(MT, [h221, h223, h226, v76, nx64k]).
+
+chk_MuxType(MT, MT) ->
+ chk_type(fun is_MuxType/1, 'MuxType', MT);
+chk_MuxType(MT1, MT2) ->
+ case (is_MuxType(MT1) andalso is_MuxType(MT2)) of
+ true ->
+ not_equal('MuxType', MT1, MT2);
+ false ->
+ wrong_type('MuxType', MT1, MT2)
+ end.
+
+
+%% -- StreamID --
+
+is_opt_StreamID(V) ->
+ is_OPTIONAL(fun is_StreamID/1, V).
+
+is_StreamID(V) ->
+ d("is_StreamID -> entry with"
+ "~n V: ~p", [V]),
+ is_INTEGER(V, {range, 0, 65535}).
+
+chk_opt_StreamID(V1, V2) ->
+ chk_OPTIONAL('StreamID', V1, V2, fun is_StreamID/1, fun chk_StreamID/2).
+
+chk_StreamID(ID, ID) ->
+ chk_type(fun is_StreamID/1, 'StreamID', ID);
+chk_StreamID(ID1, ID2) ->
+ case (is_StreamID(ID1) andalso is_StreamID(ID2)) of
+ true ->
+ not_equal('StreamID', ID1, ID2);
+ false ->
+ wrong_type('StreamID', ID1, ID2)
+ end.
+
+
+%% -- EventsDescriptor --
+
+is_EventsDescriptor(#'EventsDescriptor'{requestID = RID,
+ eventList = EVL}) ->
+ d("is_EventsDescriptor -> entry with"
+ "~n RID: ~p"
+ "~n EVL: ~p", [RID, EVL]),
+ is_opt_RequestID(RID) andalso is_EventsDescriptor_eventList(EVL);
+is_EventsDescriptor(_) ->
+ false.
+
+is_EventsDescriptor_eventList([]) ->
+ true;
+is_EventsDescriptor_eventList([H|T]) ->
+ is_RequestedEvent(H) andalso is_EventsDescriptor_eventList(T);
+is_EventsDescriptor_eventList(_) ->
+ false.
+
+chk_EventsDescriptor(D, D) ->
+ chk_type(fun is_EventsDescriptor/1, 'EventsDescriptor', D);
+chk_EventsDescriptor(#'EventsDescriptor'{requestID = RID1,
+ eventList = EVL1},
+ #'EventsDescriptor'{requestID = RID2,
+ eventList = EVL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end, 'EventsDescriptor'),
+ chk_EventsDescriptor_eventList(EVL1, EVL2),
+ ok;
+chk_EventsDescriptor(D1, D2) ->
+ wrong_type('EventsDescriptor', D1, D2).
+
+chk_EventsDescriptor_eventList([], []) ->
+ ok;
+chk_EventsDescriptor_eventList([] = EVL1, EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList(EVL1, [] = EVL2) ->
+ not_equal('EventsDescriptor_eventList', EVL1, EVL2);
+chk_EventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_RequestedEvent(H) of
+ true ->
+ chk_EventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('EventsDescriptor_eventList_val', H)
+ end;
+chk_EventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_RequestedEvent(H1, H2) end,
+ 'EventsDescriptor_eventList_val'),
+ chk_EventsDescriptor_eventList(T1, T2);
+chk_EventsDescriptor_eventList(EVL1, EVL2) ->
+ wrong_type('EventsDescriptor_eventList', EVL1, EVL2).
+
+
+%% -- RequestedEvent --
+
+is_RequestedEvent(#'RequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ d("is_RequestedEvent -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n EA: ~p"
+ "~n EPL: ~p", [N, SID, EA, EPL]),
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_RequestedActions(EA) andalso
+ is_RequestedEvent_evParList(EPL);
+is_RequestedEvent(_) ->
+ false.
+
+is_RequestedEvent_evParList([]) ->
+ true;
+is_RequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_RequestedEvent_evParList(T);
+is_RequestedEvent_evParList(_) ->
+ false.
+
+chk_RequestedEvent(RE, RE) ->
+ chk_type(fun is_RequestedEvent/1, 'RequestedEvent', RE);
+chk_RequestedEvent(#'RequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'RequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'RequestedEvent'),
+ validate(fun() -> chk_opt_RequestedActions(EA1, EA2) end,
+ 'RequestedEvent'),
+ chk_RequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_RequestedEvent(RE1, RE2) ->
+ wrong_type('RequestedEvent', RE1, RE2).
+
+chk_RequestedEvent_evParList([], []) ->
+ ok;
+chk_RequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('RequestedEvent_evParList', EPL1, EPL2);
+chk_RequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_RequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('RequestedEvent_evParList_val', H)
+ end;
+chk_RequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'RequestedEvent_evParList_val'),
+ chk_RequestedEvent_evParList(T1, T2);
+chk_RequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('RequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- RegulatedEmbeddedDescriptor --
+
+is_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE,
+ signalsDescriptor = SD}) ->
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD);
+is_RegulatedEmbeddedDescriptor(_) ->
+ false.
+
+
+chk_RegulatedEmbeddedDescriptor(
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE1,
+ signalsDescriptor = SD1},
+ #'RegulatedEmbeddedDescriptor'{secondEvent = SE2,
+ signalsDescriptor = SD2}) ->
+ chk_RegulatedEmbeddedDescriptor_secondEvent(SE1, SE2),
+ chk_RegulatedEmbeddedDescriptor_signalsDescriptor(SD1, SD2),
+ ok;
+chk_RegulatedEmbeddedDescriptor(RED1, RED2) ->
+ wrong_type('RegulatedEmbeddedDescriptor', RED1, RED2).
+
+chk_RegulatedEmbeddedDescriptor_secondEvent(SE1, SE2) ->
+ validate(fun() -> chk_opt_SecondEventsDescriptor(SE1, SE2) end,
+ 'RegulatedEmbeddedDescriptor_secondEvent').
+
+chk_RegulatedEmbeddedDescriptor_signalsDescriptor(SD1, SD2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(SD1, SD2) end,
+ 'RegulatedEmbeddedDescriptor_signalsDescriptor').
+
+
+%% -- NotifyBehaviour --
+
+tags_NotifyBehaviour() ->
+ [
+ {notifyImmediate,
+ fun is_NULL/1,
+ fun chk_NULL/2},
+
+ {notifyRegulated,
+ fun is_RegulatedEmbeddedDescriptor/1,
+ fun chk_RegulatedEmbeddedDescriptor/2},
+
+ {neverNotify,
+ fun is_NULL/1,
+ fun chk_NULL/2}
+ ].
+
+is_opt_NotifyBehaviour(asn1_NOVALUE) ->
+ true;
+is_opt_NotifyBehaviour(NB) ->
+ is_NotifyBehaviour(NB).
+
+is_NotifyBehaviour(NB) ->
+ is_CHOICE(NB, tags_NotifyBehaviour()).
+
+chk_opt_NotifyBehaviour(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_NotifyBehaviour(NB1, NB2) ->
+ chk_NotifyBehaviour(NB1, NB2).
+
+chk_NotifyBehaviour(NB1, NB2) ->
+ chk_CHOICE(NB1, NB2, 'NotifyBehaviour', tags_NotifyBehaviour()).
+
+
+%% -- RequestedActions --
+
+is_opt_RequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_RequestedActions(RA) ->
+ is_RequestedActions(RA).
+
+is_RequestedActions(#'RequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ secondEvent = SE,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ d("is_RequestedActions -> entry with"
+ "~n KA: ~p"
+ "~n EDM: ~p"
+ "~n SE: ~p"
+ "~n SD: ~p"
+ "~n NB: ~p"
+ "~n RED: ~p", [KA, EDM, SE, SD, NB, RED]),
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SecondEventsDescriptor(SE) andalso
+ is_opt_SignalsDescriptor(SD) andalso
+ is_opt_NotifyBehaviour(SD) andalso
+ is_opt_NULL(SD);
+is_RequestedActions(_) ->
+ false.
+
+chk_opt_RequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestedActions(RA1, RA2) ->
+ chk_RequestedActions(RA1, RA2).
+
+chk_RequestedActions(RA, RA) ->
+ chk_type(fun is_RequestedActions/1, 'RequestedActions', RA);
+chk_RequestedActions(#'RequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ secondEvent = SE1,
+ signalsDescriptor = SD1,
+ notifyBehaviour = NB1,
+ resetEventsDescriptor = RED1},
+ #'RequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ secondEvent = SE2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RED2}) ->
+ chk_RequestedActions_keepActive(KA1, KA2),
+ chk_RequestedActions_eventDM(EDM1, EDM2),
+ chk_RequestedActions_secondEvent(SE1, SE2),
+ chk_RequestedActions_signalsDescriptor(SD1, SD2),
+ chk_RequestedActions_notifyBehaviour(NB1, NB2),
+ chk_RequestedActions_resetEventsDescriptor(RED1, RED2),
+ ok;
+chk_RequestedActions(RA1, RA2) ->
+ wrong_type('RequestedActions', RA1, RA2).
+
+chk_RequestedActions_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end,
+ 'RequestedActions_keepActive').
+
+chk_RequestedActions_eventDM(V1, V2) ->
+ validate(fun() -> chk_opt_EventDM(V1, V2) end,
+ 'RequestedActions_eventDM').
+
+chk_RequestedActions_secondEvent(V1, V2) ->
+ validate(fun() -> chk_opt_SecondEventsDescriptor(V1, V2) end,
+ 'RequestedActions_secondEvent').
+
+chk_RequestedActions_signalsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(V1, V2) end,
+ 'RequestedActions_signalsDescriptor').
+
+chk_RequestedActions_notifyBehaviour(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyBehaviour(V1, V2) end,
+ 'RequestedActions_notifyBehaviour').
+
+chk_RequestedActions_resetEventsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_NULL(V1, V2) end,
+ 'RequestedActions_resetEventsDescriptor').
+
+
+%% -- EventDM --
+
+is_opt_EventDM(EDM) ->
+ is_OPTIONAL(fun is_EventDM/1, EDM).
+
+is_EventDM({Tag, Val}) ->
+ is_EventDM_tag(Tag) andalso is_EventDM_val(Tag, Val);
+is_EventDM(_) ->
+ false.
+
+is_EventDM_tag(Tag) ->
+ Tags = [digitMapName, digitMapValue],
+ lists:member(Tag, Tags).
+
+is_EventDM_val(digitMapName, Val) ->
+ is_DigitMapName(Val);
+is_EventDM_val(digitMapValue, Val) ->
+ is_DigitMapValue(Val).
+
+chk_opt_EventDM(EDM1, EDM2) ->
+ chk_OPTIONAL('EventDM', EDM1, EDM2, fun is_EventDM/1, fun chk_EventDM/2).
+
+chk_EventDM(EDM, EDM) ->
+ chk_type(fun is_EventDM/1, 'EventDM', EDM);
+chk_EventDM({Tag, Val1} = EDM1, {Tag, Val2} = EDM2) ->
+ case (is_EventDM_tag(Tag) andalso
+ is_EventDM_val(Tag, Val1) andalso
+ is_EventDM_val(Tag, Val2)) of
+ true ->
+ chk_EventDM_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM({Tag1, Val1} = EDM1, {Tag2, Val2} = EDM2) ->
+ case ((is_EventDM_tag(Tag1) andalso
+ is_EventDM_val(Tag1, Val1)) andalso
+ (is_EventDM_tag(Tag2) andalso
+ is_EventDM_val(Tag2, Val2))) of
+ true ->
+ not_equal('EventDM', EDM1, EDM2);
+ false ->
+ wrong_type('EventDM', EDM1, EDM2)
+ end;
+chk_EventDM(EDM1, EDM2) ->
+ wrong_type('EventDM', EDM1, EDM2).
+
+chk_EventDM_val(digitMapName, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapName(Val1, Val2) end, 'EventDM');
+chk_EventDM_val(digitMapValue, Val1, Val2) ->
+ validate(fun() -> chk_DigitMapValue(Val1, Val2) end, 'EventDM').
+
+
+%% -- SecondEventsDescriptor --
+
+is_opt_SecondEventsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SecondEventsDescriptor(D) ->
+ is_SecondEventsDescriptor(D).
+
+is_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID,
+ eventList = EL}) ->
+ is_opt_RequestID(RID) andalso is_SecondEventsDescriptor_eventList(EL);
+is_SecondEventsDescriptor(_) ->
+ false.
+
+is_SecondEventsDescriptor_eventList([]) ->
+ true;
+is_SecondEventsDescriptor_eventList([H|T]) ->
+ is_SecondRequestedEvent(H) andalso is_SecondEventsDescriptor_eventList(T);
+is_SecondEventsDescriptor_eventList(_) ->
+ false.
+
+chk_opt_SecondEventsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondEventsDescriptor(D1, D2) ->
+ chk_SecondEventsDescriptor(D1, D2).
+
+chk_SecondEventsDescriptor(D, D) ->
+ chk_type(fun is_SecondEventsDescriptor/1, 'SecondEventsDescriptor', D);
+chk_SecondEventsDescriptor(#'SecondEventsDescriptor'{requestID = RID1,
+ eventList = EL1},
+ #'SecondEventsDescriptor'{requestID = RID2,
+ eventList = EL2}) ->
+ validate(fun() -> chk_opt_RequestID(RID1, RID2) end,
+ 'SecondEventsDescriptor'),
+ chk_SecondEventsDescriptor_eventList(EL1, EL2),
+ ok;
+chk_SecondEventsDescriptor(D1, D2) ->
+ wrong_type('SecondEventsDescriptor', D1, D2).
+
+chk_SecondEventsDescriptor_eventList([], []) ->
+ ok;
+chk_SecondEventsDescriptor_eventList([] = EL1, EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList(EL1, [] = EL2) ->
+ not_equal('SecondEventsDescriptor_eventList', EL1, EL2);
+chk_SecondEventsDescriptor_eventList([H|T1], [H|T2]) ->
+ case is_SecondRequestedEvent(H) of
+ true ->
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+ false ->
+ wrong_type('SecondEventsDescriptor_eventList_val', H)
+ end;
+chk_SecondEventsDescriptor_eventList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SecondRequestedEvent(H1, H2) end,
+ 'SecondEventsDescriptor_eventList_val'),
+ chk_SecondEventsDescriptor_eventList(T1, T2);
+chk_SecondEventsDescriptor_eventList(L1, L2) ->
+ wrong_type('SecondEventsDescriptor_eventList_val', L1, L2).
+
+
+%% -- SecondRequestedEvent --
+
+is_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N,
+ streamID = SID,
+ eventAction = EA,
+ evParList = EPL}) ->
+ is_PkgdName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SecondRequestedActions(EA) andalso
+ is_SecondRequestedEvent_evParList(EPL);
+is_SecondRequestedEvent(_) ->
+ false.
+
+is_SecondRequestedEvent_evParList([]) ->
+ true;
+is_SecondRequestedEvent_evParList([H|T]) ->
+ is_EventParameter(H) andalso is_SecondRequestedEvent_evParList(T);
+is_SecondRequestedEvent_evParList(_) ->
+ false.
+
+chk_SecondRequestedEvent(RE, RE) ->
+ chk_type(fun is_SecondRequestedEvent/1, 'SecondRequestedEvent', RE);
+chk_SecondRequestedEvent(#'SecondRequestedEvent'{pkgdName = N1,
+ streamID = SID1,
+ eventAction = EA1,
+ evParList = EPL1},
+ #'SecondRequestedEvent'{pkgdName = N2,
+ streamID = SID2,
+ eventAction = EA2,
+ evParList = EPL2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end,
+ 'SecondRequestedEvent'),
+ validate(fun() -> chk_opt_SecondRequestedActions(EA1, EA2) end,
+ 'SecondRequestedEvent'),
+ chk_SecondRequestedEvent_evParList(EPL1, EPL2),
+ ok;
+chk_SecondRequestedEvent(RE1, RE2) ->
+ wrong_type('SecondRequestedEvent', RE1, RE2).
+
+chk_SecondRequestedEvent_evParList([], []) ->
+ ok;
+chk_SecondRequestedEvent_evParList([] = EPL1, EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList(EPL1, [] = EPL2) ->
+ not_equal('SecondRequestedEvent_evParList', EPL1, EPL2);
+chk_SecondRequestedEvent_evParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_SecondRequestedEvent_evParList(T1, T2);
+ false ->
+ wrong_type('SecondRequestedEvent_evParList_val', H)
+ end;
+chk_SecondRequestedEvent_evParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'SecondRequestedEvent_evParList_val'),
+ chk_SecondRequestedEvent_evParList(T1, T2);
+chk_SecondRequestedEvent_evParList(EPL1, EPL2) ->
+ wrong_type('SecondRequestedEvent_evParList', EPL1, EPL2).
+
+
+%% -- SecondRequestedActions --
+
+is_opt_SecondRequestedActions(asn1_NOVALUE) ->
+ true;
+is_opt_SecondRequestedActions(SRA) ->
+ is_SecondRequestedActions(SRA).
+
+is_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA,
+ eventDM = EDM,
+ signalsDescriptor = SD,
+ notifyBehaviour = NB,
+ resetEventsDescriptor = RED}) ->
+ is_opt_BOOLEAN(KA) andalso
+ is_opt_EventDM(EDM) andalso
+ is_opt_SignalsDescriptor(SD) andalso
+ is_opt_NotifyBehaviour(NB) andalso
+ is_opt_NULL(RED);
+is_SecondRequestedActions(_) ->
+ false.
+
+chk_opt_SecondRequestedActions(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SecondRequestedActions(SRA1, SRA2) ->
+ chk_SecondRequestedActions(SRA1, SRA2).
+
+chk_SecondRequestedActions(SRA, SRA) ->
+ chk_type(fun is_SecondRequestedActions/1, 'SecondRequestedActions', SRA);
+chk_SecondRequestedActions(
+ #'SecondRequestedActions'{keepActive = KA1,
+ eventDM = EDM1,
+ signalsDescriptor = SD1,
+ notifyBehaviour = NB1,
+ resetEventsDescriptor = RED1},
+ #'SecondRequestedActions'{keepActive = KA2,
+ eventDM = EDM2,
+ signalsDescriptor = SD2,
+ notifyBehaviour = NB2,
+ resetEventsDescriptor = RED2}) ->
+ chk_SecondRequestedActions_keepActive(KA1, KA2),
+ chk_SecondRequestedActions_eventDM(EDM1, EDM2),
+ chk_SecondRequestedActions_signalsDescriptor(SD1, SD2),
+ chk_SecondRequestedActions_notifyBehaviour(NB1, NB2),
+ chk_SecondRequestedActions_resetEventsDescriptor(RED1, RED2),
+ ok;
+chk_SecondRequestedActions(SRA1, SRA2) ->
+ wrong_type('SecondRequestedActions', SRA1, SRA2).
+
+chk_SecondRequestedActions_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end,
+ 'SecondRequestedActions_keepActive').
+
+chk_SecondRequestedActions_eventDM(V1, V2) ->
+ validate(fun() -> chk_opt_EventDM(V1, V2) end,
+ 'SecondRequestedActions_eventDM').
+
+chk_SecondRequestedActions_signalsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_SignalsDescriptor(V1, V2) end,
+ 'SecondRequestedActions_signalsDescriptor').
+
+chk_SecondRequestedActions_notifyBehaviour(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyBehaviour(V1, V2) end,
+ 'SecondRequestedActions_notifyBehaviour').
+
+chk_SecondRequestedActions_resetEventsDescriptor(V1, V2) ->
+ validate(fun() -> chk_opt_NULL(V1, V2) end,
+ 'SecondRequestedActions_resetEventsDescriptor').
+
+
+%% -- EventBufferDescriptor --
+
+is_EventBufferDescriptor(D) ->
+ is_SEQUENCE_OF(D, fun is_EventSpec/1).
+
+chk_EventBufferDescriptor(D1, D2) ->
+ chk_SEQUENCE_OF(D1, D2, 'EventBufferDescriptor',
+ fun is_EventSpec/1, fun chk_EventSpec/2).
+
+
+%% -- EventSpec --
+
+is_EventSpec(#'EventSpec'{eventName = N,
+ streamID = SID,
+ eventParList = EPL}) ->
+ is_EventName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_EventSpec_eventParList(EPL);
+is_EventSpec(_) ->
+ false.
+
+is_EventSpec_eventParList([]) ->
+ true;
+is_EventSpec_eventParList([H|T]) ->
+ is_EventParameter(H) andalso is_EventSpec_eventParList(T);
+is_EventSpec_eventParList(_) ->
+ false.
+
+chk_EventSpec(ES, ES) ->
+ chk_type(fun is_EventSpec/1, 'EventSpec', ES);
+chk_EventSpec(#'EventSpec'{eventName = N1,
+ streamID = SID1,
+ eventParList = EPL1},
+ #'EventSpec'{eventName = N2,
+ streamID = SID2,
+ eventParList = EPL2}) ->
+ validate(fun() -> chk_EventName(N1, N2) end, 'EventSpec'),
+ validate(fun() -> chk_opt_StreamID(SID1, SID2) end, 'EventSpec'),
+ chk_EventSpec_eventParList(EPL1, EPL2),
+ ok;
+chk_EventSpec(ES1, ES2) ->
+ wrong_type('EventSpec', ES1, ES2).
+
+chk_EventSpec_eventParList([], []) ->
+ ok;
+chk_EventSpec_eventParList([] = EPL1, EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList(EPL1, [] = EPL2) ->
+ not_equal('EventSpec_eventParList', EPL1, EPL2);
+chk_EventSpec_eventParList([H|T1], [H|T2]) ->
+ case is_EventParameter(H) of
+ true ->
+ chk_EventSpec_eventParList(T1, T2);
+ false ->
+ wrong_type('EventSpec_eventParList_val', H)
+ end;
+chk_EventSpec_eventParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_EventParameter(H1, H2) end,
+ 'EventSpec_eventParList_val'),
+ chk_EventSpec_eventParList(T1, T2);
+chk_EventSpec_eventParList(EPL1, EPL2) ->
+ wrong_type('EventSpec_eventParList', EPL1, EPL2).
+
+
+%% -- SignalsDescriptor --
+
+is_opt_SignalsDescriptor(asn1_NOVALUE) ->
+ true;
+is_opt_SignalsDescriptor(D) ->
+ is_SignalsDescriptor(D).
+
+is_SignalsDescriptor(D) ->
+ is_SEQUENCE_OF(D, fun is_SignalRequest/1).
+
+chk_opt_SignalsDescriptor(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_SignalsDescriptor(D1, D2) ->
+ chk_SignalsDescriptor(D1, D2).
+
+chk_SignalsDescriptor(D1, D2) ->
+ chk_SEQUENCE_OF(D1, D2, 'SignalsDescriptor',
+ fun is_SignalRequest/1, fun chk_SignalRequest/2).
+
+
+%% -- SignalRequest --
+
+tags_SignalRequest() ->
+ [
+ {signal, fun is_Signal/1, fun chk_Signal/2},
+ {seqSigList, fun is_SeqSigList/1, fun chk_SeqSigList/2}
+ ].
+
+is_SignalRequest(SR) ->
+ is_CHOICE(SR, tags_SignalRequest()).
+
+chk_SignalRequest(R1, R2) ->
+ chk_CHOICE(R1, R2, 'SignalRequest', tags_SignalRequest()).
+
+
+%% -- SeqSigList --
+
+%% fields_SeqSigList() ->
+%% [
+%% {id,
+%% 'INTEGER(0,65535)',
+%% fun(ID) -> is_INTEGER(ID, {range, 0, 65535}) end,
+%% fun(ID1, ID2) -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end},
+
+%% {signalList,
+%% 'SEQUENCE OF Signal',
+%% fun(S) ->
+%% is_SEQUENCE_OF(S, fun is_Signal/1)
+%% end,
+%% fun(S1, S2) ->
+%% chk_SEQUENCE_OF(S1, S2, fun is_Signal/1, fun chk_Signal/2)
+%% end}
+%% ].
+
+%% is_SeqSigList(V) ->
+%% is_SEQUENCE(V, 'SeqSigList', fields_SeqSigList()).
+
+
+is_SeqSigList(#'SeqSigList'{id = ID,
+ signalList = SL}) ->
+ is_INTEGER(ID, {range, 0, 65535}) andalso
+ is_SeqSigList_signalList(SL);
+is_SeqSigList(_) ->
+ false.
+
+is_SeqSigList_signalList([]) ->
+ true;
+is_SeqSigList_signalList([H|T]) ->
+ is_Signal(H) andalso is_SeqSigList_signalList(T);
+is_SeqSigList_signalList(_) ->
+ false.
+
+chk_SeqSigList(L, L) ->
+ chk_type(fun is_SeqSigList/1, 'SeqSigList', L);
+chk_SeqSigList(#'SeqSigList'{id = ID1,
+ signalList = SL1},
+ #'SeqSigList'{id = ID2,
+ signalList = SL2}) ->
+ validate(fun() -> chk_INTEGER(ID1, ID2, {range, 0, 65535}) end,
+ 'SeqSigList'),
+ chk_SeqSigList_signalList(SL1, SL2),
+ ok;
+chk_SeqSigList(L1, L2) ->
+ wrong_type('SeqSigList', L1, L2).
+
+chk_SeqSigList_signalList([], []) ->
+ ok;
+chk_SeqSigList_signalList([] = L1, L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList(L1, [] = L2) ->
+ not_equal('SeqSigList_signalList', L1, L2);
+chk_SeqSigList_signalList([H|T1], [H|T2]) ->
+ case is_Signal(H) of
+ true ->
+ chk_SeqSigList_signalList(T1, T2);
+ false ->
+ wrong_type('SeqSigList_signalList_val', H)
+ end;
+chk_SeqSigList_signalList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_Signal(H1, H2) end,
+ 'SeqSigList_signalList_val'),
+ chk_SeqSigList_signalList(T1, T2);
+chk_SeqSigList_signalList(L1, L2) ->
+ wrong_type('SeqSigList_signalList', L1, L2).
+
+
+%% -- Signal --
+
+is_Signal(#'Signal'{signalName = N,
+ streamID = SID,
+ sigType = ST,
+ duration = Dur,
+ notifyCompletion = NC,
+ keepActive = KA,
+ sigParList = SPL,
+ direction = Dir,
+ requestID = RID,
+ intersigDelay = ISD}) ->
+ d("is_Signal -> entry with"
+ "~n N: ~p"
+ "~n SID: ~p"
+ "~n ST: ~p"
+ "~n Dur: ~p"
+ "~n NC: ~p"
+ "~n KA: ~p"
+ "~n SPL: ~p"
+ "~n Dir: ~p"
+ "~n RID: ~p"
+ "~n ISD: ~p", [N, SID, ST, Dur, NC, KA, SPL, Dir, RID, ISD]),
+ is_SignalName(N) andalso
+ is_opt_StreamID(SID) andalso
+ is_opt_SignalType(ST) andalso
+ is_opt_INTEGER(Dur, {range, 0, 65535}) andalso
+ is_opt_NotifyCompletion(NC) andalso
+ is_opt_BOOLEAN(KA) andalso
+ is_Signal_sigParList(SPL) andalso
+ is_opt_SignalDirection(Dir) andalso
+ is_opt_RequestID(RID) andalso
+ is_opt_INTEGER(ISD, {range, 0, 65535}).
+
+is_Signal_sigParList([]) ->
+ true;
+is_Signal_sigParList([H|T]) ->
+ is_SigParameter(H) andalso is_Signal_sigParList(T);
+is_Signal_sigParList(_) ->
+ false.
+
+chk_Signal(S, S) ->
+ chk_type(fun is_Signal/1, 'Signal', S);
+chk_Signal(#'Signal'{signalName = N1,
+ streamID = SID1,
+ sigType = ST1,
+ duration = Dur1,
+ notifyCompletion = NC1,
+ keepActive = KA1,
+ sigParList = SPL1,
+ direction = Dir1,
+ requestID = RID1,
+ intersigDelay = ISD1},
+ #'Signal'{signalName = N2,
+ streamID = SID2,
+ sigType = ST2,
+ duration = Dur2,
+ notifyCompletion = NC2,
+ keepActive = KA2,
+ sigParList = SPL2,
+ direction = Dir2,
+ requestID = RID2,
+ intersigDelay = ISD2}) ->
+ chk_Signal_signalName(N1, N2),
+ chk_Signal_streamID(SID1, SID2),
+ chk_Signal_sigType(ST1, ST2),
+ chk_Signal_duration(Dur1, Dur2),
+ chk_Signal_notifyCompletion(NC1, NC2),
+ chk_Signal_keepActive(KA1, KA2),
+ chk_Signal_sigParList(SPL1, SPL2),
+ chk_Signal_direction(Dir1, Dir2),
+ chk_Signal_requestID(RID1, RID2),
+ chk_Signal_intersigDelay(ISD1, ISD2),
+ ok;
+chk_Signal(S1, S2) ->
+ wrong_type('Signal', S1, S2).
+
+chk_Signal_signalName(N1, N2) ->
+ validate(fun() -> chk_SignalName(N1, N2) end, 'Signal_signalName').
+
+chk_Signal_streamID(V1, V2) ->
+ validate(fun() -> chk_opt_StreamID(V1, V2) end, 'Signal_streamID').
+
+chk_Signal_sigType(V1, V2) ->
+ validate(fun() -> chk_opt_SignalType(V1, V2) end, 'Signal_sigType').
+
+chk_Signal_duration(V1, V2) ->
+ validate(fun() ->
+ chk_opt_INTEGER(V1, V2, {range, 0, 65535})
+ end,
+ 'Signal_duration').
+
+chk_Signal_notifyCompletion(V1, V2) ->
+ validate(fun() -> chk_opt_NotifyCompletion(V1, V2) end,
+ 'Signal_notifyCompletion').
+
+chk_Signal_keepActive(false, asn1_NOVALUE) ->
+ ok;
+chk_Signal_keepActive(asn1_NOVALUE, false) ->
+ ok;
+chk_Signal_keepActive(V1, V2) ->
+ validate(fun() -> chk_opt_BOOLEAN(V1, V2) end, 'Signal_keepActive').
+
+chk_Signal_sigParList([], []) ->
+ ok;
+chk_Signal_sigParList([] = L1, L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList(L1, [] = L2) ->
+ not_equal('Signal_sigParList', L1, L2);
+chk_Signal_sigParList([H|T1], [H|T2]) ->
+ case is_SigParameter(H) of
+ true ->
+ chk_Signal_sigParList(T1, T2);
+ false ->
+ wrong_type('Signal_sigParList_val', H)
+ end;
+chk_Signal_sigParList([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_SigParameter(H1, H2) end,
+ 'Signal_sigParList_val'),
+ chk_Signal_sigParList(T1, T2);
+chk_Signal_sigParList(L1, L2) ->
+ wrong_type('Signal_sigParList', L1, L2).
+
+chk_Signal_direction(V1, V2) ->
+ validate(fun() -> chk_opt_SignalDirection(V1, V2) end, 'Signal_direction').
+
+chk_Signal_requestID(V1, V2) ->
+ validate(fun() -> chk_opt_RequestID(V1, V2) end, 'Signal_requestID').
+
+chk_Signal_intersigDelay(V1, V2) ->
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 65535}) end,
+ 'Signal_intersigDelay').
+
+
+%% -- SignalType --
+
+is_opt_SignalType(T) ->
+ is_OPTIONAL(fun is_SignalType/1, T).
+
+is_SignalType(T) ->
+ d("is_SignalType -> entry with"
+ "~n T: ~p", [T]),
+ Types = [brief, onOff, timeOut],
+ lists:member(T, Types).
+
+chk_opt_SignalType(T1, T2) ->
+ chk_OPTIONAL('SignalType', T1, T2,
+ fun is_SignalType/1, fun chk_SignalType/2).
+
+chk_SignalType(T, T) ->
+ chk_type(fun is_SignalType/1, 'SignalType', T);
+chk_SignalType(T1, T2) ->
+ case (is_SignalType(T1) andalso is_SignalType(T2)) of
+ true ->
+ not_equal('SignalType', T1, T2);
+ false ->
+ wrong_type('SignalType', T1, T2)
+ end.
+
+
+%% -- SignalDirection --
+
+is_opt_SignalDirection(T) ->
+ is_OPTIONAL(fun is_SignalDirection/1, T).
+
+is_SignalDirection(Dir) ->
+ d("is_SignalDirection -> entry with"
+ "~n Dir: ~p", [Dir]),
+ Dirs = [internal, external, both],
+ lists:member(Dir, Dirs).
+
+chk_opt_SignalDirection(T1, T2) ->
+ chk_OPTIONAL('SignalDirection', T1, T2,
+ fun is_SignalDirection/1, fun chk_SignalDirection/2).
+
+chk_SignalDirection(Dir, Dir) ->
+ chk_type(fun is_SignalDirection/1, 'SignalDirection', Dir);
+chk_SignalDirection(Dir1, Dir2) ->
+ case (is_SignalDirection(Dir1) andalso is_SignalDirection(Dir2)) of
+ true ->
+ not_equal('SignalDirection', Dir1, Dir2);
+ false ->
+ wrong_type('SignalDirection', Dir1, Dir2)
+ end.
+
+
+%% -- SignalName --
+
+is_SignalName(N) ->
+ d("is_SignalName -> entry with"
+ "~n N: ~p", [N]),
+ is_PkgdName(N).
+
+chk_SignalName(N1, N2) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'SignalName').
+
+
+%% -- NotifyCompletion --
+
+is_opt_NotifyCompletion(NC) ->
+ is_OPTIONAL(fun is_NotifyCompletion/1, NC).
+
+is_NotifyCompletion(NC) ->
+ d("is_NotifyCompletion -> entry with"
+ "~n NC: ~p", [NC]),
+ Valids = [onTimeOut,
+ onInterruptByEvent,
+ onInterruptByNewSignalDescr,
+ otherReason],
+ lists:all(fun(X) -> lists:member(X, Valids) end, NC).
+
+chk_opt_NotifyCompletion(NC1, NC2) ->
+ chk_OPTIONAL('NotifyCompletion', NC1, NC2,
+ fun is_NotifyCompletion/1,
+ fun chk_NotifyCompletion/2).
+
+chk_NotifyCompletion(NC, NC) ->
+ chk_type(fun is_NotifyCompletion/1, 'NotifyCompletion', NC);
+chk_NotifyCompletion(NC1, NC2) ->
+ case (is_NotifyCompletion(NC1) andalso is_NotifyCompletion(NC2)) of
+ true ->
+ not_equal('NotifyCompletion', NC1, NC2);
+ false ->
+ wrong_type('NotifyCompletion', NC1, NC2)
+ end.
+
+
+%% -- SigParameter --
+
+is_SigParameter(#'SigParameter'{sigParameterName = N,
+ value = V,
+ extraInfo = I}) ->
+ d("is_SigParameter -> entry with"
+ "~n N: ~p"
+ "~n V: ~p"
+ "~n I: ~p", [N, V, I]),
+ is_Name(N) andalso
+ is_Value(V) andalso
+ is_SigParameter_extraInfo(I);
+is_SigParameter(_) ->
+ false.
+
+is_SigParameter_extraInfo(asn1_NOVALUE) ->
+ true;
+is_SigParameter_extraInfo({Tag, Val}) ->
+ is_SigParameter_extraInfo_tag(Tag) andalso
+ is_SigParameter_extraInfo_val(Tag, Val);
+is_SigParameter_extraInfo(_) ->
+ false.
+
+is_SigParameter_extraInfo_tag(Tag) ->
+ Tags = [relation, range, sublist],
+ lists:member(Tag, Tags).
+
+is_SigParameter_extraInfo_val(relation, Val) ->
+ is_Relation(Val);
+is_SigParameter_extraInfo_val(range, Val) ->
+ is_BOOLEAN(Val);
+is_SigParameter_extraInfo_val(sublist, Val) ->
+ is_BOOLEAN(Val).
+
+chk_SigParameter(P, P) ->
+ chk_type(fun is_SigParameter/1, 'SigParameter', P);
+chk_SigParameter(#'SigParameter'{sigParameterName = N1,
+ value = V1,
+ extraInfo = I1},
+ #'SigParameter'{sigParameterName = N2,
+ value = V2,
+ extraInfo = I2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'SigParameter'),
+ validate(fun() -> chk_Value(V1, V2) end, 'SigParameter'),
+ chk_SigParameter_extraInfo(I1, I2),
+ ok;
+chk_SigParameter(P1, P2) ->
+ wrong_type('SigParameter', P1, P2).
+
+chk_SigParameter_extraInfo(EI, EI) ->
+ chk_type(fun is_SigParameter_extraInfo/1, 'SigParameter_extraInfo', EI);
+chk_SigParameter_extraInfo({Tag, Val1} = EI1, {Tag, Val2} = EI2) ->
+ case (is_SigParameter_extraInfo_tag(Tag) and
+ is_SigParameter_extraInfo_val(Tag, Val1) and
+ is_SigParameter_extraInfo_val(Tag, Val2)) of
+ true ->
+ chk_SigParameter_extraInfo_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo({Tag1, Val1} = EI1, {Tag2, Val2} = EI2) ->
+ case ((is_SigParameter_extraInfo_tag(Tag1) and
+ is_SigParameter_extraInfo_val(Tag1, Val1)) and
+ (is_SigParameter_extraInfo_tag(Tag2) and
+ is_SigParameter_extraInfo_val(Tag2, Val2))) of
+ true ->
+ not_equal('SigParameter_extraInfo', EI1, EI2);
+ false ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2)
+ end;
+chk_SigParameter_extraInfo(EI1, EI2) ->
+ wrong_type('SigParameter_extraInfo', EI1, EI2).
+
+chk_SigParameter_extraInfo_val(relation, Val1, Val2) ->
+ validate(fun() -> chk_Relation(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(range, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo');
+chk_SigParameter_extraInfo_val(sublist, Val1, Val2) ->
+ validate(fun() -> chk_BOOLEAN(Val1, Val2) end, 'SigParameter_extraInfo').
+
+
+%% -- RequestID --
+
+is_opt_RequestID(asn1_NOVALUE) ->
+ true;
+is_opt_RequestID(V) ->
+ is_RequestID(V).
+
+is_RequestID(V) -> is_INTEGER(V, {range, 0, 4294967295}).
+
+chk_opt_RequestID(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_RequestID(V1, V2) ->
+ chk_RequestID(V1, V2).
+
+chk_RequestID(ID, ID) ->
+ chk_type(fun is_RequestID/1, 'RequestID', ID);
+chk_RequestID(ID1, ID2) ->
+ case (is_RequestID(ID1) andalso is_RequestID(ID2)) of
+ true ->
+ not_equal('RequestID', ID1, ID2);
+ false ->
+ wrong_type('RequestID', ID1, ID2)
+ end.
+
+
+%% -- ModemDescriptor --
+
+is_ModemDescriptor(D) when is_record(D, 'ModemDescriptor') ->
+ true;
+is_ModemDescriptor(_) ->
+ false.
+
+chk_ModemDescriptor(D, D) when is_record(D, 'ModemDescriptor') ->
+ ok;
+chk_ModemDescriptor(#'ModemDescriptor'{mtl = MTL1,
+ mpl = MPL1,
+ nonStandardData = NSD1},
+ #'ModemDescriptor'{mtl = MTL2,
+ mpl = MPL2,
+ nonStandardData = NSD2}) ->
+ chk_ModemDescriptor_mtl(MTL1, MTL2),
+ chk_ModemDescriptor_mpl(MPL1, MPL2),
+ chk_opt_NonStandardData(NSD1, NSD2),
+ ok;
+chk_ModemDescriptor(D1, D2) ->
+ wrong_type('ModemDescriptor', D1, D2).
+
+chk_ModemDescriptor_mtl([], []) ->
+ ok;
+chk_ModemDescriptor_mtl([] = MTL1, MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl(MTL1, [] = MTL2) ->
+ not_equal('ModemDescriptor_mtl', MTL1, MTL2);
+chk_ModemDescriptor_mtl([H|T1], [H|T2]) ->
+ case is_ModemType(H) of
+ true ->
+ chk_ModemDescriptor_mtl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mtl_val', H)
+ end;
+chk_ModemDescriptor_mtl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_ModemType(H1, H2) end, 'ModemDescriptor_mtl_val'),
+ chk_ModemDescriptor_mtl(T1, T2);
+chk_ModemDescriptor_mtl(MTL1, MTL2) ->
+ wrong_type('ModemDescriptor_mtl', MTL1, MTL2).
+
+
+chk_ModemDescriptor_mpl([], []) ->
+ ok;
+chk_ModemDescriptor_mpl([] = MPL1, MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl(MPL1, [] = MPL2) ->
+ not_equal('ModemDescriptor_mpl', MPL1, MPL2);
+chk_ModemDescriptor_mpl([H|T1], [H|T2]) ->
+ case is_PropertyParm(H) of
+ true ->
+ chk_ModemDescriptor_mpl(T1, T2);
+ false ->
+ wrong_type('ModemDescriptor_mpl_val', H)
+ end;
+chk_ModemDescriptor_mpl([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PropertyParm(H1, H2) end, 'ModemDescriptor_mpl_val'),
+ chk_ModemDescriptor_mpl(T1, T2);
+chk_ModemDescriptor_mpl(MPL1, MPL2) ->
+ wrong_type('ModemDescriptor_mpl', MPL1, MPL2).
+
+
+%% -- ModemType --
+
+chk_ModemType(MT, MT) ->
+ case is_ModemType(MT) of
+ true ->
+ ok;
+ false ->
+ wrong_type('ModemType', MT, MT)
+ end;
+chk_ModemType(MT1, MT2) ->
+ case (is_ModemType(MT1) andalso is_ModemType(MT2)) of
+ true ->
+ not_equal('ModemType', MT1, MT2);
+ false ->
+ wrong_type('ModemType', MT1, MT2)
+ end.
+
+is_ModemType(MT) ->
+ lists:member(MT,
+ [v18, v22, v22bis, v32, v32bis, v34, v90, v91, synchISDN]).
+
+
+%% -- DigitMapDescriptor --
+
+is_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name,
+ digitMapValue = Val}) ->
+ is_opt_DigitMapName(Name) andalso is_opt_DigitMapValue(Val);
+is_DigitMapDescriptor(_) ->
+ false.
+
+chk_DigitMapDescriptor(D, D) ->
+ chk_type(fun is_DigitMapDescriptor/1, 'DigitMapDescriptor', D);
+chk_DigitMapDescriptor(#'DigitMapDescriptor'{digitMapName = Name1,
+ digitMapValue = Val1},
+ #'DigitMapDescriptor'{digitMapName = Name2,
+ digitMapValue = Val2}) ->
+ d("chk_DigitMapDescriptor -> entry with"
+ "~n Name1: ~p"
+ "~n Name2: ~p"
+ "~n Val1: ~p"
+ "~n Val2: ~p", [Name1, Name2, Val1, Val2]),
+ validate(fun() -> chk_opt_DigitMapName(Name1, Name2) end,
+ 'DigitMapDescriptor'),
+ validate(fun() -> chk_opt_DigitMapValue(Val1, Val2) end,
+ 'DigitMapDescriptor'),
+ ok;
+chk_DigitMapDescriptor(D1, D2) ->
+ wrong_type('DigitMapDescriptor', D1, D2).
+
+
+%% -- DigitMapName --
+
+is_opt_DigitMapName(asn1_NOVALUE) ->
+ true;
+is_opt_DigitMapName(N) ->
+ is_DigitMapName(N).
+
+is_DigitMapName(N) -> is_Name(N).
+
+chk_opt_DigitMapName(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_DigitMapName(N1, N2) ->
+ chk_DigitMapName(N1, N2).
+
+chk_DigitMapName(N, N) ->
+ chk_type(fun is_DigitMapName/1, 'DigitMapName', N);
+chk_DigitMapName(N1, N2) ->
+ case (is_DigitMapName(N1) andalso is_DigitMapName(N2)) of
+ true ->
+ not_equal('DigitMapName', N1, N2);
+ false ->
+ wrong_type('DigitMapName', N1, N2)
+ end.
+
+
+%% -- DigitMapValue --
+
+is_opt_DigitMapValue(V) ->
+ is_OPTIONAL(fun is_DigitMapValue/1, V).
+
+is_DigitMapValue(#'DigitMapValue'{startTimer = Start,
+ shortTimer = Short,
+ longTimer = Long,
+ digitMapBody = Body,
+ durationTimer = Dur}) ->
+ is_DigitMapValue_startTimer(Start) andalso
+ is_DigitMapValue_shortTimer(Short) andalso
+ is_DigitMapValue_longTimer(Long) andalso
+ is_IA5String(Body) andalso
+ is_DigitMapValue_durationTimer(Dur);
+is_DigitMapValue(_) ->
+ false.
+
+is_DigitMapValue_startTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_startTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_shortTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_shortTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_longTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_longTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+is_DigitMapValue_durationTimer(asn1_NOVALUE) -> true;
+is_DigitMapValue_durationTimer(T) -> is_INTEGER(T, {range, 0, 99}).
+
+chk_opt_DigitMapValue(V1, V2) ->
+ chk_OPTIONAL('DigitMapValue', V1, V2,
+ fun is_DigitMapValue/1, fun chk_DigitMapValue/2).
+
+chk_DigitMapValue(#'DigitMapValue'{startTimer = Start1,
+ shortTimer = Short1,
+ longTimer = Long1,
+ digitMapBody = Body1,
+ durationTimer = Dur1},
+ #'DigitMapValue'{startTimer = Start2,
+ shortTimer = Short2,
+ longTimer = Long2,
+ digitMapBody = Body2,
+ durationTimer = Dur2}) ->
+ d("chk_DigitMapValue -> entry with"
+ "~n Start1: ~p"
+ "~n Start2: ~p"
+ "~n Short1: ~p"
+ "~n Short2: ~p"
+ "~n Long1: ~p"
+ "~n Long2: ~p"
+ "~n Body1: ~p"
+ "~n Body2: ~p"
+ "~n Dur1: ~p"
+ "~n Dur2: ~p", [Start1, Start2,
+ Short1, Short2,
+ Long1, Long2,
+ Body1, Body2,
+ Dur1, Dur2]),
+ chk_DigitMapValue_startTimer(Start1, Start2),
+ chk_DigitMapValue_shortTimer(Short1, Short2),
+ chk_DigitMapValue_longTimer(Long1, Long2),
+ chk_DigitMapValue_digitMapBody(Body1, Body2),
+ chk_DigitMapValue_durationTimer(Dur1, Dur2),
+ ok;
+chk_DigitMapValue(V1, V2) ->
+ wrong_type('DigitMapValue', V1, V2).
+
+chk_DigitMapValue_startTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_startTimer/1, 'DigitMapValue_startTimer', T);
+chk_DigitMapValue_startTimer(T1, T2) ->
+ case (is_DigitMapValue_startTimer(T1) andalso
+ is_DigitMapValue_startTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_startTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_startTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_shortTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_shortTimer/1, 'DigitMapValue_shortTimer', T);
+chk_DigitMapValue_shortTimer(T1, T2) ->
+ case (is_DigitMapValue_shortTimer(T1) andalso
+ is_DigitMapValue_shortTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_shortTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_shortTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_longTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_longTimer/1, 'DigitMapValue_longTimer', T);
+chk_DigitMapValue_longTimer(T1, T2) ->
+ case (is_DigitMapValue_longTimer(T1) andalso
+ is_DigitMapValue_longTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_longTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_longTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_durationTimer(T, T) ->
+ chk_type(fun is_DigitMapValue_durationTimer/1,
+ 'DigitMapValue_durationTimer', T);
+chk_DigitMapValue_durationTimer(T1, T2) ->
+ case (is_DigitMapValue_durationTimer(T1) andalso
+ is_DigitMapValue_durationTimer(T2)) of
+ true ->
+ not_equal('DigitMapValue_durationTimer', T1, T2);
+ false ->
+ wrong_type('DigitMapValue_durationTimer', T1, T2)
+ end.
+
+chk_DigitMapValue_digitMapBody(B, B) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B: ~p", [B]),
+ chk_type(fun is_IA5String/1, 'DigitMapValue_digitMapBody', B);
+chk_DigitMapValue_digitMapBody(B1, B2) ->
+ d("chk_DigitMapValue_digitMapBody -> entry with"
+ "~n B1: ~p"
+ "~n B2: ~p", [B1, B2]),
+ case (is_IA5String(B1) andalso is_IA5String(B2)) of
+ true ->
+ %% If they are different it could be because
+ %% of trailing tab's and newline's.
+ case compare_strings(B1, B2) of
+ {[], []} ->
+ ok;
+ {Str1, []} ->
+ case strip_tab_and_newline(Str1) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ {[], Str2} ->
+ case strip_tab_and_newline(Str2) of
+ [] ->
+ ok;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ _ ->
+ not_equal('DigitMapValue_digitMapBody', B1, B2)
+ end;
+ false ->
+ wrong_type('DigitMapValue_digitMapBody', B1, B2)
+ end.
+
+%% -- ServiceChangeParm --
+
+is_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ serviceChangeReason = R,
+ serviceChangeDelay = D,
+ serviceChangeMgcId = Id,
+ timeStamp = TS,
+ nonStandardData = NSD,
+ serviceChangeInfo = I}) ->
+ is_ServiceChangeMethod(M) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_Value(R) andalso
+ is_opt_INTEGER(D, {range, 0, 4294967295}) andalso
+ is_opt_MId(Id) andalso
+ is_opt_TimeNotation(TS) andalso
+ is_opt_NonStandardData(NSD) andalso
+ is_opt_AuditDescriptor(I);
+is_ServiceChangeParm(_) ->
+ false.
+
+chk_ServiceChangeParm(P, P) ->
+ chk_type(fun is_ServiceChangeParm/1, 'ServiceChangeParm', P);
+chk_ServiceChangeParm(#'ServiceChangeParm'{serviceChangeMethod = M1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ serviceChangeReason = R1,
+ serviceChangeDelay = D1,
+ serviceChangeMgcId = Id1,
+ timeStamp = TS1,
+ nonStandardData = NSD1,
+ serviceChangeInfo = I1},
+ #'ServiceChangeParm'{serviceChangeMethod = M2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ serviceChangeReason = R2,
+ serviceChangeDelay = D2,
+ serviceChangeMgcId = Id2,
+ timeStamp = TS2,
+ nonStandardData = NSD2,
+ serviceChangeInfo = I2}) ->
+ validate(fun() -> chk_ServiceChangeMethod(M1, M2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_Value(R1, R2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_INTEGER(D1, D2, {range, 0, 4294967295}) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_MId(Id1, Id2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_NonStandardData(NSD1, NSD2) end,
+ 'ServiceChangeParm'),
+ validate(fun() -> chk_opt_AuditDescriptor(I1, I2) end,
+ 'ServiceChangeParm'),
+ ok;
+chk_ServiceChangeParm(P1, P2) ->
+ wrong_type('ServiceChangeParm', P1, P2).
+
+
+%% -- ServiceChangeAddress --
+
+is_opt_ServiceChangeAddress(A) ->
+ is_OPTIONAL(fun is_ServiceChangeAddress/1, A).
+
+is_ServiceChangeAddress({Tag, Val}) ->
+ is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val);
+is_ServiceChangeAddress(_) ->
+ false.
+
+is_ServiceChangeAddress_tag(Tag) ->
+ Tags = [portNumber, ip4Address, ip6Address, domainName, deviceName,
+ mtpAddress],
+ lists:member(Tag, Tags).
+
+is_ServiceChangeAddress_val(portNumber, Val) ->
+ is_INTEGER(Val, {range, 0, 65535});
+is_ServiceChangeAddress_val(ip4Address, Val) ->
+ is_IP4Address(Val);
+is_ServiceChangeAddress_val(ip6Address, Val) ->
+ is_IP6Address(Val);
+is_ServiceChangeAddress_val(domainName, Val) ->
+ is_DomainName(Val);
+is_ServiceChangeAddress_val(deviceName, Val) ->
+ is_PathName(Val);
+is_ServiceChangeAddress_val(mtpAddress, Val) ->
+ is_OCTET_STRING(Val, {range, 2, 4}).
+
+
+chk_opt_ServiceChangeAddress(A1, A2) ->
+ chk_OPTIONAL('ServiceChangeAddress', A1, A2,
+ fun is_ServiceChangeAddress/1,
+ fun chk_ServiceChangeAddress/2).
+
+chk_ServiceChangeAddress(A, A) ->
+ chk_type(fun is_ServiceChangeAddress/1, 'ServiceChangeAddress', A);
+chk_ServiceChangeAddress({Tag, Val1} = A1, {Tag, Val2} = A2) ->
+ case (is_ServiceChangeAddress_tag(Tag) andalso
+ is_ServiceChangeAddress_val(Tag, Val1) andalso
+ is_ServiceChangeAddress_val(Tag, Val2)) of
+ true ->
+ chk_ServiceChangeAddress_val(Tag, Val1, Val2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress({Tag1, Val1} = A1, {Tag2, Val2} = A2) ->
+ case ((is_ServiceChangeAddress_tag(Tag1) andalso
+ is_ServiceChangeAddress_val(Tag1, Val1)) andalso
+ (is_ServiceChangeAddress_tag(Tag2) andalso
+ is_ServiceChangeAddress_val(Tag2, Val2))) of
+ true ->
+ not_equal('ServiceChangeAddress', A1, A2);
+ false ->
+ wrong_type('ServiceChangeAddress', A1, A2)
+ end;
+chk_ServiceChangeAddress(A1, A2) ->
+ wrong_type('ServiceChangeAddress', A1, A2).
+
+chk_ServiceChangeAddress_val(portNumber, Val1, Val2) ->
+ validate(fun() -> chk_INTEGER(Val1, Val2, {range, 0, 99}) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip4Address, Val1, Val2) ->
+ validate(fun() -> chk_IP4Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(ip6Address, Val1, Val2) ->
+ validate(fun() -> chk_IP6Address(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(domainName, Val1, Val2) ->
+ validate(fun() -> chk_DomainName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(deviceName, Val1, Val2) ->
+ validate(fun() -> chk_PathName(Val1, Val2) end,
+ 'ServiceChangeAddress');
+chk_ServiceChangeAddress_val(mtpAddress, Val1, Val2) ->
+ validate(fun() -> chk_OCTET_STRING(Val1, Val2, {range, 2, 4}) end,
+ 'ServiceChangeAddress').
+
+
+%% -- ServiceChangeResParm --
+
+is_ServiceChangeResParm(#'ServiceChangeResParm'{serviceChangeMgcId = Id,
+ serviceChangeAddress = A,
+ serviceChangeVersion = V,
+ serviceChangeProfile = P,
+ timeStamp = TS}) ->
+ is_opt_MId(Id) andalso
+ is_opt_ServiceChangeAddress(A) andalso
+ is_opt_INTEGER(V, {range, 0, 99}) andalso
+ is_opt_ServiceChangeProfile(P) andalso
+ is_opt_TimeNotation(TS);
+is_ServiceChangeResParm(_) ->
+ false.
+
+chk_ServiceChangeResParm(P, P) ->
+ chk_type(fun is_ServiceChangeResParm/1, 'ServiceChangeResParm', P);
+chk_ServiceChangeResParm(
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id1,
+ serviceChangeAddress = A1,
+ serviceChangeVersion = V1,
+ serviceChangeProfile = P1,
+ timeStamp = TS1},
+ #'ServiceChangeResParm'{serviceChangeMgcId = Id2,
+ serviceChangeAddress = A2,
+ serviceChangeVersion = V2,
+ serviceChangeProfile = P2,
+ timeStamp = TS2}) ->
+ validate(fun() -> chk_opt_MId(Id1, Id2) end, 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeAddress(A1, A2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_INTEGER(V1, V2, {range, 0, 99}) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_ServiceChangeProfile(P1, P2) end,
+ 'ServiceChangeResParm'),
+ validate(fun() -> chk_opt_TimeNotation(TS1, TS2) end,
+ 'ServiceChangeResParm'),
+ ok;
+chk_ServiceChangeResParm(P1, P2) ->
+ wrong_type('ServiceChangeResParm', P1, P2).
+
+
+%% -- ServiceChangeMethod --
+
+is_ServiceChangeMethod(M) ->
+ Methods = [failover, forced, graceful, restart, disconnected, handOff],
+ lists:member(M, Methods).
+
+chk_ServiceChangeMethod(M, M) ->
+ chk_type(fun is_ServiceChangeMethod/1, 'ServiceChangeMethod', M);
+chk_ServiceChangeMethod(M1, M2) ->
+ case (is_ServiceChangeMethod(M1) andalso is_ServiceChangeMethod(M2)) of
+ true ->
+ not_equal('ServiceChangeMethod', M1, M2);
+ false ->
+ wrong_type('ServiceChangeMethod', M1, M2)
+ end.
+
+
+%% -- ServiceChangeProfile --
+
+is_opt_ServiceChangeProfile(P) ->
+ is_OPTIONAL(fun is_ServiceChangeProfile/1, P).
+
+is_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N}) ->
+ is_IA5String(N, {range, 1, 67});
+is_ServiceChangeProfile(_) ->
+ false.
+
+chk_opt_ServiceChangeProfile(P1, P2) ->
+ chk_OPTIONAL('ServiceChangeProfile', P1, P2,
+ fun is_ServiceChangeProfile/1,
+ fun chk_ServiceChangeProfile/2).
+
+chk_ServiceChangeProfile(P, P) ->
+ chk_type(fun is_ServiceChangeProfile/1, 'ServiceChangeProfile', P);
+chk_ServiceChangeProfile(#'ServiceChangeProfile'{profileName = N1},
+ #'ServiceChangeProfile'{profileName = N2}) ->
+ validate(fun() -> chk_IA5String(N1, N2, {range, 1, 67}) end,
+ 'ServiceChangeProfile'),
+ ok;
+chk_ServiceChangeProfile(P1, P2) ->
+ wrong_type('ServiceChangeProfile', P1, P2).
+
+
+%% -- PackagesDescriptor --
+
+is_PackagesDescriptor([]) ->
+ true;
+is_PackagesDescriptor([H|T]) ->
+ is_PackagesItem(H) andalso is_PackagesDescriptor(T);
+is_PackagesDescriptor(_) ->
+ false.
+
+chk_PackagesDescriptor([], []) ->
+ ok;
+chk_PackagesDescriptor([] = D1, D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor(D1, [] = D2) ->
+ not_equal('PackagesDescriptor', D1, D2);
+chk_PackagesDescriptor([H|T1], [H|T2]) ->
+ case is_PackagesItem(H) of
+ true ->
+ chk_PackagesDescriptor(T1, T2);
+ false ->
+ wrong_type('PackagesDescriptor_val', H)
+ end;
+chk_PackagesDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_PackagesItem(H1, H2) end,
+ 'PackagesDescriptor_val'),
+ chk_PackagesDescriptor(T1, T2);
+chk_PackagesDescriptor(D1, D2) ->
+ wrong_type('PackagesDescriptor_val', D1, D2).
+
+
+%% -- PackagesItem --
+
+is_PackagesItem(#'PackagesItem'{packageName = N,
+ packageVersion = V}) ->
+ is_Name(N) andalso is_INTEGER(V, {range, 0, 99});
+is_PackagesItem(_) ->
+ false.
+
+chk_PackagesItem(I, I) ->
+ chk_type(fun is_PackagesItem/1, 'PackagesItem', I);
+chk_PackagesItem(#'PackagesItem'{packageName = N1,
+ packageVersion = V1},
+ #'PackagesItem'{packageName = N2,
+ packageVersion = V2}) ->
+ validate(fun() -> chk_Name(N1, N2) end, 'PackagesItem'),
+ validate(fun() -> chk_INTEGER(V1, V2, {range, 0, 99}) end, 'PackagesItem'),
+ ok;
+chk_PackagesItem(I1, I2) ->
+ wrong_type('PackagesItem', I1, I2).
+
+
+%% -- StatisticsDescriptor --
+
+is_opt_StatisticsDescriptor(D) ->
+ is_OPTIONAL(fun is_StatisticsDescriptor/1, D).
+
+is_StatisticsDescriptor([]) ->
+ true;
+is_StatisticsDescriptor([H|T]) ->
+ is_StatisticsParameter(H) andalso is_StatisticsDescriptor(T);
+is_StatisticsDescriptor(_) ->
+ false.
+
+chk_opt_StatisticsDescriptor(D1, D2) ->
+ chk_OPTIONAL('StatisticsDescriptor', D1, D2,
+ fun is_StatisticsDescriptor/1,
+ fun chk_StatisticsDescriptor/2).
+
+chk_StatisticsDescriptor([], []) ->
+ ok;
+chk_StatisticsDescriptor([] = D1, D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor(D1, [] = D2) ->
+ not_equal('StatisticsDescriptor', D1, D2);
+chk_StatisticsDescriptor([H|T1], [H|T2]) ->
+ case is_StatisticsParameter(H) of
+ true ->
+ chk_StatisticsDescriptor(T1, T2);
+ false ->
+ wrong_type('StatisticsDescriptor_val', H)
+ end;
+chk_StatisticsDescriptor([H1|T1], [H2|T2]) ->
+ validate(fun() -> chk_StatisticsParameter(H1, H2) end,
+ 'StatisticsDescriptor_val'),
+ chk_StatisticsDescriptor(T1, T2);
+chk_StatisticsDescriptor(D1, D2) ->
+ wrong_type('StatisticsDescriptor_val', D1, D2).
+
+
+%% -- StatisticsParameter --
+
+is_StatisticsParameter(#'StatisticsParameter'{statName = N,
+ statValue = V}) ->
+ is_PkgdName(N) andalso is_opt_Value(V);
+is_StatisticsParameter(_) ->
+ false.
+
+chk_StatisticsParameter(P, P) ->
+ chk_type(fun is_StatisticsParameter/1, 'StatisticsParameter', P);
+chk_StatisticsParameter(#'StatisticsParameter'{statName = N1,
+ statValue = V1},
+ #'StatisticsParameter'{statName = N2,
+ statValue = V2}) ->
+ validate(fun() -> chk_PkgdName(N1, N2) end, 'StatisticsParameter'),
+ validate(fun() -> chk_opt_Value(V1, V2) end, 'StatisticsParameter'),
+ ok;
+chk_StatisticsParameter(P1, P2) ->
+ wrong_type('StatisticsParameter', P1, P2).
+
+
+%% -- NonStandardData --
+
+is_opt_NonStandardData(asn1_NOVALUE) ->
+ true;
+is_opt_NonStandardData(NSD) ->
+ is_NonStandardData(NSD).
+
+%% is_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id,
+%% data = D}) ->
+%% is_NonStandardIdentifier(Id) andalso is_OCTET_STRING(D);
+%% is_NonStandardData(_) ->
+%% false.
+
+is_NonStandardData(_) ->
+ true.
+
+chk_opt_NonStandardData(asn1_NOVALUE, asn1_NOVALUE) ->
+ true;
+chk_opt_NonStandardData(NSD1, NSD2) ->
+ chk_NonStandardData(NSD1, NSD2).
+
+chk_NonStandardData(NSD, NSD) ->
+ chk_type(fun is_NonStandardData/1, 'NonStandardData', NSD);
+%% chk_NonStandardData(#'NonStandardData'{nonStandardIdentifier = Id1,
+%% data = D1},
+%% #'NonStandardData'{nonStandardIdentifier = Id2,
+%% data = D2}) ->
+%% validate(fun() -> chk_NonStandardIdentifier(Id1, Id2) end,
+%% 'NonStandardData'),
+%% validate(fun() -> chk_OCTET_STRING(D1, D2) end, 'NonStandardData'),
+%% ok;
+%% chk_NonStandardData(NSD1, NSD2) ->
+%% wrong_type('NonStandardData', NSD1, NSD2).
+chk_NonStandardData(NSD1, NSD2) ->
+ not_equal('NonStandardData', NSD1, NSD2).
+
+
+%% -- NonStandardIdentifier --
+
+%% is_NonStandardIdentifier({Tag, Val}) ->
+%% is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val);
+%% is_NonStandardIdentifier(_) ->
+%% false.
+
+%% is_NonStandardIdentifier_tag(Tag) ->
+%% Tags = [object, h221NonStandard, experimental],
+%% lists:member(Tag, Tags).
+
+%% is_NonStandardIdentifier_val(object, Val) ->
+%% is_OBJECT_IDENTIFIER(Val);
+%% is_NonStandardIdentifier_val(h221NonStandard, Val) ->
+%% is_H221NonStandard(Val);
+%% is_NonStandardIdentifier_val(experimental, Val) ->
+%% is_IA5String(Val, {exact, 8}).
+
+%% chk_NonStandardIdentifier(Id, Id) ->
+%% chk_type(fun is_NonStandardIdentifier/1, 'NonStandardIdentifier', Id);
+%% chk_NonStandardIdentifier({Tag, Val1} = Id1, {Tag, Val2} = Id2) ->
+%% case (is_NonStandardIdentifier_tag(Tag) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1) andalso
+%% is_NonStandardIdentifier_val(Tag, Val1)) of
+%% true ->
+%% chk_NonStandardIdentifier_val(Tag, Val1, Val2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier({Tag1, Val1} = Id1, {Tag2, Val2} = Id2) ->
+%% case ((is_NonStandardIdentifier_tag(Tag1) andalso
+%% is_NonStandardIdentifier_val(Tag1, Val1)) andalso
+%% (is_NonStandardIdentifier_tag(Tag2) andalso
+%% is_NonStandardIdentifier_val(Tag2, Val1))) of
+%% true ->
+%% not_equal('NonStandardIdentifier', Id1, Id2);
+%% false ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2)
+%% end;
+%% chk_NonStandardIdentifier(Id1, Id2) ->
+%% wrong_type('NonStandardIdentifier', Id1, Id2).
+
+%% chk_NonStandardIdentifier_val(object, Val1, Val2) ->
+%% chk_OBJECT_IDENTIFIER(Val1, Val2);
+%% chk_NonStandardIdentifier_val(h221NonStandard, Val1, Val2) ->
+%% chk_H221NonStandard(Val1, Val2);
+%% chk_NonStandardIdentifier_val(experimental, Val1, Val2) ->
+%% chk_IA5String(Val1, Val2, {exact, 8}).
+
+
+%% -- H221NonStandard --
+
+%% is_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC1,
+%% t35CountryCode2 = CC2,
+%% t35Extension = Ext,
+%% manufacturerCode = MC}) ->
+%% is_INTEGER(CC1, {range, 0, 255}) andalso
+%% is_INTEGER(CC2, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 255}) andalso
+%% is_INTEGER(Ext, {range, 0, 65535});
+%% is_H221NonStandard(_) ->
+%% false.
+
+%% chk_H221NonStandard(NS, NS) ->
+%% chk_type(fun is_H221NonStandard/1, 'H221NonStandard', NS);
+%% chk_H221NonStandard(#'H221NonStandard'{t35CountryCode1 = CC11,
+%% t35CountryCode2 = CC21,
+%% t35Extension = Ext1,
+%% manufacturerCode = MC1},
+%% #'H221NonStandard'{t35CountryCode1 = CC12,
+%% t35CountryCode2 = CC22,
+%% t35Extension = Ext2,
+%% manufacturerCode = MC2}) ->
+%% validate(fun() -> chk_INTEGER(CC11, CC12, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(CC21, CC22, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(Ext1, Ext2, {range, 0, 255}) end,
+%% 'H221NonStandard'),
+%% validate(fun() -> chk_INTEGER(MC1, MC2, {range, 0, 65535}) end,
+%% 'H221NonStandard'),
+%% ok;
+%% chk_H221NonStandard(NS1, NS2) ->
+%% wrong_type('H221NonStandard', NS1, NS2).
+
+
+%% -- TimeNotation --
+
+is_opt_TimeNotation(asn1_NOVALUE) ->
+ true;
+is_opt_TimeNotation(TN) ->
+ is_TimeNotation(TN).
+
+is_TimeNotation(#'TimeNotation'{date = D, time = T}) ->
+ is_IA5String(D, {exact, 8}) andalso is_IA5String(T, {exact, 8});
+is_TimeNotation(_) ->
+ false.
+
+chk_opt_TimeNotation(asn1_NOVALUE, asn1_NOVALUE) ->
+ ok;
+chk_opt_TimeNotation(TN1, TN2) ->
+ chk_TimeNotation(TN1, TN2).
+
+chk_TimeNotation(TN, TN) ->
+ chk_type(fun is_TimeNotation/1, 'TimeNotation', TN);
+chk_TimeNotation(#'TimeNotation'{date = D1, time = T1},
+ #'TimeNotation'{date = D2, time = T2}) ->
+ validate(fun() -> chk_IA5String(D1, D2, {exact, 8}) end, 'TimeNotation'),
+ validate(fun() -> chk_IA5String(T1, T2, {exact, 8}) end, 'TimeNotation'),
+ ok;
+chk_TimeNotation(TN1, TN2) ->
+ wrong_type('TimeNotation', TN1, TN2).
+
+
+%% -- Value --
+
+is_opt_Value(V) ->
+ is_OPTIONAL(fun is_Value/1, V).
+
+is_Value([]) ->
+ true;
+is_Value([H|T]) ->
+ is_OCTET_STRING(H) andalso is_Value(T);
+is_Value(_) ->
+ false.
+
+chk_opt_Value(V1, V2) ->
+ chk_OPTIONAL('Value', V1, V2, fun is_Value/1, fun chk_Value/2).
+
+chk_Value(V, V) ->
+ case is_Value(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type('Value', V, V)
+ end;
+chk_Value(V1, V2) ->
+ case (is_Value(V1) andalso is_Value(V2)) of
+ true ->
+ not_equal('Value', V1, V2);
+ false ->
+ wrong_type('Value', V1, V2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Basic type check functions
+%% ----------------------------------------------------------------------
+
+
+is_opt_BOOLEAN(B) ->
+ is_OPTIONAL(fun is_BOOLEAN/1, B).
+
+is_BOOLEAN(B) ->
+ d("is_BOOLEAN -> entry with"
+ "~n B: ~p", [B]),
+ lists:member(B, [true, false]).
+
+chk_opt_BOOLEAN(B1, B2) ->
+ chk_OPTIONAL('BOOLEAN', B1, B2, fun is_BOOLEAN/1, fun chk_BOOLEAN/2).
+
+chk_BOOLEAN(B, B) ->
+ chk_type(fun is_BOOLEAN/1, 'BOOLEAN', B);
+chk_BOOLEAN(B1, B2) ->
+ case (is_BOOLEAN(B1) andalso is_BOOLEAN(B2)) of
+ true ->
+ not_equal('BOOLEAN', B1, B2);
+ false ->
+ wrong_type('BOOLEAN', B1, B2)
+ end.
+
+
+is_IA5String(S) when is_list(S) ->
+ true;
+is_IA5String(_) ->
+ false.
+
+% chk_IA5String(S, S) ->
+% chk_type(fun is_IA5String/1, 'IA5String', S);
+% chk_IA5String(S1, S2) ->
+% case (is_IA5String(S1) andalso is_IA5String(S2)) of
+% true ->
+% not_equal('IA5String', S1, S2);
+% false ->
+% wrong_type('IA5String', S1, S2)
+% end.
+
+is_IA5String(S, _) when is_list(S) ->
+ true;
+is_IA5String(_, _) ->
+ false.
+
+chk_IA5String(S, S, R) ->
+ chk_type(fun is_IA5String/2, 'IA5String', S, R);
+chk_IA5String(S1, S2, R) ->
+ case (is_IA5String(S1, R) andalso is_IA5String(S2, R)) of
+ true ->
+ not_equal('IA5String', S1, S2);
+ false ->
+ wrong_type('IA5String', S1, S2)
+ end.
+
+
+is_OCTET_STRING(L) -> is_OCTET_STRING(L, any).
+
+is_OCTET_STRING(L, any) when is_list(L) ->
+ true;
+is_OCTET_STRING(L, {exact, Len}) when is_list(L) and (length(L) == Len) ->
+ true;
+is_OCTET_STRING(L, {atleast, Len}) when is_list(L) and (Len =< length(L)) ->
+ true;
+is_OCTET_STRING(L, {atmost, Len}) when is_list(L) and (length(L) =< Len) ->
+ true;
+is_OCTET_STRING(L, {range, Min, Max})
+ when is_list(L) and (Min =< length(L)) and (length(L) =< Max) ->
+ true;
+is_OCTET_STRING(_, _) ->
+ false.
+
+%% chk_OCTET_STRING(L1, L2) ->
+%% chk_OCTET_STRING(L1, L2, any).
+
+chk_OCTET_STRING(L, L, R) ->
+ chk_type(fun is_OCTET_STRING/2, 'OCTET STRING', L, R);
+chk_OCTET_STRING(L1, L2, R) ->
+ case (is_OCTET_STRING(L1, R) andalso is_OCTET_STRING(L2, R)) of
+ true ->
+ not_equal('OCTET STRING', L1, L2);
+ false ->
+ wrong_type('OCTET STRING', L1, L2)
+ end.
+
+
+%% is_OBJECT_IDENTIFIER(_) ->
+%% true.
+
+%% chk_OBJECT_IDENTIFIER(X, X) ->
+%% ok;
+%% chk_OBJECT_IDENTIFIER(X1, X2) ->
+%% not_equal('OBJECT IDENTIFIER', X1, X2).
+
+
+is_opt_NULL(N) ->
+ is_OPTIONAL(fun is_NULL/1, N).
+
+is_NULL('NULL') ->
+ true;
+is_NULL(_) ->
+ false.
+
+chk_opt_NULL(N1, N2) ->
+ chk_OPTIONAL('NULL', N1, N2, fun is_NULL/1, fun chk_NULL/2).
+
+chk_NULL(N, N) ->
+ chk_type(fun is_NULL/1, 'NULL', N);
+chk_NULL(N1, N2) ->
+ case (is_NULL(N1) andalso is_NULL(N2)) of
+ true ->
+ not_equal('NULL', N1, N2);
+ false ->
+ wrong_type('NULL', N1, N2)
+ end.
+
+
+is_opt_INTEGER(I, R) ->
+ d("is_opt_INTEGER -> entry with"
+ "~n I: ~p"
+ "~n R: ~p", [I, R]),
+ is_OPTIONAL(fun(X) -> is_INTEGER(X, R) end, I).
+
+is_INTEGER(I, any) when is_integer(I) ->
+ true;
+is_INTEGER(I, {exact, I}) when is_integer(I) ->
+ true;
+is_INTEGER(I, {atleast, Min}) when
+ is_integer(I) and is_integer(Min) and (Min =< I) ->
+ true;
+is_INTEGER(I, {atmost, Max})
+ when is_integer(I) and is_integer(Max) and (I =< Max) ->
+ true;
+is_INTEGER(I, {range, Min, Max})
+ when is_integer(I) and
+ is_integer(Min) and (Min =< I) and
+ is_integer(Max) and (I =< Max) ->
+ true;
+is_INTEGER(_, _) ->
+ false.
+
+chk_opt_INTEGER(I1, I2, R) ->
+ chk_OPTIONAL('INTEGER', I1, I2,
+ fun(X) -> is_INTEGER(X, R) end,
+ fun(Y1, Y2) -> chk_INTEGER(Y1, Y2, R) end).
+
+chk_INTEGER(I, I, R) ->
+ chk_type(fun is_INTEGER/2, 'INTEGER', I, R);
+chk_INTEGER(I1, I2, R) ->
+ case (is_INTEGER(I1, R) andalso is_INTEGER(I2, R)) of
+ true ->
+ not_equal('INTEGER', I1, I2);
+ false ->
+ wrong_type('INTEGER', I1, I2)
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% Various utility functions
+%% ----------------------------------------------------------------------
+
+
+to_lower([C|Cs]) when (C >= $A) and (C =< $Z) ->
+ [C+($a-$A)|to_lower(Cs)];
+to_lower([C|Cs]) ->
+ [C|to_lower(Cs)];
+to_lower([]) ->
+ [].
+
+
+validate(F, Type) when is_function(F) ->
+ case (catch F()) of
+ {error, Reason} ->
+ error({Type, Reason});
+ ok ->
+ ok
+ end.
+
+
+chk_type(F, T, V) when is_function(F) and is_atom(T) ->
+ case F(V) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V)
+ end.
+
+chk_type(F, T, V1, V2) when is_function(F) and is_atom(T) ->
+ case F(V1, V2) of
+ true ->
+ ok;
+ false ->
+ wrong_type(T, V1)
+ end.
+
+
+is_OPTIONAL(_, asn1_NOVALUE) ->
+ true;
+is_OPTIONAL(F, Val) when is_function(F) ->
+ F(Val).
+
+chk_OPTIONAL(_, asn1_NOVALUE, asn1_NOVALUE, _, _) ->
+ ok;
+chk_OPTIONAL(Type, asn1_NOVALUE = V1, V2, IS, _CHK) when is_function(IS) ->
+ case IS(V2) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(Type, V1, asn1_NOVALUE = V2, IS, _CHK) when is_function(IS) ->
+ case IS(V1) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_OPTIONAL(_Type, V1, V2, _IS, CHK) when is_function(CHK) ->
+ CHK(V1, V2).
+
+
+%% -- CHOICE --
+
+is_CHOICE({Tag, Val}, Tags) when is_list(Tags) ->
+ d("is_CHOICE -> entry with"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
+ is_CHOICE_tag(Tag, Tags) andalso
+ is_CHOICE_val(Tag, Val, Tags);
+is_CHOICE(_, _) ->
+ false.
+
+is_CHOICE_tag(Tag, Tags) ->
+ lists:keymember(Tag, 1, Tags).
+
+is_CHOICE_val(Tag, Val, Tags) ->
+ {value, {_, IsVal, _}} = lists:keysearch(Tag, 1, Tags),
+ IsVal(Val).
+
+
+chk_CHOICE(V1, V2, Type, Tags) when is_atom(Type) and is_list(Tags) ->
+ IsTag = fun(Tag) -> is_CHOICE_tag(Tag, Tags) end,
+ IsVal = fun(Tag, Val) -> is_CHOICE_val(Tag, Val, Tags) end,
+ ChkVal = fun(Tag, Val1, Val2) ->
+ chk_CHOICE_val(Tag, Val1, Val2, Tags)
+ end,
+ chk_CHOICE(V1, V2, Type, IsTag, IsVal, ChkVal).
+
+chk_CHOICE_val(Tag, Val1, Val2, Tags) ->
+ {value, {_, _, ChkVal}} = lists:keysearch(Tag, 1, Tags),
+ ChkVal(Val1, Val2).
+
+chk_CHOICE({Tag, Val1} = V1, {Tag, Val2} = V2, Type, IsTag, IsVal, ChkVal) ->
+ case (IsTag(Tag) andalso
+ IsVal(Tag, Val1) andalso IsVal(Tag, Val2)) of
+ true ->
+ ChkVal(Tag, Val1, Val2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_CHOICE({Tag1, Val1} = V1, {Tag2, Val2} = V2, Type,
+ IsTag, IsVal, _ChkVal) ->
+ case ((IsTag(Tag1) andalso IsVal(Tag1, Val1)) andalso
+ (IsTag(Tag2) andalso IsVal(Tag2, Val2))) of
+ true ->
+ not_equal(Type, V1, V2);
+ false ->
+ wrong_type(Type, V1, V2)
+ end;
+chk_CHOICE(V1, V2, Type, _, _, _) ->
+ wrong_type(Type, V1, V2).
+
+
+%% -- SEQUENCE OF --
+
+is_SEQUENCE_OF([], _) ->
+ true;
+is_SEQUENCE_OF([H|T], IS) when is_function(IS) ->
+ IS(H) andalso is_SEQUENCE_OF(T, IS);
+is_SEQUENCE_OF(_, _) ->
+ false.
+
+chk_SEQUENCE_OF([], [], _, _, _) ->
+ ok;
+chk_SEQUENCE_OF([] = V1, V2, Type, _, _) ->
+ not_equal(Type, V1, V2);
+chk_SEQUENCE_OF(V1, [] = V2, Type, _, _) ->
+ not_equal(Type, V1, V2);
+chk_SEQUENCE_OF([H|T1], [H|T2], Type, IS, CHK) ->
+ case IS(H) of
+ true ->
+ chk_SEQUENCE_OF(T1, T2, Type, IS, CHK);
+ false ->
+ Type2 = list_to_atom(atom_to_list(Type) ++ "_val"),
+ wrong_type(Type2, H)
+ end;
+chk_SEQUENCE_OF([H1|T1], [H2|T2], Type, IS, CHK) ->
+ Type2 = list_to_atom(atom_to_list(Type) ++ "_val"),
+ validate(fun() -> CHK(H1, H2) end, Type2),
+ chk_SEQUENCE_OF(T1, T2, Type, IS, CHK);
+chk_SEQUENCE_OF(V1, V2, Type, _, _) ->
+ wrong_type(Type, V1, V2).
+
+
+%% ----------------------------------------------------------------------
+
+compare_strings([] = L1, L2) ->
+ {L1, L2};
+compare_strings(L1, [] = L2) ->
+ {L1, L2};
+compare_strings([H|T1], [H|T2]) ->
+ compare_strings(T1, T2);
+compare_strings(L1, L2) ->
+ {L1, L2}.
+
+strip_tab_and_newline([]) ->
+ [];
+strip_tab_and_newline([$\n|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([$\t|T]) ->
+ strip_tab_and_newline(T);
+strip_tab_and_newline([H|T]) ->
+ [H|strip_tab_and_newline(T)].
+
+
+%% ----------------------------------------------------------------------
+
+maybe_sort(L) when is_list(L) ->
+ lists:sort(L);
+maybe_sort(X) ->
+ X.
+
+
+%% ----------------------------------------------------------------------
+
+atmost_once(Type, Val) ->
+ error({atmost_once, {Type, Val}}).
+
+wrong_type(Type, Val) ->
+ error({wrong_type, {Type, Val}}).
+
+wrong_type(Type, Val1, Val2) ->
+ error({wrong_type, {Type, Val1, Val2}}).
+
+not_equal(What, Val1, Val2) ->
+ error({not_equal, {What, Val1, Val2}}).
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(dbg), F, A).
+
+d(true, F, A) ->
+ io:format("DBG:" ++ F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/megaco/test/megaco_test_tcp_generator.erl b/lib/megaco/test/megaco_test_tcp_generator.erl
new file mode 100644
index 0000000000..e4f27f32f5
--- /dev/null
+++ b/lib/megaco/test/megaco_test_tcp_generator.erl
@@ -0,0 +1,504 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: megaco_tcp sequence generator for the megaco test suite
+%%----------------------------------------------------------------------
+
+-module(megaco_test_tcp_generator).
+
+-behaviour(megaco_test_generator).
+
+%% API
+-export([
+ start_link/1, start_link/2,
+ stop/1,
+ exec/2, exec/3
+ ]).
+
+%% genarator behaviour callback exports
+-export([
+ init/1,
+ handle_parse/2,
+ handle_exec/2,
+ terminate/2
+ ]).
+
+
+-record(state,
+ {
+ listen, % Listen socket
+ connection, % Connection socket
+ encode, % Encode fun
+ decode, % Decode fun
+ result = [] % Accumulated results from exec
+ }).
+
+
+%%----------------------------------------------------------------------
+%% API
+%%----------------------------------------------------------------------
+
+start_link(Name) ->
+ megaco_test_generator:start_link(?MODULE, [], Name).
+
+start_link(Name, Node) ->
+ megaco_test_generator:start_link(?MODULE, [], Name, Node).
+
+stop(Server) ->
+ megaco_test_generator:stop(Server).
+
+exec(Server, Instructions) when is_list(Instructions) ->
+ megaco_test_generator:exec(Server, Instructions).
+
+exec(Server, Instructions, Timeout) when is_list(Instructions) ->
+ megaco_test_generator:exec(Server, Instructions, Timeout).
+
+
+%%----------------------------------------------------------------------
+%% generator callback functions
+%%----------------------------------------------------------------------
+
+init([]) ->
+ {ok, #state{}}.
+
+
+%% ----- instruction parser -----
+
+handle_parse({debug, Debug} = Instruction, State)
+ when (Debug == true) orelse (Debug == false) ->
+ {ok, Instruction, State};
+
+handle_parse({decode, Decode} = Instruction, State)
+ when is_function(Decode) ->
+ {ok, Instruction, State};
+
+handle_parse({encode, Encode} = Instruction, State)
+ when is_function(Encode) ->
+ {ok, Instruction, State};
+
+handle_parse(disconnect = Instruction, State) ->
+ {ok, Instruction, State};
+
+handle_parse({listen, Port} = Instruction, State)
+ when is_integer(Port) andalso (Port >= 0) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_accept, any} = _Instruction, State) ->
+ {ok, {expect_accept, {any, infinity}}, State};
+
+handle_parse({expect_accept, {any, To}} = Instruction, State)
+ when (is_integer(To) andalso (To >= 0)) orelse (To == infinity) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_accept, {Host, To}} = _Instruction, State)
+ when (is_integer(To) andalso (To >= 0)) orelse (To == infinity) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Addr} ->
+ Instruction = {expect_accept, {Addr, To}},
+ {ok, Instruction, State};
+ {error, Reason} ->
+ {error, {bad_host, Host, Reason}}
+ end;
+
+handle_parse({expect_accept, Host} = _Instruction, State) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Addr} ->
+ Instruction = {expect_accept, {Addr, infinity}},
+ {ok, Instruction, State};
+ {error, Reason} ->
+ {error, {bad_host, Host, Reason}}
+ end;
+
+handle_parse({active, NewState} = Instruction, State)
+ when (NewState == true) orelse
+ (NewState == false) orelse
+ (NewState == once) ->
+ {ok, Instruction, State};
+
+handle_parse({connect, Port} = _Instruction, State)
+ when is_integer(Port) andalso (Port >= 0) ->
+ Host =
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ Hostname;
+ {error, Reason1} ->
+ error({failed_geting_own_hostname, Reason1})
+ end,
+ case inet:getaddr(Host, inet) of
+ {ok, Address} ->
+ Instruction = {connect, {Address, Port, infinity}},
+ {ok, Instruction, State};
+ {error, Reason2} ->
+ {error, {bad_host, Host, Reason2}}
+ end;
+
+handle_parse({connect, {Port, To}} = _Instruction, State)
+ when (is_integer(Port) andalso
+ (Port >= 0)) andalso ((is_integer(To) andalso (To >= 0)) orelse
+ (To == infinity)) ->
+ Host =
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ Hostname;
+ {error, Reason1} ->
+ error({failed_geting_own_hostname, Reason1})
+ end,
+ case inet:getaddr(Host, inet) of
+ {ok, Address} ->
+ Instruction = {connect, {Address, Port, To}},
+ {ok, Instruction, State};
+ {error, Reason2} ->
+ {error, {bad_host, Host, Reason2}}
+ end;
+
+handle_parse({connect, {Host, Port}} = _Instruction, State)
+ when (is_integer(Port) andalso (Port >= 0)) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Address} ->
+ Instruction = {connect, {Address, Port, infinity}},
+ {ok, Instruction, State};
+ {error, Reason} ->
+ {error, {bad_host, Host, Reason}}
+ end;
+
+handle_parse({connect, {Host, Port, To}} = _Instruction, State)
+ when (is_integer(Port) andalso
+ (Port >= 0)) andalso ((is_integer(To) andalso (To >= 0)) orelse
+ (To == infinity)) ->
+ case inet:getaddr(Host, inet) of
+ {ok, Address} ->
+ Instruction = {connect, {Address, Port, To}},
+ {ok, Instruction, State};
+ {error, Reason} ->
+ {error, {bad_host, Host, Reason}}
+ end;
+
+handle_parse({sleep, To} = Instruction, State)
+ when is_integer(To) andalso (To > 0) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_nothing, To} = Instruction, State)
+ when is_integer(To) andalso (To > 0) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_closed, To} = Instruction, State)
+ when is_integer(To) andalso (To > 0) ->
+ {ok, Instruction, State};
+
+handle_parse({expect_receive, Desc, Verify} = _Instruction, State)
+ when is_list(Desc) andalso is_function(Verify) ->
+ Instruction = {expect_receive, Desc, {Verify, infinity}},
+ {ok, Instruction, State};
+
+handle_parse({expect_receive, Desc, {Verify, To}} = Instruction, State)
+ when is_list(Desc) andalso
+ is_function(Verify) andalso
+ ((is_integer(To) andalso (To >= 0)) orelse (To == infinity)) ->
+ {ok, Instruction, State};
+
+handle_parse({send, Desc, Msg} = Instruction, State)
+ when is_list(Desc) andalso (is_tuple(Msg) orelse is_binary(Msg)) ->
+ {ok, Instruction, State};
+
+handle_parse({trigger, Desc, Trigger} = Instruction, State)
+ when is_list(Desc) andalso is_function(Trigger) ->
+ {ok, Instruction, State};
+
+handle_parse(Instruction, _State) ->
+ {error, {unknown_instruction, Instruction}}.
+
+
+%% ----- instruction exececutor -----
+
+handle_exec({debug, Debug},
+ State) ->
+ p("debug: ~p", [Debug]),
+ put(debug, Debug),
+ {ok, State};
+
+handle_exec({encode, Encode},
+ State) ->
+ p("encode: ~p", [Encode]),
+ {ok, State#state{encode = Encode}};
+
+handle_exec({decode, Decode},
+ State) ->
+ p("Decode: ~p", [Decode]),
+ {ok, State#state{decode = Decode}};
+
+handle_exec(disconnect,
+ #state{listen = Listen,
+ connection = Sock,
+ result = Res} = State) ->
+ p("disconnect"),
+ (catch gen_tcp:close(Sock)),
+ (catch gen_tcp:close(Listen)),
+ {ok, State#state{listen = undefined,
+ connection = undefined,
+ result = [disconnected|Res]}};
+
+handle_exec({listen, Port}, #state{result = Res} = State) ->
+ p("listen to ~p", [Port]),
+ Opts = [binary,
+ {packet, tpkt},
+ {active, false},
+ {reuseaddr, true},
+ {nodelay, true}],
+ case (catch gen_tcp:listen(Port, Opts)) of
+ {ok, Listen} ->
+ d("listen -> listen socket created"),
+ {ok, State#state{listen = Listen, result = [listening | Res]}};
+ {error, Reason} ->
+ e("failed creating listen socket: ~p", [Reason]),
+ {error, {failed_creating_listen_socket, Reason, Res}}
+ end;
+
+handle_exec({expect_accept, {Addr, To}},
+ #state{listen = Listen,
+ result = Res} = State) ->
+ p("expect_accept from ~p (~p)", [Addr, To]),
+ case (catch gen_tcp:accept(Listen, To)) of
+ {ok, Sock} ->
+ d("expect_accept -> connection accepted"),
+ case (catch inet:peername(Sock)) of
+ {ok, {Addr, _Port}} ->
+ d("expect_accept -> valid address"),
+ NewState =
+ State#state{connection = Sock,
+ result = [{connected, Addr}|Res]},
+ {ok, NewState};
+ {ok, {OtherAddr, _Port}} when Addr == any ->
+ d("expect_accept -> valid (~p)", [OtherAddr]),
+ NewState =
+ State#state{connection = Sock,
+ result = [{connected, OtherAddr}|Res]},
+ {ok, NewState};
+ {ok, AddrAndPort} ->
+ {error, {invalid_connect, AddrAndPort, Res}};
+ {error, Reason} ->
+ e("failed getting peername for socket: ~p", [Reason]),
+ (catch gen_tcp:close(Sock)),
+ {error, {failed_getting_peername, Sock, Reason}}
+ end;
+ {error, Reason} ->
+ e("failed accepting connection: ~p", [Reason]),
+ (catch gen_tcp:close(Listen)),
+ {error, {failed_accepting_conection, Reason, Listen}}
+ end;
+
+handle_exec({active, NewState},
+ #state{connection = Sock,
+ result = Res} = State) ->
+ p("active to ~p", [NewState]),
+ case inet:setopts(Sock, [{active, NewState}]) of
+ ok ->
+ d("active -> state changed"),
+ {ok, State#state{result = [{active, NewState}|Res]}};
+ {error, Reason} ->
+ e("failed changing active state to ~w: ~p", [NewState, Reason]),
+ {error, {failed_setting_active, Reason}}
+ end;
+
+handle_exec({connect, {Addr, Port, To}},
+ #state{result = Res} = State) ->
+ p("connect to ~p, ~p", [Addr, Port]),
+ Opts = [binary, {packet, tpkt}, {active, once}, {nodelay, true}],
+ case (catch gen_tcp:connect(Addr, Port, Opts, To)) of
+ {ok, Sock} ->
+ d("connect -> connected"),
+ {ok, State#state{connection = Sock,
+ result = [{connected, Addr, Port}|Res]}};
+ {error, Reason} ->
+ e("failed connecting: ~p", [Reason]),
+ {error, {failed_connect, Addr, Port, Reason}}
+ end;
+
+%% Already encoded
+handle_exec({send, Desc, Bin},
+ #state{connection = Sock,
+ result = Res} = State)
+ when is_binary(Bin) ->
+ p("send ~s message", [Desc]),
+ NewBin = add_tpkt_header(Bin),
+ d("send -> tpkt header added [~w], now send", [sz(NewBin)]),
+ case (catch gen_tcp:send(Sock, NewBin)) of
+ ok ->
+ d("send -> message sent"),
+ {ok, State#state{result = [{sent, Desc}|Res]}};
+ {error, Reason} ->
+ e("send -> send failed: ~n~p",[Reason]),
+ {error, {failed_send, Reason}}
+ end;
+
+handle_exec({send, Desc, Msg},
+ #state{connection = Sock,
+ encode = Encode,
+ result = Res} = State) ->
+ p("send ~s message", [Desc]),
+ case (catch Encode(Msg)) of
+ {ok, Bin} ->
+ d("send -> message encoded [~w], now add tpkt header: ~n~s",
+ [sz(Bin), binary_to_list(Bin)]),
+ NewBin = add_tpkt_header(Bin),
+ d("send -> tpkt header added [~w], now send", [sz(NewBin)]),
+ case (catch gen_tcp:send(Sock, NewBin)) of
+ ok ->
+ d("send -> message sent"),
+ {ok, State#state{result = [{sent, Desc}|Res]}};
+ {error, Reason} ->
+ e("send -> send failed: ~n~p", [Reason]),
+ {error, {failed_send, Reason}}
+ end;
+ Error ->
+ e("send -> encode failed: ~n~p", [Error]),
+ {error, {encode_failed, Error}}
+ end;
+
+handle_exec({expect_receive, Desc, {Verify, To}},
+ #state{connection = Sock,
+ decode = Decode,
+ result = Acc} = State) ->
+ p("expect_receive ~s message", [Desc]),
+ inet:setopts(Sock, [{active, once}]),
+ receive
+ {tcp, Sock, <<3:8, _X:8, Length:16, Msg/binary>>} ->
+ d("expect_receive -> received message: Length = ~p", [Length]),
+ case (catch Decode(Msg)) of
+ {ok, MegaMsg} when is_tuple(MegaMsg) ->
+ d("expect_receive -> decode successfull, now verify"),
+ case (catch Verify(MegaMsg)) of
+ {ok, Res} ->
+ d("expect_receive -> verify successfull"),
+ {ok, State#state{result = [Res|Acc]}};
+ Else ->
+ e("failed to verify message: ~n~p~n~p",
+ [Else, MegaMsg]),
+ {error, {expect_receive, {verify_failed, Else}}}
+ end;
+ Error ->
+ e("failed decoding message: ~p", [Error]),
+ {error, {expect_receive, Error}}
+ end;
+ Else ->
+ e("received unknown message: ~p", [Else]),
+ {error, {expect_receive, {unexpected_message, Else}}}
+ after To ->
+ {error, {expect_receive, timeout}}
+ end;
+
+handle_exec({expect_closed, To},
+ #state{connection = Sock,
+ result = Acc} = State) ->
+ p("expect_closed ~w", [To]),
+ inet:setopts(Sock, [{active, once}]),
+ p("expect_closed - await closed", []),
+ receive
+ {tcp_closed, Sock} ->
+ p("expect_closed - received closed"),
+ {ok, State#state{connection = undefined,
+ result = [closed|Acc]}}
+ after To ->
+ e("expect_closed timeout after ~w", [To]),
+ {error, {expect_closed, timeout}}
+ end;
+
+handle_exec({expect_nothing, To},
+ #state{connection = Sock,
+ result = Acc} = State) ->
+ p("expect_nothing ~w", [To]),
+ inet:setopts(Sock, [{active, once}]),
+ p("expect_nothing - await anything", []),
+ receive
+ Any ->
+ e("expect_nothing - received: ~p", [Any]),
+ {error, {expect_nothing, Any}}
+ after To ->
+ p("expect_nothing timeout after ~w", [To]),
+ {ok, State#state{result = [{nothing, To}|Acc]}}
+ end;
+
+handle_exec({trigger, Desc, Trigger},
+ #state{result = Acc} = State) when is_function(Trigger) ->
+ p("trigger: ~s", [Desc]),
+ Trigger(),
+ {ok, State#state{result = [triggered|Acc]}};
+
+handle_exec({sleep, To},
+ #state{result = Acc} = State) ->
+ p("sleep ~p", [To]),
+ sleep(To),
+ {ok, State#state{result = [{slept, To}|Acc]}};
+
+handle_exec(Instruction, _State) ->
+ {error, {unknown_instruction, Instruction}}.
+
+
+%% ----- terminate -----
+
+terminate(normal, #state{listen = Listen,
+ connection = Sock,
+ result = Result}) ->
+ (catch gen_tcp:close(Sock)),
+ (catch gen_tcp:close(Listen)),
+ {ok, Result};
+terminate(Reason, #state{listen = Listen,
+ connection = Sock,
+ result = Result}) ->
+ (catch gen_tcp:close(Sock)),
+ (catch gen_tcp:close(Listen)),
+ {error, {Reason, Result}}.
+
+
+%%----------------------------------------------------------------------
+%% internal utility functions
+%%----------------------------------------------------------------------
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%%% ----------------------------------------------------------------
+
+add_tpkt_header(Bin) when is_binary(Bin) ->
+ L = size(Bin) + 4,
+ SZ1 = ((L) bsr 8) band 16#ff,
+ SZ2 = (L) band 16#ff,
+ <<3, 0, SZ1, SZ2, Bin/binary>>;
+add_tpkt_header(IOList) when is_list(IOList) ->
+ add_tpkt_header(list_to_binary(IOList)).
+
+sleep(X) -> megaco_test_generator:sleep(X).
+
+sz(X) -> megaco_test_generator:sz(X).
+
+
+%%% ----------------------------------------------------------------
+
+d(F) -> megaco_test_generator:debug(F).
+d(F, A) -> megaco_test_generator:debug(F, A).
+
+e(F, A) -> megaco_test_generator:error(F, A).
+
+p(F ) -> p("", F, []).
+p(F, A) -> p("", F, A).
+p(P, F, A) -> megaco_test_generator:print(P, F, A).
+
+
diff --git a/lib/megaco/test/megaco_timer_test.erl b/lib/megaco/test/megaco_timer_test.erl
new file mode 100644
index 0000000000..8bcfc5a907
--- /dev/null
+++ b/lib/megaco/test/megaco_timer_test.erl
@@ -0,0 +1,472 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(megaco_timer_test).
+
+-export([
+ t/0, t/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ all/1,
+
+ simple/1,
+ simple_init/1,
+ simple_usage/1,
+
+ integer_timer/1,
+ integer_timer_start_and_expire/1,
+ integer_timer_start_and_stop/1%% ,
+
+%% incr_timer/1
+
+ ]).
+
+-export([
+ timeout/3
+ ]).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+
+-define(TEST_VERBOSITY, info). % silence | info | debug
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+%% Test server callbacks
+%% init_per_testcase(multi_user_extreme_load = Case, Config) ->
+%% C = lists:keydelete(tc_timeout, 1, Config),
+%% do_init_per_testcase(Case, [{tc_timeout, min(20)}|C]);
+init_per_testcase(Case, Config) ->
+ do_init_per_testcase(Case, Config).
+
+do_init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ {ok, _Pid} = megaco_monitor:start_link(),
+ megaco_test_lib:init_per_testcase(Case, [{monitor_running, true}|Config]).
+
+fin_per_testcase(Case, Config) ->
+ io:format("fin_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p"
+ "~n", [Case, Config]),
+ process_flag(trap_exit, false),
+ case lists:keydelete(monitor_running, 1, Config) of
+ Config ->
+ megaco_test_lib:fin_per_testcase(Case, Config);
+ Config2 ->
+ megaco_monitor:stop(),
+ megaco_test_lib:fin_per_testcase(Case, Config2)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ simple,
+ integer_timer%% ,
+%% incr_timer
+ ],
+ Cases.
+
+
+simple(suite) ->
+ Cases =
+ [
+ simple_init,
+ simple_usage
+ ],
+ Cases.
+
+
+integer_timer(suite) ->
+ Cases =
+ [
+ integer_timer_start_and_expire,
+ integer_timer_start_and_stop
+ ],
+ Cases.
+
+
+%% incr_timer(suite) ->
+%% Cases =
+%% [
+%% ],
+%% Cases.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+simple_init(suite) ->
+ [];
+simple_init(doc) ->
+ [];
+simple_init(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, si),
+ put(sname, "TEST"),
+ put(verbosity, info),
+ i("starting"),
+
+ Init =
+ fun(Tmr) ->
+ case (catch megaco_timer:init(Tmr)) of
+ {WaitFor, {NewTmr, _}} when
+ (((WaitFor == infinity) or is_integer(WaitFor)) andalso
+ is_record(NewTmr, megaco_incr_timer) andalso
+ (is_record(Tmr, megaco_incr_timer) andalso
+ (Tmr#megaco_incr_timer.max_retries == infinity_restartable))) ->
+ ok;
+ {WaitFor, NewTmr} when
+ (((WaitFor == infinity) or is_integer(WaitFor)) andalso
+ ((NewTmr == timeout) or is_record(NewTmr, megaco_incr_timer))) ->
+ ok;
+ X ->
+ d("initiation of timer failed: "
+ "~n X: ~p", [X]),
+ {error, X}
+ end
+ end,
+ Verify =
+ fun(A, A) ->
+ ok;
+ (error, {error, Reason}) ->
+ d("Error reason: ~p", [Reason]),
+ ok;
+ (A, B) ->
+ d("unexpected result: "
+ "~n Expected: ~p"
+ "~n Actual: ~p", [A, B]),
+ error({unexpected_result, A, B})
+ end,
+ VerifyTMR =
+ fun(false, Tmr) ->
+ not megaco_timer:verify(Tmr);
+ (true, Tmr) ->
+ megaco_timer:verify(Tmr)
+ end,
+
+ d(" 1) verify infinity timer"),
+ TMR01 = infinity,
+ Verify(true, VerifyTMR(true, TMR01)),
+ Verify(ok, Init(TMR01)),
+
+ d(" 2) verify integer (2007) timer"),
+ TMR02 = 2007,
+ Verify(true, VerifyTMR(true, TMR02)),
+ Verify(ok, Init(TMR02)),
+
+ d(" 3) verify default megaco incr timer timer"),
+ TMR03 = #megaco_incr_timer{},
+ Verify(true, VerifyTMR(true, TMR03)),
+ Verify(ok, Init(TMR03)),
+
+ d(" 4) verify megaco incr timer timer"),
+ TMR04 = #megaco_incr_timer{max_retries = infinity_restartable},
+ Verify(true, VerifyTMR(true, TMR04)),
+ Verify(ok, Init(TMR04)),
+
+ d(" 5) verify megaco incr timer timer"),
+ TMR05 = #megaco_incr_timer{incr = -1}, %% This is new
+ Verify(true, VerifyTMR(true, TMR05)),
+ Verify(ok, Init(TMR05)),
+
+ d(" 6) verify invalid timer"),
+ TMR06 = infinit,
+ Verify(true, VerifyTMR(false, TMR06)),
+ Verify(error, Init(TMR06)),
+
+ d(" 7) verify invalid timer"),
+ TMR07 = -2007,
+ Verify(true, VerifyTMR(false, TMR07)),
+ Verify(error, Init(TMR07)),
+
+ d(" 8) verify invalid timer"),
+ TMR08 = 20.33,
+ Verify(true, VerifyTMR(false, TMR08)),
+ Verify(error, Init(TMR08)),
+
+ d(" 9) verify invalid timer"),
+ TMR09 = -20.33,
+ Verify(true, VerifyTMR(false, TMR09)),
+ Verify(error, Init(TMR09)),
+
+ d("10) verify invalid timer"),
+ TMR10 = "kalle anka",
+ Verify(true, VerifyTMR(false, TMR10)),
+ Verify(error, Init(TMR10)),
+
+ d("11) verify invalid timer"),
+ TMR11 = #megaco_incr_timer{wait_for = 10,
+ factor = 1,
+ incr = 0,
+ max_retries = infinit},
+ Verify(true, VerifyTMR(false, TMR11)),
+ Verify(error, Init(TMR11)),
+
+ i("done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+simple_usage(suite) ->
+ [];
+simple_usage(doc) ->
+ [];
+simple_usage(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, su),
+ put(sname, "TEST"),
+ i("starting"),
+
+ Verify = fun(Tmr) -> megaco_timer:verify(Tmr) end,
+ Init = fun(Tmr) -> megaco_timer:init(Tmr) end,
+ Restart = fun(Tmr) -> megaco_timer:restart(Tmr) end,
+
+ VerifyRes =
+ fun(A, A) ->
+ ok;
+ (A, B) ->
+ error({unexpected_result, A, B})
+ end,
+
+
+ %% Timer 1
+ d(" 1) verify (infinity) timer"),
+ TMR01 = infinity,
+ VerifyRes(true, Verify(TMR01)),
+ d(" 1) init (infinity) timer"),
+ VerifyRes({TMR01, timeout}, Init(TMR01)),
+
+ %% Timer 2
+ d(" 2) verify (integer) timer"),
+ TMR02 = 1000,
+ VerifyRes(true, Verify(TMR02)),
+ d(" 2) init (integer) timer"),
+ VerifyRes({TMR02, timeout}, Init(TMR02)),
+
+ %% Timer 3
+ d(" 3) verify (megaco_incr_timer) timer"),
+ TMR03 = #megaco_incr_timer{wait_for = TMR02,
+ factor = 1,
+ incr = 0,
+ max_retries = infinity},
+ VerifyRes(true, Verify(TMR03)),
+ d(" 3) init (megaco_incr_timer) timer"),
+ {TMR02, NewTMR03_1} = Init(TMR03),
+ d(" 3) restart (megaco_incr_timer) timer"),
+ {TMR02, _} = Restart(NewTMR03_1),
+
+ %% Timer 4
+ d(" 4) verify (megaco_incr_timer) timer"),
+ TMR04 = #megaco_incr_timer{wait_for = 1000,
+ factor = 1,
+ incr = 0,
+ max_retries = 2},
+ VerifyRes(true, Verify(TMR04)),
+ d(" 4) init (megaco_incr_timer) timer"),
+ {TMR02, NewTMR04_1} = Init(TMR04),
+ d(" 4) restart (megaco_incr_timer) timer"),
+ {TMR02, NewTMR04_2} = Restart(NewTMR04_1),
+ d(" 4) last restart (megaco_incr_timer) timer"),
+ {TMR02, timeout} = Restart(NewTMR04_2),
+
+ %% Timer 5
+ d(" 5) verify (megaco_incr_timer) timer"),
+ TMR05 = #megaco_incr_timer{wait_for = 1000,
+ factor = 1,
+ incr = -300,
+ max_retries = infinity},
+ VerifyRes(true, Verify(TMR05)),
+ d(" 5) init (megaco_incr_timer) timer"),
+ {TMR02, NewTMR05_1} = Init(TMR05),
+ d(" 5) restart (1) (megaco_incr_timer) timer"),
+ TMR05_1 = TMR02-300,
+ {TMR05_1, NewTMR05_2} = Restart(NewTMR05_1),
+ d(" 5) restart (2) (megaco_incr_timer) timer"),
+ TMR05_2 = TMR05_1-300,
+ {TMR05_2, NewTMR05_3} = Restart(NewTMR05_2),
+ d(" 5) restart (3) (megaco_incr_timer) timer"),
+ TMR05_3 = TMR05_2-300,
+ {TMR05_3, NewTMR05_4} = Restart(NewTMR05_3),
+ d(" 5) restart (4) (megaco_incr_timer) timer"),
+ {0, NewTMR05_5} = Restart(NewTMR05_4),
+ d(" 5) restart (5) (megaco_incr_timer) timer"),
+ {0, _} = Restart(NewTMR05_5),
+
+ i("done", []),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+integer_timer_start_and_expire(suite) ->
+ [];
+integer_timer_start_and_expire(doc) ->
+ [];
+integer_timer_start_and_expire(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, itsae),
+ put(sname, "TEST"),
+ i("starting"),
+
+ Timeout = 5000,
+ Ref = tmr_start(Timeout),
+ receive
+ {timeout, Timeout} ->
+ ok
+ after Timeout + 100 ->
+ tmr_stop(Ref),
+ error(no_timeout)
+ end,
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+integer_timer_start_and_stop(suite) ->
+ [];
+integer_timer_start_and_stop(doc) ->
+ [];
+integer_timer_start_and_stop(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(tc, itsas),
+ put(sname, "TEST"),
+ i("starting"),
+
+ Timeout = 5000,
+ Ref = tmr_start(Timeout),
+ receive
+ {timeout, Timeout} ->
+ error(bad_timeout)
+ after Timeout - 100 ->
+ tmr_stop(Ref)
+ end,
+
+ %% Make sure it does not reach us after we attempted to stop it.
+ receive
+ {timeout, Timeout} ->
+ error(unexpected_timeout)
+ after Timeout ->
+ ok
+ end,
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tmr_start(Timeout) ->
+ Pid = self(),
+ megaco_monitor:apply_after(?MODULE, timeout, [Pid, Timeout, get(tc)], Timeout).
+
+tmr_stop(Ref) ->
+ megaco_monitor:cancel_apply_after(Ref).
+
+timeout(Pid, Timeout, Tc) ->
+ put(sname, timer),
+ put(tc, Tc),
+ print("DBG",
+ "timeout -> entry with"
+ "~n Pid: ~p"
+ "~n Timeout: ~p", [Pid, Timeout]),
+ Pid ! {timeout, Timeout}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% tim() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+%% min(M) -> timer:minutes(M).
+
+%% sleep(X) -> receive after X -> ok end.
+
+error(Reason) -> throw({error, Reason}).
+
+%% error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, "INF", F, A).
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, "DBG", F, A).
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+
+print(Severity, Prefix, F, A) ->
+ print1(printable(Severity, get(verbosity)), Prefix, F, A).
+
+print1(true, Prefix, F, A) ->
+ print(Prefix, F, A);
+print1(_, _, _, _) ->
+ ok.
+
+print(Prefix, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [formated_timestamp(), Prefix, self(), get(sname), get(tc) | A]).
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+formated_timestamp() ->
+ format_timestamp(now()).
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
diff --git a/lib/megaco/test/megaco_trans_test.erl b/lib/megaco/test/megaco_trans_test.erl
new file mode 100644
index 0000000000..44d4b3fff7
--- /dev/null
+++ b/lib/megaco/test/megaco_trans_test.erl
@@ -0,0 +1,9401 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Verify that the transaction sender works with acks.
+%%
+%% Test: ts:run(megaco, megaco_trans_test, [batch]).
+%%
+%%----------------------------------------------------------------------
+-module(megaco_trans_test).
+
+-compile(export_all).
+
+-include("megaco_test_lib.hrl").
+-include_lib("megaco/include/megaco.hrl").
+-include_lib("megaco/include/megaco_message_v1.hrl").
+
+-define(VERSION, 1).
+-define(TEST_VERBOSITY, debug).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
+
+-define(LOAD_COUNTER_START, 10).
+-define(A4444, ["11111111", "00000000", "00000000"]).
+-define(A4445, ["11111111", "00000000", "11111111"]).
+-define(A5555, ["11111111", "11111111", "00000000"]).
+-define(A5556, ["11111111", "11111111", "11111111"]).
+
+-define(MGC_START(Pid, Mid, ET, Verb),
+ megaco_test_mgc:start(Pid, Mid, ET, Verb)).
+-define(MGC_STOP(Pid), megaco_test_mgc:stop(Pid)).
+-define(MGC_GET_STATS(Pid, No), megaco_test_mgc:get_stats(Pid, No)).
+-define(MGC_RESET_STATS(Pid), megaco_test_mgc:reset_stats(Pid)).
+-define(MGC_REQ_DISC(Pid,To), megaco_test_mgc:request_discard(Pid,To)).
+-define(MGC_REQ_PEND(Pid,To), megaco_test_mgc:request_pending(Pid,To)).
+-define(MGC_REQ_HAND(Pid), megaco_test_mgc:request_handle(Pid)).
+-define(MGC_REQ_HANDS(Pid), megaco_test_mgc:request_handle_sloppy(Pid)).
+-define(MGC_UPDATE_UI(Pid,Tag,Val),
+ megaco_test_mgc:update_user_info(Pid,Tag,Val)).
+-define(MGC_UPDATE_CI(Pid,Tag,Val),
+ megaco_test_mgc:update_conn_info(Pid,Tag,Val)).
+-define(MGC_USER_INFO(Pid,Tag), megaco_test_mgc:user_info(Pid,Tag)).
+-define(MGC_CONN_INFO(Pid,Tag), megaco_test_mgc:conn_info(Pid,Tag)).
+-define(MGC_ACK_INFO(Pid,To), megaco_test_mgc:ack_info(Pid,To)).
+-define(MGC_REQ_INFO(Pid,To), megaco_test_mgc:req_info(Pid,To)).
+
+-define(MG_START(Pid, Mid, Enc, Transp, Conf, Verb),
+ megaco_test_mg:start(Pid, Mid, Enc, Transp, Conf, Verb)).
+-define(MG_STOP(Pid), megaco_test_mg:stop(Pid)).
+-define(MG_GET_STATS(Pid), megaco_test_mg:get_stats(Pid)).
+-define(MG_RESET_STATS(Pid), megaco_test_mg:reset_stats(Pid)).
+-define(MG_SERV_CHANGE(Pid), megaco_test_mg:service_change(Pid)).
+-define(MG_NOTIF_RAR(Pid), megaco_test_mg:notify_request_and_reply(Pid)).
+-define(MG_NOTIF_REQ(Pid), megaco_test_mg:notify_request(Pid)).
+-define(MG_NOTIF_AR(Pid), megaco_test_mg:await_notify_reply(Pid)).
+-define(MG_CANCEL(Pid,R), megaco_test_mg:cancel_request(Pid,R)).
+-define(MG_APPLY_LOAD(Pid,CntStart), megaco_test_mg:apply_load(Pid,CntStart)).
+-define(MG_UPDATE_UI(Pid,Tag,Val),
+ megaco_test_mg:update_user_info(Pid,Tag,Val)).
+-define(MG_UPDATE_CI(Pid,Tag,Val),
+ megaco_test_mg:update_conn_info(Pid,Tag,Val)).
+-define(MG_USER_INFO(Pid,Tag), megaco_test_mg:user_info(Pid,Tag)).
+-define(MG_CONN_INFO(Pid,Tag), megaco_test_mg:conn_info(Pid,Tag)).
+-define(MG_GRP_REQ(Pid,N), megaco_test_mg:group_requests(Pid,N)).
+-define(MG_ACK_INFO(Pid,To), megaco_test_mg:ack_info(Pid,To)).
+-define(MG_REP_INFO(Pid,To), megaco_test_mg:rep_info(Pid,To)).
+
+t() -> megaco_test_lib:t(?MODULE).
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%% Test server callbacks
+init_per_testcase(multi_ack_maxcount = Case, Config) ->
+ process_flag(trap_exit, true),
+ C = lists:keydelete(tc_timeout, 1, Config),
+ megaco_test_lib:init_per_testcase(Case, [{tc_timeout,timer:minutes(10)}|C]);
+init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+fin_per_testcase(Case, Config) ->
+ process_flag(trap_exit, false),
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ [
+ ack,
+ trans_req,
+ trans_req_and_ack,
+ pending,
+ reply,
+
+ tickets
+ ].
+
+ack(suite) ->
+ [
+ single_ack,
+ multi_ack_timeout,
+ multi_ack_maxcount
+ ].
+
+trans_req(suite) ->
+ [
+ single_trans_req,
+ multi_trans_req_timeout,
+ multi_trans_req_maxcount1,
+ multi_trans_req_maxcount2,
+ multi_trans_req_maxsize1,
+ multi_trans_req_maxsize2
+ ].
+
+trans_req_and_ack(suite) ->
+ [
+ single_trans_req_and_ack,
+ multi_trans_req_and_ack_timeout,
+ multi_trans_req_and_ack_ackmaxcount,
+ multi_trans_req_and_ack_reqmaxcount,
+ multi_trans_req_and_ack_maxsize1,
+ multi_trans_req_and_ack_maxsize2
+ ].
+
+pending(suite) ->
+ [
+ single_trans_req_and_pending,
+ multi_trans_req_and_pending,
+ multi_trans_req_and_ack_and_pending,
+ multi_ack_and_pending
+ ].
+
+reply(suite) ->
+ [
+ multi_trans_req_and_reply,
+ multi_trans_req_and_ack_and_reply,
+ multi_ack_and_reply
+ ].
+
+tickets(suite) ->
+ [
+ otp_7192
+ ].
+
+otp_7192(suite) ->
+ [
+ otp_7192_1,
+ otp_7192_2,
+ otp_7192_3
+ ].
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_ack(suite) ->
+ [];
+single_ack(doc) ->
+ [];
+single_ack(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, single_ack),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ %% MgConf0 = [{MgNode, "mg", text, tcp, ?MG_VERBOSITY}],
+ MgMid = {deviceName, "mg"},
+ MgConfig = [{auto_ack, true}, {trans_timer, 5000}, {trans_ack, true}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect to the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ d("ensure the megaco stack calls the handle_trans_ack callback"),
+ ?MGC_REQ_HANDS(Mgc),
+
+ d("tell the MGC to send the ack's to us"),
+ ?MGC_ACK_INFO(Mgc, self()),
+
+ d("send the notify"),
+ ?MG_GRP_REQ(Mg, 1),
+
+ d("send the notify"),
+ ?MG_NOTIF_REQ(Mg),
+
+ d("await the ack"),
+ await_ack(Mgc, 1, infinity, ok),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_ack_timeout(suite) ->
+ [];
+multi_ack_timeout(doc) ->
+ [];
+multi_ack_timeout(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [win32, {unix, [darwin, linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_ack_timeout),
+ i("starting"),
+
+
+ MaxCount = 20,
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ %% MgConf0 = [{MgNode, "mg", text, tcp, ?MG_VERBOSITY}],
+ MgMid = {deviceName, "mg"},
+ MgConfig = [{auto_ack, true},
+ {trans_ack, true},
+ {trans_timer, 10000},
+ {trans_ack_maxcount, MaxCount + 10}],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ i("wait some time"),
+ sleep(1000),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ {ok, _OldAction} = ?MGC_REQ_HANDS(Mgc),
+
+ d("tell the MGC to send the ack's to us"),
+ ?MGC_ACK_INFO(Mgc, self()),
+
+ d("set group size to ~p", [MaxCount]),
+ ?MG_GRP_REQ(Mg, MaxCount),
+
+ d("[MG] send a group of requests (and await the replies)"),
+ ?MG_NOTIF_RAR(Mg),
+
+ d("await the ack(s)"),
+ await_ack(Mgc, MaxCount, 60000, ok),
+
+ i("wait some time before closing down"),
+ sleep(5000),
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done"),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_ack_maxcount(suite) ->
+ [];
+multi_ack_maxcount(doc) ->
+ [];
+multi_ack_maxcount(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_ack_maxcount),
+ i("starting"),
+
+ MaxCount = 10,
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+ %% Start the MGC and MGs
+ i("[MGC] start"),
+ ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
+ {ok, Mgc} =
+ ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
+
+ i("[MG] start"),
+ %% MgConf0 = [{MgNode, "mg", text, tcp, ?MG_VERBOSITY}],
+ MgMid = {deviceName, "mg"},
+ MgConfig = [%% {auto_ack, true},
+ %% {trans_timer, 120000},
+ %% {trans_ack_maxcount, MaxCount}
+ ],
+ {ok, Mg} = ?MG_START(MgNode, MgMid, text, tcp, MgConfig, ?MG_VERBOSITY),
+
+ d("MG user info: ~p", [?MG_USER_INFO(Mg, all)]),
+
+ i("[MG] connect the MGC (service change)"),
+ ServChRes = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [ServChRes]),
+
+ i("wait some time"),
+ sleep(1000),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ ?MG_UPDATE_CI(Mg,auto_ack,true),
+ ?MG_UPDATE_CI(Mg,trans_timer,120000),
+ ?MG_UPDATE_CI(Mg,trans_ack_maxcount,MaxCount),
+ ?MG_UPDATE_CI(Mg,trans_ack,true),
+
+ d("MG conn info: ~p", [?MG_CONN_INFO(Mg, all)]),
+
+ {ok, _OldAction} = ?MGC_REQ_HANDS(Mgc),
+
+ d("tell the MGC to send the ack's to us"),
+ ?MGC_ACK_INFO(Mgc, self()),
+
+ d("set group size to ~p", [MaxCount]),
+ ?MG_GRP_REQ(Mg, MaxCount),
+
+ d("[MG] send a group of requests (and await the replies)"),
+ ?MG_NOTIF_RAR(Mg),
+
+ d("await the ack"),
+ await_ack(Mgc, MaxCount, 60000, ok),
+
+ i("wait some time before closing down"),
+ sleep(5000),
+
+
+ %% Tell MG to stop
+ i("[MG] stop"),
+ ?MG_STOP(Mg),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done"),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_trans_req(suite) ->
+ [];
+single_trans_req(doc) ->
+ [];
+single_trans_req(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, single_trans_req),
+ process_flag(trap_exit, true),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = str_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = str_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(str_mgc_connect_verify_fun(),
+ {?MODULE, str_mgc_verify_handle_connect, []}).
+-define(str_mgc_service_change_req_verify_fun(Mid),
+ {?MODULE, str_mgc_verify_service_change_req, [Mid]}).
+-define(str_mgc_notify_req_verify_fun(),
+ {?MODULE, str_mgc_verify_notify_request, []}).
+-define(str_mgc_disco_verify_fun(),
+ {?MODULE, str_mgc_verify_handle_disconnect, []}).
+-else.
+-define(str_mgc_connect_verify_fun(),
+ fun str_mgc_verify_handle_connect/1).
+-define(str_mgc_service_change_req_verify_fun(Mid),
+ str_mgc_verify_service_change_req_fun(Mid)).
+-define(str_mgc_notify_req_verify_fun(),
+ str_mgc_verify_notify_request_fun()).
+-define(str_mgc_disco_verify_fun(),
+ fun str_mgc_verify_handle_disconnect/1).
+-endif.
+
+str_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?str_mgc_connect_verify_fun(),
+ ServiceChangeReqVerify = ?str_mgc_service_change_req_verify_fun(Mid),
+ NotifyReqVerify = ?str_mgc_notify_req_verify_fun(),
+ DiscoVerify = ?str_mgc_disco_verify_fun(),
+%% ConnectVerify = fun str_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = str_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = str_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun str_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, false},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+str_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("str_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+str_mgc_verify_handle_connect(Else) ->
+ io:format("str_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+str_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ str_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+str_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("str_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [str_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = str_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = str_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = str_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = str_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = str_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+str_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("str_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = str_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+
+str_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ str_mgc_verify_notify_request(Ev)
+ end.
+
+str_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("str_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [str_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = str_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+str_mgc_verify_notify_request(Else) ->
+ io:format("str_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = str_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+
+str_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("str_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+str_mgc_verify_handle_disconnect(Else) ->
+ io:format("str_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+str_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+str_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = str_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+str_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+str_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = str_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(str_mg_connect_verify_fun(),
+ {?MODULE, str_mg_verify_handle_connect, []}).
+-define(str_mg_service_change_reply_verify_fun(),
+ {?MODULE, str_mg_verify_service_change_reply, []}).
+-define(str_mg_notify_reply_verify_fun(),
+ {?MODULE, str_mg_verify_notify_reply, []}).
+-else.
+-define(str_mg_connect_verify_fun(),
+ fun str_mg_verify_handle_connect/1).
+-define(str_mg_service_change_reply_verify_fun(),
+ fun str_mg_verify_service_change_reply/1).
+-define(str_mg_notify_reply_verify_fun(),
+ fun str_mg_verify_notify_reply/1).
+-endif.
+
+str_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [str_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [str_mg_notify_request_ar(1, Tid, 1)],
+ ConnectVerify = ?str_mg_connect_verify_fun(),
+ ServiceChangeReplyVerify = ?str_mg_service_change_reply_verify_fun(),
+ NotifyReplyVerify = ?str_mg_notify_reply_verify_fun(),
+ %% ConnectVerify = fun str_mg_verify_handle_connect/1,
+ %% ServiceChangeReplyVerify = fun str_mg_verify_service_change_reply/1,
+ %% NotifyReplyVerify = fun str_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, max},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_cast, NotifyReq, []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+str_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("str_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+str_mg_verify_handle_connect(Else) ->
+ io:format("str_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+str_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("str_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+str_mg_verify_service_change_reply(Else) ->
+ io:format("str_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+str_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("str_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+str_mg_verify_notify_reply(Else) ->
+ io:format("str_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+str_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+str_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = str_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+str_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+str_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = str_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the single_trans_req test case
+%%
+
+str_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_timeout(suite) ->
+ [];
+multi_trans_req_timeout(doc) ->
+ [];
+multi_trans_req_timeout(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_timeout),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrt_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrt_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrt_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrt_mgc_verify_handle_connect, []}).
+-define(mtrt_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrt_mgc_verify_service_change_req, [Mid]}).
+-define(mtrt_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrt_mgc_verify_notify_request, []}).
+-define(mtrt_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrt_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrt_mgc_verify_handle_connect_fun(),
+ fun mtrt_mgc_verify_handle_connect/1).
+-define(mtrt_mgc_verify_service_change_req_fun(Mid),
+ mtrt_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrt_mgc_verify_notify_req_fun(),
+ mtrt_mgc_verify_notify_request_fun()).
+-define(mtrt_mgc_verify_handle_disconnect_fun(),
+ fun mtrt_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrt_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrt_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrt_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrt_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?mtrt_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrt_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrt_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrt_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun mtrt_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrt_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrt_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrt_mgc_verify_handle_connect(Else) ->
+ io:format("mtrt_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrt_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrt_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrt_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrt_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrt_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrt_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrt_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrt_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrt_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrt_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrt_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrt_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrt_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrt_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrt_mgc_verify_notify_request(Ev)
+ end.
+
+mtrt_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrt_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrt_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrt_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrt_mgc_verify_notify_request(Else) ->
+ io:format("mtrt_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrt_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrt_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrt_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrt_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrt_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrt_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrt_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrt_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrt_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrt_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrt_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrt_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrt_mg_verify_handle_connect, []}).
+-define(mtrt_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrt_mg_verify_service_change_reply, []}).
+-define(mtrt_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrt_mg_verify_notify_reply, []}).
+-else.
+-define(mtrt_mg_verify_handle_connect_fun(),
+ fun mtrt_mg_verify_handle_connect/1).
+-define(mtrt_mg_verify_service_change_reply_fun(),
+ fun mtrt_mg_verify_service_change_reply/1).
+-define(mtrt_mg_verify_notify_reply_fun(),
+ fun mtrt_mg_verify_notify_reply/1).
+-endif.
+
+mtrt_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrt_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [mtrt_mg_notify_request_ar(1, Tid, 1)],
+ ConnectVerify = ?mtrt_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrt_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrt_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, trans_timer, 5000},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrt_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrt_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrt_mg_verify_handle_connect(Else) ->
+ io:format("mtrt_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrt_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrt_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrt_mg_verify_service_change_reply(Else) ->
+ io:format("mtrt_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrt_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrt_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrt_mg_verify_notify_reply(Else) ->
+ io:format("mtrt_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrt_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrt_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrt_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrt_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrt_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrt_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrt_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_maxcount1(suite) ->
+ [];
+multi_trans_req_maxcount1(doc) ->
+ "Test that a message is sent when req_maxcount is reached";
+multi_trans_req_maxcount1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_maxcount1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrmc1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrmc1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrmc1_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrmc1_mgc_verify_handle_connect, []}).
+-define(mtrmc1_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrmc1_mgc_verify_service_change_req, [Mid]}).
+-define(mtrmc1_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrmc1_mgc_verify_notify_request, []}).
+-define(mtrmc1_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrmc1_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrmc1_mgc_verify_handle_connect_fun(),
+ fun mtrmc1_mgc_verify_handle_connect/1).
+-define(mtrmc1_mgc_verify_service_change_req_fun(Mid),
+ mtrmc1_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrmc1_mgc_verify_notify_req_fun(),
+ mtrmc1_mgc_verify_notify_request_fun()).
+-define(mtrmc1_mgc_verify_handle_disconnect_fun(),
+ fun mtrmc1_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrmc1_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrmc1_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrmc1_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrmc1_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?mtrmc1_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrmc1_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrmc1_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrmc1_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun mtrmc1_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrmc1_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrmc1_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrmc1_mgc_verify_handle_connect(Else) ->
+ io:format("mtrmc1_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc1_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrmc1_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrmc1_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrmc1_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrmc1_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrmc1_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrmc1_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrmc1_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrmc1_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrmc1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrmc1_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrmc1_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrmc1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrmc1_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrmc1_mgc_verify_notify_request(Ev)
+ end.
+
+mtrmc1_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrmc1_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrmc1_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrmc1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrmc1_mgc_verify_notify_request(Else) ->
+ io:format("mtrmc1_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrmc1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrmc1_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrmc1_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrmc1_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrmc1_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrmc1_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrmc1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrmc1_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrmc1_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrmc1_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrmc1_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrmc1_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrmc1_mg_verify_handle_connect, []}).
+-define(mtrmc1_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrmc1_mg_verify_service_change_reply, []}).
+-define(mtrmc1_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrmc1_mg_verify_notify_reply, []}).
+-else.
+-define(mtrmc1_mg_verify_handle_connect_fun(),
+ fun mtrmc1_mg_verify_handle_connect/1).
+-define(mtrmc1_mg_verify_service_change_reply_fun(),
+ fun mtrmc1_mg_verify_service_change_reply/1).
+-define(mtrmc1_mg_verify_notify_reply_fun(),
+ fun mtrmc1_mg_verify_notify_reply/1).
+-endif.
+
+mtrmc1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrmc1_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq = [mtrmc1_mg_notify_request_ar(1, Tid, 1)],
+ ConnectVerify = ?mtrmc1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrmc1_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrmc1_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrmc1_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrmc1_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrmc1_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, trans_req_maxcount, 5},
+ {megaco_update_conn_info, trans_req_maxsize, 4096},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_cast, NotifyReq, []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrmc1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrmc1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrmc1_mg_verify_handle_connect(Else) ->
+ io:format("mtrmc1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc1_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrmc1_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrmc1_mg_verify_service_change_reply(Else) ->
+ io:format("mtrmc1_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc1_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrmc1_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrmc1_mg_verify_notify_reply(Else) ->
+ io:format("mtrmc1_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrmc1_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrmc1_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrmc1_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrmc1_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrmc1_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrmc1_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_maxcount2(suite) ->
+ [];
+multi_trans_req_maxcount2(doc) ->
+ "Test that the message is sent when req_maxcount is reached "
+ "with a request bigger then maxsize limit";
+multi_trans_req_maxcount2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_maxcount2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrmc2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrmc2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrmc2_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrmc2_mgc_verify_handle_connect, []}).
+-define(mtrmc2_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrmc2_mgc_verify_service_change_req, [Mid]}).
+-define(mtrmc2_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrmc2_mgc_verify_notify_request, []}).
+-define(mtrmc2_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrmc2_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrmc2_mgc_verify_handle_connect_fun(),
+ fun mtrmc2_mgc_verify_handle_connect/1).
+-define(mtrmc2_mgc_verify_service_change_req_fun(Mid),
+ mtrmc2_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrmc2_mgc_verify_notify_req_fun(),
+ mtrmc2_mgc_verify_notify_request_fun()).
+-define(mtrmc2_mgc_verify_handle_disconnect_fun(),
+ fun mtrmc2_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrmc2_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrmc2_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrmc2_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrmc2_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?mtrmc2_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrmc2_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrmc2_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrmc2_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun mtrmc2_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrmc2_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrmc2_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrmc2_mgc_verify_handle_connect(Else) ->
+ io:format("mtrmc2_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc2_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrmc2_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrmc2_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrmc2_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrmc2_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrmc2_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrmc2_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrmc2_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrmc2_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrmc2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrmc2_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrmc2_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrmc2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrmc2_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrmc2_mgc_verify_notify_request(Ev)
+ end.
+
+mtrmc2_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrmc2_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ io:format("mtrmc2_mgc_verify_notify_request:fun -> "
+ "single command",[]),
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack,
+ [mtrmc2_mgc_notify_reply_ar1(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CRs} ->
+ io:format("mtrmc2_mgc_verify_notify_request:fun -> "
+ "multi command (~w)",[length(CRs)]),
+ Tids = [Tid ||
+ #'CommandRequest'{command =
+ {notifyReq,
+ #'NotifyRequest'{
+ terminationID = [Tid]}}}
+ <- CRs],
+ Reply =
+ {discard_ack,
+ [mtrmc2_mgc_notify_reply_ar2(Cid, Tids)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrmc2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrmc2_mgc_verify_notify_request(Else) ->
+ io:format("mtrmc2_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrmc2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrmc2_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrmc2_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrmc2_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrmc2_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrmc2_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrmc2_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrmc2_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrmc2_mgc_notify_reply_ar1(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrmc2_mgc_notify_reply_ar2(Cid, Tids) ->
+ CRs = [cre_cmdReply(cre_notifyReply([Tid])) || Tid <- Tids],
+ cre_actionReply(Cid, CRs).
+
+mtrmc2_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrmc2_mgc_notify_reply_ar1(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrmc2_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrmc2_mg_verify_handle_connect, []}).
+-define(mtrmc2_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrmc2_mg_verify_service_change_reply, []}).
+-define(mtrmc2_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrmc2_mg_verify_notify_reply, []}).
+-else.
+-define(mtrmc2_mg_verify_handle_connect_fun(),
+ fun mtrmc2_mg_verify_handle_connect/1).
+-define(mtrmc2_mg_verify_service_change_reply_fun(),
+ fun mtrmc2_mg_verify_service_change_reply/1).
+-define(mtrmc2_mg_verify_notify_reply_fun(),
+ fun mtrmc2_mg_verify_notify_reply/1).
+-endif.
+
+mtrmc2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrmc2_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR1 = fun(N) ->
+ [mtrmc2_mg_notify_request_ar1(N, Tid, N)]
+ end,
+ NR2 = fun(N) ->
+ [mtrmc2_mg_notify_request_ar2(N, Tid, N)]
+ end,
+ ConnectVerify = ?mtrmc2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrmc2_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrmc2_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrmc2_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrmc2_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrmc2_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, trans_req_maxcount, 5},
+ {megaco_update_conn_info, trans_req_maxsize, 1024},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR1(1), []},
+ {megaco_cast, [NR1(2), NR1(3)], []},
+ {megaco_cast, NR1(4), []},
+ {megaco_cast, NR2(5), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrmc2_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrmc2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrmc2_mg_verify_handle_connect(Else) ->
+ io:format("mtrmc2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc2_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrmc2_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrmc2_mg_verify_service_change_reply(Else) ->
+ io:format("mtrmc2_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc2_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrmc2_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [{notifyReply, _NR}]} ->
+ io:format("mtrmc2_mg_verify_notify_reply -> "
+ "single notify reply", []),
+ {ok, AR, ok};
+ #'ActionReply'{commandReply = [{notifyReply, _NR}|_] = CR} ->
+ io:format("mtrmc2_mg_verify_notify_reply -> "
+ "multi notify reply: (~w)", [length(CR)]),
+ {ok, AR, ok};
+ _ ->
+ {error, {invalid_action_reply, AR}, ok}
+ end;
+mtrmc2_mg_verify_notify_reply(Else) ->
+ io:format("mtrmc2_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrmc2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrmc2_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrmc2_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrmc2_mg_notify_request_ar1(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrmc2_mg_notify_request_ar2(Rid, Tid, Cid) ->
+ F = fun(N) ->
+ T = 22000000 + N,
+ TS = integer_to_list(T),
+ TT = cre_timeNotation("19990729", TS),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid+N, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ cre_cmdReq(CMD)
+ end,
+ Ns = [0,1,2,3,4,5,6,7,8,9],
+ CRs = [F(N) || N <- Ns],
+ cre_actionReq(Cid, CRs).
+
+mtrmc2_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrmc2_mg_notify_request_ar1(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrmc2_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_maxsize1(suite) ->
+ [];
+multi_trans_req_maxsize1(doc) ->
+ "Test that the message is sent when req_maxsize is reached";
+multi_trans_req_maxsize1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_maxsize1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrms1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrms1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrms1_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrms1_mgc_verify_handle_connect, []}).
+-define(mtrms1_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrms1_mgc_verify_service_change_req, [Mid]}).
+-define(mtrms1_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrms1_mgc_verify_notify_request, []}).
+-define(mtrms1_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrms1_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrms1_mgc_verify_handle_connect_fun(),
+ fun mtrms1_mgc_verify_handle_connect/1).
+-define(mtrms1_mgc_verify_service_change_req_fun(Mid),
+ mtrms1_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrms1_mgc_verify_notify_req_fun(),
+ mtrms1_mgc_verify_notify_request_fun()).
+-define(mtrms1_mgc_verify_handle_disconnect_fun(),
+ fun mtrms1_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrms1_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrms1_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrms1_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrms1_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?mtrms1_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrms1_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrms1_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify1 = mtrms1_mgc_verify_notify_request_fun1(),
+%% DiscoVerify = fun mtrms1_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrms1_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrms1_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrms1_mgc_verify_handle_connect(Else) ->
+ io:format("mtrms1_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms1_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrms1_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrms1_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrms1_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrms1_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrms1_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrms1_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrms1_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrms1_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrms1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrms1_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrms1_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrms1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrms1_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrms1_mgc_verify_notify_request(Ev)
+ end.
+
+mtrms1_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrms1_mgc_verify_notify_request:fun1 -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack,
+ [mtrms1_mgc_notify_reply_ar1(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrms1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrms1_mgc_verify_notify_request(Else) ->
+ io:format("mtrms1_mgc_verify_notify_request:fun1 -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrms1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrms1_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrms1_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrms1_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrms1_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrms1_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrms1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrms1_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrms1_mgc_notify_reply_ar1(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrms1_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrms1_mgc_notify_reply_ar1(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrms1_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrms1_mg_verify_handle_connect, []}).
+-define(mtrms1_mg_verify_service_change_reply_fun(Mid),
+ {?MODULE, mtrms1_mg_verify_service_change_reply, [Mid]}).
+-define(mtrms1_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrms1_mg_verify_notify_reply, []}).
+-else.
+-define(mtrms1_mg_verify_handle_connect_fun(),
+ fun mtrms1_mg_verify_handle_connect/1).
+-define(mtrms1_mg_verify_service_change_reply_fun(),
+ fun mtrms1_mg_verify_service_change_reply/1).
+-define(mtrms1_mg_verify_notify_reply_fun(),
+ fun mtrms1_mg_verify_notify_reply/1).
+-endif.
+
+mtrms1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrms1_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(N) ->
+ [mtrms1_mg_notify_request_ar1(N, Tid, N)]
+ end,
+ ConnectVerify = ?mtrms1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrms1_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrms1_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrms1_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrms1_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrms1_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxsize, 650},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1), []},
+ {megaco_cast, [NR(2), NR(3)], []},
+ {megaco_cast, NR(4), []},
+ {megaco_cast, NR(5), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrms1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrms1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrms1_mg_verify_handle_connect(Else) ->
+ io:format("mtrms1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms1_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrms1_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrms1_mg_verify_service_change_reply(Else) ->
+ io:format("mtrms1_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms1_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrms1_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrms1_mg_verify_notify_reply(Else) ->
+ io:format("mtrms1_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrms1_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrms1_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrms1_mg_notify_request_ar1(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrms1_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrms1_mg_notify_request_ar1(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+mtrms1_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_maxsize2(suite) ->
+ [];
+multi_trans_req_maxsize2(doc) ->
+ "Test that the message is sent when req_maxsize is reached, "
+ "when the 'last' message is bigger then req_maxsize itself";
+multi_trans_req_maxsize2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_maxsize2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrms2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrms2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrms2_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrms2_mgc_verify_handle_connect, []}).
+-define(mtrms2_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrms2_mgc_verify_service_change_req, [Mid]}).
+-define(mtrms2_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrms2_mgc_verify_notify_request, []}).
+-define(mtrms2_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrms2_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrms2_mgc_verify_handle_connect_fun(),
+ fun mtrms2_mgc_verify_handle_connect/1).
+-define(mtrms2_mgc_verify_service_change_req_fun(Mid),
+ mtrms2_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrms2_mgc_verify_notify_req_fun(),
+ mtrms2_mgc_verify_notify_request_fun()).
+-define(mtrms2_mgc_verify_handle_disconnect_fun(),
+ fun mtrms2_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrms2_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrms2_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrms2_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrms2_mgc_verify_notify_req_fun(),
+ DiscoVerify = ?mtrms2_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrms2_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrms2_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrms2_mgc_verify_notify_request_fun(),
+%% DiscoVerify = fun mtrms2_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrms2_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrms2_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrms2_mgc_verify_handle_connect(Else) ->
+ io:format("mtrms2_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms2_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrms2_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrms2_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrms2_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrms2_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrms2_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrms2_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrms2_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrms2_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrms2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrms2_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrms2_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrms2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrms2_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrms2_mgc_verify_notify_request(Ev)
+ end.
+
+mtrms2_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrms2_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = [CR]} ->
+ io:format("mtrms2_mgc_verify_notify_request:fun -> "
+ "single command", []),
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack,
+ [mtrms2_mgc_notify_reply_ar1(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = Cid,
+ commandRequests = CRs} ->
+ io:format("mtrms2_mgc_verify_notify_request:fun -> "
+ "multi command (~w)", [length(CRs)]),
+ Tids = [Tid ||
+ #'CommandRequest'{command =
+ {notifyReq,
+ #'NotifyRequest'{
+ terminationID = [Tid]}}}
+ <- CRs],
+ Reply =
+ {discard_ack,
+ [mtrms2_mgc_notify_reply_ar2(Cid, Tids)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrms2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrms2_mgc_verify_notify_request(Else) ->
+ io:format("mtrms2_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrms2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrms2_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrms2_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrms2_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrms2_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrms2_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrms2_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrms2_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrms2_mgc_notify_reply_ar1(Cid, Tid) ->
+ NR = cre_notifyReply([Tid]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrms2_mgc_notify_reply_ar2(Cid, Tids) ->
+ CRs = [cre_cmdReply(cre_notifyReply([Tid])) || Tid <- Tids],
+ cre_actionReply(Cid, CRs).
+
+mtrms2_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrms2_mgc_notify_reply_ar1(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrms2_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrms2_mg_verify_handle_connect, []}).
+-define(mtrms2_mg_verify_service_change_reply_fun(Mid),
+ {?MODULE, mtrms2_mg_verify_service_change_reply, [Mid]}).
+-define(mtrms2_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrms2_mg_verify_notify_reply, []}).
+-else.
+-define(mtrms2_mg_verify_handle_connect_fun(),
+ fun mtrms2_mg_verify_handle_connect/1).
+-define(mtrms2_mg_verify_service_change_reply_fun(),
+ fun mtrms2_mg_verify_service_change_reply/1).
+-define(mtrms2_mg_verify_notify_reply_fun(),
+ fun mtrms2_mg_verify_notify_reply/1).
+-endif.
+
+mtrms2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrms2_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NotifyReq1 = [mtrms2_mg_notify_request_ar1(1, Tid, 1)],
+ NotifyReq2 = [mtrms2_mg_notify_request_ar2(2, Tid, 2)],
+ ConnectVerify = ?mtrms2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrms2_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrms2_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrms2_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrms2_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrms2_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxsize, 1024},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NotifyReq1, []},
+ {megaco_cast, [NotifyReq1, NotifyReq1], []},
+ {megaco_cast, NotifyReq1, []},
+ {megaco_cast, NotifyReq2, []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrms2_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrms2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrms2_mg_verify_handle_connect(Else) ->
+ io:format("mtrms2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms2_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrms2_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrms2_mg_verify_service_change_reply(Else) ->
+ io:format("mtrms2_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms2_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrms2_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [{notifyReply, _NR}]} ->
+ io:format("mtrms2_mg_verify_notify_reply -> "
+ "single notify reply", []),
+ {ok, AR, ok};
+ #'ActionReply'{commandReply = [{notifyReply, _NR}|_] = CR} ->
+ io:format("mtrms2_mg_verify_notify_reply -> "
+ "multi notify reply: (~w)", [length(CR)]),
+ {ok, AR, ok};
+ _ ->
+ {error, {invalid_action_reply, AR}, ok}
+ end;
+mtrms2_mg_verify_notify_reply(Else) ->
+ io:format("mtrms2_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrms2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrms2_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrms2_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrms2_mg_notify_request_ar1(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrms2_mg_notify_request_ar2(Rid, Tid, Cid) ->
+ F = fun(N) ->
+ T = 22000000 + N,
+ TS = integer_to_list(T),
+ TT = cre_timeNotation("19990729", TS),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid+N, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ cre_cmdReq(CMD)
+ end,
+ Ns = [0,1,2,3,4,5,6,7,8,9],
+ CRs = [F(N) || N <- Ns],
+ cre_actionReq(Cid, CRs).
+
+mtrms2_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrms2_mg_notify_request_ar1(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+mtrms2_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_trans_req_and_ack(suite) ->
+ [];
+single_trans_req_and_ack(doc) ->
+ [];
+single_trans_req_and_ack(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, single_trans_req_and_ack),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = straa_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = straa_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(straa_mgc_verify_handle_connect_fun(),
+ {?MODULE, straa_mgc_verify_handle_connect, []}).
+-define(straa_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, straa_mgc_verify_service_change_req, [Mid]}).
+-define(straa_mgc_verify_notify_req_fun(),
+ {?MODULE, straa_mgc_verify_notify_request, []}).
+-define(straa_mgc_verify_ack_fun(),
+ {?MODULE, straa_mgc_verify_ack, []}).
+-define(straa_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, straa_mgc_verify_handle_disconnect, []}).
+-else.
+-define(straa_mgc_verify_handle_connect_fun(),
+ fun straa_mgc_verify_handle_connect/1).
+-define(straa_mgc_verify_service_change_req_fun(Mid),
+ straa_mgc_verify_service_change_req_fun(Mid)).
+-define(straa_mgc_verify_notify_req_fun(),
+ straa_mgc_verify_notify_request_fun()).
+-define(straa_mgc_verify_ack_fun(),
+ fun straa_mgc_verify_ack/1).
+-define(straa_mgc_verify_handle_disconnect_fun(),
+ fun straa_mgc_verify_handle_disconnect/1).
+-endif.
+
+straa_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?straa_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?straa_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?straa_mgc_verify_notify_req_fun(),
+ AckVerify = ?straa_mgc_verify_ack_fun(),
+ DiscoVerify = ?straa_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun straa_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = straa_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = straa_mgc_verify_notify_request_fun(),
+%% AckVerify = fun straa_mgc_verify_ack/1,
+%% DiscoVerify = fun straa_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+straa_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("straa_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+straa_mgc_verify_handle_connect(Else) ->
+ io:format("straa_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straa_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ straa_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+straa_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("straa_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [straa_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = straa_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = straa_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = straa_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = straa_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = straa_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+straa_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("straa_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = straa_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+straa_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ straa_mgc_verify_notify_request(Ev)
+ end.
+
+straa_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("straa_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [straa_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack,
+ [straa_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = straa_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+straa_mgc_verify_notify_request(Else) ->
+ io:format("straa_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = straa_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+straa_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("straa_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+straa_mgc_verify_ack(Else) ->
+ io:format("straa_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straa_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("straa_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+straa_mgc_verify_handle_disconnect(Else) ->
+ io:format("straa_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+straa_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+straa_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = straa_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+straa_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+straa_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = straa_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(straa_mg_verify_handle_connect_fun(),
+ {?MODULE, straa_mg_verify_handle_connect, []}).
+-define(straa_mg_verify_service_change_reply_fun(),
+ {?MODULE, straa_mg_verify_service_change_reply, []}).
+-define(straa_mg_verify_notify_reply_fun(),
+ {?MODULE, straa_mg_verify_notify_reply, []}).
+-else.
+-define(straa_mg_verify_handle_connect_fun(),
+ fun straa_mg_verify_handle_connect/1).
+-define(straa_mg_verify_service_change_reply_fun(),
+ fun straa_mg_verify_service_change_reply/1).
+-define(straa_mg_verify_notify_reply_fun(),
+ fun straa_mg_verify_notify_reply/1).
+-endif.
+
+straa_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [straa_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(N) ->
+ [straa_mg_notify_request_ar(N, Tid, N)]
+ end,
+ ConnectVerify = ?straa_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?straa_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?straa_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun straa_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun straa_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun straa_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {sleep, 1000},
+ {megaco_cast, NR(1), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, NR(2), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+straa_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("straa_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+straa_mg_verify_handle_connect(Else) ->
+ io:format("straa_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straa_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("straa_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+straa_mg_verify_service_change_reply(Else) ->
+ io:format("straa_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straa_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("straa_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+straa_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {error, Err}, _}) ->
+ io:format("straa_mg_verify_notify_reply -> error"
+ "~n Err: ~p~n", [Err]),
+ {error, Err, ok};
+straa_mg_verify_notify_reply(Else) ->
+ io:format("straa_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+straa_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+straa_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = straa_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+straa_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+straa_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = straa_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the single_trans_req test case
+%%
+
+straa_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_timeout(suite) ->
+ [];
+multi_trans_req_and_ack_timeout(doc) ->
+ [];
+multi_trans_req_and_ack_timeout(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_timeout),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrtaat_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrtaat_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaat_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrtaat_mgc_verify_handle_connect, []}).
+-define(mtrtaat_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrtaat_mgc_verify_service_change_req, [Mid]}).
+-define(mtrtaat_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrtaat_mgc_verify_notify_request, []}).
+-define(mtrtaat_mgc_verify_ack_fun(),
+ {?MODULE, mtrtaat_mgc_verify_ack, []}).
+-define(mtrtaat_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrtaat_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrtaat_mgc_verify_handle_connect_fun(),
+ fun mtrtaat_mgc_verify_handle_connect/1).
+-define(mtrtaat_mgc_verify_service_change_req_fun(Mid),
+ mtrtaat_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrtaat_mgc_verify_notify_req_fun(),
+ mtrtaat_mgc_verify_notify_request_fun()).
+-define(mtrtaat_mgc_verify_ack_fun(),
+ fun mtrtaat_mgc_verify_ack/1).
+-define(mtrtaat_mgc_verify_handle_disconnect_fun(),
+ fun mtrtaat_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrtaat_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrtaat_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrtaat_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrtaat_mgc_verify_notify_req_fun(),
+ AckVerify = ?mtrtaat_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtrtaat_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrtaat_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrtaat_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrtaat_mgc_verify_notify_request_fun(),
+%% AckVerify = fun mtrtaat_mgc_verify_ack/1,
+%% DiscoVerify = fun mtrtaat_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrtaat_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaat_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaat_mgc_verify_handle_connect(Else) ->
+ io:format("mtrtaat_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaat_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrtaat_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrtaat_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrtaat_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrtaat_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrtaat_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrtaat_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrtaat_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrtaat_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrtaat_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrtaat_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrtaat_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaat_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaat_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrtaat_mgc_verify_notify_request(Ev)
+ end.
+
+mtrtaat_mgc_verify_notify_request({handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrtaat_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [mtrtaat_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrtaat_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrtaat_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrtaat_mgc_verify_notify_request(Else) ->
+ io:format("mtrtaat_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaat_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+
+mtrtaat_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("mtrtaat_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+mtrtaat_mgc_verify_ack(Else) ->
+ io:format("mtrtaat_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaat_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrtaat_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrtaat_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrtaat_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrtaat_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaat_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrtaat_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaat_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaat_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrtaat_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaat_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrtaat_mg_verify_handle_connect, []}).
+-define(mtrtaat_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrtaat_mg_verify_service_change_reply, []}).
+-define(mtrtaat_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrtaat_mg_verify_notify_reply, []}).
+-else.
+-define(mtrtaat_mg_verify_handle_connect_fun(),
+ fun mtrtaat_mg_verify_handle_connect/1).
+-define(mtrtaat_mg_verify_service_change_reply_fun(),
+ fun mtrtaat_mg_verify_service_change_reply/1).
+-define(mtrtaat_mg_verify_notify_reply_fun(),
+ fun mtrtaat_mg_verify_notify_reply/1).
+-endif.
+
+mtrtaat_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrtaat_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtrtaat_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtrtaat_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrtaat_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrtaat_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrtaat_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrtaat_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrtaat_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrtaat_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaat_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaat_mg_verify_handle_connect(Else) ->
+ io:format("mtrtaat_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaat_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaat_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrtaat_mg_verify_service_change_reply(Else) ->
+ io:format("mtrtaat_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaat_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaat_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrtaat_mg_verify_notify_reply(Else) ->
+ io:format("mtrtaat_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaat_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaat_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrtaat_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaat_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaat_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrtaat_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrtaat_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_ackmaxcount(suite) ->
+ [];
+multi_trans_req_and_ack_ackmaxcount(doc) ->
+ [];
+multi_trans_req_and_ack_ackmaxcount(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_ackmaxcount),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrtaaamc_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrtaaamc_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaaamc_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrtaaamc_mgc_verify_handle_connect, []}).
+-define(mtrtaaamc_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrtaaamc_mgc_verify_service_change_req, [Mid]}).
+-define(mtrtaaamc_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrtaaamc_mgc_verify_notify_request, []}).
+-define(mtrtaaamc_mgc_verify_ack_fun(),
+ {?MODULE, mtrtaaamc_mgc_verify_ack, []}).
+-define(mtrtaaamc_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrtaaamc_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrtaaamc_mgc_verify_handle_connect_fun(),
+ fun mtrtaaamc_mgc_verify_handle_connect/1).
+-define(mtrtaaamc_mgc_verify_service_change_req_fun(Mid),
+ mtrtaaamc_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrtaaamc_mgc_verify_notify_req_fun(),
+ mtrtaaamc_mgc_verify_notify_request_fun()).
+-define(mtrtaaamc_mgc_verify_ack_fun(),
+ fun mtrtaaamc_mgc_verify_ack/1).
+-define(mtrtaaamc_mgc_verify_handle_disconnect_fun(),
+ fun mtrtaaamc_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrtaaamc_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrtaaamc_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrtaaamc_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrtaaamc_mgc_verify_notify_req_fun(),
+ AckVerify = ?mtrtaaamc_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtrtaaamc_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrtaaamc_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrtaaamc_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrtaaamc_mgc_verify_notify_request_fun(),
+%% AckVerify = fun mtrtaaamc_mgc_verify_ack/1,
+%% DiscoVerify = fun mtrtaaamc_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrtaaamc_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaaamc_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaaamc_mgc_verify_handle_connect(Else) ->
+ io:format("mtrtaaamc_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaaamc_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrtaaamc_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrtaaamc_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrtaaamc_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrtaaamc_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrtaaamc_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrtaaamc_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrtaaamc_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrtaaamc_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrtaaamc_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrtaaamc_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrtaaamc_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaaamc_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaaamc_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrtaaamc_mgc_verify_notify_request(Ev)
+ end.
+
+mtrtaaamc_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrtaaamc_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{requestId = Rid,
+ observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, {kalle, Rid}},
+ Reply = {HandleAck,
+ [mtrtaaamc_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrtaaamc_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrtaaamc_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrtaaamc_mgc_verify_notify_request(Else) ->
+ io:format("mtrtaaamc_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaaamc_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaaamc_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok,
+ {kalle, Rid}}) ->
+ io:format("mtrtaaamc_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n Rid: ~p"
+ "~n", [CH, Rid]),
+ {ok, CH, ok};
+mtrtaaamc_mgc_verify_ack(Else) ->
+ io:format("mtrtaaamc_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaaamc_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrtaaamc_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrtaaamc_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrtaaamc_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrtaaamc_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaaamc_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrtaaamc_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaaamc_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaaamc_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrtaaamc_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaaamc_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrtaaamc_mg_verify_handle_connect, []}).
+-define(mtrtaaamc_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrtaaamc_mg_verify_service_change_reply, []}).
+-define(mtrtaaamc_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrtaaamc_mg_verify_notify_reply, []}).
+-else.
+-define(mtrtaaamc_mg_verify_handle_connect_fun(),
+ fun mtrtaaamc_mg_verify_handle_connect/1).
+-define(mtrtaaamc_mg_verify_service_change_reply_fun(),
+ fun mtrtaaamc_mg_verify_service_change_reply/1).
+-define(mtrtaaamc_mg_verify_notify_reply_fun(),
+ fun mtrtaaamc_mg_verify_notify_reply/1).
+-endif.
+
+mtrtaaamc_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrtaaamc_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtrtaaamc_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtrtaaamc_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrtaaamc_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrtaaamc_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrtaaamc_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrtaaamc_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrtaaamc_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 4},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 5000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_cast, NR(1,4), [{trans_req,false}]},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrtaaamc_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaaamc_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaaamc_mg_verify_handle_connect(Else) ->
+ io:format("mtrtaaamc_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaaamc_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaaamc_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrtaaamc_mg_verify_service_change_reply(Else) ->
+ io:format("mtrtaaamc_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaaamc_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaaamc_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrtaaamc_mg_verify_notify_reply(Else) ->
+ io:format("mtrtaaamc_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaaamc_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaaamc_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrtaaamc_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaaamc_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaaamc_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrtaaamc_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrtaaamc_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_reqmaxcount(suite) ->
+ [];
+multi_trans_req_and_ack_reqmaxcount(doc) ->
+ [];
+multi_trans_req_and_ack_reqmaxcount(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_reqmaxcount),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrtaarac_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrtaarac_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaarac_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrtaarac_mgc_verify_handle_connect, []}).
+-define(mtrtaarac_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrtaarac_mgc_verify_service_change_req, [Mid]}).
+-define(mtrtaarac_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrtaarac_mgc_verify_notify_request, []}).
+-define(mtrtaarac_mgc_verify_ack_fun(),
+ {?MODULE, mtrtaarac_mgc_verify_ack, []}).
+-define(mtrtaarac_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrtaarac_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrtaarac_mgc_verify_handle_connect_fun(),
+ fun mtrtaarac_mgc_verify_handle_connect/1).
+-define(mtrtaarac_mgc_verify_service_change_req_fun(Mid),
+ mtrtaarac_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrtaarac_mgc_verify_notify_req_fun(),
+ mtrtaarac_mgc_verify_notify_request_fun()).
+-define(mtrtaarac_mgc_verify_ack_fun(),
+ fun mtrtaarac_mgc_verify_ack/1).
+-define(mtrtaarac_mgc_verify_handle_disconnect_fun(),
+ fun mtrtaarac_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrtaarac_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrtaarac_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrtaarac_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrtaarac_mgc_verify_notify_req_fun(),
+ AckVerify = ?mtrtaarac_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtrtaarac_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrtaarac_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrtaarac_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrtaarac_mgc_verify_notify_request_fun(),
+%% AckVerify = fun mtrtaarac_mgc_verify_ack/1,
+%% DiscoVerify = fun mtrtaarac_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrtaarac_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaarac_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaarac_mgc_verify_handle_connect(Else) ->
+ io:format("mtrtaarac_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaarac_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrtaarac_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrtaarac_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrtaarac_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrtaarac_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrtaarac_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrtaarac_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrtaarac_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrtaarac_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrtaarac_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrtaarac_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrtaarac_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaarac_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaarac_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrtaarac_mgc_verify_notify_request(Ev)
+ end.
+
+mtrtaarac_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrtaarac_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{requestId = Rid,
+ observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, {kalle, Rid}},
+ Reply = {HandleAck,
+ [mtrtaarac_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrtaarac_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrtaarac_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrtaarac_mgc_verify_notify_request(Else) ->
+ io:format("mtrtaarac_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaarac_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaarac_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok,
+ {kalle, Rid}}) ->
+ io:format("mtrtaarac_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n Rid: ~p"
+ "~n", [CH, Rid]),
+ {ok, CH, ok};
+mtrtaarac_mgc_verify_ack(Else) ->
+ io:format("mtrtaarac_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaarac_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrtaarac_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrtaarac_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrtaarac_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrtaarac_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaarac_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrtaarac_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaarac_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaarac_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrtaarac_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaarac_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrtaarac_mg_verify_handle_connect, []}).
+-define(mtrtaarac_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrtaarac_mg_verify_service_change_reply, []}).
+-define(mtrtaarac_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrtaarac_mg_verify_notify_reply, []}).
+-else.
+-define(mtrtaarac_mg_verify_handle_connect_fun(),
+ fun mtrtaarac_mg_verify_handle_connect/1).
+-define(mtrtaarac_mg_verify_service_change_reply_fun(),
+ fun mtrtaarac_mg_verify_service_change_reply/1).
+-define(mtrtaarac_mg_verify_notify_reply_fun(),
+ fun mtrtaarac_mg_verify_notify_reply/1).
+-endif.
+
+mtrtaarac_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrtaarac_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtrtaarac_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtrtaarac_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrtaarac_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrtaarac_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrtaarac_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrtaarac_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrtaarac_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 4},
+ {megaco_update_conn_info, trans_timer, 5000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_cast, NR(2,4), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrtaarac_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaarac_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaarac_mg_verify_handle_connect(Else) ->
+ io:format("mtrtaarac_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaarac_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaarac_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrtaarac_mg_verify_service_change_reply(Else) ->
+ io:format("mtrtaarac_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaarac_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaarac_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrtaarac_mg_verify_notify_reply(Else) ->
+ io:format("mtrtaarac_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaarac_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaarac_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrtaarac_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaarac_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaarac_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrtaarac_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrtaarac_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_maxsize1(suite) ->
+ [];
+multi_trans_req_and_ack_maxsize1(doc) ->
+ [];
+multi_trans_req_and_ack_maxsize1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_maxsize1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrtaams1_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrtaams1_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaams1_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrtaams1_mgc_verify_handle_connect, []}).
+-define(mtrtaams1_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrtaams1_mgc_verify_service_change_req, [Mid]}).
+-define(mtrtaams1_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrtaams1_mgc_verify_notify_request, []}).
+-define(mtrtaams1_mgc_verify_ack_fun(),
+ {?MODULE, mtrtaams1_mgc_verify_ack, []}).
+-define(mtrtaams1_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrtaams1_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrtaams1_mgc_verify_handle_connect_fun(),
+ fun mtrtaams1_mgc_verify_handle_connect/1).
+-define(mtrtaams1_mgc_verify_service_change_req_fun(Mid),
+ mtrtaams1_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrtaams1_mgc_verify_notify_req_fun(),
+ mtrtaams1_mgc_verify_notify_request_fun()).
+-define(mtrtaams1_mgc_verify_ack_fun(),
+ fun mtrtaams1_mgc_verify_ack/1).
+-define(mtrtaams1_mgc_verify_handle_disconnect_fun(),
+ fun mtrtaams1_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrtaams1_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrtaams1_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrtaams1_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrtaams1_mgc_verify_notify_req_fun(),
+ AckVerify = ?mtrtaams1_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtrtaams1_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrtaams1_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrtaams1_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrtaams1_mgc_verify_notify_request_fun(),
+%% AckVerify = fun mtrtaams1_mgc_verify_ack/1,
+%% DiscoVerify = fun mtrtaams1_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrtaams1_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaams1_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaams1_mgc_verify_handle_connect(Else) ->
+ io:format("mtrtaams1_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaams1_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrtaams1_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrtaams1_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtrtaams1_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrtaams1_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrtaams1_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrtaams1_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrtaams1_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrtaams1_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrtaams1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrtaams1_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtrtaams1_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaams1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaams1_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrtaams1_mgc_verify_notify_request(Ev)
+ end.
+
+mtrtaams1_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtrtaams1_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{requestId = Rid,
+ observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, {kalle, Rid}},
+ Reply = {HandleAck,
+ [mtrtaams1_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtrtaams1_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrtaams1_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrtaams1_mgc_verify_notify_request(Else) ->
+ io:format("mtrtaams1_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtrtaams1_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaams1_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok,
+ {kalle, Rid}}) ->
+ io:format("mtrtaams1_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n Rid: ~p"
+ "~n", [CH, Rid]),
+ {ok, CH, ok};
+mtrtaams1_mgc_verify_ack(Else) ->
+ io:format("mtrtaams1_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaams1_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtrtaams1_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtrtaams1_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtrtaams1_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtrtaams1_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaams1_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrtaams1_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaams1_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaams1_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrtaams1_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaams1_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrtaams1_mg_verify_handle_connect, []}).
+-define(mtrtaams1_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrtaams1_mg_verify_service_change_reply, []}).
+-define(mtrtaams1_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrtaams1_mg_verify_notify_reply, []}).
+-else.
+-define(mtrtaams1_mg_verify_handle_connect_fun(),
+ fun mtrtaams1_mg_verify_handle_connect/1).
+-define(mtrtaams1_mg_verify_service_change_reply_fun(),
+ fun mtrtaams1_mg_verify_service_change_reply/1).
+-define(mtrtaams1_mg_verify_notify_reply_fun(),
+ fun mtrtaams1_mg_verify_notify_reply/1).
+-endif.
+
+mtrtaams1_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrtaams1_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtrtaams1_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtrtaams1_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrtaams1_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrtaams1_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrtaams1_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrtaams1_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrtaams1_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxsize, 650},
+ {megaco_update_conn_info, trans_timer, 5000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, [NR(1,2), NR(1,3), NR(1,4)], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_cast, NR(2,4), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrtaams1_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtrtaams1_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtrtaams1_mg_verify_handle_connect(Else) ->
+ io:format("mtrtaams1_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaams1_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaams1_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrtaams1_mg_verify_service_change_reply(Else) ->
+ io:format("mtrtaams1_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaams1_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtrtaams1_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtrtaams1_mg_verify_notify_reply(Else) ->
+ io:format("mtrtaams1_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtrtaams1_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaams1_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrtaams1_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaams1_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaams1_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrtaams1_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrtaams1_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_maxsize2(suite) ->
+ [];
+multi_trans_req_and_ack_maxsize2(doc) ->
+ [];
+multi_trans_req_and_ack_maxsize2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_maxsize2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtrtaams2_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtrtaams2_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaams2_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtrtaams2_mgc_verify_handle_connect, []}).
+-define(mtrtaams2_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtrtaams2_mgc_verify_service_change_req, [Mid]}).
+-define(mtrtaams2_mgc_verify_notify_req_fun(),
+ {?MODULE, mtrtaams2_mgc_verify_notify_request, []}).
+-define(mtrtaams2_mgc_verify_ack_fun(),
+ {?MODULE, mtrtaams2_mgc_verify_ack, []}).
+-define(mtrtaams2_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtrtaams2_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtrtaams2_mgc_verify_handle_connect_fun(),
+ fun mtrtaams2_mgc_verify_handle_connect/1).
+-define(mtrtaams2_mgc_verify_service_change_req_fun(Mid),
+ mtrtaams2_mgc_verify_service_change_req_fun(Mid)).
+-define(mtrtaams2_mgc_verify_notify_req_fun(),
+ mtrtaams2_mgc_verify_notify_request_fun()).
+-define(mtrtaams2_mgc_verify_ack_fun(),
+ fun mtrtaams2_mgc_verify_ack/1).
+-define(mtrtaams2_mgc_verify_handle_disconnect_fun(),
+ fun mtrtaams2_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtrtaams2_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ConnectVerify = ?mtrtaams2_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtrtaams2_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtrtaams2_mgc_verify_notify_req_fun(),
+ AckVerify = ?mtrtaams2_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtrtaams2_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtrtaams2_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtrtaams2_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtrtaams2_mgc_verify_notify_request_fun(),
+%% AckVerify = fun mtrtaams2_mgc_verify_ack/1,
+%% DiscoVerify = fun mtrtaams2_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {listen, [{serialize, true}]},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_ack, AckVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtrtaams2_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ p("mtrtaams2_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p", [CH]),
+ {ok, CH, ok};
+mtrtaams2_mgc_verify_handle_connect(Else) ->
+ p("mtrtaams2_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p", [Else]),
+ {error, Else, ok}.
+
+mtrtaams2_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtrtaams2_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtrtaams2_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ p("mtrtaams2_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtrtaams2_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtrtaams2_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtrtaams2_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtrtaams2_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtrtaams2_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtrtaams2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtrtaams2_mgc_verify_service_change_req(Else, _Min) ->
+ p("mtrtaams2_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p", [Else]),
+ ED = mtrtaams2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaams2_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtrtaams2_mgc_verify_notify_request(Ev)
+ end.
+
+mtrtaams2_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ p("mtrtaams2_mgc_verify_notify_request:fun -> ok"
+ "~n AR: ~p", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ p("mtrtaams2_mgc_verify_notify_request:fun -> "
+ "single command", []),
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{requestId = Rid,
+ observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, {kalle, Rid}},
+ Reply = {HandleAck,
+ [mtrtaams2_mgc_notify_reply_ar1(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = CRs} ->
+ p("mtrtaams2_mgc_verify_notify_request:fun -> "
+ "multi command (~w)", [length(CRs)]),
+ Tids = [Tid ||
+ #'CommandRequest'{command =
+ {notifyReq,
+ #'NotifyRequest'{
+ terminationID = [Tid]}}}
+ <- CRs],
+ Reply =
+ {discard_ack,
+ [mtrtaams2_mgc_notify_reply_ar2(Cid, Tids)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtrtaams2_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtrtaams2_mgc_verify_notify_request(Else) ->
+ p("mtrtaams2_mgc_verify_notify_request:fun -> unknown"
+ "~n Else: ~p", [Else]),
+ ED = mtrtaams2_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtrtaams2_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok,
+ {kalle, Rid}}) ->
+ p("mtrtaams2_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n Rid: ~p", [CH, Rid]),
+ {ok, CH, ok};
+mtrtaams2_mgc_verify_ack(Else) ->
+ p("mtrtaams2_mgc_verify_ack -> Else: "
+ "~n~p", [Else]),
+ {error, Else, ok}.
+
+mtrtaams2_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ p("mtrtaams2_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p", [CH, R]),
+ {ok, CH, ok};
+mtrtaams2_mgc_verify_handle_disconnect(Else) ->
+ p("mtrtaams2_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p", [Else]),
+ {error, Else, ok}.
+
+
+mtrtaams2_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaams2_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtrtaams2_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaams2_mgc_notify_reply_ar1(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtrtaams2_mgc_notify_reply_ar2(Cid, Tids) ->
+ CRs = [cre_cmdReply(cre_notifyReply([Tid])) || Tid <- Tids],
+ cre_actionReply(Cid, CRs).
+
+mtrtaams2_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtrtaams2_mgc_notify_reply_ar1(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtrtaams2_mg_verify_handle_connect_fun(),
+ {?MODULE, mtrtaams2_mg_verify_handle_connect, []}).
+-define(mtrtaams2_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtrtaams2_mg_verify_service_change_reply, []}).
+-define(mtrtaams2_mg_verify_notify_reply_fun(),
+ {?MODULE, mtrtaams2_mg_verify_notify_reply, []}).
+-else.
+-define(mtrtaams2_mg_verify_handle_connect_fun(),
+ fun mtrtaams2_mg_verify_handle_connect/1).
+-define(mtrtaams2_mg_verify_service_change_reply_fun(),
+ fun mtrtaams2_mg_verify_service_change_reply/1).
+-define(mtrtaams2_mg_verify_notify_reply_fun(),
+ fun mtrtaams2_mg_verify_notify_reply/1).
+-endif.
+
+mtrtaams2_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtrtaams2_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR1 = fun(Cid, Rid) ->
+ [mtrtaams2_mg_notify_request_ar1(10 + Rid, Tid, Cid)]
+ end,
+ NR2 = fun(Cid, Rid) ->
+ [mtrtaams2_mg_notify_request_ar2(20 + Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtrtaams2_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtrtaams2_mg_verify_service_change_reply_fun(),
+ NotifyReplyVerify = ?mtrtaams2_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtrtaams2_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtrtaams2_mg_verify_service_change_reply/1,
+%% NotifyReplyVerify = fun mtrtaams2_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {connect, [{serialize, true}]},
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxsize, 1024},
+ {megaco_update_conn_info, trans_timer, 5000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, [NR1(1,2), NR1(1,3), NR1(1,4)], []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_cast, [NR1(2,5), NR1(2,6), NR1(2,7)], []},
+ {megaco_cast, NR2(2,1), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtrtaams2_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ p("mtrtaams2_mg_verify_handle_connect -> ok"
+ "~n CH: ~p", [CH]),
+ {ok, CH, ok};
+mtrtaams2_mg_verify_handle_connect(Else) ->
+ p("mtrtaams2_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p", [Else]),
+ {error, Else, ok}.
+
+mtrtaams2_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ p("mtrtaams2_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtrtaams2_mg_verify_service_change_reply(Else) ->
+ p("mtrtaams2_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p", [Else]),
+ {error, Else, ok}.
+
+mtrtaams2_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ p("mtrtaams2_mg_verify_notify_reply -> ok"
+ "~n AR: ~p", [AR]),
+ {ok, AR, ok};
+mtrtaams2_mg_verify_notify_reply(Else) ->
+ p("mtrtaams2_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p", [Else]),
+ {error, Else, ok}.
+
+mtrtaams2_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaams2_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtrtaams2_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtrtaams2_mg_notify_request_ar1(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtrtaams2_mg_notify_request_ar2(Rid, Tid, Cid) ->
+ F = fun(N) ->
+ T = 22000000 + N,
+ TS = integer_to_list(T),
+ TT = cre_timeNotation("19990729", TS),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid+N, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ cre_cmdReq(CMD)
+ end,
+ Ns = [0,1,2,3,4,5,6,7,8,9],
+ CRs = [F(N) || N <- Ns],
+ cre_actionReq(Cid, CRs).
+
+mtrtaams2_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtrtaams2_mg_notify_request_ar1(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtrtaams2_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+single_trans_req_and_pending(suite) ->
+ [];
+single_trans_req_and_pending(doc) ->
+ [];
+single_trans_req_and_pending(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_pending(suite) ->
+ [];
+multi_trans_req_and_pending(doc) ->
+ [];
+multi_trans_req_and_pending(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_and_pending(suite) ->
+ [];
+multi_trans_req_and_ack_and_pending(doc) ->
+ [];
+multi_trans_req_and_ack_and_pending(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, mtraaap),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtraaap_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtraaap_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtraaap_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtraaap_mgc_verify_handle_connect, []}).
+-define(mtraaap_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtraaap_mgc_verify_service_change_req, [Mid]}).
+-define(mtraaap_mgc_verify_notify_req_fun(),
+ {?MODULE, mtraaap_mgc_verify_notify_request, []}).
+-define(mtraaap_mgc_verify_notify_reply_fun(),
+ {?MODULE, mtraaap_mgc_verify_notify_reply, []}).
+-define(mtraaap_mgc_verify_ack_fun(),
+ {?MODULE, mtraaap_mgc_verify_ack, []}).
+-define(mtraaap_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtraaap_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtraaap_mgc_verify_handle_connect_fun(),
+ fun mtraaap_mgc_verify_handle_connect/1).
+-define(mtraaap_mgc_verify_service_change_req_fun(Mid),
+ mtraaap_mgc_verify_service_change_req_fun(Mid)).
+-define(mtraaap_mgc_verify_notify_req_fun(),
+ mtraaap_mgc_verify_notify_request_fun()).
+-define(mtraaap_mgc_verify_notify_reply_fun(),
+ fun mtraaap_mgc_verify_notify_reply/1).
+-define(mtraaap_mgc_verify_ack_fun(),
+ fun mtraaap_mgc_verify_ack/1).
+-define(mtraaap_mgc_verify_handle_disconnect_fun(),
+ fun mtraaap_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtraaap_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtraaap_mgc_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ReqTmr = #megaco_incr_timer{wait_for = 500,
+ factor = 1,
+ max_retries = 1},
+ ConnectVerify = ?mtraaap_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtraaap_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtraaap_mgc_verify_notify_req_fun(),
+ NotifyReplyVerify = ?mtraaap_mgc_verify_notify_reply_fun(),
+ AckVerify = ?mtraaap_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtraaap_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtraaap_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtraaap_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtraaap_mgc_verify_notify_request_fun(),
+%% NotifyReplyVerify = fun mtraaap_mgc_verify_notify_reply/1,
+%% AckVerify = fun mtraaap_mgc_verify_ack/1,
+%% DiscoVerify = fun mtraaap_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_update_conn_info, request_timer, ReqTmr},
+ {megaco_cast, NR(1,1), []},
+ {megaco_callback, [{handle_trans_ack, 3, AckVerify},
+ {handle_trans_request, 3, NotifyReqVerify},
+ {handle_trans_reply, 1, NotifyReplyVerify}]},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtraaap_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtraaap_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtraaap_mgc_verify_handle_connect(Else) ->
+ io:format("mtraaap_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtraaap_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtraaap_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtraaap_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtraaap_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtraaap_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtraaap_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtraaap_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtraaap_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtraaap_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtraaap_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtraaap_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaap_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaap_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtraaap_mgc_verify_notify_request(Ev)
+ end.
+
+mtraaap_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtraaap_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [mtraaap_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtraaap_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtraaap_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtraaap_mgc_verify_notify_request(Else) ->
+ io:format("mtraaap_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaap_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaap_mgc_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaap_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtraaap_mgc_verify_notify_reply(Else) ->
+ io:format("mtraaap_mgc_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("mtraaap_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+mtraaap_mgc_verify_ack(Else) ->
+ io:format("mtraaap_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtraaap_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtraaap_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtraaap_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtraaap_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaap_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtraaap_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtraaap_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "44000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaap_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaap_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtraaap_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtraaap_mg_verify_handle_connect_fun(),
+ {?MODULE, mtraaap_mg_verify_handle_connect, []}).
+-define(mtraaap_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtraaap_mg_verify_service_change_reply, []}).
+-define(mtraaap_mg_verify_notify_req_fun(),
+ {?MODULE, mtraaap_mgc_verify_notify_request, []}).
+-define(mtraaap_mg_verify_notify_reply_fun(),
+ {?MODULE, mtraaap_mg_verify_notify_reply, []}).
+-else.
+-define(mtraaap_mg_verify_handle_connect_fun(),
+ fun mtraaap_mg_verify_handle_connect/1).
+-define(mtraaap_mg_verify_service_change_reply_fun(),
+ fun mtraaap_mg_verify_service_change_reply/1).
+-define(mtraaap_mg_verify_notify_req_fun(),
+ mtraaap_mgc_verify_notify_request_fun()).
+-define(mtraaap_mg_verify_notify_reply_fun(),
+ fun mtraaap_mg_verify_notify_reply/1).
+-endif.
+
+mtraaap_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtraaap_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtraaap_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtraaap_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtraaap_mg_verify_service_change_reply_fun(),
+ NotifyReqVerify = ?mtraaap_mg_verify_notify_req_fun(),
+ NotifyReplyVerify = ?mtraaap_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtraaap_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtraaap_mg_verify_service_change_reply/1,
+%% NotifyReqVerify = mtraaap_mg_verify_notify_request_fun(),
+%% NotifyReplyVerify = fun mtraaap_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtraaap_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtraaap_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtraaap_mg_verify_handle_connect(Else) ->
+ io:format("mtraaap_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaap_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtraaap_mg_verify_service_change_reply(Else) ->
+ io:format("mtraaap_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mg_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtraaap_mg_verify_notify_request(Ev)
+ end.
+
+mtraaap_mg_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtraaap_mg_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtraaap_mg_notify_reply_ar(Cid, Tid)]},
+ {ok, 3000, AR, Reply};
+ _ ->
+ ED = mtraaap_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtraaap_mg_verify_notify_request(Else) ->
+ io:format("mtraaap_mg_verify_notify_request:fun -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaap_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaap_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaap_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtraaap_mg_verify_notify_reply(Else) ->
+ io:format("mtraaap_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaap_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaap_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtraaap_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtraaap_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaap_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaap_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtraaap_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for this test case
+%%
+
+mtraaap_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_ack_and_pending(suite) ->
+ [];
+multi_ack_and_pending(doc) ->
+ [];
+multi_ack_and_pending(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_reply(suite) ->
+ [];
+multi_trans_req_and_reply(doc) ->
+ [];
+multi_trans_req_and_reply(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_trans_req_and_ack_and_reply(suite) ->
+ [];
+multi_trans_req_and_ack_and_reply(doc) ->
+ [];
+multi_trans_req_and_ack_and_reply(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_and_ack_and_reply),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = mtraaar_mgc_event_sequence(text, tcp),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = mtraaar_mg_event_sequence(text, tcp),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator reply(s)"),
+ await_completion([MgcId, MgId]),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtraaar_mgc_verify_handle_connect_fun(),
+ {?MODULE, mtraaar_mgc_verify_handle_connect, []}).
+-define(mtraaar_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, mtraaar_mgc_verify_service_change_req, [Mid]}).
+-define(mtraaar_mgc_verify_notify_req_fun(),
+ {?MODULE, mtraaar_mgc_verify_notify_request, []}).
+-define(mtraaar_mgc_verify_notify_reply_fun(),
+ {?MODULE, mtraaar_mgc_verify_notify_reply, []}).
+-define(mtraaar_mgc_verify_ack_fun(),
+ {?MODULE, mtraaar_mgc_verify_ack, []}).
+-define(mtraaar_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, mtraaar_mgc_verify_handle_disconnect, []}).
+-else.
+-define(mtraaar_mgc_verify_handle_connect_fun(),
+ fun mtraaar_mgc_verify_handle_connect/1).
+-define(mtraaar_mgc_verify_service_change_req_fun(Mid),
+ mtraaar_mgc_verify_service_change_req_fun(Mid)).
+-define(mtraaar_mgc_verify_notify_req_fun(),
+ mtraaar_mgc_verify_notify_request_fun()).
+-define(mtraaar_mgc_verify_notify_reply_fun(),
+ fun mtraaar_mgc_verify_notify_reply/1).
+-define(mtraaar_mgc_verify_ack_fun(),
+ fun mtraaar_mgc_verify_ack/1).
+-define(mtraaar_mgc_verify_handle_disconnect_fun(),
+ fun mtraaar_mgc_verify_handle_disconnect/1).
+-endif.
+
+mtraaar_mgc_event_sequence(text, tcp) ->
+ Mid = {deviceName,"ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtraaar_mgc_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtraaar_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?mtraaar_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?mtraaar_mgc_verify_notify_req_fun(),
+ NotifyReplyVerify = ?mtraaar_mgc_verify_notify_reply_fun(),
+ AckVerify = ?mtraaar_mgc_verify_ack_fun(),
+ DiscoVerify = ?mtraaar_mgc_verify_handle_disconnect_fun(),
+%% ConnectVerify = fun mtraaar_mgc_verify_handle_connect/1,
+%% ServiceChangeReqVerify = mtraaar_mgc_verify_service_change_req_fun(Mid),
+%% NotifyReqVerify = mtraaar_mgc_verify_notify_request_fun(),
+%% NotifyReplyVerify = fun mtraaar_mgc_verify_notify_reply/1,
+%% AckVerify = fun mtraaar_mgc_verify_ack/1,
+%% DiscoVerify = fun mtraaar_mgc_verify_handle_disconnect/1,
+ EvSeq = [
+ {debug, true},
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_update_conn_info, request_timer, 1000},
+ {megaco_cast, NR(1,1), []},
+
+ {megaco_callback, [{handle_trans_ack, 3, AckVerify},
+ {handle_trans_request, 3, NotifyReqVerify},
+ {handle_trans_reply, 1, NotifyReplyVerify}]},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+mtraaar_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtraaar_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtraaar_mgc_verify_handle_connect(Else) ->
+ io:format("mtraaar_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaar_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ mtraaar_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+mtraaar_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("mtraaar_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [mtraaar_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = mtraaar_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = mtraaar_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = mtraaar_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = mtraaar_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = mtraaar_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+mtraaar_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("mtraaar_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaar_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaar_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtraaar_mgc_verify_notify_request(Ev)
+ end.
+
+mtraaar_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtraaar_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [mtraaar_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtraaar_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtraaar_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtraaar_mgc_verify_notify_request(Else) ->
+ io:format("mtraaar_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaar_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaar_mgc_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaar_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtraaar_mgc_verify_notify_reply({handle_trans_reply, CH, ?VERSION,
+ UnknownResult, _}) ->
+ io:format("mtraaar_mgc_verify_notify_reply -> unknown result"
+ "~n UnknownResult: ~p~n", [UnknownResult]),
+ {error, {unknown_reply_result, UnknownResult, CH}, ok};
+mtraaar_mgc_verify_notify_reply(Else) ->
+ io:format("mtraaar_mgc_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, {unknown_reply, Else}, ok}.
+
+mtraaar_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("mtraaar_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+mtraaar_mgc_verify_ack(Else) ->
+ io:format("mtraaar_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaar_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("mtraaar_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+mtraaar_mgc_verify_handle_disconnect(Else) ->
+ io:format("mtraaar_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+mtraaar_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaar_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = mtraaar_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtraaar_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "44000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaar_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaar_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = mtraaar_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(mtraaar_mg_verify_handle_connect_fun(),
+ {?MODULE, mtraaar_mg_verify_handle_connect, []}).
+-define(mtraaar_mg_verify_service_change_reply_fun(),
+ {?MODULE, mtraaar_mg_verify_service_change_reply, []}).
+-define(mtraaar_mg_verify_notify_req_fun(),
+ {?MODULE, mtraaar_mgc_verify_notify_request, []}).
+-define(mtraaar_mg_verify_notify_reply_fun(),
+ {?MODULE, mtraaar_mg_verify_notify_reply, []}).
+-else.
+-define(mtraaar_mg_verify_handle_connect_fun(),
+ fun mtraaar_mg_verify_handle_connect/1).
+-define(mtraaar_mg_verify_service_change_reply_fun(),
+ fun mtraaar_mg_verify_service_change_reply/1).
+-define(mtraaar_mg_verify_notify_req_fun(),
+ mtraaar_mgc_verify_notify_request_fun()).
+-define(mtraaar_mg_verify_notify_reply_fun(),
+ fun mtraaar_mg_verify_notify_reply/1).
+-endif.
+
+mtraaar_mg_event_sequence(text, tcp) ->
+ Mid = {deviceName,"mg"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [mtraaar_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [mtraaar_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?mtraaar_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?mtraaar_mg_verify_service_change_reply_fun(),
+ NotifyReqVerify = ?mtraaar_mg_verify_notify_req_fun(),
+ NotifyReplyVerify = ?mtraaar_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun mtraaar_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun mtraaar_mg_verify_service_change_reply/1,
+%% NotifyReqVerify = mtraaar_mg_verify_notify_request_fun(),
+%% NotifyReplyVerify = fun mtraaar_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+mtraaar_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("mtraaar_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+mtraaar_mg_verify_handle_connect(Else) ->
+ io:format("mtraaar_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaar_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaar_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+mtraaar_mg_verify_service_change_reply(Else) ->
+ io:format("mtraaar_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaar_mg_verify_notify_request_fun() ->
+ fun(Ev) ->
+ mtraaar_mg_verify_notify_request(Ev)
+ end.
+
+mtraaar_mg_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("mtraaar_mg_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [mtraaar_mg_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = mtraaar_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+mtraaar_mg_verify_notify_request(Else) ->
+ io:format("mtraaar_mg_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = mtraaar_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+mtraaar_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("mtraaar_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+mtraaar_mg_verify_notify_reply(Else) ->
+ io:format("mtraaar_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+mtraaar_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaar_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = mtraaar_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+mtraaar_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+mtraaar_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+mtraaar_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = mtraaar_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+mtraaar_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+multi_ack_and_reply(suite) ->
+ [];
+multi_ack_and_reply(doc) ->
+ [];
+multi_ack_and_reply(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7192_1(suite) ->
+ [];
+otp_7192_1(doc) ->
+ [""];
+otp_7192_1(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_7192_1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+
+ MgMid = {deviceName,"mg"},
+
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp71921_mgc_event_sequence(text, tcp, MgMid),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp71921_mg_event_sequence(text, tcp, MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator(s) completion"),
+ await_completion([MgcId, MgId], 30000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp71921_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp71921_mgc_verify_handle_connect, []}).
+-define(otp71921_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp71921_mgc_verify_service_change_req, [Mid]}).
+-define(otp71921_mgc_verify_notify_req_fun(),
+ {?MODULE, otp71921_mgc_verify_notify_request, []}).
+-define(otp71921_mgc_verify_notify_reply_fun(),
+ {?MODULE, otp71921_mgc_verify_notify_reply, []}).
+-define(otp71921_mgc_verify_ack_fun(),
+ {?MODULE, otp71921_mgc_verify_ack, []}).
+-define(otp71921_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp71921_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp71921_mgc_verify_handle_connect_fun(),
+ fun otp71921_mgc_verify_handle_connect/1).
+-define(otp71921_mgc_verify_service_change_req_fun(Mid),
+ otp71921_mgc_verify_service_change_req_fun(Mid)).
+-define(otp71921_mgc_verify_notify_req_fun(),
+ otp71921_mgc_verify_notify_request_fun()).
+-define(otp71921_mgc_verify_notify_reply_fun(),
+ fun otp71921_mgc_verify_notify_reply/1).
+-define(otp71921_mgc_verify_ack_fun(),
+ fun otp71921_mgc_verify_ack/1).
+-define(otp71921_mgc_verify_handle_disconnect_fun(),
+ fun otp71921_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp71921_mgc_event_sequence(text, tcp, MgMid) ->
+ Mid = {deviceName, "ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp71921_mgc_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ LocalConnectVerify = ?otp71921_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?otp71921_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?otp71921_mgc_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp71921_mgc_verify_notify_reply_fun(),
+ AckVerify = ?otp71921_mgc_verify_ack_fun(),
+ DiscoVerify = ?otp71921_mgc_verify_handle_disconnect_fun(),
+ EvSeq = [
+ {debug, true},
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_connect, MgMid},
+ {megaco_callback, handle_connect, LocalConnectVerify},
+ %% {megaco_callback, handle_connect, RemoteConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_update_conn_info, request_timer, 1000},
+ {megaco_cast, NR(1,1), []},
+
+ {megaco_callback, [{handle_trans_ack, 3, AckVerify},
+ {handle_trans_request, 3, NotifyReqVerify},
+ {handle_trans_reply, 1, NotifyReplyVerify}]},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+otp71921_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp71921_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp71921_mgc_verify_handle_connect(Else) ->
+ io:format("otp71921_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71921_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ otp71921_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+otp71921_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("otp71921_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp71921_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp71921_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp71921_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp71921_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp71921_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp71921_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp71921_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("otp71921_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71921_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71921_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp71921_mgc_verify_notify_request(Ev)
+ end.
+
+otp71921_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp71921_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [otp71921_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp71921_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp71921_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp71921_mgc_verify_notify_request(Else) ->
+ io:format("otp71921_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71921_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71921_mgc_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71921_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp71921_mgc_verify_notify_reply({handle_trans_reply, CH, ?VERSION,
+ UnknownResult, _}) ->
+ io:format("otp71921_mgc_verify_notify_reply -> unknown result"
+ "~n UnknownResult: ~p~n", [UnknownResult]),
+ {error, {unknown_reply_result, UnknownResult, CH}, ok};
+otp71921_mgc_verify_notify_reply(Else) ->
+ io:format("otp71921_mgc_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, {unknown_reply, Else}, ok}.
+
+otp71921_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("otp71921_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp71921_mgc_verify_ack(Else) ->
+ io:format("otp71921_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71921_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("otp71921_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+otp71921_mgc_verify_handle_disconnect(Else) ->
+ io:format("otp71921_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp71921_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+otp71921_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = otp71921_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp71921_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "44000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71921_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp71921_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = otp71921_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp71921_mg_verify_handle_connect_fun(),
+ {?MODULE, otp71921_mg_verify_handle_connect, []}).
+-define(otp71921_mg_verify_service_change_reply_fun(),
+ {?MODULE, otp71921_mg_verify_service_change_reply, []}).
+-define(otp71921_mg_verify_notify_req_fun(),
+ {?MODULE, otp71921_mgc_verify_notify_request, []}).
+-define(otp71921_mg_verify_notify_reply_fun(),
+ {?MODULE, otp71921_mg_verify_notify_reply, []}).
+-else.
+-define(otp71921_mg_verify_handle_connect_fun(),
+ fun otp71921_mg_verify_handle_connect/1).
+-define(otp71921_mg_verify_service_change_reply_fun(),
+ fun otp71921_mg_verify_service_change_reply/1).
+-define(otp71921_mg_verify_notify_req_fun(),
+ otp71921_mgc_verify_notify_request_fun()).
+-define(otp71921_mg_verify_notify_reply_fun(),
+ fun otp71921_mg_verify_notify_reply/1).
+-endif.
+
+otp71921_mg_event_sequence(text, tcp, Mid) ->
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [otp71921_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp71921_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?otp71921_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?otp71921_mg_verify_service_change_reply_fun(),
+ NotifyReqVerify = ?otp71921_mg_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp71921_mg_verify_notify_reply_fun(),
+%% ConnectVerify = fun otp71921_mg_verify_handle_connect/1,
+%% ServiceChangeReplyVerify = fun otp71921_mg_verify_service_change_reply/1,
+%% NotifyReqVerify = otp71921_mg_verify_notify_request_fun(),
+%% NotifyReplyVerify = fun otp71921_mg_verify_notify_reply/1,
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+otp71921_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp71921_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp71921_mg_verify_handle_connect(Else) ->
+ io:format("otp71921_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71921_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71921_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+otp71921_mg_verify_service_change_reply(Else) ->
+ io:format("otp71921_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71921_mg_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp71921_mg_verify_notify_request(Ev)
+ end.
+
+otp71921_mg_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp71921_mg_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp71921_mg_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp71921_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp71921_mg_verify_notify_request(Else) ->
+ io:format("otp71921_mg_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71921_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71921_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71921_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp71921_mg_verify_notify_reply(Else) ->
+ io:format("otp71921_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71921_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71921_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp71921_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp71921_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp71921_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71921_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = otp71921_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+otp71921_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7192_2(suite) ->
+ [];
+otp_7192_2(doc) ->
+ [];
+otp_7192_2(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_7192_2),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+
+ MgMid = {deviceName,"mg"},
+
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp71922_mgc_event_sequence(text, tcp, MgMid),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp71922_mg_event_sequence(text, tcp, MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator(s) completion"),
+ await_completion([MgcId, MgId], 30000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp71922_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp71922_mgc_verify_handle_connect, []}).
+-define(otp71922_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp71922_mgc_verify_service_change_req, [Mid]}).
+-define(otp71922_mgc_verify_notify_req_fun(),
+ {?MODULE, otp71922_mgc_verify_notify_request, []}).
+-define(otp71922_mgc_verify_notify_reply_fun(),
+ {?MODULE, otp71922_mgc_verify_notify_reply, []}).
+-define(otp71922_mgc_verify_ack_fun(),
+ {?MODULE, otp71922_mgc_verify_ack, []}).
+-define(otp71922_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp71922_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp71922_mgc_verify_handle_connect_fun(),
+ fun otp71922_mgc_verify_handle_connect/1).
+-define(otp71922_mgc_verify_service_change_req_fun(Mid),
+ otp71922_mgc_verify_service_change_req_fun(Mid)).
+-define(otp71922_mgc_verify_notify_req_fun(),
+ otp71922_mgc_verify_notify_request_fun()).
+-define(otp71922_mgc_verify_notify_reply_fun(),
+ fun otp71922_mgc_verify_notify_reply/1).
+-define(otp71922_mgc_verify_ack_fun(),
+ fun otp71922_mgc_verify_ack/1).
+-define(otp71922_mgc_verify_handle_disconnect_fun(),
+ fun otp71922_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp71922_mgc_event_sequence(text, tcp, MgMid) ->
+ Mid = {deviceName, "ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp71922_mgc_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ LocalConnectVerify = ?otp71922_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?otp71922_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?otp71922_mgc_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp71922_mgc_verify_notify_reply_fun(),
+ AckVerify = ?otp71922_mgc_verify_ack_fun(),
+ DiscoVerify = ?otp71922_mgc_verify_handle_disconnect_fun(),
+ EvSeq = [
+ {debug, true},
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_connect, MgMid},
+ {megaco_callback, handle_connect, LocalConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_update_conn_info, request_timer, 1000},
+ {megaco_cast, NR(1,1), []},
+
+ {megaco_callback, [{handle_trans_ack, 3, AckVerify},
+ {handle_trans_request, 3, NotifyReqVerify},
+ {handle_trans_reply, 1, NotifyReplyVerify}]},
+ {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+otp71922_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp71922_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, timer:seconds(2), CH, ok};
+otp71922_mgc_verify_handle_connect(Else) ->
+ io:format("otp71922_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71922_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ otp71922_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+otp71922_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("otp71922_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp71922_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp71922_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp71922_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp71922_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp71922_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp71922_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp71922_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("otp71922_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71922_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71922_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp71922_mgc_verify_notify_request(Ev)
+ end.
+
+otp71922_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp71922_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [otp71922_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp71922_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp71922_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp71922_mgc_verify_notify_request(Else) ->
+ io:format("otp71922_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71922_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71922_mgc_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71922_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp71922_mgc_verify_notify_reply({handle_trans_reply, CH, ?VERSION,
+ UnknownResult, _}) ->
+ io:format("otp71922_mgc_verify_notify_reply -> unknown result"
+ "~n UnknownResult: ~p~n", [UnknownResult]),
+ {error, {unknown_reply_result, UnknownResult, CH}, ok};
+otp71922_mgc_verify_notify_reply(Else) ->
+ io:format("otp71922_mgc_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, {unknown_reply, Else}, ok}.
+
+otp71922_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("otp71922_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp71922_mgc_verify_ack(Else) ->
+ io:format("otp71922_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71922_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+ io:format("otp71922_mgc_verify_handle_disconnect -> ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
+ {ok, CH, ok};
+otp71922_mgc_verify_handle_disconnect(Else) ->
+ io:format("otp71922_mgc_verify_handle_disconnect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+
+otp71922_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+otp71922_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = otp71922_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp71922_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "44000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71922_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp71922_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = otp71922_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp71922_mg_verify_handle_connect_fun(),
+ {?MODULE, otp71922_mg_verify_handle_connect, []}).
+-define(otp71922_mg_verify_service_change_reply_fun(),
+ {?MODULE, otp71922_mg_verify_service_change_reply, []}).
+-define(otp71922_mg_verify_notify_req_fun(),
+ {?MODULE, otp71922_mgc_verify_notify_request, []}).
+-define(otp71922_mg_verify_notify_reply_fun(),
+ {?MODULE, otp71922_mg_verify_notify_reply, []}).
+-else.
+-define(otp71922_mg_verify_handle_connect_fun(),
+ fun otp71922_mg_verify_handle_connect/1).
+-define(otp71922_mg_verify_service_change_reply_fun(),
+ fun otp71922_mg_verify_service_change_reply/1).
+-define(otp71922_mg_verify_notify_req_fun(),
+ otp71922_mgc_verify_notify_request_fun()).
+-define(otp71922_mg_verify_notify_reply_fun(),
+ fun otp71922_mg_verify_notify_reply/1).
+-endif.
+
+otp71922_mg_event_sequence(text, tcp, Mid) ->
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_tcp}
+ ],
+ ServiceChangeReq = [otp71922_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp71922_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?otp71922_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?otp71922_mg_verify_service_change_reply_fun(),
+ NotifyReqVerify = ?otp71922_mg_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp71922_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ {debug, true},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+otp71922_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp71922_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp71922_mg_verify_handle_connect(Else) ->
+ io:format("otp71922_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71922_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71922_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+otp71922_mg_verify_service_change_reply(Else) ->
+ io:format("otp71922_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71922_mg_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp71922_mg_verify_notify_request(Ev)
+ end.
+
+otp71922_mg_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp71922_mg_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp71922_mg_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp71922_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp71922_mg_verify_notify_request(Else) ->
+ io:format("otp71922_mg_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp71922_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp71922_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp71922_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp71922_mg_verify_notify_reply(Else) ->
+ io:format("otp71922_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp71922_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71922_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp71922_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp71922_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp71922_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp71922_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = otp71922_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+otp71922_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp_7192_3(suite) ->
+ [];
+otp_7192_3(doc) ->
+ ["Same as otp_7192_2 but transport is UDP instead of TCP"];
+otp_7192_3(Config) when is_list(Config) ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, otp_7192_3),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+
+ MgMid = {deviceName,"mg"},
+
+ ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+
+
+ d("[MGC] start the simulator "),
+ {ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
+
+ d("[MGC] create the event sequence"),
+ MgcEvSeq = otp72923_mgc_event_sequence(text, udp, MgMid),
+
+ i("wait some time before starting the MGC simulation"),
+ sleep(1000),
+
+ d("[MGC] start the simulation"),
+ {ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
+
+ i("wait some time before starting the MG simulator"),
+ sleep(1000),
+
+ d("[MG] start the simulator (generator)"),
+ {ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
+
+ d("[MG] create the event sequence"),
+ MgEvSeq = otp72923_mg_event_sequence(text, udp, MgMid),
+
+ i("wait some time before starting the MG simulation"),
+ sleep(1000),
+
+ d("[MG] start the simulation"),
+ {ok, MgId} = megaco_test_megaco_generator:exec(Mg, MgEvSeq),
+
+ d("await the generator(s) completion"),
+ await_completion([MgcId, MgId], 60000),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop generator"),
+ megaco_test_megaco_generator:stop(Mgc),
+
+ %% Tell Mg to stop
+ i("[MG] stop generator"),
+ megaco_test_megaco_generator:stop(Mg),
+
+ i("done", []),
+ ok.
+
+
+%%
+%% MGC generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp72923_mgc_verify_handle_connect_fun(),
+ {?MODULE, otp72923_mgc_verify_handle_connect, []}).
+-define(otp72923_mgc_verify_service_change_req_fun(Mid),
+ {?MODULE, otp72923_mgc_verify_service_change_req, [Mid]}).
+-define(otp72923_mgc_verify_notify_req_fun(),
+ {?MODULE, otp72923_mgc_verify_notify_request, []}).
+-define(otp72923_mgc_verify_notify_reply_fun(),
+ {?MODULE, otp72923_mgc_verify_notify_reply, []}).
+-define(otp72923_mgc_verify_ack_fun(),
+ {?MODULE, otp72923_mgc_verify_ack, []}).
+-define(otp72923_mgc_verify_handle_disconnect_fun(),
+ {?MODULE, otp72923_mgc_verify_handle_disconnect, []}).
+-else.
+-define(otp72923_mgc_verify_handle_connect_fun(),
+ fun otp72923_mgc_verify_handle_connect/1).
+-define(otp72923_mgc_verify_service_change_req_fun(Mid),
+ otp72923_mgc_verify_service_change_req_fun(Mid)).
+-define(otp72923_mgc_verify_notify_req_fun(),
+ otp72923_mgc_verify_notify_request_fun()).
+-define(otp72923_mgc_verify_notify_reply_fun(),
+ fun otp72923_mgc_verify_notify_reply/1).
+-define(otp72923_mgc_verify_ack_fun(),
+ fun otp72923_mgc_verify_ack/1).
+-define(otp72923_mgc_verify_handle_disconnect_fun(),
+ fun otp72923_mgc_verify_handle_disconnect/1).
+-endif.
+
+otp72923_mgc_event_sequence(text, udp, MgMid) ->
+ Mid = {deviceName, "ctrl"},
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_udp}
+ ],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp72923_mgc_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ LocalConnectVerify = ?otp72923_mgc_verify_handle_connect_fun(),
+ ServiceChangeReqVerify = ?otp72923_mgc_verify_service_change_req_fun(Mid),
+ NotifyReqVerify = ?otp72923_mgc_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp72923_mgc_verify_notify_reply_fun(),
+ AckVerify = ?otp72923_mgc_verify_ack_fun(),
+ %% DiscoVerify = ?otp72923_mgc_verify_handle_disconnect_fun(),
+ EvSeq = [
+ {debug, true},
+ {megaco_trace, max},
+ %% {megaco_trace, disable},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ listen,
+ {megaco_connect, MgMid},
+ {megaco_callback, handle_connect, LocalConnectVerify},
+ {megaco_callback, handle_trans_request, ServiceChangeReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_update_conn_info, request_timer, 1000},
+ {megaco_cast, NR(1,1), []},
+
+ {megaco_callback, [{handle_trans_ack, 3, AckVerify},
+ {handle_trans_request, 3, NotifyReqVerify},
+ {handle_trans_reply, 1, NotifyReplyVerify}]},
+ %% {megaco_callback, handle_disconnect, DiscoVerify},
+ {sleep, 1000},
+ megaco_stop_user,
+ megaco_stop
+ ],
+ EvSeq.
+
+
+otp72923_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp72923_mgc_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, timer:seconds(2), CH, ok};
+otp72923_mgc_verify_handle_connect(Else) ->
+ io:format("otp72923_mgc_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp72923_mgc_verify_service_change_req_fun(Mid) ->
+ fun(Ev) ->
+ otp72923_mgc_verify_service_change_req(Ev, Mid)
+ end.
+
+otp72923_mgc_verify_service_change_req(
+ {handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
+ io:format("otp72923_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{commandRequests = [CR]} ->
+ case CR of
+ #'CommandRequest'{command = Cmd} ->
+ case Cmd of
+ {serviceChangeReq,
+ #'ServiceChangeRequest'{terminationID = [Tid],
+ serviceChangeParms = Parms}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Parms of
+ #'ServiceChangeParm'{
+ serviceChangeMethod = restart,
+ serviceChangeReason = [[$9,$0,$1|_]]} ->
+ Reply =
+ {discard_ack,
+ [otp72923_mgc_service_change_reply_ar(Mid, 1)]},
+ {ok, AR, Reply};
+ _ ->
+ Err = {invalid_SCP, Parms},
+ ED = otp72923_err_desc(Parms),
+ ErrReply = {discard_ack,
+ ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ ED = otp72923_err_desc(Tid),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command, Cmd},
+ ED = otp72923_err_desc(Cmd),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_command_request, CR},
+ ED = otp72923_err_desc(CR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+ _ ->
+ Err = {invalid_action_request, AR},
+ ED = otp72923_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, Err, ErrReply}
+ end;
+otp72923_mgc_verify_service_change_req(Else, _Mid) ->
+ io:format("otp72923_mgc_verify_service_change_req -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp72923_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp72923_mgc_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp72923_mgc_verify_notify_request(Ev)
+ end.
+
+otp72923_mgc_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp72923_mgc_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ HandleAck = {handle_sloppy_ack, kalle},
+ Reply = {HandleAck,
+ [otp72923_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ #'ActionRequest'{contextId = 2 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp72923_mgc_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp72923_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp72923_mgc_verify_notify_request(Else) ->
+ io:format("otp72923_mgc_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp72923_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp72923_mgc_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp72923_mgc_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp72923_mgc_verify_notify_reply({handle_trans_reply, CH, ?VERSION,
+ UnknownResult, _}) ->
+ io:format("otp72923_mgc_verify_notify_reply -> unknown result"
+ "~n UnknownResult: ~p~n", [UnknownResult]),
+ {error, {unknown_reply_result, UnknownResult, CH}, ok};
+otp72923_mgc_verify_notify_reply(Else) ->
+ io:format("otp72923_mgc_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, {unknown_reply, Else}, ok}.
+
+otp72923_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok, kalle}) ->
+ io:format("otp72923_mgc_verify_ack -> ok"
+ "~n CH: ~p"
+ "~n", [CH]),
+ {ok, CH, ok};
+otp72923_mgc_verify_ack(Else) ->
+ io:format("otp72923_mgc_verify_ack -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+%% otp72923_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
+%% io:format("otp72923_mgc_verify_handle_disconnect -> ok"
+%% "~n CH: ~p"
+%% "~n R: ~p"
+%% "~n", [CH, R]),
+%% {ok, CH, ok};
+%% otp72923_mgc_verify_handle_disconnect(Else) ->
+%% io:format("otp72923_mgc_verify_handle_disconnect -> unknown"
+%% "~n Else: ~p~n", [Else]),
+%% {error, Else, ok}.
+
+
+otp72923_mgc_service_change_reply_ar(Mid, Cid) ->
+ SCRP = cre_serviceChangeResParm(Mid),
+ SCRes = cre_serviceChangeResult(SCRP),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReply([Root], SCRes),
+ CR = cre_cmdReply(SCR),
+ cre_actionReply(Cid, [CR]).
+
+otp72923_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
+ AR = otp72923_mgc_service_change_reply_ar(Mid, Cid),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp72923_mgc_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "44000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp72923_mgc_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp72923_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
+ AR = otp72923_mgc_notify_reply_ar(Cid, TermId),
+ TRes = cre_transResult([AR]),
+ TR = cre_transReply(TransId, TRes),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% MG generator stuff
+%%
+-ifdef(megaco_hipe_special).
+-define(otp72923_mg_verify_handle_connect_fun(),
+ {?MODULE, otp72923_mg_verify_handle_connect, []}).
+-define(otp72923_mg_verify_service_change_reply_fun(),
+ {?MODULE, otp72923_mg_verify_service_change_reply, []}).
+-define(otp72923_mg_verify_notify_req_fun(),
+ {?MODULE, otp72923_mgc_verify_notify_request, []}).
+-define(otp72923_mg_verify_notify_reply_fun(),
+ {?MODULE, otp72923_mg_verify_notify_reply, []}).
+-else.
+-define(otp72923_mg_verify_handle_connect_fun(),
+ fun otp72923_mg_verify_handle_connect/1).
+-define(otp72923_mg_verify_service_change_reply_fun(),
+ fun otp72923_mg_verify_service_change_reply/1).
+-define(otp72923_mg_verify_notify_req_fun(),
+ otp72923_mgc_verify_notify_request_fun()).
+-define(otp72923_mg_verify_notify_reply_fun(),
+ fun otp72923_mg_verify_notify_reply/1).
+-endif.
+
+otp72923_mg_event_sequence(text, udp, Mid) ->
+ RI = [
+ {port, 2944},
+ {encoding_module, megaco_pretty_text_encoder},
+ {encoding_config, []},
+ {transport_module, megaco_udp}
+ ],
+ ServiceChangeReq = [otp72923_mg_service_change_request_ar(Mid, 1)],
+ Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ NR = fun(Cid, Rid) ->
+ [otp72923_mg_notify_request_ar(Rid, Tid, Cid)]
+ end,
+ ConnectVerify = ?otp72923_mg_verify_handle_connect_fun(),
+ ServiceChangeReplyVerify = ?otp72923_mg_verify_service_change_reply_fun(),
+ NotifyReqVerify = ?otp72923_mg_verify_notify_req_fun(),
+ NotifyReplyVerify = ?otp72923_mg_verify_notify_reply_fun(),
+ EvSeq = [
+ %% {debug, true},
+ {debug, false},
+ megaco_start,
+ {megaco_start_user, Mid, RI, []},
+ start_transport,
+ %% {megaco_trace, max},
+ {megaco_trace, disable},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ connect,
+ {megaco_callback, handle_connect, ConnectVerify},
+ megaco_connect,
+ {megaco_cast, ServiceChangeReq, []},
+ {megaco_callback, handle_connect, ConnectVerify},
+ {megaco_callback, handle_trans_reply, ServiceChangeReplyVerify},
+ {sleep, 1000},
+ {megaco_system_info, users},
+ {megaco_system_info, connections},
+ {sleep, 1000},
+ {megaco_update_conn_info, auto_ack, true},
+ {megaco_update_conn_info, trans_ack_maxcount, 10},
+ {megaco_update_conn_info, trans_req_maxcount, 10},
+ {megaco_update_conn_info, trans_timer, 1000},
+ {megaco_update_conn_info, trans_ack, true},
+ {megaco_update_conn_info, trans_req, true},
+ {megaco_conn_info, all},
+ {megaco_cast, NR(1,1), []},
+ {megaco_cast, NR(1,2), []},
+ {megaco_cast, NR(1,3), []},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_update_conn_info, trans_timer, 120000},
+ {megaco_cast, NR(2,1), []},
+ {megaco_cast, NR(2,2), []},
+ {megaco_cast, NR(2,3), []},
+ {megaco_callback, handle_trans_request, NotifyReqVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {sleep, 3000},
+ megaco_stop_user,
+ megaco_stop,
+ {sleep, 1000}
+ ],
+ EvSeq.
+
+otp72923_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
+ io:format("otp72923_mg_verify_handle_connect -> ok"
+ "~n CH: ~p~n", [CH]),
+ {ok, CH, ok};
+otp72923_mg_verify_handle_connect(Else) ->
+ io:format("otp72923_mg_verify_handle_connect -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp72923_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp72923_mg_verify_service_change_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionReply'{commandReply = [SCR]} ->
+ case SCR of
+ {serviceChangeReply,
+ #'ServiceChangeReply'{terminationID = [Tid],
+ serviceChangeResult = Res}} ->
+ case Tid of
+ #megaco_term_id{contains_wildcards = false,
+ id = ["root"]} ->
+ case Res of
+ {serviceChangeResParms,
+ #'ServiceChangeResParm'{
+ serviceChangeMgcId = _RemoteMid}} ->
+ {ok, AR, ok};
+ {Tag, Val} ->
+ Err = {invalid_service_change_result,
+ Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_termination_id, Tid},
+ {error, Err, ok}
+ end;
+ {Tag, Val} ->
+ Err = {invalid_command_reply, Tag, Val},
+ {error, Err, ok}
+ end;
+ _ ->
+ Err = {invalid_action_reply, AR},
+ {error, Err, ok}
+ end;
+otp72923_mg_verify_service_change_reply(Else) ->
+ io:format("otp72923_mg_verify_service_change_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp72923_mg_verify_notify_request_fun() ->
+ fun(Ev) ->
+ otp72923_mg_verify_notify_request(Ev)
+ end.
+
+otp72923_mg_verify_notify_request(
+ {handle_trans_request, _, ?VERSION, [AR]}) ->
+ io:format("otp72923_mg_verify_notify_request -> ok"
+ "~n AR: ~p~n", [AR]),
+ case AR of
+ #'ActionRequest'{contextId = 1 = Cid,
+ commandRequests = [CR]} ->
+ #'CommandRequest'{command = Cmd} = CR,
+ {notifyReq, NR} = Cmd,
+ #'NotifyRequest'{terminationID = [Tid],
+ observedEventsDescriptor = OED,
+ errorDescriptor = asn1_NOVALUE} = NR,
+ #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEvent'{eventName = "al/of"} = OE,
+ Reply = {discard_ack, [otp72923_mg_notify_reply_ar(Cid, Tid)]},
+ {ok, AR, Reply};
+ _ ->
+ ED = otp72923_err_desc(AR),
+ ErrReply = {discard_ack, ED},
+ {error, AR, ErrReply}
+ end;
+otp72923_mg_verify_notify_request(Else) ->
+ io:format("otp72923_mg_verify_notify_request -> unknown"
+ "~n Else: ~p~n", [Else]),
+ ED = otp72923_err_desc(Else),
+ ErrReply = {discard_ack, ED},
+ {error, Else, ErrReply}.
+
+otp72923_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
+ {ok, [AR]}, _}) ->
+ io:format("otp72923_mg_verify_notify_reply -> ok"
+ "~n AR: ~p~n", [AR]),
+ {ok, AR, ok};
+otp72923_mg_verify_notify_reply(Else) ->
+ io:format("otp72923_mg_verify_notify_reply -> unknown"
+ "~n Else: ~p~n", [Else]),
+ {error, Else, ok}.
+
+otp72923_mg_service_change_request_ar(_Mid, Cid) ->
+ Prof = cre_serviceChangeProf("resgw", 1),
+ SCP = cre_serviceChangeParm(restart, ["901 mg col boot"], Prof),
+ Root = #megaco_term_id{id = ["root"]},
+ SCR = cre_serviceChangeReq([Root], SCP),
+ CMD = cre_command(SCR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp72923_mg_service_change_request_msg(Mid, TransId, Cid) ->
+ AR = otp72923_mg_service_change_request_ar(Mid, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+otp72923_mg_notify_reply_ar(Cid, TermId) ->
+ NR = cre_notifyReply([TermId]),
+ CR = cre_cmdReply(NR),
+ cre_actionReply(Cid, [CR]).
+
+otp72923_mg_notify_request_ar(Rid, Tid, Cid) ->
+ TT = cre_timeNotation("19990729", "22000000"),
+ Ev = cre_obsEvent("al/of", TT),
+ EvsDesc = cre_obsEvsDesc(Rid, [Ev]),
+ NR = cre_notifyReq([Tid], EvsDesc),
+ CMD = cre_command(NR),
+ CR = cre_cmdReq(CMD),
+ cre_actionReq(Cid, [CR]).
+
+otp72923_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
+ AR = otp72923_mg_notify_request_ar(Rid, TermId, Cid),
+ TR = cre_transReq(TransId, [AR]),
+ Trans = cre_transaction(TR),
+ Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
+ cre_megacoMessage(Mess).
+
+
+%%
+%% Common functions for the multi_trans_req_timeout test case
+%%
+
+otp72923_err_desc(T) ->
+ EC = ?megaco_internal_gateway_error,
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%
+%% Common message creation functions
+%%
+
+cre_ErrDesc(T) ->
+ cre_ErrDesc(?megaco_internal_gateway_error, T).
+
+cre_ErrDesc(EC, T) ->
+ ET = lists:flatten(io_lib:format("~w",[T])),
+ #'ErrorDescriptor'{errorCode = EC, errorText = ET}.
+
+cre_serviceChangeParm(M,R,P) ->
+ #'ServiceChangeParm'{serviceChangeMethod = M,
+ serviceChangeReason = R,
+ serviceChangeProfile = P}.
+
+cre_serviceChangeReq(Tid, Parms) ->
+ #'ServiceChangeRequest'{terminationID = Tid,
+ serviceChangeParms = Parms}.
+
+cre_timeNotation(D,T) ->
+ #'TimeNotation'{date = D, time = T}.
+
+cre_obsEvent(Name, Not) ->
+ #'ObservedEvent'{eventName = Name,
+ timeNotation = Not}.
+cre_obsEvent(Name, Not, Par) ->
+ #'ObservedEvent'{eventName = Name,
+ timeNotation = Not,
+ eventParList = Par}.
+
+cre_obsEvsDesc(Id, EvList) ->
+ #'ObservedEventsDescriptor'{requestId = Id,
+ observedEventLst = EvList}.
+
+cre_notifyReq(Tid, EvsDesc) ->
+ #'NotifyRequest'{terminationID = Tid,
+ observedEventsDescriptor = EvsDesc}.
+
+cre_command(R) when is_record(R, 'NotifyRequest') ->
+ {notifyReq, R};
+cre_command(R) when is_record(R, 'ServiceChangeRequest') ->
+ {serviceChangeReq, R}.
+
+cre_cmdReq(Cmd) ->
+ #'CommandRequest'{command = Cmd}.
+
+cre_actionReq(CtxId, CmdReqs) when is_list(CmdReqs) ->
+ #'ActionRequest'{contextId = CtxId,
+ commandRequests = CmdReqs}.
+
+cre_transReq(TransId, ARs) when is_list(ARs) ->
+ #'TransactionRequest'{transactionId = TransId,
+ actions = ARs}.
+
+%% --
+
+cre_serviceChangeResParm(Mid) ->
+ #'ServiceChangeResParm'{serviceChangeMgcId = Mid}.
+
+cre_serviceChangeResult(SCRP) when is_record(SCRP, 'ServiceChangeResParm') ->
+ {serviceChangeResParms, SCRP};
+cre_serviceChangeResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {errorDescriptor, ED}.
+
+cre_serviceChangeReply(Tid, Res) ->
+ #'ServiceChangeReply'{terminationID = Tid,
+ serviceChangeResult = Res}.
+
+cre_cmdReply(R) when is_record(R, 'NotifyReply') ->
+ {notifyReply, R};
+cre_cmdReply(R) when is_record(R, 'ServiceChangeReply') ->
+ {serviceChangeReply, R}.
+
+cre_notifyReply(Tid) ->
+ #'NotifyReply'{terminationID = Tid}.
+
+cre_actionReply(CtxId, CmdRep) ->
+ #'ActionReply'{contextId = CtxId,
+ commandReply = CmdRep}.
+
+cre_transResult(ED) when is_record(ED, 'ErrorDescriptor') ->
+ {transactionError, ED};
+cre_transResult([AR|_] = ARs) when is_record(AR, 'ActionReply') ->
+ {actionReplies, ARs}.
+
+cre_transReply(TransId, Res) ->
+ #'TransactionReply'{transactionId = TransId,
+ transactionResult = Res}.
+
+
+%% --
+
+cre_serviceChangeProf(Name, Ver) when is_list(Name) andalso is_integer(Ver) ->
+ #'ServiceChangeProfile'{profileName = Name,
+ version = Ver}.
+
+cre_transaction(Trans) when is_record(Trans, 'TransactionRequest') ->
+ {transactionRequest, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionPending') ->
+ {transactionPending, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionReply') ->
+ {transactionReply, Trans};
+cre_transaction(Trans) when is_record(Trans, 'TransactionAck') ->
+ {transactionResponseAck, Trans}.
+
+cre_transactions(Trans) when is_list(Trans) ->
+ {transactions, Trans}.
+
+cre_message(Version, Mid, Body) ->
+ #'Message'{version = Version,
+ mId = Mid,
+ messageBody = Body}.
+
+cre_megacoMessage(Mess) ->
+ #'MegacoMessage'{mess = Mess}.
+
+
+%%
+%% Common functions
+%%
+
+encode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:encode_message(Conf, M)
+ end.
+encode_msg_fun(Mod, Conf, Ver) ->
+ fun(M) ->
+ Mod:encode_message(Conf, Ver, M)
+ end.
+
+decode_msg_fun(Mod, Conf) ->
+ fun(M) ->
+ Mod:decode_message(Conf, M)
+ end.
+decode_msg_fun(Mod, Conf, Ver) ->
+ fun(M) ->
+ Mod:decode_message(Conf, Ver, M)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_ack(_User, 0, Timeout, _Expected) ->
+ d("await_ack -> done when Timeout = ~p", [Timeout]),
+ ok;
+await_ack(User, N, Timeout, Expected) when (N > 0) andalso is_integer(Timeout) ->
+ d("await_ack -> entry with N: ~p, Timeout: ~p", [N,Timeout]),
+ T = tim(),
+ receive
+ {ack_received, User, Expected} ->
+ d("await_ack -> received another ack"),
+ await_ack(User, N-1, Timeout - (tim() - T), Expected);
+ {ack_received, User, UnExpected} ->
+ d("await_ack -> unexpected ack result: ~p", [UnExpected]),
+ exit({unexpected_ack_result, UnExpected, Expected})
+ after Timeout ->
+ exit({await_ack_timeout, N})
+ end;
+await_ack(User, N, infinity, Expected) when N > 0 ->
+ d("await_ack -> entry with N: ~p", [N]),
+ receive
+ {ack_received, User, Expected} ->
+ d("await_ack -> received another ack"),
+ await_ack(User, N-1, infinity, Expected);
+ {ack_received, User, UnExpected} ->
+ d("await_ack -> unexpected ack result: ~p", [UnExpected]),
+ exit({unexpected_ack_result, UnExpected, Expected})
+ end.
+
+await_req(_User, 0, Timeout) ->
+ d("await_req -> done when Timeout = ~p", [Timeout]),
+ ok;
+await_req(User, N, Timeout) when (N > 0) andalso is_integer(Timeout) ->
+ d("await_req -> entry with N: ~p, Timeout: ~p", [N,Timeout]),
+ T = tim(),
+ receive
+ {req_received, User, ARs} ->
+ d("await_req -> received req(s) when N = ~w", [N]),
+ N1 = await_req1(N, ARs),
+ await_req(User, N1, Timeout - (tim() - T))
+ after Timeout ->
+ exit({await_req_timeout, N})
+ end;
+await_req(User, N, infinity) when N > 0 ->
+ d("await_req -> entry with N: ~p", [N]),
+ receive
+ {req_received, User, ARs} ->
+ d("await_req -> received req(s) when N = ~2",[N]),
+ N1 = await_req1(N, ARs),
+ await_req(User, N1, infinity)
+ end.
+
+await_req1(N, []) when N >= 0 ->
+ N;
+await_req1(N, [AR|ARs]) when (N > 0) andalso is_record(AR, 'ActionRequest') ->
+ await_req1(N-1, ARs);
+await_req1(N, ARs) ->
+ exit({unexpected_req_result, N, ARs}).
+
+% await_rep(_User, 0, Timeout) ->
+% d("await_rep -> done when Timeout = ~p", [Timeout]),
+% ok;
+% await_rep(User, N, Timeout) when N > 0, integer(Timeout) ->
+% d("await_rep -> entry with N: ~p, Timeout: ~p", [N,Timeout]),
+% T = tim(),
+% receive
+% {rep_received, User, ARs} ->
+% d("await_rep -> received rep(s)"),
+% N1 = await_rep1(N, ARs),
+% await_rep(User, N1, Timeout - (tim() - T))
+% after Timeout ->
+% exit({await_rep_timeout, N})
+% end;
+% await_rep(User, N, infinity) when N > 0 ->
+% d("await_rep -> entry with N: ~p", [N]),
+% receive
+% {rep_received, User, ARs} ->
+% d("await_rep -> received rep(s)"),
+% N1 = await_rep1(N, ARs),
+% await_rep(User, N1, infinity)
+% end.
+
+% await_rep1(N, []) when N >= 0 ->
+% N;
+% await_rep1(N, [AR|ARs]) when N > 0, record(AR, 'ActionReply') ->
+% await_rep1(N-1, ARs);
+% await_rep1(N, ARs) ->
+% exit({unexpected_rep_result, N, ARs}).
+
+tim() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+await_completion(Ids) ->
+ case megaco_test_generator_lib:await_completion(Ids) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, Reply} ->
+ d("ERROR => Reply: ~n~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+await_completion(Ids, Timeout) ->
+ case megaco_test_generator_lib:await_completion(Ids, Timeout) of
+ {ok, Reply} ->
+ d("OK => Reply: ~n~p", [Reply]),
+ ok;
+ {error, Reply} ->
+ d("ERROR => Reply: ~n~p", [Reply]),
+ ?ERROR({failed, Reply})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sleep(X) -> receive after X -> ok end.
+
+error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ print(info, get(verbosity), now(), get(tc), "INF", F, A).
+
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ print(debug, get(verbosity), now(), get(tc), "DBG", F, A).
+
+
+printable(_, debug) -> true;
+printable(info, info) -> true;
+printable(_,_) -> false.
+
+print(Severity, Verbosity, Ts, Tc, P, F, A) ->
+ print(printable(Severity,Verbosity), Ts, Tc, P, F, A).
+
+print(true, Ts, Tc, P, F, A) ->
+ io:format("*** [~s] ~s ~p ~s:~w ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(Ts), P, self(), get(tc), Tc | A]);
+print(_, _, _, _, _, _) ->
+ ok.
+
+
+p(F, A) ->
+ io:format("*** [~s] ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()) | A]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+random_init() ->
+ {A,B,C} = now(),
+ random:seed(A,B,C).
+
+random() ->
+ 10 * random:uniform(50).
+
+apply_load_timer() ->
+ erlang:send_after(random(), self(), apply_load_timeout).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+
diff --git a/lib/megaco/test/megaco_udp_test.erl b/lib/megaco/test/megaco_udp_test.erl
new file mode 100644
index 0000000000..2e2f5465dd
--- /dev/null
+++ b/lib/megaco/test/megaco_udp_test.erl
@@ -0,0 +1,1251 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(megaco_udp_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include_lib("megaco/src/udp/megaco_udp.hrl").
+-include("megaco_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+
+ start/1,
+ start_normal/1,
+ start_invalid_opt/1,
+ start_and_stop/1,
+
+ sending/1,
+ sendreceive/1,
+ block_unblock/1,
+
+ errors/1,
+ socket_failure/1,
+
+ init_per_testcase/2, fin_per_testcase/2,
+
+ t/0, t/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ receive_message/4,
+ process_received_message/4
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+-record(command, {id, desc, cmd}).
+-record(server, {parent, transport_ref, control_pid, handle, remote}).
+-record(client, {parent, transport_ref, control_pid, handle, remote}).
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: t/0
+%% Description: Run all test cases
+%%----------------------------------------------------------------------
+t() -> megaco_test_lib:t(?MODULE).
+
+
+%%----------------------------------------------------------------------
+%% Function: t/1
+%% Description: Run the specified test cases
+%%----------------------------------------------------------------------
+t(Case) -> megaco_test_lib:t({?MODULE, Case}).
+
+
+%%======================================================================
+%% Test server callbacks
+%%======================================================================
+%%----------------------------------------------------------------------
+%% Function: init_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+init_per_testcase(Case, Config) ->
+ megaco_test_lib:init_per_testcase(Case, Config).
+
+
+%%----------------------------------------------------------------------
+%% Function: fin_per_testcase/2
+%% Description:
+%%----------------------------------------------------------------------
+fin_per_testcase(Case, Config) ->
+ megaco_test_lib:fin_per_testcase(Case, Config).
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+
+all(suite) ->
+ [
+ start,
+ sending,
+ errors
+ ].
+
+start(suite) ->
+ [
+ start_normal,
+ start_invalid_opt,
+ start_and_stop
+ ].
+
+sending(suite) ->
+ [
+ sendreceive,
+ block_unblock
+
+ ].
+
+errors(suite) ->
+ [
+ socket_failure
+ ].
+
+
+%% =================================================
+%%
+%% ------------------ start ------------------------
+%%
+%% =================================================
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_normal(suite) ->
+ [];
+start_normal(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Opts = [{port, 0}, {receive_handle, apa}],
+ {ok, Pid} = start_case(Opts, ok),
+ megaco_udp:stop_transport(Pid),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_invalid_opt(suite) ->
+ [];
+start_invalid_opt(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ Opts = [{port, 0}, {receivehandle, apa}],
+ start_case(Opts, error).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop(suite) ->
+ [];
+start_and_stop(doc) ->
+ ["This test case sets up a connection and then cloises it. "
+ "No data is sent. "];
+start_and_stop(Config) when is_list(Config) ->
+ put(sname, "start_and_stop"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = start_and_stop_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = start_and_stop_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {operational, Server} ->
+ p("received listening message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok;
+ {'EXIT', Server, {skip, Reason}} ->
+ ?SKIP(Reason);
+ {'EXIT', Client, {skip, Reason}} ->
+ ?SKIP(Reason)
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+start_and_stop_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify operational",
+ cmd = fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ server_await_nothing(State, 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Close",
+ cmd = fun(State) ->
+ server_close(State)
+ end},
+
+ #command{id = 7,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+start_and_stop_client_commands(ServerPort, _ServerHost) ->
+ Opts = [{port, ServerPort}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 5,
+ desc = "Await nothing",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Close",
+ cmd = fun(State) ->
+ client_close(State)
+ end},
+
+ #command{id = 7,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+
+%% =================================================
+%%
+%% ------------------ sending ------------------------
+%%
+%% =================================================
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sendreceive(suite) ->
+ [];
+sendreceive(doc) ->
+ ["Test send and receive with the UDP transport. "];
+sendreceive(Config) when is_list(Config) ->
+ put(sname, "sendreceive"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = sendreceive_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = sendreceive_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ ok =
+ receive
+ {operational, Server} ->
+ p("received operational message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok;
+ {'EXIT', Server, {skip, Reason}} ->
+ ?SKIP(Reason);
+ {'EXIT', Client, {skip, Reason}} ->
+ ?SKIP(Reason)
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+sendreceive_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify operational",
+ cmd = fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await nothing before sending a message (hejsan)",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 1000)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before closing",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 11,
+ desc = "Close",
+ cmd = fun(State) ->
+ server_close(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+sendreceive_client_commands(ServerPort, ServerHost) ->
+ OwnPort = ServerPort+1,
+ Opts = [{port, OwnPort}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 5,
+ desc = "Connect",
+ cmd = fun(State) ->
+ client_connect(State, ServerHost, ServerPort)
+ end},
+
+ #command{id = 6,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 7,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #command{id = 9,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before closing",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 11,
+ desc = "Close",
+ cmd = fun(State) ->
+ client_close(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+block_unblock(suite) ->
+ [];
+block_unblock(doc) ->
+ ["Test the block/unblock functions of the UDP transport. "];
+block_unblock(Config) when is_list(Config) ->
+ put(sname, "block_unblock"),
+ p("BEGIN TEST-CASE"),
+
+ process_flag(trap_exit, true),
+
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
+
+ %% Create command sequences
+ p("create command sequences"),
+ ServerPort = 2944,
+ ServerCmds = block_unblock_server_commands(ServerPort),
+ {ok, ServerHost} = inet:gethostname(),
+ ClientCmds = block_unblock_client_commands(ServerPort, ServerHost),
+
+ %% Start the test procs used in the test-case, one for each node
+ p("start command handlers"),
+ Server = server_start_command_handler(ServerNode, ServerCmds),
+ p("server command handler started: ~p", [Server]),
+ Client = client_start_command_handler(ClientNode, ClientCmds),
+ p("client command handler started: ~p", [Client]),
+
+ %% Wait for the server to become ready for operation
+ %% and then tell the client to continue
+ ok =
+ receive
+ {operational, Server} ->
+ p("received operational message from server [~p] => "
+ "send continue to client [~p]~n", [Server, Client]),
+ Client ! {continue, self()},
+ ok;
+ {'EXIT', Server, {skip, Reason1}} ->
+ ?SKIP(Reason1);
+ {'EXIT', Client, {skip, Reason2}} ->
+ ?SKIP(Reason2)
+ after 5000 ->
+ {error, server_timeout}
+ end,
+
+ %% Wait for the client to become blocked
+ %% and then tell the server to continue
+ ok =
+ receive
+ {blocked, Client} ->
+ p("received blocked message from client [~p] => "
+ "send continue to server [~p]~n", [Client, Server]),
+ Server ! {continue, self()},
+ ok;
+ {'EXIT', Server, {skip, Reason3}} ->
+ ?SKIP(Reason3);
+ {'EXIT', Client, {skip, Reason4}} ->
+ ?SKIP(Reason4)
+ after 5000 ->
+ {error, timeout}
+ end,
+
+ ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ p("done"),
+ ok.
+
+
+block_unblock_server_commands(Port) ->
+ Opts = [{port, Port}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#server{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Notify operational",
+ cmd = fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #command{id = 5,
+ desc = "Await initial message (ping)",
+ cmd = fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #command{id = 6,
+ desc = "Send reply (pong) to initial message",
+ cmd = fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #command{id = 7,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ server_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 8,
+ desc = "Send message (hejsan)",
+ cmd = fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #command{id = 9,
+ desc = "Await nothing before receiving (hoppsan) reply",
+ cmd = fun(State) ->
+ server_await_nothing(State, 4000)
+ end},
+
+ #command{id = 10,
+ desc = "Await reply (hoppsan) to message",
+ cmd = fun(State) ->
+ server_await_message(State, "hoppsan", 2000)
+ end},
+
+ #command{id = 11,
+ desc = "Await nothing before closing",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 12,
+ desc = "Close",
+ cmd = fun(State) ->
+ server_close(State)
+ end},
+
+ #command{id = 13,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #command{id = 14,
+ desc = "Stop",
+ cmd = fun(State) ->
+ server_stop_transport(State)
+ end}
+
+ ].
+
+block_unblock_client_commands(ServerPort, ServerHost) ->
+ OwnPort = ServerPort+1,
+ Opts = [{port, OwnPort}],
+ Self = self(),
+ [
+ #command{id = 1,
+ desc = "Command sequence init",
+ cmd = fun(State) ->
+ {ok, State#client{parent = Self}}
+ end},
+
+ #command{id = 2,
+ desc = "Start transport",
+ cmd = fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #command{id = 3,
+ desc = "Open",
+ cmd = fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #command{id = 4,
+ desc = "Await continue",
+ cmd = fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #command{id = 5,
+ desc = "[pseudo] Connect",
+ cmd = fun(State) ->
+ client_connect(State, ServerHost, ServerPort)
+ end},
+
+ #command{id = 6,
+ desc = "Send initial message (ping)",
+ cmd = fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #command{id = 7,
+ desc = "Await reply (pong) to initial message",
+ cmd = fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #command{id = 8,
+ desc = "Block",
+ cmd = fun(State) ->
+ client_block(State)
+ end},
+
+ #command{id = 9,
+ desc = "Notify blocked",
+ cmd = fun(State) ->
+ client_notify_blocked(State)
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before unblocking",
+ cmd = fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #command{id = 11,
+ desc = "Unblock",
+ cmd = fun(State) ->
+ client_unblock(State)
+ end},
+
+ #command{id = 8,
+ desc = "Await message (hejsan)",
+ cmd = fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #command{id = 9,
+ desc = "Send reply (hoppsan) to message",
+ cmd = fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #command{id = 10,
+ desc = "Await nothing before closing",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 11,
+ desc = "Close",
+ cmd = fun(State) ->
+ client_close(State)
+ end},
+
+ #command{id = 12,
+ desc = "Await nothing before stopping transport",
+ cmd = fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #command{id = 13,
+ desc = "Stop transport",
+ cmd = fun(State) ->
+ client_stop_transport(State)
+ end}
+ ].
+
+
+%% =================================================
+%%
+%% ------------------ errors ------------------------
+%%
+%% =================================================
+
+socket_failure(suite) ->
+ [];
+socket_failure(Config) when is_list(Config) ->
+ ?ACQUIRE_NODES(1, Config),
+ failing_socket().
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+start_case(Opts, Expect) ->
+ case (catch megaco_udp:start_transport()) of
+ {ok, Pid} ->
+ case (catch megaco_udp:open(Pid, Opts)) of
+ {ok, _Handle, _CtrlPid} when Expect =:= ok ->
+ {ok, Pid};
+ {ok, Handle, CtrlPid} ->
+ megaco_udp:stop_transport(Pid),
+ ?ERROR({unexpected_start_sucesss, Handle, CtrlPid});
+ {error, _Reason} when Expect =:= error ->
+ megaco_udp:stop_transport(Pid),
+ ok;
+ {error, Reason} ->
+ megaco_udp:stop_transport(Pid),
+ ?ERROR({unexpected_start_failure, Reason});
+ Error ->
+ ?ERROR({unexpected_result, Error})
+ end;
+ {error, Reason} ->
+ ?ERROR({failed_starting_transport, Reason})
+ end.
+
+
+failing_socket() ->
+ ?SKIP(not_yet_implemented).
+
+
+
+%%----------------------------------------------------------------------
+%% Message Callback functions
+%%----------------------------------------------------------------------
+
+receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {receive_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
+ when is_pid(ReceiveHandle) andalso is_binary(BinMsg) ->
+ Msg = binary_to_list(BinMsg),
+ ReceiveHandle ! {process_received_message, {ControlPid, SendHandle, Msg}},
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% ------- Server command handler and utility functions ----------
+
+server_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #server{}, "server").
+
+server_start_transport(State) when is_record(State, server) ->
+ case (catch megaco_udp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#server{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+server_open(#server{transport_ref = Ref} = State, Options)
+ when is_record(State, server) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_udp:open(Ref, Opts)) of
+ {ok, Socket, ControlPid} ->
+ {ok, State#server{handle = {socket, Socket}, % Temporary
+ control_pid = ControlPid}};
+ {error, {could_not_open_udp_port, eaddrinuse}} ->
+ {skip, {server, eaddrinuse}};
+ Error ->
+ Error
+ end.
+
+server_notify_operational(#server{parent = Parent} = State)
+ when is_record(State, server) ->
+ Parent ! {operational, self()},
+ {ok, State}.
+
+server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_await_initial_message(State, InitialMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {ControlPid, Handle, InitialMessage}} ->
+ p("received expected event with: "
+ "~n ControlPid: ~p"
+ "~n Handle: ~p", [ControlPid, Handle]),
+ NewState = State#server{handle = Handle},
+ {ok, NewState};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_send_message(#server{handle = Handle} = State, Message) ->
+ Bin = if
+ is_list(Message) ->
+ list_to_binary(Message);
+ true ->
+ Message
+ end,
+ megaco_udp:send_message(Handle, Bin),
+ {ok, State}.
+
+server_await_nothing(State, Timeout)
+ when is_record(State, server) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {ok, State}
+ end.
+
+
+server_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, server) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ p("received expected message [~p]", [ExpectMessage]),
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+server_close(#server{handle = {socket, Socket}} = State) ->
+ megaco_udp:close(Socket),
+ {ok, State#server{handle = undefined, control_pid = undefined}};
+server_close(#server{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_udp:close(Handle),
+ {ok, State#server{handle = undefined, control_pid = undefined}}.
+
+%% server_block(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_udp:block(Handle),
+%% {ok, State}.
+
+%% server_unblock(#server{handle = Handle} = State)
+%% when (Handle =/= undefined) ->
+%% megaco_udp:unblock(Handle),
+%% {ok, State}.
+
+server_stop_transport(#server{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_udp:stop_transport(Ref),
+ {ok, State#server{transport_ref = undefined}}.
+
+
+%% ------- Client command handler and utility functions ----------
+
+client_start_command_handler(Node, Commands) ->
+ start_command_handler(Node, Commands, #client{}, "client").
+
+client_start_transport(State) when is_record(State, client) ->
+ case (catch megaco_udp:start_transport()) of
+ {ok, Ref} ->
+ {ok, State#client{transport_ref = Ref}};
+ Error ->
+ Error
+ end.
+
+client_open(#client{transport_ref = Ref} = State, Options)
+ when is_record(State, client) andalso is_list(Options) ->
+ Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
+ case (catch megaco_udp:open(Ref, Opts)) of
+ {ok, Socket, ControlPid} ->
+ {ok, State#client{handle = {socket, Socket},
+ control_pid = ControlPid}};
+ {error, {could_not_open_udp_port, eaddrinuse}} ->
+ {skip, {client, eaddrinuse}};
+ Error ->
+ Error
+ end.
+
+client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
+ receive
+ {continue, Parent} ->
+ {ok, State}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_notify_blocked(#client{parent = Parent} = State) ->
+ Parent ! {blocked, self()},
+ {ok, State}.
+
+client_await_nothing(State, Timeout)
+ when is_record(State, client) ->
+ receive
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+ after Timeout ->
+ {ok, State}
+ end.
+
+client_connect(#client{handle = {socket, Socket}} = State, Host, Port) ->
+ Handle = megaco_udp:create_send_handle(Socket, Host, Port),
+ {ok, State#client{handle = Handle}}.
+
+client_send_message(#client{handle = Handle} = State, Message) ->
+ Bin = if
+ is_list(Message) ->
+ list_to_binary(Message);
+ true ->
+ Message
+ end,
+ megaco_udp:send_message(Handle, Bin),
+ {ok, State}.
+
+client_await_message(State, ExpectMessage, Timeout)
+ when is_record(State, client) ->
+ receive
+ {receive_message, {_, _, ExpectMessage}} ->
+ {ok, State};
+
+ Any ->
+ p("received unexpected event: ~p", [Any]),
+ {error, {unexpected_event, Any}}
+
+ after Timeout ->
+ {error, timeout}
+ end.
+
+client_block(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_udp:block(Handle),
+ {ok, State}.
+
+client_unblock(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_udp:unblock(Handle),
+ {ok, State}.
+
+client_close(#client{handle = {socket, Socket}} = State) ->
+ megaco_udp:close(Socket),
+ {ok, State#client{handle = undefined, control_pid = undefined}};
+client_close(#client{handle = Handle} = State)
+ when (Handle =/= undefined) ->
+ megaco_udp:close(Handle),
+ {ok, State#client{handle = undefined, control_pid = undefined}}.
+
+client_stop_transport(#client{transport_ref = Ref} = State)
+ when (Ref =/= undefined) ->
+ megaco_udp:stop_transport(Ref),
+ {ok, State#client{transport_ref = undefined}}.
+
+
+%% -------- Command handler ---------
+
+start_command_handler(Node, Commands, State, ShortName) ->
+ Fun = fun() ->
+ put(sname, ShortName),
+ process_flag(trap_exit, true),
+ Result = (catch command_handler(Commands, State)),
+ p("command handler terminated with: "
+ "~n Result: ~p", [Result]),
+ exit(Result)
+ end,
+ erlang:spawn_link(Node, Fun).
+
+command_handler([], State) ->
+ p("command_handler -> entry when done with"
+ "~n State: ~p", [State]),
+ {ok, State};
+command_handler([#command{id = Id,
+ desc = Desc,
+ cmd = Cmd}|Commands], State) ->
+ p("command_handler -> entry with"
+ "~n Id: ~p"
+ "~n Desc: ~p", [Id, Desc]),
+ case (catch Cmd(State)) of
+ {ok, NewState} ->
+ p("command_handler -> cmd ~w ok", [Id]),
+ command_handler(Commands, NewState);
+ {skip, _} = SKIP ->
+ p("command_handler -> cmd ~w skip", [Id]),
+ SKIP;
+ {error, Reason} ->
+ p("command_handler -> cmd ~w error: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_error, Reason}};
+ {'EXIT', Reason} ->
+ p("command_handler -> cmv ~w exit: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_exit, Reason}};
+ Error ->
+ p("command_handler -> cmd ~w failure: "
+ "~n Error: ~p", [Id, Error]),
+ {error, {cmd_failure, Error}}
+ end.
+
+
+await_command_handler_completion(Pids, Timeout) ->
+ await_command_handler_completion(Pids, [], [], Timeout).
+
+await_command_handler_completion([], [], _Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done"),
+ ok;
+await_command_handler_completion([], Bad, Good, _Timeout) ->
+ p("await_command_handler_completion -> entry when done with bad result: "
+ "~n Bad: ~p"
+ "~n Good: ~p", [Bad, Good]),
+ {error, Bad, Good};
+await_command_handler_completion(Pids, Bad, Good, Timeout) ->
+ p("await_command_handler_completion -> entry when waiting for"
+ "~n Pids: ~p"
+ "~n Bad: ~p"
+ "~n Good: ~p"
+ "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
+ Begin = ms(),
+ receive
+ {'EXIT', Pid, {ok, FinalState}} ->
+ p("await_command_handler_completion -> "
+ "received ok EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done", [Pid]),
+ await_command_handler_completion(Pids2,
+ Bad,
+ [{Pid, FinalState}|Good],
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {error, Reason}} ->
+ p("await_command_handler_completion -> "
+ "received error EXIT signal from ~p", [Pid]),
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ await_command_handler_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ p("await_command_handler_completion -> ~p done with"
+ "~n ~p", [Pid, Reason]),
+ await_command_handler_completion(Pids2,
+ [{Pid, Reason}|Bad],
+ Good,
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {skip, Reason}} ->
+ p("await_command_handler_completion -> "
+ "received skip EXIT signal from ~p with"
+ "~p", [Pid, Reason]),
+ ?SKIP(Reason)
+
+ after Timeout ->
+ p("await_command_handler_completion -> timeout"),
+ exit({timeout, Pids})
+ end.
+
+
+
+%% ------- Misc functions --------
+
+make_node_name(Name) ->
+ case string:tokens(atom_to_list(node()), [$@]) of
+ [_,Host] ->
+ list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host]));
+ _ ->
+ exit("Test node must be started with '-sname'")
+ end.
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(sname), F, A).
+
+p(S, F, A) when is_list(S) ->
+ io:format("*** [~s] ~p ~s ***"
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), S | A]);
+p(_S, F, A) ->
+ io:format("*** [~s] ~p ~s *** "
+ "~n " ++ F ++ "~n",
+ [format_timestamp(now()), self(), "undefined" | A]).
+
+
+ms() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
diff --git a/lib/megaco/test/modules.mk b/lib/megaco/test/modules.mk
new file mode 100644
index 0000000000..0186a84c26
--- /dev/null
+++ b/lib/megaco/test/modules.mk
@@ -0,0 +1,82 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+TEST_SPEC_FILE = megaco.spec
+
+BEHAVIOUR_MODULES = \
+ megaco_test_generator
+
+MODULES = \
+ $(BEHAVIOUR_MODULES) \
+ megaco_SUITE \
+ megaco_app_test \
+ megaco_appup_test \
+ megaco_actions_test \
+ megaco_binary_term_id_test \
+ megaco_call_flow_test \
+ megaco_codec_test \
+ megaco_codec_test_lib \
+ megaco_codec_flex_lib \
+ megaco_codec_v1_test \
+ megaco_codec_v2_test \
+ megaco_codec_prev3a_test \
+ megaco_codec_prev3b_test \
+ megaco_codec_prev3c_test \
+ megaco_codec_v3_test \
+ megaco_codec_mini_test \
+ megaco_config_test \
+ megaco_digit_map_test \
+ megaco_examples_test \
+ megaco_flex_test \
+ megaco_load_test \
+ megaco_mess_test \
+ megaco_mess_user_test \
+ megaco_mess_otp8212_test \
+ megaco_mib_test \
+ megaco_mreq_test \
+ megaco_pending_limit_test \
+ megaco_profile \
+ megaco_segment_test \
+ megaco_sdp_test \
+ megaco_tc_controller \
+ megaco_tcp_test \
+ megaco_timer_test \
+ megaco_trans_test \
+ megaco_udp_test \
+ megaco_test_generator_lib \
+ megaco_test_megaco_generator \
+ megaco_test_tcp_generator \
+ megaco_test_deliver \
+ megaco_test_generic_transport \
+ megaco_test_mgc \
+ megaco_test_mg \
+ megaco_test_msg_v1_lib \
+ megaco_test_msg_v2_lib \
+ megaco_test_msg_prev3a_lib \
+ megaco_test_msg_prev3b_lib \
+ megaco_test_msg_prev3c_lib \
+ megaco_test_msg_v3_lib \
+ megaco_test_lib
+
+
+INTERNAL_HRL_FILES = \
+ megaco_test_lib.hrl
+
+
+
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
new file mode 100644
index 0000000000..6ec7f3192a
--- /dev/null
+++ b/lib/megaco/vsn.mk
@@ -0,0 +1,144 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+MEGACO_VSN = 3.13
+PRE_VSN =
+APP_VSN = "megaco-$(MEGACO_VSN)$(PRE_VSN)"
+
+TICKETS = OTP-8205 OTP-8239 OTP-8249
+
+TICKETS_3_12 = OTP-8183 OTP-8212
+
+TICKETS_3_11_3 = OTP-8164 OTP-8167 OTP-8191
+
+TICKETS_3_11_2 = OTP-8123
+
+TICKETS_3_11_1 = OTP-8081 OTP-8114
+
+TICKETS_3_11 = OTP-7302 OTP-7995
+
+TICKETS_3_10_1 = OTP-7926 OTP-7936
+
+TICKETS_3_10_0_1 = OTP-7851
+
+TICKETS_3_10 = OTP-7713 OTP-7743
+
+TICKETS_3_9_4 = OTP-7728 OTP-7733
+
+TICKETS_3_9_3 = OTP-7700
+
+TICKETS_3_9_2 = OTP-7671 OTP-7672
+
+TICKETS_3_9_1_1 = OTP-7614
+
+TICKETS_3_9_1 = OTP-7572 OTP-7573 OTP-7576
+
+TICKETS_3_9 = OTP-7431
+
+TICKETS_3_8_2 = OTP-7534
+
+TICKETS_3_8_1 = OTP-7398 OTP-7417 OTP-7444 OTP-7449 OTP-7455 OTP-7457 OTP-7459
+
+TICKETS_3_8 = OTP-7192 OTP-7228 OTP-7259
+
+TICKETS_3_7_5 = OTP-7286 OTP-7303
+
+TICKETS_3_7_4 = OTP-7249 OTP-7251
+
+TICKETS_3_7_3 = OTP-7168 OTP-7180 OTP-7189 OTP-7216
+
+TICKETS_3_7_2 = OTP-6972 OTP-7138
+
+TICKETS_3_7_1 = OTP-6919 OTP-6971 OTP-6992 OTP-6999 OTP-7000 OTP-7005 OTP-7124
+
+TICKETS_3_7 = OTP-5979 OTP-6753 OTP-6804 OTP-6865 OTP-6919 OTP-6976
+
+TICKETS_3_6_2 = OTP-6921
+
+TICKETS_3_6_1 = OTP-6803
+
+TICKETS_3_6_0_1 = OTP-6704
+
+TICKETS_3_6 = OTP-6185 OTP-6578 OTP-6441 OTP-6442 OTP-6544 OTP-6605 OTP-6609
+
+TICKETS_3_5_3 = OTP-6520 OTP-6549
+
+TICKETS_3_5_2 = OTP-6404 OTP-6422 OTP-6490 OTP-6503
+
+TICKETS_3_5_1 = OTP-6275 OTP-6276
+
+TICKETS_3_5 = OTP-6223 OTP-6253 OTP-6256
+
+TICKETS_3_4_4 = OTP-6181 OTP-6182 OTP-6217 OTP-6219
+
+TICKETS_3_4_3 = OTP-6170 OTP-6171 OTP-6172
+
+TICKETS_3_4_2 = OTP-6148
+
+TICKETS_3_4_1 = OTP-6113
+
+TICKETS_3_4 = \
+ OTP-5769 \
+ OTP-5980 \
+ OTP-6009 \
+ OTP-6025 \
+ OTP-6028 \
+ OTP-6030 \
+ OTP-6048 \
+ OTP-6051 \
+ OTP-6052 \
+ OTP-6055 \
+ OTP-6089 \
+ OTP-6090
+
+TICKETS_3_3_5 = OTP-6108
+
+TICKETS_3_3_4 = OTP-6076
+
+TICKETS_3_3_3 = OTP-6046
+
+TICKETS_3_3_2 = OTP-6017 OTP-6022
+
+TICKETS_3_3_1 = OTP-5993
+
+TICKETS_3_3 = OTP-5965 OTP-5973
+
+TICKETS_3_2_7 = OTP-5948 OTP-5952 OTP-5953
+
+TICKETS_3_2_6 = OTP-5918 OTP-5919 OTP-5920
+
+TICKETS_3_2_5 = OTP-5887
+
+TICKETS_3_2_4 = OTP-5867 OTP-5879 OTP-5880 OTP-5881 OTP-5882 OTP-5885 OTP-5886
+
+TICKETS_3_2_3 = OTP-5826 OTP-5830 OTP-5833 OTP-5836 OTP-5839
+
+TICKETS_3_2_2 = OTP-5799 OTP-5803 OTP-5804 OTP-5805 OTP-5816
+
+TICKETS_3_2_1 = OTP-5725 OTP-5793
+
+TICKETS_3_2 = OTP-5717 OTP-5750
+
+TICKETS_3_1 = OTP-5542 OTP-5597 OTP-5600 OTP-5601 OTP-5619 OTP-5664
+
+TICKETS_3_0_1 = \
+ OTP-5401 \
+ OTP-5446 \
+ OTP-5447
+